0
|
1
|
|
2 /* Digital Mars DMDScript source code.
|
|
3 * Copyright (c) 2000-2002 by Chromium Communications
|
|
4 * D version Copyright (c) 2004-2005 by Digital Mars
|
|
5 * All Rights Reserved
|
|
6 * written by Walter Bright
|
|
7 * www.digitalmars.com
|
|
8 * Use at your own risk. There is no warranty, express or implied.
|
|
9 * License for redistribution is by the GNU General Public License in gpl.txt.
|
|
10 *
|
|
11 * A binary, non-exclusive license for commercial use can be
|
|
12 * purchased from www.digitalmars.com/dscript/buy.html.
|
|
13 *
|
|
14 * DMDScript is implemented in the D Programming Language,
|
|
15 * www.digitalmars.com/d/
|
|
16 *
|
|
17 * For a C++ implementation of DMDScript, including COM support,
|
|
18 * see www.digitalmars.com/dscript/cppscript.html.
|
|
19 */
|
|
20
|
|
21
|
|
22 module dmdscript.dfunction;
|
|
23
|
|
24 import std.string;
|
|
25 import std.c.stdlib;
|
|
26
|
|
27 import dmdscript.script;
|
|
28 import dmdscript.dobject;
|
|
29 import dmdscript.value;
|
|
30 import dmdscript.protoerror;
|
|
31 import dmdscript.threadcontext;
|
|
32 import dmdscript.text;
|
|
33 import dmdscript.errmsgs;
|
|
34 import dmdscript.property;
|
|
35 import dmdscript.scopex;
|
|
36 import dmdscript.dnative;
|
|
37 import dmdscript.functiondefinition;
|
|
38 import dmdscript.parse;
|
|
39 import dmdscript.ddeclaredfunction;
|
|
40
|
|
41 /* ===================== Dfunction_constructor ==================== */
|
|
42
|
|
43 class Dfunction_constructor : Dfunction
|
|
44 {
|
|
45 this(ThreadContext *tc)
|
|
46 {
|
|
47 super(1, tc.Dfunction_prototype);
|
|
48
|
|
49 // Actually put in later by Dfunction::init()
|
|
50 //unsigned attributes = DontEnum | DontDelete | ReadOnly;
|
|
51 //Put(TEXT_prototype, Dfunction::getPrototype(), attributes);
|
|
52 }
|
|
53
|
|
54 void *Construct(CallContext *cc, Value *ret, Value[] arglist)
|
|
55 {
|
|
56 // ECMA 15.3.2.1
|
|
57 d_string bdy;
|
|
58 d_string P;
|
|
59 FunctionDefinition fd;
|
|
60 ErrInfo errinfo;
|
|
61
|
|
62 //writef("Dfunction_constructor::Construct()\n");
|
|
63
|
|
64 // Get parameter list (P) and body from arglist[]
|
|
65 if (arglist.length)
|
|
66 {
|
|
67 bdy = arglist[arglist.length - 1].toString();
|
|
68 if (arglist.length >= 2)
|
|
69 {
|
|
70 for (uint a = 0; a < arglist.length - 1; a++)
|
|
71 {
|
|
72 if (a)
|
|
73 P ~= ',';
|
|
74 P ~= arglist[a].toString();
|
|
75 }
|
|
76 }
|
|
77 }
|
|
78
|
|
79 if (Parser.parseFunctionDefinition(fd, P, bdy, errinfo))
|
|
80 goto Lsyntaxerror;
|
|
81
|
|
82 if (fd)
|
|
83 {
|
|
84 Scope sc;
|
|
85
|
|
86 sc.ctor(fd);
|
|
87 fd.semantic(&sc);
|
|
88 errinfo = sc.errinfo;
|
|
89 if (errinfo.message)
|
|
90 goto Lsyntaxerror;
|
|
91 fd.toIR(null);
|
|
92 Dfunction fobj = new DdeclaredFunction(fd);
|
|
93 ret.putVobject(fobj);
|
|
94 }
|
|
95 else
|
|
96 ret.putVundefined();
|
|
97
|
|
98 return null;
|
|
99
|
|
100 Lsyntaxerror:
|
|
101 Dobject o;
|
|
102
|
|
103 ret.putVundefined();
|
|
104 o = new syntaxerror.D0(&errinfo);
|
|
105 Value* v = new Value;
|
|
106 v.putVobject(o);
|
|
107 return v;
|
|
108 }
|
|
109
|
|
110 void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
|
|
111 {
|
|
112 // ECMA 15.3.1
|
|
113 return Construct(cc, ret, arglist);
|
|
114 }
|
|
115 }
|
|
116
|
|
117
|
|
118 /* ===================== Dfunction_prototype_toString =============== */
|
|
119
|
|
120 void* Dfunction_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
|
|
121 {
|
|
122 d_string s;
|
|
123 Dfunction f;
|
|
124
|
|
125 //writef("function.prototype.toString()\n");
|
|
126 // othis must be a Function
|
|
127 if (!othis.isClass(TEXT_Function))
|
|
128 { ErrInfo errinfo;
|
|
129 ret.putVundefined();
|
|
130 return Dobject.RuntimeError(&errinfo, 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 case 1:
|
|
168 thisArg = &arglist[0];
|
|
169 break;
|
|
170 }
|
|
171
|
|
172 if (thisArg.isUndefinedOrNull())
|
|
173 o = cc.global;
|
|
174 else
|
|
175 o = thisArg.toObject();
|
|
176
|
|
177 if (argArray.isUndefinedOrNull())
|
|
178 {
|
|
179 v = othis.Call(cc, o, ret, null);
|
|
180 }
|
|
181 else
|
|
182 {
|
|
183 if (argArray.isPrimitive())
|
|
184 {
|
|
185 Ltypeerror:
|
|
186 ret.putVundefined();
|
|
187 ErrInfo errinfo;
|
|
188 return Dobject.RuntimeError(&errinfo, ERR_ARRAY_ARGS);
|
|
189 }
|
|
190 Dobject a;
|
|
191
|
|
192 a = argArray.toObject();
|
|
193
|
|
194 // Must be array or arguments object
|
|
195 if (!a.isDarray() && !a.isDarguments())
|
|
196 goto Ltypeerror;
|
|
197
|
|
198 uint len;
|
|
199 uint i;
|
|
200 Value[] alist;
|
|
201 Value* x;
|
|
202
|
|
203 x = a.Get(TEXT_length);
|
|
204 len = x ? x.toUint32() : 0;
|
|
205
|
|
206 Value[] p1;
|
|
207 Value* v1;
|
|
208 if (len < 128)
|
|
209 v1 = cast(Value*)alloca(len * Value.sizeof);
|
|
210 if (v1)
|
|
211 alist = v1[0 .. len];
|
|
212 else
|
|
213 { p1 = new Value[len];
|
|
214 alist = p1;
|
|
215 }
|
|
216
|
|
217 for (i = 0; i < len; i++)
|
|
218 {
|
|
219 x = a.Get(i);
|
|
220 Value.copy(&alist[i], x);
|
|
221 }
|
|
222
|
|
223 v = othis.Call(cc, o, ret, alist);
|
|
224
|
|
225 delete p1;
|
|
226 }
|
|
227 return v;
|
|
228 }
|
|
229
|
|
230 /* ===================== Dfunction_prototype_call =============== */
|
|
231
|
|
232 void* Dfunction_prototype_call(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
|
|
233 {
|
|
234 // ECMA v3 15.3.4.4
|
|
235 Value* thisArg;
|
|
236 Dobject o;
|
|
237 void* v;
|
|
238
|
|
239 if (arglist.length == 0)
|
|
240 {
|
|
241 o = cc.global;
|
|
242 v = othis.Call(cc, o, ret, arglist);
|
|
243 }
|
|
244 else
|
|
245 {
|
|
246 thisArg = &arglist[0];
|
|
247 if (thisArg.isUndefinedOrNull())
|
|
248 o = cc.global;
|
|
249 else
|
|
250 o = thisArg.toObject();
|
|
251 v = othis.Call(cc, o, ret, arglist[1 .. length]);
|
|
252 }
|
|
253 return v;
|
|
254 }
|
|
255
|
|
256 /* ===================== Dfunction_prototype ==================== */
|
|
257
|
|
258 class Dfunction_prototype : Dfunction
|
|
259 {
|
|
260 this(ThreadContext *tc)
|
|
261 {
|
|
262 super(0, tc.Dobject_prototype);
|
|
263
|
|
264 uint attributes = DontEnum;
|
|
265
|
|
266 classname = TEXT_Function;
|
|
267 name = "prototype";
|
|
268 Put(TEXT_constructor, tc.Dfunction_constructor, attributes);
|
|
269
|
|
270 static NativeFunctionData nfd[] =
|
|
271 [
|
|
272 { &TEXT_toString, &Dfunction_prototype_toString, 0 },
|
|
273 { &TEXT_apply, &Dfunction_prototype_apply, 2 },
|
|
274 { &TEXT_call, &Dfunction_prototype_call, 1 },
|
|
275 ];
|
|
276
|
|
277 DnativeFunction.init(this, nfd, attributes);
|
|
278 }
|
|
279
|
|
280 void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
|
|
281 {
|
|
282 // ECMA v3 15.3.4
|
|
283 // Accept any arguments and return "undefined"
|
|
284 ret.putVundefined();
|
|
285 return null;
|
|
286 }
|
|
287 }
|
|
288
|
|
289
|
|
290 /* ===================== Dfunction ==================== */
|
|
291
|
|
292 class Dfunction : Dobject
|
|
293 { tchar[] name;
|
|
294 Dobject[] scopex; // Function object's scope chain per 13.2 step 7
|
|
295
|
|
296 this(d_uint32 length)
|
|
297 {
|
|
298 this(length, Dfunction.getPrototype());
|
|
299 }
|
|
300
|
|
301 this(d_uint32 length, Dobject prototype)
|
|
302 {
|
|
303 super(prototype);
|
|
304 classname = TEXT_Function;
|
|
305 name = TEXT_Function;
|
|
306 Put(TEXT_length, length, DontDelete | DontEnum | ReadOnly);
|
|
307 Put(TEXT_arity, length, DontDelete | DontEnum | ReadOnly);
|
|
308 }
|
|
309
|
|
310 d_string getTypeof()
|
|
311 { // ECMA 11.4.3
|
|
312 return TEXT_function;
|
|
313 }
|
|
314
|
|
315 d_string toString()
|
|
316 {
|
|
317 // Native overrides of this function replace Identifier with the actual name.
|
|
318 // Don't need to do parameter list, though.
|
|
319 d_string s;
|
|
320
|
|
321 s = std.string.format("function %s() { [native code] }", name);
|
|
322 return s;
|
|
323 }
|
|
324
|
|
325 void *HasInstance(Value* ret, Value* v)
|
|
326 {
|
|
327 // ECMA v3 15.3.5.3
|
|
328 Dobject V;
|
|
329 Value* w;
|
|
330 Dobject o;
|
|
331
|
|
332 if (v.isPrimitive())
|
|
333 goto Lfalse;
|
|
334 V = v.toObject();
|
|
335 w = Get(TEXT_prototype);
|
|
336 if (w.isPrimitive())
|
|
337 { ErrInfo errinfo;
|
|
338 return RuntimeError(&errinfo, errmsgtbl[ERR_MUST_BE_OBJECT], w.getType());
|
|
339 }
|
|
340 o = w.toObject();
|
|
341 for (;;)
|
|
342 {
|
|
343 V = V.internal_prototype;
|
|
344 if (!V)
|
|
345 goto Lfalse;
|
|
346 if (o == V)
|
|
347 goto Ltrue;
|
|
348 }
|
|
349
|
|
350 Ltrue:
|
|
351 ret.putVboolean(true);
|
|
352 return null;
|
|
353
|
|
354 Lfalse:
|
|
355 ret.putVboolean(false);
|
|
356 return null;
|
|
357 }
|
|
358
|
|
359 static Dfunction isFunction(Value* v)
|
|
360 {
|
|
361 Dfunction r;
|
|
362 Dobject o;
|
|
363
|
|
364 r = null;
|
|
365 if (!v.isPrimitive())
|
|
366 {
|
|
367 o = v.toObject();
|
|
368 if (o.isClass(TEXT_Function))
|
|
369 r = cast(Dfunction)o;
|
|
370 }
|
|
371 return r;
|
|
372 }
|
|
373
|
|
374
|
|
375 static Dfunction getConstructor()
|
|
376 {
|
|
377 ThreadContext *tc = ThreadContext.getThreadContext();
|
|
378 assert(tc);
|
|
379 return tc.Dfunction_constructor;
|
|
380 }
|
|
381
|
|
382 static Dobject getPrototype()
|
|
383 {
|
|
384 ThreadContext *tc = ThreadContext.getThreadContext();
|
|
385 assert(tc);
|
|
386 return tc.Dfunction_prototype;
|
|
387 }
|
|
388
|
|
389 static void init(ThreadContext *tc)
|
|
390 {
|
|
391 tc.Dfunction_constructor = new Dfunction_constructor(tc);
|
|
392 tc.Dfunction_prototype = new Dfunction_prototype(tc);
|
|
393
|
|
394 tc.Dfunction_constructor.Put(TEXT_prototype, tc.Dfunction_prototype, DontEnum | DontDelete | ReadOnly);
|
|
395
|
|
396 tc.Dfunction_constructor.internal_prototype = tc.Dfunction_prototype;
|
|
397 tc.Dfunction_constructor.proptable.previous = tc.Dfunction_prototype.proptable;
|
|
398 }
|
|
399 }
|