1 /* Digital Mars DMDScript source code. 2 * Copyright (c) 2000-2002 by Chromium Communications 3 * D version Copyright (c) 2004-2010 by Digital Mars 4 * Distributed under the Boost Software License, Version 1.0. 5 * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 * written by Walter Bright 7 * http://www.digitalmars.com 8 * 9 * D2 port by Dmitry Olshansky 10 * 11 * DMDScript is implemented in the D Programming Language, 12 * http://www.digitalmars.com/d/ 13 * 14 * For a C++ implementation of DMDScript, including COM support, see 15 * http://www.digitalmars.com/dscript/cppscript.html 16 */ 17 18 module dmdscript.ddeclaredfunction; 19 20 import std.stdio; 21 import core.stdc.stdlib; 22 import std.exception; 23 import dmdscript.script; 24 import dmdscript.dobject; 25 import dmdscript.dfunction; 26 import dmdscript.darguments; 27 import dmdscript.opcodes; 28 import dmdscript.ir; 29 import dmdscript.identifier; 30 import dmdscript.value; 31 import dmdscript.functiondefinition; 32 import dmdscript.text; 33 import dmdscript.property; 34 35 /* ========================== DdeclaredFunction ================== */ 36 37 class DdeclaredFunction : Dfunction 38 { 39 FunctionDefinition fd; 40 41 this(CallContext* cc, FunctionDefinition fd) 42 { 43 super(cc, cast(uint)fd.parameters.length, Dfunction.getPrototype(cc)); 44 assert(Dfunction.getPrototype(cc)); 45 assert(internal_prototype); 46 this.fd = fd; 47 48 Dobject o; 49 50 // ECMA 3 13.2 51 o = new Dobject(cc, Dobject.getPrototype(cc)); // step 9 52 Put(cc, TEXT_prototype, o, DontEnum); // step 11 53 o.Put(cc, TEXT_constructor, this, DontEnum); // step 10 54 } 55 56 override void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist) 57 { 58 // 1. Create activation object per ECMA 10.1.6 59 // 2. Instantiate function variables as properties of 60 // activation object 61 // 3. The 'this' value is the activation object 62 63 Dobject actobj; // activation object 64 Darguments args; 65 Value[] locals; 66 uint i; 67 void *result; 68 69 //writefln("DdeclaredFunction.Call() '%s'", toString()); 70 //writefln("this.scopex.length = %d", this.scopex.length); 71 //writefln("\tinstantiate(this = %x, fd = %x)", cast(uint)cast(void*)this, cast(uint)cast(void*)fd); 72 73 // if it's an empty function, just return 74 if(fd.code[0].opcode == IRret) 75 { 76 return null; 77 } 78 79 // Generate the activation object 80 // ECMA v3 10.1.6 81 actobj = new Dobject(cc, null); 82 83 Value vtmp;//should not be referenced by the end of func 84 if(fd.name){ 85 vtmp.putVobject(this); 86 actobj.Put(cc, fd.name,&vtmp,DontDelete); 87 } 88 // Instantiate the parameters 89 { 90 uint a = 0; 91 foreach(Identifier* p; fd.parameters) 92 { 93 Value* v = (a < arglist.length) ? &arglist[a++] : &vundefined; 94 actobj.Put(cc, p.toString(), v, DontDelete); 95 } 96 } 97 98 // Generate the Arguments Object 99 // ECMA v3 10.1.8 100 args = new Darguments(cc, cc.caller, this, actobj, fd.parameters, arglist); 101 102 actobj.Put(cc, TEXT_arguments, args, DontDelete); 103 104 // The following is not specified by ECMA, but seems to be supported 105 // by jscript. The url www.grannymail.com has the following code 106 // which looks broken to me but works in jscript: 107 // 108 // function MakeArray() { 109 // this.length = MakeArray.arguments.length 110 // for (var i = 0; i < this.length; i++) 111 // this[i+1] = arguments[i] 112 // } 113 // var cardpic = new MakeArray("LL","AP","BA","MB","FH","AW","CW","CV","DZ"); 114 Put(cc, TEXT_arguments, args, DontDelete); // make grannymail bug work 115 116 117 118 119 Dobject[] newScopex; 120 newScopex = this.scopex.dup;//copy this function object scope chain 121 assert(newScopex.length != 0); 122 newScopex ~= actobj;//and put activation object on top of it 123 124 fd.instantiate(cc, newScopex, actobj, DontDelete); 125 126 Dobject[] scopesave = cc.scopex; 127 cc.scopex = newScopex; 128 auto scoperootsave = cc.scoperoot; 129 cc.scoperoot++;//to accaunt extra activation object on scopex chain 130 Dobject variablesave = cc.variable; 131 cc.variable = actobj; 132 auto callersave = cc.caller; 133 cc.caller = this; 134 auto callerfsave = cc.callerf; 135 cc.callerf = fd; 136 137 Value[] p1; 138 Value* v; 139 if(fd.nlocals < 128) 140 v = cast(Value*)alloca(fd.nlocals * Value.sizeof); 141 if(v) 142 locals = v[0 .. fd.nlocals]; 143 else 144 { 145 p1 = new Value[fd.nlocals]; 146 locals = p1; 147 } 148 149 result = IR.call(cc, othis, fd.code, ret, locals.ptr); 150 151 destroy(p1); 152 153 cc.callerf = callerfsave; 154 cc.caller = callersave; 155 cc.variable = variablesave; 156 cc.scopex = scopesave; 157 cc.scoperoot = scoperootsave; 158 159 // Remove the arguments object 160 //Value* v; 161 //v=Get(TEXT_arguments); 162 //writef("1v = %x, %s, v.object = %x\n", v, v.getType(), v.object); 163 Put(cc, TEXT_arguments, &vundefined, 0); 164 //actobj.Put(TEXT_arguments, &vundefined, 0); 165 166 version(none) 167 { 168 writef("args = %x, actobj = %x\n", args, actobj); 169 v = Get(TEXT_arguments); 170 writef("2v = %x, %s, v.object = %x\n", v, v.getType(), v.object); 171 v.object = null; 172 173 { 174 uint *p = cast(uint *)0x40a49a80; 175 uint i; 176 for(i = 0; i < 16; i++) 177 { 178 writef("p[%x] = %x\n", &p[i], p[i]); 179 } 180 } 181 } 182 183 return result; 184 } 185 186 override void *Construct(CallContext *cc, Value *ret, Value[] arglist) 187 { 188 // ECMA 3 13.2.2 189 Dobject othis; 190 Dobject proto; 191 Value* v; 192 void *result; 193 194 v = Get(TEXT_prototype); 195 if(v.isPrimitive()) 196 proto = Dobject.getPrototype(cc); 197 else 198 proto = v.toObject(cc); 199 othis = new Dobject(cc, proto); 200 result = Call(cc, othis, ret, arglist); 201 if(!result) 202 { 203 if(ret.isPrimitive()) 204 ret.putVobject(othis); 205 } 206 return result; 207 } 208 209 override string toString() 210 { 211 char[] s; 212 213 //writef("DdeclaredFunction.toString()\n"); 214 fd.toBuffer(s); 215 return assumeUnique(s); 216 } 217 } 218 219