1 /* -*- mode: java; tab-width: 4; insert-tabs-mode: nil; indent-tabs-mode: nil; -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is [Open Source Virtual Machine.].
17 * The Initial Developer of the Original Code is
18 * Adobe System Incorporated.
19 * Portions created by the Initial Developer are Copyright (C) 2004-2006
20 * the Initial Developer. All Rights Reserved.
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.
37 * ***** END LICENSE BLOCK ***** */
39 /* FIXME: handling 'super'.
44 * calls the super class's "m" with "this" as the receiver:
45 * 'callsuper' instruction
48 * calls the super class's constructor on the arguments:
49 * 'constructsuper' instruction
50 * only legal in a constructor, the parser annotates the Ctor structure with the args,
51 * don't need to handle this as an expression
54 * These have yet to be handled:
57 * picks up the 'x' member from the super class:
58 * 'getsuper' instruction
61 * calls the super class's "m" with "o" as the receiver (o must be of a reasonable type):
62 * 'callsuper' instruction
65 use default namespace Gen,
74 internal var lastline = -1;
76 function cgExpr(ctx, e) {
77 if (emit_debug && e.pos > 0 && e.pos != lastline) {
78 ctx.asm.I_debugline(e.pos);
82 case (e:TernaryExpr) { cgTernaryExpr(ctx, e) }
83 case (e:BinaryExpr) { cgBinaryExpr(ctx, e) }
84 case (e:BinaryTypeExpr) { cgBinaryTypeExpr(ctx, e) }
85 case (e:UnaryExpr) { cgUnaryExpr(ctx, e) }
86 case (e:TypeOpExpr) { cgTypeOpExpr(ctx, e) }
87 case (e:ThisExpr) { cgThisExpr(ctx, e) }
88 case (e:YieldExpr) { cgYieldExpr(ctx, e) }
90 Gen::syntaxError(ctx, "A 'super' expression can't appear here");
92 case (e:LiteralExpr) { cgLiteralExpr(ctx, e) }
93 case (e:CallExpr) { cgCallExpr(ctx, e) }
94 case (e:ApplyTypeExpr) { cgApplyTypeExpr(ctx, e) }
95 case (e:LetExpr) { cgLetExpr(ctx, e) }
96 case (e:DynamicOverrideExpr) { cgDynamicOverrideExpr(ctx, e) }
97 case (e:NewExpr) { cgNewExpr(ctx, e) }
98 case (e:ObjectRef) { cgObjectRef(ctx, e) }
99 case (e:IdentExpr) { cgIdentExprNode(ctx, e) }
100 case (e:SetExpr) { cgSetExpr(ctx, e) }
101 case (e:InitExpr) { cgInitExpr(ctx, e) }
102 case (e:GetTemp) { cgGetTempExpr(ctx, e) }
103 case (e:GetParam) { cgGetParamExpr(ctx, e) }
104 case (e:GetCogenTemp) { cgGetCogenTemp(ctx, e) }
105 case (e:EvalScopeInitExpr) { cgEvalScopeInitExpr(ctx,e) }
107 Gen::internalError(ctx, "Unimplemented expression type " + e);
112 function cgTernaryExpr(ctx, { e1: test, e2: consequent, e3: alternate }) {
115 let L0 = asm.I_iffalse(undefined);
116 cgExpr(ctx, consequent);
118 let L1 = asm.I_jump(undefined);
120 cgExpr(ctx, alternate);
125 function cgBinaryExpr(ctx, e) {
127 if (e.op == logicalAndOp) {
129 asm.I_coerce_a(); // wrong, should coerce to LUB of lhs and rhs
132 let L0 = asm.I_iffalse(undefined);
135 asm.I_coerce_a(); // wrong, should coerce to LUB of lhs and rhs
138 else if (e.op == logicalOrOp) {
140 asm.I_coerce_a(); // wrong, should coerce to LUB of lhs and rhs
143 let L0 = asm.I_iftrue(undefined);
146 asm.I_coerce_a(); // wrong, should coerce to LUB of lhs and rhs
149 else if (e.op == commaOp) {
158 case plusOp: asm.I_add(); break;
159 case minusOp: asm.I_subtract(); break;
160 case timesOp: asm.I_multiply(); break;
161 case divideOp: asm.I_divide(); break;
162 case remainderOp: asm.I_modulo(); break;
163 case leftShiftOp: asm.I_lshift(); break;
164 case rightShiftOp: asm.I_rshift(); break;
165 case rightShiftUnsignedOp: asm.I_urshift(); break;
166 case bitwiseAndOp: asm.I_bitand(); break;
167 case bitwiseOrOp: asm.I_bitor(); break;
168 case bitwiseXorOp: asm.I_bitxor(); break;
169 case instanceOfOp: asm.I_instanceof(); break;
170 case inOp: asm.I_in(); break;
171 case equalOp: asm.I_equals(); break;
172 case notEqualOp: asm.I_equals(); asm.I_not(); break;
173 case strictEqualOp: asm.I_strictequals(); break;
174 case strictNotEqualOp: asm.I_strictequals(); asm.I_not(); break;
175 case lessOp: asm.I_lessthan(); break;
176 case lessOrEqualOp: asm.I_lessequals(); break;
177 case greaterOp: asm.I_greaterthan(); break;
178 case greaterOrEqualOp: asm.I_greaterequals(); break;
179 default: Gen::internalError(ctx, "Unimplemented binary operator " + e);
184 internal var id_TypeError = new Ast::Identifier(Token::sym_TypeError, Ast::publicNSSL);
186 function cgBinaryTypeExpr(ctx, {op, e1, e2}) {
192 // OPTIMIZEME. This would benefit from an "OP_coercelate"
193 // opcode for brevity and less control flow but the code
194 // below should be correct as far as the language and
195 // verifier are concerned.
197 // OPTIMIZEME. Early-bind the right hand side if possible
198 // and use simpler code here (probably just a single
199 // OP_coerce instruction if that does not invoke any user
200 // defined converters).
203 cgTypeExprHelper(ctx, e2);
205 let L0 = asm.I_iftrue(undefined);
207 // FIXME: should lookup directly in global obj or be unforgeable name.
208 asm.I_findproperty(cgIdentExpr(ctx, id_TypeError));
209 asm.I_pushstring(cp.stringUtf8("Cast failed."));
210 asm.I_constructprop(cgIdentExpr(ctx, id_TypeError), 1);
219 // OPTIMIZEME. Early-bind the right hand side if possible
220 // and use simpler code here (probably just a single
221 // OP_istype instruction).
223 cgTypeExprHelper(ctx, e2);
228 Gen::internalError(ctx, "Unimplemented binary type operator " + op);
232 function cgTypeOpExpr(ctx, {ex}) {
233 cgTypeExprHelper(ctx, ex);
236 function cgTypeExprHelper(ctx, ty) {
237 let {asm, emitter} = ctx;
240 asm.I_findpropstrict(cgIdentExpr(ctx, ty.ident));
241 asm.I_getproperty(cgIdentExpr(ctx, ty.ident));
245 Gen::internalError(ctx, "Unimplemented type expression type " + ty);
250 function cgUnaryExpr(ctx, e) {
251 let {asm, emitter} = ctx;
253 switch (e.op & strictMask) {
255 // FIXME: delete operator strict mode
257 case (lr: IdentExpr) {
258 let bind = getIdentBinding(ctx, lr);
259 if( bind === Ast::nobind ) {
260 asm.I_findproperty(cgIdentExpr(ctx, lr));
261 asm.I_deleteproperty(cgIdentExpr(ctx, lr));
264 asm.I_pushtrue(); // can't delete a fixed property
266 case (or: ObjectRef) {
267 cgExpr(ctx, or.base);
268 asm.I_deleteproperty(cgIdentExpr(ctx, or.ident));
282 asm.I_pushundefined();
286 if (e.e1 is IdentExpr) {
287 cgFindProp(ctx, e.e1);
288 cgGetProp(ctx, e.e1);
308 incdec(false, false);
332 Gen::internalError(ctx, "Unimplemented unary operation " + op);
335 function incdec(pre, inc) {
337 case (lr: IdentExpr) {
338 if (cgFindPropStrict(ctx, lr)) // Ugly-ish. Object will be used by cgSetProp later.
340 cgGetProp(ctx, e.e1);
342 case (or:ObjectRef) {
343 cgExpr(ctx, or.base);
345 cgGetProp(ctx, e.e1.ident);
348 Gen::syntaxError(ctx, "Expression is not an lvalue: " + e.e1);
351 let t = asm.getTemp();
361 // Postfix ops return value after conversion to number.
371 case (lr: IdentExpr) {
374 case (or: ObjectRef) {
375 cgSetProp(ctx, or.ident);
383 function cgThisExpr({asm}, e) {
387 function cgYieldExpr(ctx, e) {
389 Gen::internalError(ctx, "Unimplemented 'yield' expression");
392 function cgCallExpr(ctx, e) {
393 let {asm, emitter} = ctx;
394 let nargs = e.args.length;
397 let isSuperCall = false;
400 if (e.spread != null)
401 Gen::internalError(ctx, "Spread expression not implemented.");
403 switch type (e.expr) {
404 case (or: ObjectRef) {
405 if (or.base is SuperExpr) {
406 assert(or.base.ex == null); // If not then super(o) form, don't know what that is yet. --lars
411 cgExpr(ctx, or.base);
413 case (lr: IdentExpr) {
414 var bind = getIdentBinding(ctx, lr);
415 if( bind is RegBind ) {
416 asm.I_getlocal(bind.reg);
417 asm.I_pushnull(); // Should we be using something else for this?
420 cgFindPropStrict(ctx, lr);
422 if (lr is Identifier && lr.ident == Token::sym_eval) {
424 evalTmp = asm.getTemp(); // save the
425 asm.I_dup(); // object
426 asm.I_setlocal(evalTmp); // for later
435 if (e.expr is ObjectRef) {
436 // Runtime/late parts appear on stack before arguments!
437 name = cgIdentExpr(ctx, e.expr.ident);
440 for ( let i=0 ; i < nargs ; i++ )
441 cgExpr(ctx, e.args[i]);
446 // Code performs 'eval', cleans the stack, and jumps to L0
447 // if the eval operator kicks in, otherwise falls through
448 // to the regular call code below.
449 L_skipcall = cgEvalPrefix(ctx, evalTmp, nargs, e.strict);
452 switch type (e.expr) {
453 case (or: ObjectRef) {
455 asm.I_callsuper(name, nargs);
457 asm.I_callproperty(name, nargs);
459 case (lr: IdentExpr) {
460 // This is not right if the function is bound by "with". In that
461 // case, I_callproperty would be more right. That's the outlier, though.
462 var bind = getIdentBinding(ctx, lr);
463 if( bind is SlotBind || bind == Ast::nobind )
464 asm.I_callproplex(cgIdentExpr(ctx, lr), nargs);
465 else if ( bind is RegBind ) {
475 asm.I_label(L_skipcall);
476 asm.killTemp(evalTmp);
480 // First check that 'eval' really gets us the global eval binding.
482 // Assuming it really is the eval operator:
484 // Since the form of the call is eval(...) we know there are no
485 // late-bound name components on the evaluation stack, just the
486 // receiver object (which is the global object). Clean up the
487 // stack by consing up an array of all the arguments.
489 // Call ESC::eval() on the argument array, a descriptor of the
490 // scopes (a string), and an array of scopes, outermost-first.
491 // The descriptor and the scope array have the same length. A
492 // letter in the descriptor is "s" if the object is a regular
493 // scope object (to be pushed by "pushscope") and "w" if it is is
494 // a "with" object (to be pushed by "pushwith").
496 // ESC::evalCompiler() returns the result of the evaluation.
498 function cgEvalPrefix(ctx, evalTmp, nargs, strict) {
500 let id_ESC = new Ast::Identifier(Token::sym_ESC, Ast::publicNSSL);
501 let id_evaluateInScopeArray = new Ast::QualifiedIdentifier(id_ESC, Token::sym_evaluateInScopeArray);
503 // Check it: Is this *really* the eval operator?
505 let L_normalcall = undefined;
507 /* FIXME: The following sanity tests only work when getglobalscope returns the object
508 that actually holds the global variables. Bugzilla 417342.
510 // The container must be === to the global object
511 asm.I_getlocal(evalTmp);
512 asm.I_getglobalscope();
513 asm.I_ifstrictne(L_normalcall);
515 // Property must be === to the predefined eval function, stored in the constant ESC::eval
516 asm.I_getlocal(evalTmp);
517 asm.I_getproperty(cgIdentExpr(ctx, lr.ident));
518 asm.I_getglobalscope();
519 asm.i_getproperty(cgIdentExpr(ctx, new Ast::QualifiedIdentifier(id_ESC,
520 new Ast::Identifier("eval", [[Ast::NoNS]]))));
521 asm.I_ifstrictne(L_normalcall);
524 asm.I_newarray(nargs); // collapse the arguments
525 asm.I_setlocal(evalTmp); // save it...
526 asm.I_pop(); // get rid of the object
527 asm.I_findpropstrict(cgIdentExpr(ctx, id_evaluateInScopeArray));
528 asm.I_getlocal(evalTmp); // argument array
530 // pushScopes() generates code that leaves an array of scope
531 // objects on the stack, followed by the scope descriptor
534 let numscopes = pushScopes(ctx);
539 asm.I_callproplex(cgIdentExpr(ctx, id_evaluateInScopeArray), 4);
541 L_skipcall = asm.I_jump(undefined);
543 if (L_normalcall != undefined)
544 asm.I_label(L_normalcall);
548 function pushScopes(ctx) {
552 function rec(stk, inner) {
555 // Do not capture the global scope
556 if (stk.tag == "script")
559 if (stk.tag == "function") {
560 level = rec(stk.link, false);
565 level = rec(stk.link, inner);
567 // FIXME: There may be two scope objects per ctx rib,
568 // because push_this may be true too.
573 scopedesc = "s" + scopedesc;
577 scopedesc = "w" + scopedesc;
588 Gen::internalError(ctx, "Unknown context tag: " + stk.tag);
593 asm.I_getscopeobject(level);
595 asm.I_getouterscope(level);
603 let numscopes = scopedesc.length;
605 ctx.asm.I_newarray(numscopes);
606 ctx.asm.I_pushstring(ctx.cp.stringUtf8(scopedesc));
612 function cgEvalScopeInitExpr(ctx, {index, how}) {
615 asm.I_getproperty(cgIdentExpr(ctx, new Ast::Identifier(String(index), Ast::publicNSSL)));
620 asm.I_pushundefined();
623 function cgApplyTypeExpr(ctx, e) {
625 Gen::internalError(ctx, "Unimplemented type application expression");
628 function cgLetExpr(ctx, {head, expr}) {
633 function cgDynamicOverrideExpr(ctx, {names, exprs, body}) {
634 assert(names.length == exprs.length);
636 // create code to secret current values away in temps
637 // set up a simplified try-finally.
638 // Duplicate the restoring code: the catch block restores
639 // and re-throws (but does not restore the scope chain?? It
640 // may need to, since variables to restore could be bound
641 // in various objects in the local scope chain.)
642 // The fallthrough code restores and continues.
647 // create code to restore values from temps
649 // FIXME: this code is only right if exceptions are not
652 // FIXME: this code evaluates subexpressions of the names several
656 let limit = names.length;
660 // Save existing values
661 for ( let i=0 ; i < limit ; i++ ) {
662 temps[i] = asm.getTemp();
663 asm.I_findpropstrict(cgIdentExpr(ctx, names[i]));
664 asm.I_getproperty(cgIdentExpr(ctx, names[i]));
665 asm.I_setlocal(temps[i]);
667 // Compute new values
668 for ( let i=0 ; i < limit ; i++ ) {
669 temps2[i] = asm.getTemp();
670 cgExpr(ctx, exprs[i]);
671 asm.I_setlocal(temps2[i]);
674 for ( let i=0 ; i < limit ; i++ ) {
675 asm.I_findpropstrict(cgIdentExpr(ctx, names[i]));
676 asm.I_getlocal(temps2[i]);
677 asm.I_setproperty(cgIdentExpr(ctx, names[i]));
678 asm.killTemp(temps2[i]);
682 // Restore old values
683 for ( let i=0 ; i < limit ; i++ ) {
684 asm.I_findpropstrict(cgIdentExpr(ctx, names[i]));
685 asm.I_getlocal(temps[i]);
686 asm.I_setproperty(cgIdentExpr(ctx, names[i]));
687 asm.killTemp(temps[i]);
689 // Result of body is left on the stack.
693 function cgNewExpr(ctx, {expr, args, spread}) {
697 Gen::internalError(ctx, "Spread expression not implemented");
700 for ( let i=0, limit=args.length ; i < limit ; i++ )
701 cgExpr(ctx, args[i]);
702 asm.I_construct(args.length);
705 function cgObjectRef(ctx, {base, ident}) {
708 asm.I_getproperty(cgIdentExpr(ctx, ident));
711 // Not to be confused with the subroutine cgIdentExpr below. That one
712 // ought to be renamed, not this one.
714 function cgIdentExprNode(ctx, ident) {
715 cgFindPropStrict(ctx, ident);
716 cgGetProp(ctx, ident);
719 function cgSetExpr(ctx, e) {
721 case (objref: Ast::ObjectRef) { cgSetObjectRefExpr(ctx, e) }
722 case (ident: Ast::IdentExpr) { cgSetIdentExpr(ctx, e) }
723 case (x: *) { Gen::syntaxError(ctx, "Illegal lvalue " + x) }
727 function cgSetIdentExpr(ctx, {op, le, re}) {
728 let {asm, emitter} = ctx;
729 let opr = op & strictMask;
730 let t = asm.getTemp();
732 if (opr == assignOp) {
737 if (cgFindPropStrict(ctx, le))
740 cgOperate(ctx, re, opr, (op & strictFlag) != 0);
750 function cgSetObjectRefExpr(ctx, {op, le, re}) {
751 let {asm, emitter} = ctx;
752 let opr = op & strictMask;
753 let t = asm.getTemp();
755 cgExpr(ctx, le.base);
756 if( le.ident is Identifier )
757 le.ident.binding = Ast::nobind;
759 if (opr == assignOp) {
760 let name = cgIdentExpr(ctx, le.ident); // order matters if it's a ComputedName
764 asm.I_setproperty(name);
767 let subtmp = null; // stores indexing expression value
768 let subname = null; // multiname to store under
769 asm.I_dup(); // object expr
771 if (le.ident is ComputedName) {
772 subtmp = asm.getTemp();
773 cgExpr(ctx, le.ident.expr);
775 asm.I_setlocal(subtmp);
776 subname = emitter.multinameL(Ast::publicNSSL, false);
777 asm.I_getproperty(subname);
780 cgGetProp(ctx, le.ident);
782 cgOperate(ctx, re, opr, (op & strictFlag) != 0);
786 if (le.ident is ComputedName) {
787 asm.I_getlocal(subtmp);
789 asm.I_setproperty(subname);
790 asm.killTemp(subtmp);
793 cgSetProp(ctx, le.ident);
799 function cgOperate(ctx, expr, op, is_strict) {
800 // FIXME: assignment operators strict mode
802 // the left-hand expression is on the stack.
804 if (op == assignLogicalAndOp || op == assignLogicalOrOp) {
807 let L0 = (op == assignLogicalAndOp) ? asm.I_iffalse(undefined) : asm.I_iftrue(undefined);
816 case assignPlusOp: asm.I_add(); break;
817 case assignMinusOp: asm.I_subtract(); break;
818 case assignTimesOp: asm.I_multiply(); break;
819 case assignDivideOp: asm.I_divide(); break;
820 case assignRemainderOp: asm.I_modulo(); break;
821 case assignLeftShiftOp: asm.I_lshift(); break;
822 case assignRightShiftOp: asm.I_rshift(); break;
823 case assignRightShiftUnsignedOp: asm.I_urshift(); break;
824 case assignBitwiseAndOp: asm.I_bitand(); break;
825 case assignBitwiseOrOp: asm.I_bitor(); break;
826 case assignBitwiseXorOp: asm.I_bitxor(); break;
827 default: Gen::internalError(ctx, "ASSIGNOP not supported " + op);
832 function cgInitExpr(ctx, e) {
834 let baseOnStk = false;
835 if (e.target == instanceInit) {
836 // Load this on the stack
840 cgInits(ctx, e.inits, baseOnStk);
841 asm.I_pushundefined(); // exprs need to leave something on the stack
842 // FIXME: should this be the value of the last init?
845 function cgLiteralExpr(ctx, e) {
847 function cgArrayInitializer(ctx, {exprs, spread}) {
850 let limit = exprs.length
853 Gen::internalError(ctx, "Spread expression in array initializer not implemented.");
855 // Use newarray to construct the dense prefix
856 for ( ; i < limit ; i++ ) {
858 if (e is Ast::LiteralUndefined)
864 // Then init the other defined slots one by one
866 let last_was_undefined = false;
867 for ( ; i < limit ; i++ ) {
869 if (!(e is Ast::LiteralUndefined)) {
872 asm.I_setproperty(cgIdentExpr(ctx, new Ast::Identifier(Token::intern(i), Ast::publicNSSL)));
873 last_was_undefined = false;
876 last_was_undefined = true;
878 if (last_was_undefined) {
880 asm.I_pushint(ctx.cp.int32(limit));
881 asm.I_setproperty(cgIdentExpr(ctx, new Ast::Identifier(Token::sym_length, Ast::publicNSSL)));
886 function cgObjectInitializer(ctx, {fields:fields}) {
887 let {asm, emitter} = ctx;
888 asm.I_findpropstrict(ctx.emitter.Object_name);
889 asm.I_constructprop(ctx.emitter.Object_name, 0);
890 let t = asm.getTemp();
892 for ( let i=0, limit=fields.length ; i < limit ; i++ ) {
893 switch type (fields[i]) {
894 case (lf: Ast::LiteralField) {
895 // SYNTACTIC CONDITION. If the object initializer is
896 // used to produce a value (it's not used for
897 // destructuring) then the ": expr" part is not
901 Gen::syntaxError(ctx, "Missing field value in object initializer: " + lf.ident);
904 cgExpr(ctx, lf.expr);
905 asm.I_setproperty(cgIdentExpr(ctx, lf.ident));
908 case (vf: Ast::VirtualField) {
909 Gen::internalError(ctx, "VirtualField support missing.");
911 case (pf: Ast::ProtoField) {
912 Gen::internalError(ctx, "ProtoField support missing.");
916 //asm.I_newobject(fields.length);
921 function cgRegExpLiteral(ctx, re) {
923 let src = re.src.text;
924 // src is "/.../flags"
926 // Note, ES4 semantics: recreate RE object every time.
927 // FIXME: re-compiles the RE every time.
928 let p = src.lastIndexOf('/');
929 // FIXME: We don't want findpropstrict because it can be used to spoof RegExp.
930 // But getglobalscope produces an object that does not have "RegExp" bound.
931 asm.I_findpropstrict(ctx.emitter.RegExp_name);
932 asm.I_pushstring(cp.stringUtf8(src.substring(1,p)));
933 asm.I_pushstring(cp.stringUtf8(src.substring(p+1)));
934 asm.I_constructprop(ctx.emitter.RegExp_name, 2);
937 let {asm, emitter} = ctx;
939 case (e:LiteralNull) { asm.I_pushnull() }
940 case (e:LiteralUndefined) { asm.I_pushundefined() }
941 case (e:LiteralInt) {
942 let val = e.intValue;
943 if (val >= -128 && val < 128)
944 asm.I_pushbyte(val & 0xFF); // pushbyte sign-extends
946 asm.I_pushint(ctx.cp.int32(val));
948 case (e:LiteralUInt) {
949 asm.I_pushuint(ctx.cp.uint32(e.uintValue));
951 case (e:LiteralDouble) {
952 let val = e.doubleValue;
956 asm.I_pushdouble(ctx.cp.float64(val));
958 case (e:LiteralDecimal) {
959 // FIXME: proper decimal support when the AVM can handle it!
960 asm.I_pushdouble(ctx.cp.float64(parseFloat(e.decimalValue)));
962 case (e:LiteralString) {
963 asm.I_pushstring(ctx.cp.symbolUtf8(e.strValue));
965 case (e:LiteralBoolean) {
971 case (e:LiteralFunction) {
972 if (e.func.name != null) {
973 // FIXME: correct for ES3 but not for ES4
974 let t = asm.getTemp();
979 asm.I_newfunction(cgFunc(ctx, e.func));
983 asm.I_setproperty(emitter.nameFromIdent(e.func.name.ident));
987 asm.I_newfunction(cgFunc(ctx, e.func));
989 case (e:LiteralArray) { cgArrayInitializer(ctx, e) }
990 case (e:LiteralObject) { cgObjectInitializer(ctx, e) }
991 case (e:LiteralRegExp) { cgRegExpLiteral(ctx, e) }
992 // case (e:LiteralNamespace) { cgNamespaceLiteral(ctx, e) }
994 Gen::internalError(ctx, "Unimplemented LiteralExpr " + e);
999 function cgGetTempExpr(ctx, {n}) {
1000 let {asm, emitter} = ctx;
1001 let id = new Ast::Identifier(Token::intern("$t" + n), Ast::publicNSSL);
1002 cgFindPropStrict(ctx, id);
1006 function cgGetParamExpr({asm}, {n}) {
1007 asm.I_getlocal(n + 1); //account for 'this'
1010 function cgGetCogenTemp({asm}, {n}) {
1014 function cgIdentExpr(ctx, e) {
1015 let {asm, emitter} = ctx;
1017 case (id:Identifier) {
1018 return emitter.multiname(id,false);
1020 case (ei:ComputedName) {
1021 cgExpr(ctx, ei.expr);
1022 return emitter.multinameL(Ast::publicNSSL,false);
1024 case (qi:QualifiedIdentifier) {
1025 switch type(qi.qual) {
1026 case( lr: Identifier ) {
1027 // Hack to deal with namespaces for now...
1028 // later we will have to implement a namespace lookup to resolve qualified typenames
1029 return emitter.qname(new Ast::Name(new Ast::UnforgeableNamespace(lr.ident), qi.ident), false);
1031 case (lr: ForgeableNamespace) {
1032 return emitter.qname(new Ast::Name(lr, qi.ident), false);
1034 case (lr: UnforgeableNamespace) {
1035 return emitter.qname(new Ast::Name(lr, qi.ident), false);
1038 /// cgExpr(ctx, qi.qual);
1039 /// return emitter.rtqname(qi);
1040 Gen::internalError(ctx, "Unsupported form of qualified identifier " + qi);
1044 case (x: PropName) {
1045 return emitter.fixtureNameToName(x);
1047 case (x: TempName) {
1048 return emitter.fixtureNameToName(x);
1051 Gen::internalError(ctx, "Unimplemented cgIdentExpr " + e);
1056 function getIdentBinding(ctx, id: IdentExpr) {
1057 if (id is Identifier) {
1058 if( id.binding === undefined )
1059 id.binding = findBinding(ctx, id.ident, id.nss);
1065 // Returns true if the result of the findprop is left on the stack
1066 function cgFindPropStrict(ctx, id:IdentExpr)
1067 cgFindProp(ctx, id, true);
1069 // Returns true if the result of the findprop is left on the stack
1070 function cgFindProp(ctx, id:IdentExpr, is_strict = false) {
1073 switch type ( getIdentBinding(ctx, id) ) {
1074 case ( rb : RegBind ) {
1075 // Do nothing, we'll get/set the value later with a register
1078 case ( sb : SlotBind ) {
1079 // Load the scope the slot is in
1080 asm.I_getlocal(sb.scope);
1084 asm.I_findpropstrict(cgIdentExpr(ctx, id));
1086 asm.I_findproperty(cgIdentExpr(ctx, id));
1092 function cgGetProp(ctx, id) {
1095 switch type ( getIdentBinding(ctx, id) ) {
1096 case ( rb : RegBind ) {
1097 // Load the register
1098 asm.I_getlocal(rb.reg);
1100 case ( sb : SlotBind ) {
1101 // Load the scope the slot is in
1103 asm.I_getproperty(cgIdentExpr(ctx, id));
1105 asm.I_getslot(sb.slot);
1108 asm.I_getproperty(cgIdentExpr(ctx, id));
1113 function cgSetProp(ctx, id) {
1116 switch type ( getIdentBinding(ctx, id) ) {
1117 case ( rb : RegBind ) {
1119 if( rb.type_index != 0 )
1120 asm.I_coerce(rb.type_index);
1123 asm.I_setlocal(rb.reg);
1125 case ( sb : SlotBind ) {
1126 // Load the scope the slot is in
1128 asm.I_setproperty(cgIdentExpr(ctx, id));
1130 asm.I_setslot(sb.slot);
1133 asm.I_setproperty(cgIdentExpr(ctx, id));