Automated checkin: version bump remove "pre" from version number for firefox 3.7a1...
[mozilla-central.git] / js / narcissus / jsexec.js
blob640c89e722c2263cfa209a6b882a4d5d8ed59ba7
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 var XCp = ExecutionContext.prototype;
171 ExecutionContext.current = XCp.caller = XCp.callee = null;
172 XCp.scope = {object: global, parent: null};
173 XCp.thisObject = global;
174 XCp.result = undefined;
175 XCp.target = null;
176 XCp.ecmaStrictMode = false;
178 function Reference(base, propertyName, node) {
179     this.base = base;
180     this.propertyName = propertyName;
181     this.node = node;
184 Reference.prototype.toString = function () { return this.node.getSource(); }
186 function getValue(v) {
187     if (v instanceof Reference) {
188         if (!v.base) {
189             throw new ReferenceError(v.propertyName + " is not defined",
190                                      v.node.filename, v.node.lineno);
191         }
192         return v.base[v.propertyName];
193     }
194     return v;
197 function putValue(v, w, vn) {
198     if (v instanceof Reference)
199         return (v.base || global)[v.propertyName] = w;
200     throw new ReferenceError("Invalid assignment left-hand side",
201                              vn.filename, vn.lineno);
204 function isPrimitive(v) {
205     var t = typeof v;
206     return (t == "object") ? v === null : t != "function";
209 function isObject(v) {
210     var t = typeof v;
211     return (t == "object") ? v !== null : t == "function";
214 // If r instanceof Reference, v == getValue(r); else v === r.  If passed, rn
215 // is the node whose execute result was r.
216 function toObject(v, r, rn) {
217     switch (typeof v) {
218       case "boolean":
219         return new global.Boolean(v);
220       case "number":
221         return new global.Number(v);
222       case "string":
223         return new global.String(v);
224       case "function":
225         return v;
226       case "object":
227         if (v !== null)
228             return v;
229     }
230     var message = r + " (type " + (typeof v) + ") has no properties";
231     throw rn ? new TypeError(message, rn.filename, rn.lineno)
232              : new TypeError(message);
235 function execute(n, x) {
236     var a, f, i, j, r, s, t, u, v;
238     switch (n.type) {
239       case FUNCTION:
240         if (n.functionForm != DECLARED_FORM) {
241             if (!n.name || n.functionForm == STATEMENT_FORM) {
242                 v = new FunctionObject(n, x.scope);
243                 if (n.functionForm == STATEMENT_FORM)
244                     x.scope.object.__defineProperty__(n.name, v, true);
245             } else {
246                 t = new Object;
247                 x.scope = {object: t, parent: x.scope};
248                 try {
249                     v = new FunctionObject(n, x.scope);
250                     t.__defineProperty__(n.name, v, true, true);
251                 } finally {
252                     x.scope = x.scope.parent;
253                 }
254             }
255         }
256         break;
258       case SCRIPT:
259         t = x.scope.object;
260         a = n.funDecls;
261         for (i = 0, j = a.length; i < j; i++) {
262             s = a[i].name;
263             f = new FunctionObject(a[i], x.scope);
264             t.__defineProperty__(s, f, x.type != EVAL_CODE);
265         }
266         a = n.varDecls;
267         for (i = 0, j = a.length; i < j; i++) {
268             u = a[i];
269             s = u.name;
270             if (u.readOnly && hasDirectProperty(t, s)) {
271                 throw new TypeError("Redeclaration of const " + s,
272                                     u.filename, u.lineno);
273             }
274             if (u.readOnly || !hasDirectProperty(t, s)) {
275                 t.__defineProperty__(s, undefined, x.type != EVAL_CODE,
276                                      u.readOnly);
277             }
278         }
279         // FALL THROUGH
281       case BLOCK:
282         for (i = 0, j = n.length; i < j; i++)
283             execute(n[i], x);
284         break;
286       case IF:
287         if (getValue(execute(n.condition, x)))
288             execute(n.thenPart, x);
289         else if (n.elsePart)
290             execute(n.elsePart, x);
291         break;
293       case SWITCH:
294         s = getValue(execute(n.discriminant, x));
295         a = n.cases;
296         var matchDefault = false;
297       switch_loop:
298         for (i = 0, j = a.length; ; i++) {
299             if (i == j) {
300                 if (n.defaultIndex >= 0) {
301                     i = n.defaultIndex - 1; // no case matched, do default
302                     matchDefault = true;
303                     continue;
304                 }
305                 break;                      // no default, exit switch_loop
306             }
307             t = a[i];                       // next case (might be default!)
308             if (t.type == CASE) {
309                 u = getValue(execute(t.caseLabel, x));
310             } else {
311                 if (!matchDefault)          // not defaulting, skip for now
312                     continue;
313                 u = s;                      // force match to do default
314             }
315             if (u === s) {
316                 for (;;) {                  // this loop exits switch_loop
317                     if (t.statements.length) {
318                         try {
319                             execute(t.statements, x);
320                         } catch (e if e == BREAK && x.target == n) {
321                             break switch_loop;
322                         }
323                     }
324                     if (++i == j)
325                         break switch_loop;
326                     t = a[i];
327                 }
328                 // NOT REACHED
329             }
330         }
331         break;
333       case FOR:
334         n.setup && getValue(execute(n.setup, x));
335         // FALL THROUGH
336       case WHILE:
337         while (!n.condition || getValue(execute(n.condition, x))) {
338             try {
339                 execute(n.body, x);
340             } catch (e if e == BREAK && x.target == n) {
341                 break;
342             } catch (e if e == CONTINUE && x.target == n) {
343                 // Must run the update expression.
344             }
345             n.update && getValue(execute(n.update, x));
346         }
347         break;
349       case FOR_IN:
350         u = n.varDecl;
351         if (u)
352             execute(u, x);
353         r = n.iterator;
354         s = execute(n.object, x);
355         v = getValue(s);
357         // ECMA deviation to track extant browser JS implementation behavior.
358         t = (v == null && !x.ecmaStrictMode) ? v : toObject(v, s, n.object);
359         a = [];
360         for (i in t)
361             a.push(i);
362         for (i = 0, j = a.length; i < j; i++) {
363             putValue(execute(r, x), a[i], r);
364             try {
365                 execute(n.body, x);
366             } catch (e if e == BREAK && x.target == n) {
367                 break;
368             } catch (e if e == CONTINUE && x.target == n) {
369                 continue;
370             }
371         }
372         break;
374       case DO:
375         do {
376             try {
377                 execute(n.body, x);
378             } catch (e if e == BREAK && x.target == n) {
379                 break;
380             } catch (e if e == CONTINUE && x.target == n) {
381                 continue;
382             }
383         } while (getValue(execute(n.condition, x)));
384         break;
386       case BREAK:
387       case CONTINUE:
388         x.target = n.target;
389         throw n.type;
391       case TRY:
392         try {
393             execute(n.tryBlock, x);
394         } catch (e if e == THROW && (j = n.catchClauses.length)) {
395             e = x.result;
396             x.result = undefined;
397             for (i = 0; ; i++) {
398                 if (i == j) {
399                     x.result = e;
400                     throw THROW;
401                 }
402                 t = n.catchClauses[i];
403                 x.scope = {object: {}, parent: x.scope};
404                 x.scope.object.__defineProperty__(t.varName, e, true);
405                 try {
406                     if (t.guard && !getValue(execute(t.guard, x)))
407                         continue;
408                     execute(t.block, x);
409                     break;
410                 } finally {
411                     x.scope = x.scope.parent;
412                 }
413             }
414         } finally {
415             if (n.finallyBlock)
416                 execute(n.finallyBlock, x);
417         }
418         break;
420       case THROW:
421         x.result = getValue(execute(n.exception, x));
422         throw THROW;
424       case RETURN:
425         x.result = getValue(execute(n.value, x));
426         throw RETURN;
428       case WITH:
429         r = execute(n.object, x);
430         t = toObject(getValue(r), r, n.object);
431         x.scope = {object: t, parent: x.scope};
432         try {
433             execute(n.body, x);
434         } finally {
435             x.scope = x.scope.parent;
436         }
437         break;
439       case VAR:
440       case CONST:
441         for (i = 0, j = n.length; i < j; i++) {
442             u = n[i].initializer;
443             if (!u)
444                 continue;
445             t = n[i].name;
446             for (s = x.scope; s; s = s.parent) {
447                 if (hasDirectProperty(s.object, t))
448                     break;
449             }
450             u = getValue(execute(u, x));
451             if (n.type == CONST)
452                 s.object.__defineProperty__(t, u, x.type != EVAL_CODE, true);
453             else
454                 s.object[t] = u;
455         }
456         break;
458       case DEBUGGER:
459         throw "NYI: " + tokens[n.type];
461       case SEMICOLON:
462         if (n.expression)
463             x.result = getValue(execute(n.expression, x));
464         break;
466       case LABEL:
467         try {
468             execute(n.statement, x);
469         } catch (e if e == BREAK && x.target == n) {
470         }
471         break;
473       case COMMA:
474         for (i = 0, j = n.length; i < j; i++)
475             v = getValue(execute(n[i], x));
476         break;
478       case ASSIGN:
479         r = execute(n[0], x);
480         t = n[0].assignOp;
481         if (t)
482             u = getValue(r);
483         v = getValue(execute(n[1], x));
484         if (t) {
485             switch (t) {
486               case BITWISE_OR:  v = u | v; break;
487               case BITWISE_XOR: v = u ^ v; break;
488               case BITWISE_AND: v = u & v; break;
489               case LSH:         v = u << v; break;
490               case RSH:         v = u >> v; break;
491               case URSH:        v = u >>> v; break;
492               case PLUS:        v = u + v; break;
493               case MINUS:       v = u - v; break;
494               case MUL:         v = u * v; break;
495               case DIV:         v = u / v; break;
496               case MOD:         v = u % v; break;
497             }
498         }
499         putValue(r, v, n[0]);
500         break;
502       case HOOK:
503         v = getValue(execute(n[0], x)) ? getValue(execute(n[1], x))
504                                        : getValue(execute(n[2], x));
505         break;
507       case OR:
508         v = getValue(execute(n[0], x)) || getValue(execute(n[1], x));
509         break;
511       case AND:
512         v = getValue(execute(n[0], x)) && getValue(execute(n[1], x));
513         break;
515       case BITWISE_OR:
516         v = getValue(execute(n[0], x)) | getValue(execute(n[1], x));
517         break;
519       case BITWISE_XOR:
520         v = getValue(execute(n[0], x)) ^ getValue(execute(n[1], x));
521         break;
523       case BITWISE_AND:
524         v = getValue(execute(n[0], x)) & getValue(execute(n[1], x));
525         break;
527       case EQ:
528         v = getValue(execute(n[0], x)) == getValue(execute(n[1], x));
529         break;
531       case NE:
532         v = getValue(execute(n[0], x)) != getValue(execute(n[1], x));
533         break;
535       case STRICT_EQ:
536         v = getValue(execute(n[0], x)) === getValue(execute(n[1], x));
537         break;
539       case STRICT_NE:
540         v = getValue(execute(n[0], x)) !== getValue(execute(n[1], x));
541         break;
543       case LT:
544         v = getValue(execute(n[0], x)) < getValue(execute(n[1], x));
545         break;
547       case LE:
548         v = getValue(execute(n[0], x)) <= getValue(execute(n[1], x));
549         break;
551       case GE:
552         v = getValue(execute(n[0], x)) >= getValue(execute(n[1], x));
553         break;
555       case GT:
556         v = getValue(execute(n[0], x)) > getValue(execute(n[1], x));
557         break;
559       case IN:
560         v = getValue(execute(n[0], x)) in getValue(execute(n[1], x));
561         break;
563       case INSTANCEOF:
564         t = getValue(execute(n[0], x));
565         u = getValue(execute(n[1], x));
566         if (isObject(u) && typeof u.__hasInstance__ == "function")
567             v = u.__hasInstance__(t);
568         else
569             v = t instanceof u;
570         break;
572       case LSH:
573         v = getValue(execute(n[0], x)) << getValue(execute(n[1], x));
574         break;
576       case RSH:
577         v = getValue(execute(n[0], x)) >> getValue(execute(n[1], x));
578         break;
580       case URSH:
581         v = getValue(execute(n[0], x)) >>> getValue(execute(n[1], x));
582         break;
584       case PLUS:
585         v = getValue(execute(n[0], x)) + getValue(execute(n[1], x));
586         break;
588       case MINUS:
589         v = getValue(execute(n[0], x)) - getValue(execute(n[1], x));
590         break;
592       case MUL:
593         v = getValue(execute(n[0], x)) * getValue(execute(n[1], x));
594         break;
596       case DIV:
597         v = getValue(execute(n[0], x)) / getValue(execute(n[1], x));
598         break;
600       case MOD:
601         v = getValue(execute(n[0], x)) % getValue(execute(n[1], x));
602         break;
604       case DELETE:
605         t = execute(n[0], x);
606         v = !(t instanceof Reference) || delete t.base[t.propertyName];
607         break;
609       case VOID:
610         getValue(execute(n[0], x));
611         break;
613       case TYPEOF:
614         t = execute(n[0], x);
615         if (t instanceof Reference)
616             t = t.base ? t.base[t.propertyName] : undefined;
617         v = typeof t;
618         break;
620       case NOT:
621         v = !getValue(execute(n[0], x));
622         break;
624       case BITWISE_NOT:
625         v = ~getValue(execute(n[0], x));
626         break;
628       case UNARY_PLUS:
629         v = +getValue(execute(n[0], x));
630         break;
632       case UNARY_MINUS:
633         v = -getValue(execute(n[0], x));
634         break;
636       case INCREMENT:
637       case DECREMENT:
638         t = execute(n[0], x);
639         u = Number(getValue(t));
640         if (n.postfix)
641             v = u;
642         putValue(t, (n.type == INCREMENT) ? ++u : --u, n[0]);
643         if (!n.postfix)
644             v = u;
645         break;
647       case DOT:
648         r = execute(n[0], x);
649         t = getValue(r);
650         u = n[1].value;
651         v = new Reference(toObject(t, r, n[0]), u, n);
652         break;
654       case INDEX:
655         r = execute(n[0], x);
656         t = getValue(r);
657         u = getValue(execute(n[1], x));
658         v = new Reference(toObject(t, r, n[0]), String(u), n);
659         break;
661       case LIST:
662         // Curse ECMA for specifying that arguments is not an Array object!
663         v = {};
664         for (i = 0, j = n.length; i < j; i++) {
665             u = getValue(execute(n[i], x));
666             v.__defineProperty__(i, u, false, false, true);
667         }
668         v.__defineProperty__('length', i, false, false, true);
669         break;
671       case CALL:
672         r = execute(n[0], x);
673         a = execute(n[1], x);
674         f = getValue(r);
675         if (isPrimitive(f) || typeof f.__call__ != "function") {
676             throw new TypeError(r + " is not callable",
677                                 n[0].filename, n[0].lineno);
678         }
679         t = (r instanceof Reference) ? r.base : null;
680         if (t instanceof Activation)
681             t = null;
682         v = f.__call__(t, a, x);
683         break;
685       case NEW:
686       case NEW_WITH_ARGS:
687         r = execute(n[0], x);
688         f = getValue(r);
689         if (n.type == NEW) {
690             a = {};
691             a.__defineProperty__('length', 0, false, false, true);
692         } else {
693             a = execute(n[1], x);
694         }
695         if (isPrimitive(f) || typeof f.__construct__ != "function") {
696             throw new TypeError(r + " is not a constructor",
697                                 n[0].filename, n[0].lineno);
698         }
699         v = f.__construct__(a, x);
700         break;
702       case ARRAY_INIT:
703         v = [];
704         for (i = 0, j = n.length; i < j; i++) {
705             if (n[i])
706                 v[i] = getValue(execute(n[i], x));
707         }
708         v.length = j;
709         break;
711       case OBJECT_INIT:
712         v = {};
713         for (i = 0, j = n.length; i < j; i++) {
714             t = n[i];
715             if (t.type == PROPERTY_INIT) {
716                 v[t[0].value] = getValue(execute(t[1], x));
717             } else {
718                 f = new FunctionObject(t, x.scope);
719                 u = (t.type == GETTER) ? '__defineGetter__'
720                                        : '__defineSetter__';
721                 v[u](t.name, thunk(f, x));
722             }
723         }
724         break;
726       case NULL:
727         v = null;
728         break;
730       case THIS:
731         v = x.thisObject;
732         break;
734       case TRUE:
735         v = true;
736         break;
738       case FALSE:
739         v = false;
740         break;
742       case IDENTIFIER:
743         for (s = x.scope; s; s = s.parent) {
744             if (n.value in s.object)
745                 break;
746         }
747         v = new Reference(s && s.object, n.value, n);
748         break;
750       case NUMBER:
751       case STRING:
752       case REGEXP:
753         v = n.value;
754         break;
756       case GROUP:
757         v = execute(n[0], x);
758         break;
760       default:
761         throw "PANIC: unknown operation " + n.type + ": " + uneval(n);
762     }
764     return v;
767 function Activation(f, a) {
768     for (var i = 0, j = f.params.length; i < j; i++)
769         this.__defineProperty__(f.params[i], a[i], true);
770     this.__defineProperty__('arguments', a, true);
773 // Null Activation.prototype's proto slot so that Object.prototype.* does not
774 // pollute the scope of heavyweight functions.  Also delete its 'constructor'
775 // property so that it doesn't pollute function scopes.  But first, we must
776 // copy __defineProperty__ down from Object.prototype.
778 Activation.prototype.__defineProperty__ = Object.prototype.__defineProperty__;
779 Activation.prototype.__proto__ = null;
780 delete Activation.prototype.constructor;
782 function FunctionObject(node, scope) {
783     this.node = node;
784     this.scope = scope;
785     this.__defineProperty__('length', node.params.length, true, true, true);
786     var proto = {};
787     this.__defineProperty__('prototype', proto, true);
788     proto.__defineProperty__('constructor', this, false, false, true);
791 var FOp = FunctionObject.prototype = {
792     // Internal methods.
793     __call__: function (t, a, x) {
794         var x2 = new ExecutionContext(FUNCTION_CODE);
795         x2.thisObject = t || global;
796         x2.caller = x;
797         x2.callee = this;
798         a.__defineProperty__('callee', this, false, false, true);
799         var f = this.node;
800         x2.scope = {object: new Activation(f, a), parent: this.scope};
802         ExecutionContext.current = x2;
803         try {
804             execute(f.body, x2);
805         } catch (e if e == RETURN) {
806             return x2.result;
807         } catch (e if e == THROW) {
808             x.result = x2.result;
809             throw THROW;
810         } finally {
811             ExecutionContext.current = x;
812         }
813         return undefined;
814     },
816     __construct__: function (a, x) {
817         var o = new Object;
818         var p = this.prototype;
819         if (isObject(p))
820             o.__proto__ = p;
821         // else o.__proto__ defaulted to Object.prototype
823         var v = this.__call__(o, a, x);
824         if (isObject(v))
825             return v;
826         return o;
827     },
829     __hasInstance__: function (v) {
830         if (isPrimitive(v))
831             return false;
832         var p = this.prototype;
833         if (isPrimitive(p)) {
834             throw new TypeError("'prototype' property is not an object",
835                                 this.node.filename, this.node.lineno);
836         }
837         var o;
838         while ((o = v.__proto__)) {
839             if (o == p)
840                 return true;
841             v = o;
842         }
843         return false;
844     },
846     // Standard methods.
847     toString: function () {
848         return this.node.getSource();
849     },
851     apply: function (t, a) {
852         // Curse ECMA again!
853         if (typeof this.__call__ != "function") {
854             throw new TypeError("Function.prototype.apply called on" +
855                                 " uncallable object");
856         }
858         if (t === undefined || t === null)
859             t = global;
860         else if (typeof t != "object")
861             t = toObject(t, t);
863         if (a === undefined || a === null) {
864             a = {};
865             a.__defineProperty__('length', 0, false, false, true);
866         } else if (a instanceof Array) {
867             var v = {};
868             for (var i = 0, j = a.length; i < j; i++)
869                 v.__defineProperty__(i, a[i], false, false, true);
870             v.__defineProperty__('length', i, false, false, true);
871             a = v;
872         } else if (!(a instanceof Object)) {
873             // XXX check for a non-arguments object
874             throw new TypeError("Second argument to Function.prototype.apply" +
875                                 " must be an array or arguments object",
876                                 this.node.filename, this.node.lineno);
877         }
879         return this.__call__(t, a, ExecutionContext.current);
880     },
882     call: function (t) {
883         // Curse ECMA a third time!
884         var a = Array.prototype.splice.call(arguments, 1);
885         return this.apply(t, a);
886     }
889 // Connect Function.prototype and Function.prototype.constructor in global.
890 reflectClass('Function', FOp);
892 // Help native and host-scripted functions be like FunctionObjects.
893 var Fp = Function.prototype;
894 var REp = RegExp.prototype;
896 if (!('__call__' in Fp)) {
897     Fp.__defineProperty__('__call__', function (t, a, x) {
898         // Curse ECMA yet again!
899         a = Array.prototype.splice.call(a, 0, a.length);
900         return this.apply(t, a);
901     }, true, true, true);
903     REp.__defineProperty__('__call__', function (t, a, x) {
904         a = Array.prototype.splice.call(a, 0, a.length);
905         return this.exec.apply(this, a);
906     }, true, true, true);
908     Fp.__defineProperty__('__construct__', function (a, x) {
909         a = Array.prototype.splice.call(a, 0, a.length);
910         return this.__applyConstructor__(a);
911     }, true, true, true);
913     // Since we use native functions such as Date along with host ones such
914     // as global.eval, we want both to be considered instances of the native
915     // Function constructor.
916     Fp.__defineProperty__('__hasInstance__', function (v) {
917         return v instanceof Function || v instanceof global.Function;
918     }, true, true, true);
921 function thunk(f, x) {
922     return function () { return f.__call__(this, arguments, x); };
925 function evaluate(s, f, l) {
926     if (typeof s != "string")
927         return s;
929     var x = ExecutionContext.current;
930     var x2 = new ExecutionContext(GLOBAL_CODE);
931     ExecutionContext.current = x2;
932     try {
933         execute(parse(s, f, l), x2);
934     } catch (e if e == THROW) {
935         if (x) {
936             x.result = x2.result;
937             throw THROW;
938         }
939         throw x2.result;
940     } finally {
941         ExecutionContext.current = x;
942     }
943     return x2.result;