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