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
|
3
|
22 module dmdscript_tango.dfunction;
|
0
|
23
|
4
|
24 //import std.string;
|
|
25 //import std.c.stdlib;
|
|
26 import tango.stdc.stdlib;
|
|
27 import tango.text.convert.Format;
|
0
|
28
|
3
|
29 import dmdscript_tango.script;
|
|
30 import dmdscript_tango.dobject;
|
|
31 import dmdscript_tango.value;
|
|
32 import dmdscript_tango.protoerror;
|
|
33 import dmdscript_tango.threadcontext;
|
|
34 import dmdscript_tango.text;
|
|
35 import dmdscript_tango.textgen.errmsgs;
|
|
36 import dmdscript_tango.property;
|
|
37 import dmdscript_tango.scopex;
|
|
38 import dmdscript_tango.dnative;
|
|
39 import dmdscript_tango.functiondefinition;
|
|
40 import dmdscript_tango.parse;
|
|
41 import dmdscript_tango.ddeclaredfunction;
|
0
|
42
|
|
43 /* ===================== Dfunction_constructor ==================== */
|
|
44
|
|
45 class Dfunction_constructor : Dfunction
|
|
46 {
|
|
47 this(ThreadContext *tc)
|
|
48 {
|
|
49 super(1, tc.Dfunction_prototype);
|
|
50
|
|
51 // Actually put in later by Dfunction::init()
|
|
52 //unsigned attributes = DontEnum | DontDelete | ReadOnly;
|
|
53 //Put(TEXT_prototype, Dfunction::getPrototype(), attributes);
|
|
54 }
|
|
55
|
|
56 void *Construct(CallContext *cc, Value *ret, Value[] arglist)
|
|
57 {
|
|
58 // ECMA 15.3.2.1
|
|
59 d_string bdy;
|
|
60 d_string P;
|
|
61 FunctionDefinition fd;
|
|
62 ErrInfo errinfo;
|
|
63
|
|
64 //writef("Dfunction_constructor::Construct()\n");
|
|
65
|
|
66 // Get parameter list (P) and body from arglist[]
|
|
67 if (arglist.length)
|
|
68 {
|
|
69 bdy = arglist[arglist.length - 1].toString();
|
|
70 if (arglist.length >= 2)
|
|
71 {
|
|
72 for (uint a = 0; a < arglist.length - 1; a++)
|
|
73 {
|
|
74 if (a)
|
|
75 P ~= ',';
|
|
76 P ~= arglist[a].toString();
|
|
77 }
|
|
78 }
|
|
79 }
|
|
80
|
|
81 if (Parser.parseFunctionDefinition(fd, P, bdy, errinfo))
|
|
82 goto Lsyntaxerror;
|
|
83
|
|
84 if (fd)
|
|
85 {
|
|
86 Scope sc;
|
|
87
|
|
88 sc.ctor(fd);
|
|
89 fd.semantic(&sc);
|
|
90 errinfo = sc.errinfo;
|
|
91 if (errinfo.message)
|
|
92 goto Lsyntaxerror;
|
|
93 fd.toIR(null);
|
|
94 Dfunction fobj = new DdeclaredFunction(fd);
|
|
95 ret.putVobject(fobj);
|
|
96 }
|
|
97 else
|
|
98 ret.putVundefined();
|
|
99
|
|
100 return null;
|
|
101
|
|
102 Lsyntaxerror:
|
|
103 Dobject o;
|
|
104
|
|
105 ret.putVundefined();
|
|
106 o = new syntaxerror.D0(&errinfo);
|
|
107 Value* v = new Value;
|
|
108 v.putVobject(o);
|
|
109 return v;
|
|
110 }
|
|
111
|
|
112 void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
|
|
113 {
|
|
114 // ECMA 15.3.1
|
|
115 return Construct(cc, ret, arglist);
|
|
116 }
|
|
117 }
|
|
118
|
|
119
|
|
120 /* ===================== Dfunction_prototype_toString =============== */
|
|
121
|
|
122 void* Dfunction_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
|
|
123 {
|
|
124 d_string s;
|
|
125 Dfunction f;
|
|
126
|
|
127 //writef("function.prototype.toString()\n");
|
|
128 // othis must be a Function
|
|
129 if (!othis.isClass(TEXT_Function))
|
|
130 { ErrInfo errinfo;
|
|
131 ret.putVundefined();
|
|
132 return Dobject.RuntimeError(&errinfo, ERR_TS_NOT_TRANSFERRABLE);
|
|
133 }
|
|
134 else
|
|
135 {
|
|
136 // Generate string that looks like a FunctionDeclaration
|
|
137 // FunctionDeclaration:
|
|
138 // function Identifier (Identifier, ...) Block
|
|
139
|
|
140 // If anonymous function, the name should be "anonymous"
|
|
141 // per ECMA 15.3.2.1.19
|
|
142
|
|
143 f = cast(Dfunction)othis;
|
|
144 s = f.toString();
|
|
145 ret.putVstring(s);
|
|
146 }
|
|
147 return null;
|
|
148 }
|
|
149
|
|
150 /* ===================== Dfunction_prototype_apply =============== */
|
|
151
|
|
152 void* Dfunction_prototype_apply(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
|
|
153 {
|
|
154 // ECMA v3 15.3.4.3
|
|
155
|
|
156 Value* thisArg;
|
|
157 Value* argArray;
|
|
158 Dobject o;
|
|
159 void* v;
|
|
160
|
|
161 thisArg = &vundefined;
|
|
162 argArray = &vundefined;
|
|
163 switch (arglist.length)
|
|
164 {
|
|
165 case 0:
|
|
166 break;
|
|
167 default:
|
|
168 argArray = &arglist[1];
|
|
169 case 1:
|
|
170 thisArg = &arglist[0];
|
|
171 break;
|
|
172 }
|
|
173
|
|
174 if (thisArg.isUndefinedOrNull())
|
|
175 o = cc.global;
|
|
176 else
|
|
177 o = thisArg.toObject();
|
|
178
|
|
179 if (argArray.isUndefinedOrNull())
|
|
180 {
|
|
181 v = othis.Call(cc, o, ret, null);
|
|
182 }
|
|
183 else
|
|
184 {
|
|
185 if (argArray.isPrimitive())
|
|
186 {
|
|
187 Ltypeerror:
|
|
188 ret.putVundefined();
|
|
189 ErrInfo errinfo;
|
|
190 return Dobject.RuntimeError(&errinfo, ERR_ARRAY_ARGS);
|
|
191 }
|
|
192 Dobject a;
|
|
193
|
|
194 a = argArray.toObject();
|
|
195
|
|
196 // Must be array or arguments object
|
|
197 if (!a.isDarray() && !a.isDarguments())
|
|
198 goto Ltypeerror;
|
|
199
|
|
200 uint len;
|
|
201 uint i;
|
|
202 Value[] alist;
|
|
203 Value* x;
|
|
204
|
|
205 x = a.Get(TEXT_length);
|
|
206 len = x ? x.toUint32() : 0;
|
|
207
|
|
208 Value[] p1;
|
|
209 Value* v1;
|
|
210 if (len < 128)
|
|
211 v1 = cast(Value*)alloca(len * Value.sizeof);
|
|
212 if (v1)
|
|
213 alist = v1[0 .. len];
|
|
214 else
|
|
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 delete 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();
|
|
253 v = othis.Call(cc, o, ret, arglist[1 .. length]);
|
|
254 }
|
|
255 return v;
|
|
256 }
|
|
257
|
|
258 /* ===================== Dfunction_prototype ==================== */
|
|
259
|
|
260 class Dfunction_prototype : Dfunction
|
|
261 {
|
|
262 this(ThreadContext *tc)
|
|
263 {
|
|
264 super(0, tc.Dobject_prototype);
|
|
265
|
|
266 uint attributes = DontEnum;
|
|
267
|
|
268 classname = TEXT_Function;
|
|
269 name = "prototype";
|
|
270 Put(TEXT_constructor, tc.Dfunction_constructor, attributes);
|
|
271
|
|
272 static 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.init(this, nfd, attributes);
|
|
280 }
|
|
281
|
|
282 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 { tchar[] name;
|
|
296 Dobject[] scopex; // Function object's scope chain per 13.2 step 7
|
|
297
|
|
298 this(d_uint32 length)
|
|
299 {
|
|
300 this(length, Dfunction.getPrototype());
|
|
301 }
|
|
302
|
|
303 this(d_uint32 length, Dobject prototype)
|
|
304 {
|
|
305 super(prototype);
|
|
306 classname = TEXT_Function;
|
|
307 name = TEXT_Function;
|
|
308 Put(TEXT_length, length, DontDelete | DontEnum | ReadOnly);
|
|
309 Put(TEXT_arity, length, DontDelete | DontEnum | ReadOnly);
|
|
310 }
|
|
311
|
|
312 d_string getTypeof()
|
|
313 { // ECMA 11.4.3
|
|
314 return TEXT_function;
|
|
315 }
|
|
316
|
|
317 d_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 d_string s;
|
|
322
|
4
|
323 s = Format("function {}() {{ [native code] }", name);
|
|
324 //s = std.string.format("function %s() { [native code] }", name);
|
0
|
325 return s;
|
|
326 }
|
|
327
|
|
328 void *HasInstance(Value* ret, Value* v)
|
|
329 {
|
|
330 // ECMA v3 15.3.5.3
|
|
331 Dobject V;
|
|
332 Value* w;
|
|
333 Dobject o;
|
|
334
|
|
335 if (v.isPrimitive())
|
|
336 goto Lfalse;
|
|
337 V = v.toObject();
|
|
338 w = Get(TEXT_prototype);
|
|
339 if (w.isPrimitive())
|
|
340 { ErrInfo errinfo;
|
|
341 return RuntimeError(&errinfo, errmsgtbl[ERR_MUST_BE_OBJECT], w.getType());
|
|
342 }
|
|
343 o = w.toObject();
|
|
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)
|
|
363 {
|
|
364 Dfunction r;
|
|
365 Dobject o;
|
|
366
|
|
367 r = null;
|
|
368 if (!v.isPrimitive())
|
|
369 {
|
|
370 o = v.toObject();
|
|
371 if (o.isClass(TEXT_Function))
|
|
372 r = cast(Dfunction)o;
|
|
373 }
|
|
374 return r;
|
|
375 }
|
|
376
|
|
377
|
|
378 static Dfunction getConstructor()
|
|
379 {
|
|
380 ThreadContext *tc = ThreadContext.getThreadContext();
|
|
381 assert(tc);
|
|
382 return tc.Dfunction_constructor;
|
|
383 }
|
|
384
|
|
385 static Dobject getPrototype()
|
|
386 {
|
|
387 ThreadContext *tc = ThreadContext.getThreadContext();
|
|
388 assert(tc);
|
|
389 return tc.Dfunction_prototype;
|
|
390 }
|
|
391
|
|
392 static void init(ThreadContext *tc)
|
|
393 {
|
|
394 tc.Dfunction_constructor = new Dfunction_constructor(tc);
|
|
395 tc.Dfunction_prototype = new Dfunction_prototype(tc);
|
|
396
|
|
397 tc.Dfunction_constructor.Put(TEXT_prototype, tc.Dfunction_prototype, DontEnum | DontDelete | ReadOnly);
|
|
398
|
|
399 tc.Dfunction_constructor.internal_prototype = tc.Dfunction_prototype;
|
|
400 tc.Dfunction_constructor.proptable.previous = tc.Dfunction_prototype.proptable;
|
|
401 }
|
|
402 }
|