Rename ecmaStrictMode to ecma3OnlyMode, use fresh prototype object initialiser for...
[mozilla-central.git] / js / narcissus / jsexec.js
blob74ce739e39b376d11c7843a061c25b26b08a9565
1 /* ***** BEGIN LICENSE BLOCK *****
2  * vim: set ts=4 sw=4 et tw=80:
3  *
4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5  *
6  * The contents of this file are subject to the Mozilla Public License Version
7  * 1.1 (the "License"); you may not use this file except in compliance with
8  * the License. You may obtain a copy of the License at
9  * http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is the Narcissus JavaScript engine.
17  *
18  * The Initial Developer of the Original Code is
19  * Brendan Eich <brendan@mozilla.org>.
20  * Portions created by the Initial Developer are Copyright (C) 2004
21  * the Initial Developer. All Rights Reserved.
22  *
23  * Contributor(s):
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either the GNU General Public License Version 2 or later (the "GPL"), or
27  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the MPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the MPL, the GPL or the LGPL.
36  *
37  * ***** END LICENSE BLOCK ***** */
40  * Narcissus - JS implemented in JS.
41  *
42  * Execution of parse trees.
43  *
44  * Standard classes except for eval, Function, Array, and String are borrowed
45  * from the host JS environment.  Function is metacircular.  Array and String
46  * are reflected via wrapping the corresponding native constructor and adding
47  * an extra level of prototype-based delegation.
48  */
50 const GLOBAL_CODE = 0, EVAL_CODE = 1, FUNCTION_CODE = 2;
52 function ExecutionContext(type) {
53     this.type = type;
56 var global = {
57     // Value properties.
58     NaN: NaN, Infinity: Infinity, undefined: undefined,
60     // Function properties.
61     eval: function eval(s) {
62         if (typeof s != "string")
63             return s;
65         var x = ExecutionContext.current;
66         var x2 = new ExecutionContext(EVAL_CODE);
67         x2.thisObject = x.thisObject;
68         x2.caller = x.caller;
69         x2.callee = x.callee;
70         x2.scope = x.scope;
71         ExecutionContext.current = x2;
72         try {
73             execute(parse(s), x2);
74         } catch (e if e == THROW) {
75             x.result = x2.result;
76             throw e;
77         } finally {
78             ExecutionContext.current = x;
79         }
80         return x2.result;
81     },
82     parseInt: parseInt, parseFloat: parseFloat,
83     isNaN: isNaN, isFinite: isFinite,
84     decodeURI: decodeURI, encodeURI: encodeURI,
85     decodeURIComponent: decodeURIComponent,
86     encodeURIComponent: encodeURIComponent,
88     // Class constructors.  Where ECMA-262 requires C.length == 1, we declare
89     // a dummy formal parameter.
90     Object: Object,
91     Function: function Function(dummy) {
92         var p = "", b = "", n = arguments.length;
93         if (n) {
94             var m = n - 1;
95             if (m) {
96                 p += arguments[0];
97                 for (var k = 1; k < m; k++)
98                     p += "," + arguments[k];
99             }
100             b += arguments[m];
101         }
103         // XXX We want to pass a good file and line to the tokenizer.
104         // Note the anonymous name to maintain parity with Spidermonkey.
105         var t = new Tokenizer("anonymous(" + p + ") {" + b + "}");
107         // NB: Use the STATEMENT_FORM constant since we don't want to push this
108         // function onto the null compilation context.
109         var f = FunctionDefinition(t, null, false, STATEMENT_FORM);
110         var s = {object: global, parent: null};
111         return new FunctionObject(f, s);
112     },
113     Array: function Array(dummy) {
114         // Array when called as a function acts as a constructor.
115         return GLOBAL.Array.apply(this, arguments);
116     },
117     String: function String(s) {
118         // Called as function or constructor: convert argument to string type.
119         s = arguments.length ? "" + s : "";
120         if (this instanceof String) {
121             // Called as constructor: save the argument as the string value
122             // of this String object and return this object.
123             this.value = s;
124             return this;
125         }
126         return s;
127     },
128     Boolean: Boolean, Number: Number, Date: Date, RegExp: RegExp,
129     Error: Error, EvalError: EvalError, RangeError: RangeError,
130     ReferenceError: ReferenceError, SyntaxError: SyntaxError,
131     TypeError: TypeError, URIError: URIError,
133     // Other properties.
134     Math: Math,
136     // Extensions to ECMA.
137     snarf: snarf, evaluate: evaluate,
138     load: function load(s) {
139         if (typeof s != "string")
140             return s;
142         evaluate(snarf(s), s, 1)
143     },
144     print: print, version: null
147 // Helper to avoid Object.prototype.hasOwnProperty polluting scope objects.
148 function hasDirectProperty(o, p) {
149     return Object.prototype.hasOwnProperty.call(o, p);
152 // Reflect a host class into the target global environment by delegation.
153 function reflectClass(name, proto) {
154     var gctor = global[name];
155     gctor.__defineProperty__('prototype', proto, true, true, true);
156     proto.__defineProperty__('constructor', gctor, false, false, true);
157     return proto;
160 // Reflect Array -- note that all Array methods are generic.
161 reflectClass('Array', new Array);
163 // Reflect String, overriding non-generic methods.
164 var gSp = reflectClass('String', new String);
165 gSp.toSource = function () { return this.value.toSource(); };
166 gSp.toString = function () { return this.value; };
167 gSp.valueOf  = function () { return this.value; };
168 global.String.fromCharCode = String.fromCharCode;
170 ExecutionContext.current = null;
172 ExecutionContext.prototype = {
173     caller: null,
174     callee: null,
175     scope: {object: global, parent: null},
176     thisObject: global,
177     result: undefined,
178     target: null,
179     ecma3OnlyMode: false
182 function Reference(base, propertyName, node) {
183     this.base = base;
184     this.propertyName = propertyName;
185     this.node = node;
188 Reference.prototype.toString = function () { return this.node.getSource(); }
190 function getValue(v) {
191     if (v instanceof Reference) {
192         if (!v.base) {
193             throw new ReferenceError(v.propertyName + " is not defined",
194                                      v.node.filename, v.node.lineno);
195         }
196         return v.base[v.propertyName];
197     }
198     return v;
201 function putValue(v, w, vn) {
202     if (v instanceof Reference)
203         return (v.base || global)[v.propertyName] = w;
204     throw new ReferenceError("Invalid assignment left-hand side",
205                              vn.filename, vn.lineno);
208 function isPrimitive(v) {
209     var t = typeof v;
210     return (t == "object") ? v === null : t != "function";
213 function isObject(v) {
214     var t = typeof v;
215     return (t == "object") ? v !== null : t == "function";
218 // If r instanceof Reference, v == getValue(r); else v === r.  If passed, rn
219 // is the node whose execute result was r.
220 function toObject(v, r, rn) {
221     switch (typeof v) {
222       case "boolean":
223         return new global.Boolean(v);
224       case "number":
225         return new global.Number(v);
226       case "string":
227         return new global.String(v);
228       case "function":
229         return v;
230       case "object":
231         if (v !== null)
232             return v;
233     }
234     var message = r + " (type " + (typeof v) + ") has no properties";
235     throw rn ? new TypeError(message, rn.filename, rn.lineno)
236              : new TypeError(message);
239 function execute(n, x) {
240     var a, f, i, j, r, s, t, u, v;
242     switch (n.type) {
243       case FUNCTION:
244         if (n.functionForm != DECLARED_FORM) {
245             if (!n.name || n.functionForm == STATEMENT_FORM) {
246                 v = new FunctionObject(n, x.scope);
247                 if (n.functionForm == STATEMENT_FORM)
248                     x.scope.object.__defineProperty__(n.name, v, true);
249             } else {
250                 t = new Object;
251                 x.scope = {object: t, parent: x.scope};
252                 try {
253                     v = new FunctionObject(n, x.scope);
254                     t.__defineProperty__(n.name, v, true, true);
255                 } finally {
256                     x.scope = x.scope.parent;
257                 }
258             }
259         }
260         break;
262       case SCRIPT:
263         t = x.scope.object;
264         a = n.funDecls;
265         for (i = 0, j = a.length; i < j; i++) {
266             s = a[i].name;
267             f = new FunctionObject(a[i], x.scope);
268             t.__defineProperty__(s, f, x.type != EVAL_CODE);
269         }
270         a = n.varDecls;
271         for (i = 0, j = a.length; i < j; i++) {
272             u = a[i];
273             s = u.name;
274             if (u.readOnly && hasDirectProperty(t, s)) {
275                 throw new TypeError("Redeclaration of const " + s,
276                                     u.filename, u.lineno);
277             }
278             if (u.readOnly || !hasDirectProperty(t, s)) {
279                 t.__defineProperty__(s, undefined, x.type != EVAL_CODE,
280                                      u.readOnly);
281             }
282         }
283         // FALL THROUGH
285       case BLOCK:
286         for (i = 0, j = n.length; i < j; i++)
287             execute(n[i], x);
288         break;
290       case IF:
291         if (getValue(execute(n.condition, x)))
292             execute(n.thenPart, x);
293         else if (n.elsePart)
294             execute(n.elsePart, x);
295         break;
297       case SWITCH:
298         s = getValue(execute(n.discriminant, x));
299         a = n.cases;
300         var matchDefault = false;
301       switch_loop:
302         for (i = 0, j = a.length; ; i++) {
303             if (i == j) {
304                 if (n.defaultIndex >= 0) {
305                     i = n.defaultIndex - 1; // no case matched, do default
306                     matchDefault = true;
307                     continue;
308                 }
309                 break;                      // no default, exit switch_loop
310             }
311             t = a[i];                       // next case (might be default!)
312             if (t.type == CASE) {
313                 u = getValue(execute(t.caseLabel, x));
314             } else {
315                 if (!matchDefault)          // not defaulting, skip for now
316                     continue;
317                 u = s;                      // force match to do default
318             }
319             if (u === s) {
320                 for (;;) {                  // this loop exits switch_loop
321                     if (t.statements.length) {
322                         try {
323                             execute(t.statements, x);
324                         } catch (e if e == BREAK && x.target == n) {
325                             break switch_loop;
326                         }
327                     }
328                     if (++i == j)
329                         break switch_loop;
330                     t = a[i];
331                 }
332                 // NOT REACHED
333             }
334         }
335         break;
337       case FOR:
338         n.setup && getValue(execute(n.setup, x));
339         // FALL THROUGH
340       case WHILE:
341         while (!n.condition || getValue(execute(n.condition, x))) {
342             try {
343                 execute(n.body, x);
344             } catch (e if e == BREAK && x.target == n) {
345                 break;
346             } catch (e if e == CONTINUE && x.target == n) {
347                 // Must run the update expression.
348             }
349             n.update && getValue(execute(n.update, x));
350         }
351         break;
353       case FOR_IN:
354         u = n.varDecl;
355         if (u)
356             execute(u, x);
357         r = n.iterator;
358         s = execute(n.object, x);
359         v = getValue(s);
361         // ECMA deviation to track extant browser JS implementation behavior.
362         t = (v == null && !x.ecma3OnlyMode) ? v : toObject(v, s, n.object);
363         a = [];
364         for (i in t)
365             a.push(i);
366         for (i = 0, j = a.length; i < j; i++) {
367             putValue(execute(r, x), a[i], r);
368             try {
369                 execute(n.body, x);
370             } catch (e if e == BREAK && x.target == n) {
371                 break;
372             } catch (e if e == CONTINUE && x.target == n) {
373                 continue;
374             }
375         }
376         break;
378       case DO:
379         do {
380             try {
381                 execute(n.body, x);
382             } catch (e if e == BREAK && x.target == n) {
383                 break;
384             } catch (e if e == CONTINUE && x.target == n) {
385                 continue;
386             }
387         } while (getValue(execute(n.condition, x)));
388         break;
390       case BREAK:
391       case CONTINUE:
392         x.target = n.target;
393         throw n.type;
395       case TRY:
396         try {
397             execute(n.tryBlock, x);
398         } catch (e if e == THROW && (j = n.catchClauses.length)) {
399             e = x.result;
400             x.result = undefined;
401             for (i = 0; ; i++) {
402                 if (i == j) {
403                     x.result = e;
404                     throw THROW;
405                 }
406                 t = n.catchClauses[i];
407                 x.scope = {object: {}, parent: x.scope};
408                 x.scope.object.__defineProperty__(t.varName, e, true);
409                 try {
410                     if (t.guard && !getValue(execute(t.guard, x)))
411                         continue;
412                     execute(t.block, x);
413                     break;
414                 } finally {
415                     x.scope = x.scope.parent;
416                 }
417             }
418         } finally {
419             if (n.finallyBlock)
420                 execute(n.finallyBlock, x);
421         }
422         break;
424       case THROW:
425         x.result = getValue(execute(n.exception, x));
426         throw THROW;
428       case RETURN:
429         x.result = getValue(execute(n.value, x));
430         throw RETURN;
432       case WITH:
433         r = execute(n.object, x);
434         t = toObject(getValue(r), r, n.object);
435         x.scope = {object: t, parent: x.scope};
436         try {
437             execute(n.body, x);
438         } finally {
439             x.scope = x.scope.parent;
440         }
441         break;
443       case VAR:
444       case CONST:
445         for (i = 0, j = n.length; i < j; i++) {
446             u = n[i].initializer;
447             if (!u)
448                 continue;
449             t = n[i].name;
450             for (s = x.scope; s; s = s.parent) {
451                 if (hasDirectProperty(s.object, t))
452                     break;
453             }
454             u = getValue(execute(u, x));
455             if (n.type == CONST)
456                 s.object.__defineProperty__(t, u, x.type != EVAL_CODE, true);
457             else
458                 s.object[t] = u;
459         }
460         break;
462       case DEBUGGER:
463         throw "NYI: " + tokens[n.type];
465       case SEMICOLON:
466         if (n.expression)
467             x.result = getValue(execute(n.expression, x));
468         break;
470       case LABEL:
471         try {
472             execute(n.statement, x);
473         } catch (e if e == BREAK && x.target == n) {
474         }
475         break;
477       case COMMA:
478         for (i = 0, j = n.length; i < j; i++)
479             v = getValue(execute(n[i], x));
480         break;
482       case ASSIGN:
483         r = execute(n[0], x);
484         t = n[0].assignOp;
485         if (t)
486             u = getValue(r);
487         v = getValue(execute(n[1], x));
488         if (t) {
489             switch (t) {
490               case BITWISE_OR:  v = u | v; break;
491               case BITWISE_XOR: v = u ^ v; break;
492               case BITWISE_AND: v = u & v; break;
493               case LSH:         v = u << v; break;
494               case RSH:         v = u >> v; break;
495               case URSH:        v = u >>> v; break;
496               case PLUS:        v = u + v; break;
497               case MINUS:       v = u - v; break;
498               case MUL:         v = u * v; break;
499               case DIV:         v = u / v; break;
500               case MOD:         v = u % v; break;
501             }
502         }
503         putValue(r, v, n[0]);
504         break;
506       case HOOK:
507         v = getValue(execute(n[0], x)) ? getValue(execute(n[1], x))
508                                        : getValue(execute(n[2], x));
509         break;
511       case OR:
512         v = getValue(execute(n[0], x)) || getValue(execute(n[1], x));
513         break;
515       case AND:
516         v = getValue(execute(n[0], x)) && getValue(execute(n[1], x));
517         break;
519       case BITWISE_OR:
520         v = getValue(execute(n[0], x)) | getValue(execute(n[1], x));
521         break;
523       case BITWISE_XOR:
524         v = getValue(execute(n[0], x)) ^ getValue(execute(n[1], x));
525         break;
527       case BITWISE_AND:
528         v = getValue(execute(n[0], x)) & getValue(execute(n[1], x));
529         break;
531       case EQ:
532         v = getValue(execute(n[0], x)) == getValue(execute(n[1], x));
533         break;
535       case NE:
536         v = getValue(execute(n[0], x)) != getValue(execute(n[1], x));
537         break;
539       case STRICT_EQ:
540         v = getValue(execute(n[0], x)) === getValue(execute(n[1], x));
541         break;
543       case STRICT_NE:
544         v = getValue(execute(n[0], x)) !== getValue(execute(n[1], x));
545         break;
547       case LT:
548         v = getValue(execute(n[0], x)) < getValue(execute(n[1], x));
549         break;
551       case LE:
552         v = getValue(execute(n[0], x)) <= getValue(execute(n[1], x));
553         break;
555       case GE:
556         v = getValue(execute(n[0], x)) >= getValue(execute(n[1], x));
557         break;
559       case GT:
560         v = getValue(execute(n[0], x)) > getValue(execute(n[1], x));
561         break;
563       case IN:
564         v = getValue(execute(n[0], x)) in getValue(execute(n[1], x));
565         break;
567       case INSTANCEOF:
568         t = getValue(execute(n[0], x));
569         u = getValue(execute(n[1], x));
570         if (isObject(u) && typeof u.__hasInstance__ == "function")
571             v = u.__hasInstance__(t);
572         else
573             v = t instanceof u;
574         break;
576       case LSH:
577         v = getValue(execute(n[0], x)) << getValue(execute(n[1], x));
578         break;
580       case RSH:
581         v = getValue(execute(n[0], x)) >> getValue(execute(n[1], x));
582         break;
584       case URSH:
585         v = getValue(execute(n[0], x)) >>> getValue(execute(n[1], x));
586         break;
588       case PLUS:
589         v = getValue(execute(n[0], x)) + getValue(execute(n[1], x));
590         break;
592       case MINUS:
593         v = getValue(execute(n[0], x)) - getValue(execute(n[1], x));
594         break;
596       case MUL:
597         v = getValue(execute(n[0], x)) * getValue(execute(n[1], x));
598         break;
600       case DIV:
601         v = getValue(execute(n[0], x)) / getValue(execute(n[1], x));
602         break;
604       case MOD:
605         v = getValue(execute(n[0], x)) % getValue(execute(n[1], x));
606         break;
608       case DELETE:
609         t = execute(n[0], x);
610         v = !(t instanceof Reference) || delete t.base[t.propertyName];
611         break;
613       case VOID:
614         getValue(execute(n[0], x));
615         break;
617       case TYPEOF:
618         t = execute(n[0], x);
619         if (t instanceof Reference)
620             t = t.base ? t.base[t.propertyName] : undefined;
621         v = typeof t;
622         break;
624       case NOT:
625         v = !getValue(execute(n[0], x));
626         break;
628       case BITWISE_NOT:
629         v = ~getValue(execute(n[0], x));
630         break;
632       case UNARY_PLUS:
633         v = +getValue(execute(n[0], x));
634         break;
636       case UNARY_MINUS:
637         v = -getValue(execute(n[0], x));
638         break;
640       case INCREMENT:
641       case DECREMENT:
642         t = execute(n[0], x);
643         u = Number(getValue(t));
644         if (n.postfix)
645             v = u;
646         putValue(t, (n.type == INCREMENT) ? ++u : --u, n[0]);
647         if (!n.postfix)
648             v = u;
649         break;
651       case DOT:
652         r = execute(n[0], x);
653         t = getValue(r);
654         u = n[1].value;
655         v = new Reference(toObject(t, r, n[0]), u, n);
656         break;
658       case INDEX:
659         r = execute(n[0], x);
660         t = getValue(r);
661         u = getValue(execute(n[1], x));
662         v = new Reference(toObject(t, r, n[0]), String(u), n);
663         break;
665       case LIST:
666         // Curse ECMA for specifying that arguments is not an Array object!
667         v = {};
668         for (i = 0, j = n.length; i < j; i++) {
669             u = getValue(execute(n[i], x));
670             v.__defineProperty__(i, u, false, false, true);
671         }
672         v.__defineProperty__('length', i, false, false, true);
673         break;
675       case CALL:
676         r = execute(n[0], x);
677         a = execute(n[1], x);
678         f = getValue(r);
679         if (isPrimitive(f) || typeof f.__call__ != "function") {
680             throw new TypeError(r + " is not callable",
681                                 n[0].filename, n[0].lineno);
682         }
683         t = (r instanceof Reference) ? r.base : null;
684         if (t instanceof Activation)
685             t = null;
686         v = f.__call__(t, a, x);
687         break;
689       case NEW:
690       case NEW_WITH_ARGS:
691         r = execute(n[0], x);
692         f = getValue(r);
693         if (n.type == NEW) {
694             a = {};
695             a.__defineProperty__('length', 0, false, false, true);
696         } else {
697             a = execute(n[1], x);
698         }
699         if (isPrimitive(f) || typeof f.__construct__ != "function") {
700             throw new TypeError(r + " is not a constructor",
701                                 n[0].filename, n[0].lineno);
702         }
703         v = f.__construct__(a, x);
704         break;
706       case ARRAY_INIT:
707         v = [];
708         for (i = 0, j = n.length; i < j; i++) {
709             if (n[i])
710                 v[i] = getValue(execute(n[i], x));
711         }
712         v.length = j;
713         break;
715       case OBJECT_INIT:
716         v = {};
717         for (i = 0, j = n.length; i < j; i++) {
718             t = n[i];
719             if (t.type == PROPERTY_INIT) {
720                 v[t[0].value] = getValue(execute(t[1], x));
721             } else {
722                 f = new FunctionObject(t, x.scope);
723                 u = (t.type == GETTER) ? '__defineGetter__'
724                                        : '__defineSetter__';
725                 v[u](t.name, thunk(f, x));
726             }
727         }
728         break;
730       case NULL:
731         v = null;
732         break;
734       case THIS:
735         v = x.thisObject;
736         break;
738       case TRUE:
739         v = true;
740         break;
742       case FALSE:
743         v = false;
744         break;
746       case IDENTIFIER:
747         for (s = x.scope; s; s = s.parent) {
748             if (n.value in s.object)
749                 break;
750         }
751         v = new Reference(s && s.object, n.value, n);
752         break;
754       case NUMBER:
755       case STRING:
756       case REGEXP:
757         v = n.value;
758         break;
760       case GROUP:
761         v = execute(n[0], x);
762         break;
764       default:
765         throw "PANIC: unknown operation " + n.type + ": " + uneval(n);
766     }
768     return v;
771 function Activation(f, a) {
772     for (var i = 0, j = f.params.length; i < j; i++)
773         this.__defineProperty__(f.params[i], a[i], true);
774     this.__defineProperty__('arguments', a, true);
777 // Null Activation.prototype's proto slot so that Object.prototype.* does not
778 // pollute the scope of heavyweight functions.  Also delete its 'constructor'
779 // property so that it doesn't pollute function scopes.  But first, we must
780 // copy __defineProperty__ down from Object.prototype.
782 Activation.prototype.__defineProperty__ = Object.prototype.__defineProperty__;
783 Activation.prototype.__proto__ = null;
784 delete Activation.prototype.constructor;
786 function FunctionObject(node, scope) {
787     this.node = node;
788     this.scope = scope;
789     this.__defineProperty__('length', node.params.length, true, true, true);
790     var proto = {};
791     this.__defineProperty__('prototype', proto, true);
792     proto.__defineProperty__('constructor', this, false, false, true);
795 var FOp = FunctionObject.prototype = {
796     // Internal methods.
797     __call__: function (t, a, x) {
798         var x2 = new ExecutionContext(FUNCTION_CODE);
799         x2.thisObject = t || global;
800         x2.caller = x;
801         x2.callee = this;
802         a.__defineProperty__('callee', this, false, false, true);
803         var f = this.node;
804         x2.scope = {object: new Activation(f, a), parent: this.scope};
806         ExecutionContext.current = x2;
807         try {
808             execute(f.body, x2);
809         } catch (e if e == RETURN) {
810             return x2.result;
811         } catch (e if e == THROW) {
812             x.result = x2.result;
813             throw THROW;
814         } finally {
815             ExecutionContext.current = x;
816         }
817         return undefined;
818     },
820     __construct__: function (a, x) {
821         var o = new Object;
822         var p = this.prototype;
823         if (isObject(p))
824             o.__proto__ = p;
825         // else o.__proto__ defaulted to Object.prototype
827         var v = this.__call__(o, a, x);
828         if (isObject(v))
829             return v;
830         return o;
831     },
833     __hasInstance__: function (v) {
834         if (isPrimitive(v))
835             return false;
836         var p = this.prototype;
837         if (isPrimitive(p)) {
838             throw new TypeError("'prototype' property is not an object",
839                                 this.node.filename, this.node.lineno);
840         }
841         var o;
842         while ((o = v.__proto__)) {
843             if (o == p)
844                 return true;
845             v = o;
846         }
847         return false;
848     },
850     // Standard methods.
851     toString: function () {
852         return this.node.getSource();
853     },
855     apply: function (t, a) {
856         // Curse ECMA again!
857         if (typeof this.__call__ != "function") {
858             throw new TypeError("Function.prototype.apply called on" +
859                                 " uncallable object");
860         }
862         if (t === undefined || t === null)
863             t = global;
864         else if (typeof t != "object")
865             t = toObject(t, t);
867         if (a === undefined || a === null) {
868             a = {};
869             a.__defineProperty__('length', 0, false, false, true);
870         } else if (a instanceof Array) {
871             var v = {};
872             for (var i = 0, j = a.length; i < j; i++)
873                 v.__defineProperty__(i, a[i], false, false, true);
874             v.__defineProperty__('length', i, false, false, true);
875             a = v;
876         } else if (!(a instanceof Object)) {
877             // XXX check for a non-arguments object
878             throw new TypeError("Second argument to Function.prototype.apply" +
879                                 " must be an array or arguments object",
880                                 this.node.filename, this.node.lineno);
881         }
883         return this.__call__(t, a, ExecutionContext.current);
884     },
886     call: function (t) {
887         // Curse ECMA a third time!
888         var a = Array.prototype.splice.call(arguments, 1);
889         return this.apply(t, a);
890     }
893 // Connect Function.prototype and Function.prototype.constructor in global.
894 reflectClass('Function', FOp);
896 // Help native and host-scripted functions be like FunctionObjects.
897 var Fp = Function.prototype;
898 var REp = RegExp.prototype;
900 if (!('__call__' in Fp)) {
901     Fp.__defineProperty__('__call__', function (t, a, x) {
902         // Curse ECMA yet again!
903         a = Array.prototype.splice.call(a, 0, a.length);
904         return this.apply(t, a);
905     }, true, true, true);
907     REp.__defineProperty__('__call__', function (t, a, x) {
908         a = Array.prototype.splice.call(a, 0, a.length);
909         return this.exec.apply(this, a);
910     }, true, true, true);
912     Fp.__defineProperty__('__construct__', function (a, x) {
913         a = Array.prototype.splice.call(a, 0, a.length);
914         return this.__applyConstructor__(a);
915     }, true, true, true);
917     // Since we use native functions such as Date along with host ones such
918     // as global.eval, we want both to be considered instances of the native
919     // Function constructor.
920     Fp.__defineProperty__('__hasInstance__', function (v) {
921         return v instanceof Function || v instanceof global.Function;
922     }, true, true, true);
925 function thunk(f, x) {
926     return function () { return f.__call__(this, arguments, x); };
929 function evaluate(s, f, l) {
930     if (typeof s != "string")
931         return s;
933     var x = ExecutionContext.current;
934     var x2 = new ExecutionContext(GLOBAL_CODE);
935     ExecutionContext.current = x2;
936     try {
937         execute(parse(s, f, l), x2);
938     } catch (e if e == THROW) {
939         if (x) {
940             x.result = x2.result;
941             throw THROW;
942         }
943         throw x2.result;
944     } finally {
945         ExecutionContext.current = x;
946     }
947     return x2.result;