Project

General

Profile

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 ***** */
38

    
39
/*
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
 */
49

    
50
// jrh
51
//module('JS.Exec');
52
// end jrh
53

    
54
GLOBAL_CODE = 0; EVAL_CODE = 1; FUNCTION_CODE = 2;
55

    
56
function ExecutionContext(type) {
57
    this.type = type;
58
}
59

    
60
// jrh
61
var agenda = new Array();
62
var skip_setup = 0;
63
// end jrh
64

    
65
var global = {
66
    // Value properties.
67
    NaN: NaN, Infinity: Infinity, undefined: undefined,
68
    alert : function(msg) { alert(msg) },
69
    confirm : function(msg) { return confirm(msg) },
70
    document : document,
71
    window : window,
72
    // jrh
73
    //debug: window.open('','debugwindow','width=600,height=400,scrollbars=yes,resizable=yes'),     
74
    // end jrh
75
    navigator : navigator,
76
    XMLHttpRequest : function() { return new XMLHttpRequest() },
77
    // Function properties.
78
    eval: function(s) {
79
        if (typeof s != "string") {
80
            return s;
81
        }
82

    
83
        var x = ExecutionContext.current;
84
        var x2 = new ExecutionContext(EVAL_CODE);
85
        x2.thisObject = x.thisObject;
86
        x2.caller = x.caller;
87
        x2.callee = x.callee;
88
        x2.scope = x.scope;
89
        ExecutionContext.current = x2;
90
        try {
91
            execute(parse(s), x2);
92
        } catch (e) {
93
            x.result = x2.result;
94
            throw e;
95
        } finally {
96
            ExecutionContext.current = x;
97
        }
98
        return x2.result;
99
    },
100
    parseInt: parseInt, parseFloat: parseFloat,
101
    isNaN: isNaN, isFinite: isFinite,
102
    decodeURI: decodeURI, encodeURI: encodeURI,
103
    decodeURIComponent: decodeURIComponent,
104
    encodeURIComponent: encodeURIComponent,
105

    
106
    // Class constructors.  Where ECMA-262 requires C.length == 1, we declare
107
    // a dummy formal parameter.
108
    Object: Object,
109
    Function: function(dummy) {
110
        var p = "", b = "", n = arguments.length;
111
        if (n) {
112
            var m = n - 1;
113
            if (m) {
114
                p += arguments[0];
115
                for (var k = 1; k < m; k++)
116
                    p += "," + arguments[k];
117
            }
118
            b += arguments[m];
119
        }
120

    
121
        // XXX We want to pass a good file and line to the tokenizer.
122
        // Note the anonymous name to maintain parity with Spidermonkey.
123
        var t = new Tokenizer("anonymous(" + p + ") {" + b + "}");
124

    
125
        // NB: Use the STATEMENT_FORM constant since we don't want to push this
126
        // function onto the null compilation context.
127
        var f = FunctionDefinition(t, null, false, STATEMENT_FORM);
128
        var s = {object: global, parent: null};
129
        return new FunctionObject(f, s);
130
    },
131
    Array: function(dummy) {
132
        // Array when called as a function acts as a constructor.
133
        return GLOBAL.Array.apply(this, arguments);
134
    },
135
    String: function(s) {
136
        // Called as function or constructor: convert argument to string type.
137
        s = arguments.length ? "" + s : "";
138
        if (this instanceof String) {
139
            // Called as constructor: save the argument as the string value
140
            // of this String object and return this object.
141
            this.value = s;
142
            return this;
143
        }
144
        return s;
145
    },
146
    Boolean: Boolean, Number: Number, Date: Date, RegExp: RegExp,
147
    Error: Error, EvalError: EvalError, RangeError: RangeError,
148
    ReferenceError: ReferenceError, SyntaxError: SyntaxError,
149
    TypeError: TypeError, URIError: URIError,
150

    
151
    // Other properties.
152
    Math: Math,
153

    
154
    // Extensions to ECMA.
155
    //snarf: snarf,
156
    evaluate: evaluate,
157
    load: function(s) {
158
        if (typeof s != "string")
159
            return s;
160
        var req = new XMLHttpRequest();
161
        req.open('GET', s, false);
162
        req.send(null);
163

    
164
        evaluate(req.responseText, s, 1)
165
    },
166
    print: print, version: null
167
};
168

    
169
// jrh
170
//global.debug.document.body.innerHTML = ''
171
// end jrh
172

    
173
// Helper to avoid Object.prototype.hasOwnProperty polluting scope objects.
174
function hasDirectProperty(o, p) {
175
    return Object.prototype.hasOwnProperty.call(o, p);
176
}
177

    
178
// Reflect a host class into the target global environment by delegation.
179
function reflectClass(name, proto) {
180
    var gctor = global[name];
181
    gctor.prototype = proto;
182
    proto.constructor = gctor;
183
    return proto;
184
}
185

    
186
// Reflect Array -- note that all Array methods are generic.
187
reflectClass('Array', new Array);
188

    
189
// Reflect String, overriding non-generic methods.
190
var gSp = reflectClass('String', new String);
191
gSp.toSource = function () { return this.value.toSource(); };
192
gSp.toString = function () { return this.value; };
193
gSp.valueOf  = function () { return this.value; };
194
global.String.fromCharCode = String.fromCharCode;
195

    
196
var XCp = ExecutionContext.prototype;
197
ExecutionContext.current = XCp.caller = XCp.callee = null;
198
XCp.scope = {object: global, parent: null};
199
XCp.thisObject = global;
200
XCp.result = undefined;
201
XCp.target = null;
202
XCp.ecmaStrictMode = false;
203

    
204
function Reference(base, propertyName, node) {
205
    this.base = base;
206
    this.propertyName = propertyName;
207
    this.node = node;
208
}
209

    
210
Reference.prototype.toString = function () { return this.node.getSource(); }
211

    
212
function getValue(v) {
213
    if (v instanceof Reference) {
214
        if (!v.base) {
215
            throw new ReferenceError(v.propertyName + " is not defined",
216
                                     v.node.filename(), v.node.lineno);
217
        }
218
        return v.base[v.propertyName];
219
    }
220
    return v;
221
}
222

    
223
function putValue(v, w, vn) {
224
    if (v instanceof Reference)
225
        return (v.base || global)[v.propertyName] = w;
226
    throw new ReferenceError("Invalid assignment left-hand side",
227
                             vn.filename(), vn.lineno);
228
}
229

    
230
function isPrimitive(v) {
231
    var t = typeof v;
232
    return (t == "object") ? v === null : t != "function";
233
}
234

    
235
function isObject(v) {
236
    var t = typeof v;
237
    return (t == "object") ? v !== null : t == "function";
238
}
239

    
240
// If r instanceof Reference, v == getValue(r); else v === r.  If passed, rn
241
// is the node whose execute result was r.
242
function toObject(v, r, rn) {
243
    switch (typeof v) {
244
      case "boolean":
245
        return new global.Boolean(v);
246
      case "number":
247
        return new global.Number(v);
248
      case "string":
249
        return new global.String(v);
250
      case "function":
251
        return v;
252
      case "object":
253
        if (v !== null)
254
            return v;
255
    }
256
    var message = r + " (type " + (typeof v) + ") has no properties";
257
    throw rn ? new TypeError(message, rn.filename(), rn.lineno)
258
             : new TypeError(message);
259
}
260

    
261
function execute(n, x) {
262
    if (!this.new_block)
263
        new_block = new Array();
264
    //alert (n)
265
    var a, f, i, j, r, s, t, u, v;
266
    switch (n.type) {
267
      case FUNCTION:
268
        if (n.functionForm != DECLARED_FORM) {
269
            if (!n.name || n.functionForm == STATEMENT_FORM) {
270
                v = new FunctionObject(n, x.scope);
271
                if (n.functionForm == STATEMENT_FORM)
272
                    x.scope.object[n.name] = v;
273
            } else {
274
                t = new Object;
275
                x.scope = {object: t, parent: x.scope};
276
                try {
277
                    v = new FunctionObject(n, x.scope);
278
                    t[n.name] = v;
279
                } finally {
280
                    x.scope = x.scope.parent;
281
                }
282
            }
283
        }
284
        break;
285

    
286
      case SCRIPT:      
287
        t = x.scope.object;
288
        a = n.funDecls;
289
        for (i = 0, j = a.length; i < j; i++) {
290
            s = a[i].name;
291
            f = new FunctionObject(a[i], x.scope);
292
            t[s] = f;
293
        }
294
        a = n.varDecls;
295
        for (i = 0, j = a.length; i < j; i++) {
296
            u = a[i];
297
            s = u.name;
298
            if (u.readOnly && hasDirectProperty(t, s)) {
299
                throw new TypeError("Redeclaration of const " + s,
300
                                    u.filename(), u.lineno);
301
            }
302
            if (u.readOnly || !hasDirectProperty(t, s)) {
303
                t[s] = null;
304
            }
305
        }
306
        // FALL THROUGH
307

    
308
      case BLOCK:        
309
        for (i = 0, j = n.$length; i < j; i++)  {  
310
            //jrh
311
            //execute(n[i], x);      
312
            //new_block.unshift([n[i], x]);            
313
            new_block.push([n[i], x]);         
314
        }
315
        new_block.reverse();        
316
        agenda = agenda.concat(new_block);   
317
        //agenda = new_block.concat(agenda)
318
        // end jrh
319
        break;
320

    
321
      case IF:
322
        if (getValue(execute(n.condition, x)))
323
            execute(n.thenPart, x);
324
        else if (n.elsePart)
325
            execute(n.elsePart, x);
326
        break;
327

    
328
      case SWITCH:
329
        s = getValue(execute(n.discriminant, x));
330
        a = n.cases;
331
        var matchDefault = false;
332
      switch_loop:
333
        for (i = 0, j = a.length; ; i++) {
334
            if (i == j) {
335
                if (n.defaultIndex >= 0) {
336
                    i = n.defaultIndex - 1; // no case matched, do default
337
                    matchDefault = true;
338
                    continue;
339
                }
340
                break;                      // no default, exit switch_loop
341
            }
342
            t = a[i];                       // next case (might be default!)
343
            if (t.type == CASE) {
344
                u = getValue(execute(t.caseLabel, x));
345
            } else {
346
                if (!matchDefault)          // not defaulting, skip for now
347
                    continue;
348
                u = s;                      // force match to do default
349
            }
350
            if (u === s) {
351
                for (;;) {                  // this loop exits switch_loop
352
                    if (t.statements.length) {
353
                        try {
354
                            execute(t.statements, x);
355
                        } catch (e) {
356
                            if (!(e == BREAK && x.target == n)) { throw e }
357
                            break switch_loop;
358
                        }
359
                    }
360
                    if (++i == j)
361
                        break switch_loop;
362
                    t = a[i];
363
                }
364
                // NOT REACHED
365
            }
366
        }
367
        break;
368

    
369
      case FOR:
370
        // jrh
371
        // added "skip_setup" so initialization doesn't get called
372
        // on every call..
373
        if (!skip_setup)
374
            n.setup && getValue(execute(n.setup, x));
375
        // FALL THROUGH
376
      case WHILE:
377
        // jrh       
378
        //while (!n.condition || getValue(execute(n.condition, x))) {
379
        if (!n.condition || getValue(execute(n.condition, x))) {
380
            try {
381
                // jrh 
382
                //execute(n.body, x);
383
                new_block.push([n.body, x]);
384
                agenda.push([n.body, x])
385
                //agenda.unshift([n.body, x])
386
                // end jrh
387
            } catch (e) {
388
                if (e == BREAK && x.target == n) {
389
                    break;
390
                } else if (e == CONTINUE && x.target == n) {
391
                    // jrh
392
                    // 'continue' is invalid inside an 'if' clause
393
                    // I don't know what commenting this out will break!
394
                    //continue;
395
                    // end jrh
396
                    
397
                } else {
398
                    throw e;
399
                }
400
            }    
401
            n.update && getValue(execute(n.update, x));
402
            // jrh
403
            new_block.unshift([n, x])
404
            agenda.splice(agenda.length-1,0,[n, x])
405
            //agenda.splice(1,0,[n, x])
406
            skip_setup = 1
407
            // end jrh
408
        } else {
409
            skip_setup = 0
410
        }
411
        
412
        break;
413

    
414
      case FOR_IN:
415
        u = n.varDecl;
416
        if (u)
417
            execute(u, x);
418
        r = n.iterator;
419
        s = execute(n.object, x);
420
        v = getValue(s);
421

    
422
        // ECMA deviation to track extant browser JS implementation behavior.
423
        t = (v == null && !x.ecmaStrictMode) ? v : toObject(v, s, n.object);
424
        a = [];
425
        for (i in t)
426
            a.push(i);
427
        for (i = 0, j = a.length; i < j; i++) {
428
            putValue(execute(r, x), a[i], r);
429
            try {
430
                execute(n.body, x);
431
            } catch (e) {
432
                if (e == BREAK && x.target == n) {
433
                    break;
434
                } else if (e == CONTINUE && x.target == n) {
435
                    continue;
436
                } else {
437
                    throw e;
438
                }
439
            }
440
        }
441
        break;
442

    
443
      case DO:
444
        do {
445
            try {
446
                execute(n.body, x);
447
            } catch (e) {
448
                if (e == BREAK && x.target == n) {
449
                    break;
450
                } else if (e == CONTINUE && x.target == n) {
451
                    continue;
452
                } else {
453
                    throw e;
454
                }
455
            }
456
        } while (getValue(execute(n.condition, x)));
457
        break;
458

    
459
      case BREAK:
460
      case CONTINUE:
461
        x.target = n.target;
462
        throw n.type;
463

    
464
      case TRY:
465
        try {
466
            execute(n.tryBlock, x);
467
        } catch (e) {
468
            if (!(e == THROW && (j = n.catchClauses.length))) {
469
                throw e;
470
            }
471
            e = x.result;
472
            x.result = undefined;
473
            for (i = 0; ; i++) {
474
                if (i == j) {
475
                    x.result = e;
476
                    throw THROW;
477
                }
478
                t = n.catchClauses[i];
479
                x.scope = {object: {}, parent: x.scope};
480
                x.scope.object[t.varName] = e;
481
                try {
482
                    if (t.guard && !getValue(execute(t.guard, x)))
483
                        continue;
484
                    execute(t.block, x);
485
                    break;
486
                } finally {
487
                    x.scope = x.scope.parent;
488
                }
489
            }
490
        } finally {
491
            if (n.finallyBlock)
492
                execute(n.finallyBlock, x);
493
        }
494
        break;
495

    
496
      case THROW:
497
        x.result = getValue(execute(n.exception, x));
498
        throw THROW;
499

    
500
      case RETURN:
501
        x.result = getValue(execute(n.value, x));
502
        throw RETURN;
503

    
504
      case WITH:
505
        r = execute(n.object, x);
506
        t = toObject(getValue(r), r, n.object);
507
        x.scope = {object: t, parent: x.scope};
508
        try {
509
            execute(n.body, x);
510
        } finally {
511
            x.scope = x.scope.parent;
512
        }
513
        break;
514

    
515
      case VAR:
516
      case CONST:
517
        for (i = 0, j = n.$length; i < j; i++) {
518
            u = n[i].initializer;
519
            if (!u)
520
                continue;
521
            t = n[i].name;
522
            for (s = x.scope; s; s = s.parent) {
523
                if (hasDirectProperty(s.object, t))
524
                    break;
525
            }
526
            u = getValue(execute(u, x));
527
            if (n.type == CONST)
528
                s.object[t] = u;
529
            else
530
                s.object[t] = u;
531
        }
532
        break;
533

    
534
      case DEBUGGER:
535
        throw "NYI: " + tokens[n.type];
536

    
537
      case REQUIRE:
538
        var req = new XMLHttpRequest();
539
        req.open('GET', n.filename, 'false');
540

    
541
      case SEMICOLON:
542
        if (n.expression)
543
            // print debugging statements
544
                     
545
            var the_start = n.start
546
            var the_end = n.end
547
            var the_statement = parse_result.tokenizer.source.slice(the_start,the_end)
548
            //global.debug.document.body.innerHTML += ('<pre>&gt;&gt;&gt; <b>' + the_statement + '</b></pre>')
549
            LOG.info('>>>' + the_statement)
550
            x.result = getValue(execute(n.expression, x));   
551
            //if (x.result)
552
            //global.debug.document.body.innerHTML += ( '<pre>&gt;&gt;&gt; ' + x.result + '</pre>')
553
            
554
        break;
555

    
556
      case LABEL:
557
        try {
558
            execute(n.statement, x);
559
        } catch (e) {
560
            if (!(e == BREAK && x.target == n)) { throw e }
561
        }
562
        break;
563

    
564
      case COMMA:
565
        for (i = 0, j = n.$length; i < j; i++)
566
            v = getValue(execute(n[i], x));
567
        break;
568

    
569
      case ASSIGN:
570
        r = execute(n[0], x);
571
        t = n[0].assignOp;
572
        if (t)
573
            u = getValue(r);
574
        v = getValue(execute(n[1], x));
575
        if (t) {
576
            switch (t) {
577
              case BITWISE_OR:  v = u | v; break;
578
              case BITWISE_XOR: v = u ^ v; break;
579
              case BITWISE_AND: v = u & v; break;
580
              case LSH:         v = u << v; break;
581
              case RSH:         v = u >> v; break;
582
              case URSH:        v = u >>> v; break;
583
              case PLUS:        v = u + v; break;
584
              case MINUS:       v = u - v; break;
585
              case MUL:         v = u * v; break;
586
              case DIV:         v = u / v; break;
587
              case MOD:         v = u % v; break;
588
            }
589
        }
590
        putValue(r, v, n[0]);
591
        break;
592

    
593
      case CONDITIONAL:
594
        v = getValue(execute(n[0], x)) ? getValue(execute(n[1], x))
595
                                       : getValue(execute(n[2], x));
596
        break;
597

    
598
      case OR:
599
        v = getValue(execute(n[0], x)) || getValue(execute(n[1], x));
600
        break;
601

    
602
      case AND:
603
        v = getValue(execute(n[0], x)) && getValue(execute(n[1], x));
604
        break;
605

    
606
      case BITWISE_OR:
607
        v = getValue(execute(n[0], x)) | getValue(execute(n[1], x));
608
        break;
609

    
610
      case BITWISE_XOR:
611
        v = getValue(execute(n[0], x)) ^ getValue(execute(n[1], x));
612
        break;
613

    
614
      case BITWISE_AND:
615
        v = getValue(execute(n[0], x)) & getValue(execute(n[1], x));
616
        break;
617

    
618
      case EQ:
619
        v = getValue(execute(n[0], x)) == getValue(execute(n[1], x));
620
        break;
621

    
622
      case NE:
623
        v = getValue(execute(n[0], x)) != getValue(execute(n[1], x));
624
        break;
625

    
626
      case STRICT_EQ:
627
        v = getValue(execute(n[0], x)) === getValue(execute(n[1], x));
628
        break;
629

    
630
      case STRICT_NE:
631
        v = getValue(execute(n[0], x)) !== getValue(execute(n[1], x));
632
        break;
633

    
634
      case LT:
635
        v = getValue(execute(n[0], x)) < getValue(execute(n[1], x));
636
        break;
637

    
638
      case LE:
639
        v = getValue(execute(n[0], x)) <= getValue(execute(n[1], x));
640
        break;
641

    
642
      case GE:
643
        v = getValue(execute(n[0], x)) >= getValue(execute(n[1], x));
644
        break;
645

    
646
      case GT:
647
        v = getValue(execute(n[0], x)) > getValue(execute(n[1], x));
648
        break;
649

    
650
      case IN:
651
        v = getValue(execute(n[0], x)) in getValue(execute(n[1], x));
652
        break;
653

    
654
      case INSTANCEOF:
655
        t = getValue(execute(n[0], x));
656
        u = getValue(execute(n[1], x));
657
        if (isObject(u) && typeof u.__hasInstance__ == "function")
658
            v = u.__hasInstance__(t);
659
        else
660
            v = t instanceof u;
661
        break;
662

    
663
      case LSH:
664
        v = getValue(execute(n[0], x)) << getValue(execute(n[1], x));
665
        break;
666

    
667
      case RSH:
668
        v = getValue(execute(n[0], x)) >> getValue(execute(n[1], x));
669
        break;
670

    
671
      case URSH:
672
        v = getValue(execute(n[0], x)) >>> getValue(execute(n[1], x));
673
        break;
674

    
675
      case PLUS:
676
        v = getValue(execute(n[0], x)) + getValue(execute(n[1], x));
677
        break;
678

    
679
      case MINUS:
680
        v = getValue(execute(n[0], x)) - getValue(execute(n[1], x));
681
        break;
682

    
683
      case MUL:
684
        v = getValue(execute(n[0], x)) * getValue(execute(n[1], x));
685
        break;
686

    
687
      case DIV:
688
        v = getValue(execute(n[0], x)) / getValue(execute(n[1], x));
689
        break;
690

    
691
      case MOD:
692
        v = getValue(execute(n[0], x)) % getValue(execute(n[1], x));
693
        break;
694

    
695
      case DELETE:
696
        t = execute(n[0], x);
697
        v = !(t instanceof Reference) || delete t.base[t.propertyName];
698
        break;
699

    
700
      case VOID:
701
        getValue(execute(n[0], x));
702
        break;
703

    
704
      case TYPEOF:
705
        t = execute(n[0], x);
706
        if (t instanceof Reference)
707
            t = t.base ? t.base[t.propertyName] : undefined;
708
        v = typeof t;
709
        break;
710

    
711
      case NOT:
712
        v = !getValue(execute(n[0], x));
713
        break;
714

    
715
      case BITWISE_NOT:
716
        v = ~getValue(execute(n[0], x));
717
        break;
718

    
719
      case UNARY_PLUS:
720
        v = +getValue(execute(n[0], x));
721
        break;
722

    
723
      case UNARY_MINUS:
724
        v = -getValue(execute(n[0], x));
725
        break;
726

    
727
      case INCREMENT:
728
      case DECREMENT:
729
        t = execute(n[0], x);
730
        u = Number(getValue(t));
731
        if (n.postfix)
732
            v = u;
733
        putValue(t, (n.type == INCREMENT) ? ++u : --u, n[0]);
734
        if (!n.postfix)
735
            v = u;
736
        break;
737

    
738
      case DOT:
739
        r = execute(n[0], x);
740
        t = getValue(r);
741
        u = n[1].value;
742
        v = new Reference(toObject(t, r, n[0]), u, n);
743
        break;
744

    
745
      case INDEX:
746
        r = execute(n[0], x);
747
        t = getValue(r);
748
        u = getValue(execute(n[1], x));
749
        v = new Reference(toObject(t, r, n[0]), String(u), n);
750
        break;
751

    
752
      case LIST:
753
        // Curse ECMA for specifying that arguments is not an Array object!
754
        v = {};
755
        for (i = 0, j = n.$length; i < j; i++) {
756
            u = getValue(execute(n[i], x));
757
            v[i] = u;
758
        }
759
        v.length = i;
760
        break;
761

    
762
      case CALL:
763
        r = execute(n[0], x);
764
        a = execute(n[1], x);
765
        f = getValue(r);
766
        if (isPrimitive(f) || typeof f.__call__ != "function") {
767
            throw new TypeError(r + " is not callable",
768
                                n[0].filename(), n[0].lineno);
769
        }
770
        t = (r instanceof Reference) ? r.base : null;
771
        if (t instanceof Activation)
772
            t = null;
773
        v = f.__call__(t, a, x);
774
        break;
775

    
776
      case NEW:
777
      case NEW_WITH_ARGS:
778
        r = execute(n[0], x);
779
        f = getValue(r);
780
        if (n.type == NEW) {
781
            a = {};
782
            a.length = 0;
783
        } else {
784
            a = execute(n[1], x);
785
        }
786
        if (isPrimitive(f) || typeof f.__construct__ != "function") {
787
            throw new TypeError(r + " is not a constructor",
788
                                n[0].filename(), n[0].lineno);
789
        }
790
        v = f.__construct__(a, x);
791
        break;
792

    
793
      case ARRAY_INIT:
794
        v = [];
795
        for (i = 0, j = n.$length; i < j; i++) {
796
            if (n[i])
797
                v[i] = getValue(execute(n[i], x));
798
        }
799
        v.length = j;
800
        break;
801

    
802
      case OBJECT_INIT:
803
        v = {};
804
        for (i = 0, j = n.$length; i < j; i++) {
805
            t = n[i];
806
            if (t.type == PROPERTY_INIT) {
807
                v[t[0].value] = getValue(execute(t[1], x));
808
            } else {
809
                f = new FunctionObject(t, x.scope);
810
                /*
811
                u = (t.type == GETTER) ? '__defineGetter__'
812
                                       : '__defineSetter__';
813
                v[u](t.name, thunk(f, x));
814
                */
815
            }
816
        }
817
        break;
818

    
819
      case NULL:
820
        v = null;
821
        break;
822

    
823
      case THIS:
824
        v = x.thisObject;
825
        break;
826

    
827
      case TRUE:
828
        v = true;
829
        break;
830

    
831
      case FALSE:
832
        v = false;
833
        break;
834

    
835
      case IDENTIFIER:
836
        for (s = x.scope; s; s = s.parent) {
837
            if (n.value in s.object)
838
                break;
839
        }
840
        v = new Reference(s && s.object, n.value, n);
841
        break;
842

    
843
      case NUMBER:
844
      case STRING:
845
      case REGEXP:
846
        v = n.value;
847
        break;
848

    
849
      case GROUP:
850
        v = execute(n[0], x);
851
        break;
852

    
853
      default:
854
        throw "PANIC: unknown operation " + n.type + ": " + uneval(n);
855
    }
856
    return v;
857
}
858

    
859
function Activation(f, a) {
860
    for (var i = 0, j = f.params.length; i < j; i++)
861
        this[f.params[i]] = a[i];
862
    this.arguments = a;
863
}
864

    
865
// Null Activation.prototype's proto slot so that Object.prototype.* does not
866
// pollute the scope of heavyweight functions.  Also delete its 'constructor'
867
// property so that it doesn't pollute function scopes.
868

    
869
Activation.prototype.__proto__ = null;
870
delete Activation.prototype.constructor;
871

    
872
function FunctionObject(node, scope) {
873
    this.node = node;
874
    this.scope = scope;
875
    this.length = node.params.length;
876
    var proto = {};
877
    this.prototype = proto;
878
    proto.constructor = this;
879
}
880

    
881
var FOp = FunctionObject.prototype = {
882
    // Internal methods.
883
    __call__: function (t, a, x) {
884
        var x2 = new ExecutionContext(FUNCTION_CODE);
885
        x2.thisObject = t || global;
886
        x2.caller = x;
887
        x2.callee = this;
888
        a.callee = this;
889
        var f = this.node;
890
        x2.scope = {object: new Activation(f, a), parent: this.scope};
891

    
892
        ExecutionContext.current = x2;
893
        try {
894
            execute(f.body, x2);
895
        } catch (e) {
896
            if (!(e == RETURN)) { throw e } else if (e == RETURN) {
897
                return x2.result;
898
            }
899
            if (e != THROW) { throw e }
900
            x.result = x2.result;
901
            throw THROW;
902
        } finally {
903
            ExecutionContext.current = x;
904
        }
905
        return undefined;
906
    },
907

    
908
    __construct__: function (a, x) {
909
        var o = new Object;
910
        var p = this.prototype;
911
        if (isObject(p))
912
            o.__proto__ = p;
913
        // else o.__proto__ defaulted to Object.prototype
914

    
915
        var v = this.__call__(o, a, x);
916
        if (isObject(v))
917
            return v;
918
        return o;
919
    },
920

    
921
    __hasInstance__: function (v) {
922
        if (isPrimitive(v))
923
            return false;
924
        var p = this.prototype;
925
        if (isPrimitive(p)) {
926
            throw new TypeError("'prototype' property is not an object",
927
                                this.node.filename(), this.node.lineno);
928
        }
929
        var o;
930
        while ((o = v.__proto__)) {
931
            if (o == p)
932
                return true;
933
            v = o;
934
        }
935
        return false;
936
    },
937

    
938
    // Standard methods.
939
    toString: function () {
940
        return this.node.getSource();
941
    },
942

    
943
    apply: function (t, a) {
944
        // Curse ECMA again!
945
        if (typeof this.__call__ != "function") {
946
            throw new TypeError("Function.prototype.apply called on" +
947
                                " uncallable object");
948
        }
949

    
950
        if (t === undefined || t === null)
951
            t = global;
952
        else if (typeof t != "object")
953
            t = toObject(t, t);
954

    
955
        if (a === undefined || a === null) {
956
            a = {};
957
            a.length = 0;
958
        } else if (a instanceof Array) {
959
            var v = {};
960
            for (var i = 0, j = a.length; i < j; i++)
961
                v[i] = a[i];
962
            v.length = i;
963
            a = v;
964
        } else if (!(a instanceof Object)) {
965
            // XXX check for a non-arguments object
966
            throw new TypeError("Second argument to Function.prototype.apply" +
967
                                " must be an array or arguments object",
968
                                this.node.filename(), this.node.lineno);
969
        }
970

    
971
        return this.__call__(t, a, ExecutionContext.current);
972
    },
973

    
974
    call: function (t) {
975
        // Curse ECMA a third time!
976
        var a = Array.prototype.splice.call(arguments, 1);
977
        return this.apply(t, a);
978
    }
979
};
980

    
981
// Connect Function.prototype and Function.prototype.constructor in global.
982
reflectClass('Function', FOp);
983

    
984
// Help native and host-scripted functions be like FunctionObjects.
985
var Fp = Function.prototype;
986
var REp = RegExp.prototype;
987

    
988
if (!('__call__' in Fp)) {
989
    Fp.__call__ = function (t, a, x) {
990
        // Curse ECMA yet again!
991
        a = Array.prototype.splice.call(a, 0, a.length);
992
        return this.apply(t, a);
993
    };
994

    
995
    REp.__call__ = function (t, a, x) {
996
        a = Array.prototype.splice.call(a, 0, a.length);
997
        return this.exec.apply(this, a);
998
    };
999

    
1000
    Fp.__construct__ = function (a, x) {
1001
        switch (a.length) {
1002
          case 0:
1003
            return new this();
1004
          case 1:
1005
            return new this(a[0]);
1006
          case 2:
1007
            return new this(a[0], a[1]);
1008
          case 3:
1009
            return new this(a[0], a[1], a[2]);
1010
          case 4:
1011
            return new this(a[0], a[1], a[2], a[3]);
1012
          case 5:
1013
            return new this(a[0], a[1], a[2], a[3], a[4]);
1014
          case 6:
1015
            return new this(a[0], a[1], a[2], a[3], a[4], a[5]);
1016
          case 7:
1017
            return new this(a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
1018
        }
1019
        throw "PANIC: too many arguments to constructor";
1020
    }
1021

    
1022
    // Since we use native functions such as Date along with host ones such
1023
    // as global.eval, we want both to be considered instances of the native
1024
    // Function constructor.
1025
    Fp.__hasInstance__ = function (v) {
1026
        return v instanceof Function || v instanceof global.Function;
1027
    };
1028
}
1029

    
1030
function thunk(f, x) {
1031
    return function () { return f.__call__(this, arguments, x); };
1032
}
1033

    
1034
function evaluate(s, f, l) {
1035
    if (typeof s != "string")
1036
        return s;
1037

    
1038
    var x = ExecutionContext.current;
1039
    var x2 = new ExecutionContext(GLOBAL_CODE);
1040
    ExecutionContext.current = x2;
1041
    try {
1042
        execute(parse(s, f, l), x2);
1043
    } catch (e) {
1044
        if (e != THROW) { throw e }
1045
        if (x) {
1046
            x.result = x2.result;
1047
            throw(THROW);
1048
        }
1049
        throw x2.result;
1050
    } finally {
1051
        ExecutionContext.current = x;
1052
    }
1053
    return x2.result;
1054
}
(7-7/20)