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 19 module dmdscript.dfunction; 20 21 import std.string; 22 import core.stdc.stdlib; 23 24 import dmdscript.script; 25 import dmdscript.dobject; 26 import dmdscript.value; 27 import dmdscript.protoerror; 28 import dmdscript.threadcontext; 29 import dmdscript.text; 30 import dmdscript.errmsgs; 31 import dmdscript.property; 32 import dmdscript.scopex; 33 import dmdscript.dnative; 34 import dmdscript.functiondefinition; 35 import dmdscript.parse; 36 import dmdscript.ddeclaredfunction; 37 38 /* ===================== Dfunction_constructor ==================== */ 39 40 class DfunctionConstructor : Dfunction 41 { 42 this(CallContext* cc) 43 { 44 super(cc, 1, cc.tc.Dfunction_prototype); 45 46 // Actually put in later by Dfunction::initialize() 47 //unsigned attributes = DontEnum | DontDelete | ReadOnly; 48 //Put(TEXT_prototype, Dfunction::getPrototype(), attributes); 49 } 50 51 override void *Construct(CallContext *cc, Value *ret, Value[] arglist) 52 { 53 // ECMA 15.3.2.1 54 immutable(char)[] bdy; 55 immutable(char)[] P; 56 FunctionDefinition fd; 57 ErrInfo errinfo; 58 59 //writef("Dfunction_constructor::Construct()\n"); 60 61 // Get parameter list (P) and body from arglist[] 62 if(arglist.length) 63 { 64 bdy = arglist[arglist.length - 1].toString(cc); 65 if(arglist.length >= 2) 66 { 67 for(uint a = 0; a < arglist.length - 1; a++) 68 { 69 if(a) 70 P ~= ','; 71 P ~= arglist[a].toString(cc); 72 } 73 } 74 } 75 76 if(Parser.parseFunctionDefinition(fd, P, bdy, errinfo)) 77 goto Lsyntaxerror; 78 79 if(fd) 80 { 81 Scope sc; 82 83 sc.ctor(fd); 84 fd.semantic(&sc); 85 errinfo = sc.errinfo; 86 if(errinfo.message) 87 goto Lsyntaxerror; 88 fd.toIR(null); 89 Dfunction fobj = new DdeclaredFunction(cc, fd); 90 assert(cc.scoperoot <= cc.scopex.length); 91 fobj.scopex = cc.scopex[0..cc.scoperoot].dup; 92 ret.putVobject(fobj); 93 } 94 else 95 ret.putVundefined(); 96 97 return null; 98 99 Lsyntaxerror: 100 Dobject o; 101 102 ret.putVundefined(); 103 o = new syntaxerror.D0(cc, &errinfo); 104 Value* v = new Value; 105 v.putVobject(o); 106 return v; 107 } 108 109 override void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist) 110 { 111 // ECMA 15.3.1 112 return Construct(cc, ret, arglist); 113 } 114 } 115 116 117 /* ===================== Dfunction_prototype_toString =============== */ 118 119 void* Dfunction_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 120 { 121 immutable(char)[] s; 122 Dfunction f; 123 124 //writef("function.prototype.toString()\n"); 125 // othis must be a Function 126 if(!othis.isClass(TEXT_Function)) 127 { 128 ErrInfo errinfo; 129 ret.putVundefined(); 130 return Dobject.RuntimeError(&errinfo, cc, ERR_TS_NOT_TRANSFERRABLE); 131 } 132 else 133 { 134 // Generate string that looks like a FunctionDeclaration 135 // FunctionDeclaration: 136 // function Identifier (Identifier, ...) Block 137 138 // If anonymous function, the name should be "anonymous" 139 // per ECMA 15.3.2.1.19 140 141 f = cast(Dfunction)othis; 142 s = f.toString(); 143 ret.putVstring(s); 144 } 145 return null; 146 } 147 148 /* ===================== Dfunction_prototype_apply =============== */ 149 150 void* Dfunction_prototype_apply(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 151 { 152 // ECMA v3 15.3.4.3 153 154 Value* thisArg; 155 Value* argArray; 156 Dobject o; 157 void* v; 158 159 thisArg = &vundefined; 160 argArray = &vundefined; 161 switch(arglist.length) 162 { 163 case 0: 164 break; 165 default: 166 argArray = &arglist[1]; 167 goto case; 168 case 1: 169 thisArg = &arglist[0]; 170 break; 171 } 172 173 if(thisArg.isUndefinedOrNull()) 174 o = cc.global; 175 else 176 o = thisArg.toObject(cc); 177 178 if(argArray.isUndefinedOrNull()) 179 { 180 v = othis.Call(cc, o, ret, null); 181 } 182 else 183 { 184 if(argArray.isPrimitive()) 185 { 186 Ltypeerror: 187 ret.putVundefined(); 188 ErrInfo errinfo; 189 return Dobject.RuntimeError(&errinfo, cc, ERR_ARRAY_ARGS); 190 } 191 Dobject a; 192 193 a = argArray.toObject(cc); 194 195 // Must be array or arguments object 196 if(!a.isDarray() && !a.isDarguments()) 197 goto Ltypeerror; 198 199 uint len; 200 uint i; 201 Value[] alist; 202 Value* x; 203 204 x = a.Get(TEXT_length); 205 len = x ? x.toUint32(cc) : 0; 206 207 Value[] p1; 208 Value* v1; 209 if(len < 128) 210 v1 = cast(Value*)alloca(len * Value.sizeof); 211 if(v1) 212 alist = v1[0 .. len]; 213 else 214 { 215 p1 = new Value[len]; 216 alist = p1; 217 } 218 219 for(i = 0; i < len; i++) 220 { 221 x = a.Get(i); 222 Value.copy(&alist[i], x); 223 } 224 225 v = othis.Call(cc, o, ret, alist); 226 227 destroy(p1); 228 } 229 return v; 230 } 231 232 /* ===================== Dfunction_prototype_call =============== */ 233 234 void* Dfunction_prototype_call(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 235 { 236 // ECMA v3 15.3.4.4 237 Value* thisArg; 238 Dobject o; 239 void* v; 240 241 if(arglist.length == 0) 242 { 243 o = cc.global; 244 v = othis.Call(cc, o, ret, arglist); 245 } 246 else 247 { 248 thisArg = &arglist[0]; 249 if(thisArg.isUndefinedOrNull()) 250 o = cc.global; 251 else 252 o = thisArg.toObject(cc); 253 v = othis.Call(cc, o, ret, arglist[1 .. $]); 254 } 255 return v; 256 } 257 258 /* ===================== Dfunction_prototype ==================== */ 259 260 class DfunctionPrototype : Dfunction 261 { 262 this(CallContext* cc) 263 { 264 super(cc, 0, cc.tc.Dobject_prototype); 265 266 uint attributes = DontEnum; 267 268 classname = TEXT_Function; 269 name = "prototype"; 270 Put(cc, TEXT_constructor, cc.tc.Dfunction_constructor, attributes); 271 272 static enum NativeFunctionData[] nfd = 273 [ 274 { TEXT_toString, &Dfunction_prototype_toString, 0 }, 275 { TEXT_apply, &Dfunction_prototype_apply, 2 }, 276 { TEXT_call, &Dfunction_prototype_call, 1 }, 277 ]; 278 279 DnativeFunction.initialize(this, cc, nfd, attributes); 280 } 281 282 override void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist) 283 { 284 // ECMA v3 15.3.4 285 // Accept any arguments and return "undefined" 286 ret.putVundefined(); 287 return null; 288 } 289 } 290 291 292 /* ===================== Dfunction ==================== */ 293 294 class Dfunction : Dobject 295 { const (char)[] name; 296 Dobject[] scopex; // Function object's scope chain per 13.2 step 7 297 298 this(CallContext* cc, d_uint32 length) 299 { 300 this(cc, length, Dfunction.getPrototype(cc)); 301 } 302 303 this(CallContext* cc, d_uint32 length, Dobject prototype) 304 { 305 super(cc, prototype); 306 classname = TEXT_Function; 307 name = TEXT_Function; 308 Put(cc, TEXT_length, length, DontDelete | DontEnum | ReadOnly); 309 Put(cc, TEXT_arity, length, DontDelete | DontEnum | ReadOnly); 310 } 311 312 override immutable(char)[] getTypeof() 313 { // ECMA 11.4.3 314 return TEXT_function; 315 } 316 317 override string toString() 318 { 319 // Native overrides of this function replace Identifier with the actual name. 320 // Don't need to do parameter list, though. 321 immutable(char)[] s; 322 323 s = std..string.format("function %s() { [native code] }", name); 324 return s; 325 } 326 327 override void *HasInstance(CallContext* cc, Value* ret, Value* v) 328 { 329 // ECMA v3 15.3.5.3 330 Dobject V; 331 Value* w; 332 Dobject o; 333 334 if(v.isPrimitive()) 335 goto Lfalse; 336 V = v.toObject(cc); 337 w = Get(TEXT_prototype); 338 if(w.isPrimitive()) 339 { 340 ErrInfo errinfo; 341 return RuntimeError(&errinfo, cc, errmsgtbl[ERR_MUST_BE_OBJECT], w.getType()); 342 } 343 o = w.toObject(cc); 344 for(;; ) 345 { 346 V = V.internal_prototype; 347 if(!V) 348 goto Lfalse; 349 if(o == V) 350 goto Ltrue; 351 } 352 353 Ltrue: 354 ret.putVboolean(true); 355 return null; 356 357 Lfalse: 358 ret.putVboolean(false); 359 return null; 360 } 361 362 static Dfunction isFunction(Value* v, CallContext* cc) 363 { 364 Dfunction r; 365 Dobject o; 366 367 r = null; 368 if(!v.isPrimitive()) 369 { 370 o = v.toObject(cc); 371 if(o.isClass(TEXT_Function)) 372 r = cast(Dfunction)o; 373 } 374 return r; 375 } 376 377 378 static Dfunction getConstructor(CallContext* cc) 379 { 380 return cc.tc.Dfunction_constructor; 381 } 382 383 static Dobject getPrototype(CallContext* cc) 384 { 385 return cc.tc.Dfunction_prototype; 386 } 387 388 static void initialize(CallContext* cc) 389 { 390 cc.tc.Dfunction_constructor = new DfunctionConstructor(cc); 391 cc.tc.Dfunction_prototype = new DfunctionPrototype(cc); 392 393 cc.tc.Dfunction_constructor.Put(cc, TEXT_prototype, cc.tc.Dfunction_prototype, DontEnum | DontDelete | ReadOnly); 394 395 cc.tc.Dfunction_constructor.internal_prototype = cc.tc.Dfunction_prototype; 396 cc.tc.Dfunction_constructor.proptable.previous = cc.tc.Dfunction_prototype.proptable; 397 } 398 }