1 /* Distributed under the Boost Software License, Version 1.0.
2  * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
3  *
4  * extending.d - experimental facility for ease of extending DMDScript 
5  *
6  * written by Dmitry Olshansky 2010
7  * 
8  * DMDScript is implemented in the D Programming Language,
9  * http://www.digitalmars.com/d/
10  *
11  * For a C++ implementation of DMDScript, including COM support, see
12  * http://www.digitalmars.com/dscript/cppscript.html
13  */
14 module dmdscript.extending;
15 
16 import dmdscript.script;
17 import dmdscript.value;
18 import dmdscript.dobject;
19 import dmdscript.dfunction;
20 import dmdscript.dnative;
21 import dmdscript.program;
22 import dmdscript.property;
23 import dmdscript.threadcontext;
24 
25 import std.typecons;
26 import std.traits;
27 import std.typetuple;
28 import std.file;
29 
30 
31 T convert(T)(Value* v){
32 	static if(is(T == int)){
33 		return v.toInt32();
34     }else static if(isSomeString!T ){
35         return v.toString();   
36 	}else{
37 		assert(0);	
38 	}
39 }
40 
41 void convertPut(T)(ref T what,Value* v){
42     static if(isIntegral!T || isFloatingPoint!T){
43         v.putVnumber(what);
44     }
45 }
46 
47 //experimental stuff, eventually will be moved to the main library
48 void extendGlobal(alias fn)(Program pg, string name)
49 if(isCallable!fn) {
50     alias ParameterTypeTuple!fn Args;
51     alias ReturnType!fn R;
52     alias staticMap!(Unqual,Args) Uargs;
53 	static void* embedded(Dobject pthis, CallContext* cc,
54                           Dobject othis, Value* ret,	Value[] arglist){
55        
56         Tuple!(Uargs) tup = convertAll!(Uargs)(arglist);
57         if(arglist.length < tup.length){
58             auto len = arglist.length;
59             arglist.length = tup.length;
60             arglist[len .. $] = vundefined;
61         }
62         arglist = arglist[0..tup.length];
63         
64         static if(is(R == void)){
65             fn(tup.expand);
66         }else{
67             R r = fn(tup.expand);
68             convertPut(r,ret);
69         }
70         return null;
71     }
72     NativeFunctionData[] nfd = [
73         {
74             name,
75             &embedded,
76             Args.length
77         }
78     ];
79     DnativeFunction.initialize(pg.callcontext.global,nfd,DontEnum);
80 }
81                                     
82 void fitArray(T...)(ref Value[] arglist){
83     enum staticLen = T.length;
84     if(arglist.length < staticLen){
85         auto len = arglist.length;
86         arglist.length = staticLen;
87         arglist[len .. $] = vundefined;
88     }
89     arglist = arglist[0..staticLen];
90 }
91                  
92 void extendMethod(T,alias fn)(Dobject obj, string name)
93 if(is(T == class) && isCallable!fn){
94     alias ParameterTypeTuple!fn Args;
95     alias ReturnType!fn R;
96     alias staticMap!(Unqual,Args) Uargs;
97 	static void* embedded(Dobject pthis, CallContext* cc,
98                           Dobject othis, Value* ret,	Value[] arglist){
99 
100         static if(Uargs.length){
101             Tuple!(Uargs) tup = convertAll!(Uargs)(arglist);
102         
103             fitArray(arglist);
104         }
105         assert(cast(T)othis,"Wrong this pointer in external func ");
106         static if(Uargs.length){
107              auto dg = (){ mixin("(cast(T)othis).wrapped."~(&fn).stringof[2..$]~"(tup.expand);"); };
108         } else{
109              auto dg = (){ mixin("(cast(T)othis).wrapped."~(&fn).stringof[2..$]~"();"); };   
110         }
111         
112         static if(is(R == void)){
113             dg();
114         }else{
115             R r = dg();
116             convertPut(r,ret);
117         }
118         return null;
119     }
120     NativeFunctionData[] nfd = [
121         {
122             name,
123             &embedded,
124             Args.length
125         }
126     ];
127     DnativeFunction.initialize(obj,nfd,DontEnum);
128 }                          
129 class Wrap(Which,string ClassName,Base=Dobject): Base{
130     Which wrapped;
131     static Wrap _prototype;
132     static Constructor _constructor;
133     static class Constructor: Dfunction{
134         this(){
135             super(ConstructorArgs.length, Dfunction_prototype);
136             name = ClassName;
137         }
138 
139         override void *Construct(CallContext *cc, Value *ret, Value[] arglist){
140             fitArray!(ConstructorArgs)(arglist);
141             Dobject o = new Wrap(convertAll!(UConstructorArgs)(arglist).expand);
142             ret.putVobject(o);
143             return null;
144         }
145 
146         override void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist){
147             return Construct(cc,ret,arglist);
148         }
149     
150     }
151     static void initialize(){
152          _prototype = new Wrap(Base.getPrototype());
153         _constructor = new Constructor();
154         _prototype.Put("constructor", _constructor, DontEnum);
155         _constructor.Put("prototype", _prototype, DontEnum | DontDelete | ReadOnly);
156         ctorTable[ClassName] = _constructor;
157     }
158     static this(){
159         threadInitTable ~= &initialize;
160     }
161     private this(Dobject prototype){ 
162         super(prototype); 
163         classname = ClassName;
164         //Put(TEXT_constructor,
165     }
166     alias ParameterTypeTuple!(Which.__ctor) ConstructorArgs;
167     alias staticMap!(Unqual,ConstructorArgs) UConstructorArgs;
168     this(ConstructorArgs args){
169         super(_prototype);
170         static if (is(Which == struct)){
171             wrapped = Which(args);
172         } 
173     }
174     static void methods(Methods...)(){
175         static if(Methods.length >= 1){
176              extendMethod!(Wrap,Methods[0])(_prototype,(&Methods[0]).stringof[2..$]);
177         
178              methods!(Methods[1..$])();
179         }
180     }
181 }       
182                         
183 auto convertAll(Args...)(Value[] dest){
184     static if(Args.length > 1){
185         return tuple(convert!(Args[0])(&dest[0]),convertAll!(Args[1..$])(dest[1..$]).expand);  
186     }else 
187         return tuple(convert!(Args[0])(&dest[0]));
188 }
189