0001: /*=============================================================================
0002: * Copyright Texas Instruments 2000-2003. All Rights Reserved.
0003: *
0004: * This program is free software; you can redistribute it and/or
0005: * modify it under the terms of the GNU Lesser General Public
0006: * License as published by the Free Software Foundation; either
0007: * version 2 of the License, or (at your option) any later version.
0008: *
0009: * This program is distributed in the hope that it will be useful,
0010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0012: * Lesser General Public License for more details.
0013: *
0014: * You should have received a copy of the GNU Lesser General Public
0015: * License along with this library; if not, write to the Free Software
0016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0017: *
0018: * $ProjectHeader: OSCRIPT 0.155 Fri, 20 Dec 2002 18:34:22 -0800 rclark $
0019: */
0020:
0021: package oscript.compiler;
0022:
0023: import oscript.syntaxtree.*;
0024: import oscript.data.*;
0025: import oscript.exceptions.*;
0026: import oscript.parser.OscriptParser;
0027: import oscript.translator.*;
0028:
0029: // The Bytecode Engineerign Library
0030: import org.apache.bcel.generic.*;
0031: import org.apache.bcel.Constants;
0032:
0033: import java.util.Vector;
0034: import java.util.LinkedList;
0035: import java.util.Iterator;
0036:
0037: /**
0038: * The CompilerVisitor is the compiler, which compiles functions to an
0039: * instance of <code>CompiledNodeEvaluator</code>.
0040: * <p>
0041: * Some assumptions are made with respect to tracking the info needed to
0042: * generate useful stack traces, for example that the entire function is
0043: * defined within the same file.
0044: *
0045: * @author Rob Clark (rob@ti.com)
0046: * <!--$Format: " * @version $Revision$"$-->
0047: * @version 1.84
0048: */
0049: public class CompilerVisitor implements oscript.visitor.Visitor,
0050: oscript.parser.OscriptParserConstants {
0051: /**
0052: * The instruction list which becomes the code of the <code>evalNode</code>
0053: * method which is generated.
0054: */
0055: CompilerInstructionList il;
0056:
0057: /**
0058: * The current method being generated.
0059: */
0060: MethodGen mg;
0061:
0062: /**
0063: */
0064: CompilerContext ctx;
0065:
0066: /**
0067: * Some nodes, when visited, leave a return node on the top of the stack,
0068: * and some remove the return value from the stack. Nodes that don't
0069: * put or remove the return value from the top of the stack leave this
0070: * flag unchanged.
0071: */
0072: private boolean retValOnStack;
0073:
0074: /**
0075: * Set <code>retValOnStack</code> with this function... it does some
0076: * error checking.
0077: */
0078: private void setRetValOnStack(boolean retValOnStack) {
0079: if (this .retValOnStack == retValOnStack)
0080: throw new ProgrammingErrorException(
0081: "retValOnStack is already " + retValOnStack);
0082: else
0083: this .retValOnStack = retValOnStack;
0084: }
0085:
0086: /**
0087: * For sanity checking, sort of like an ASSERT() for <code>retValOnStack</code>.
0088: */
0089: private void checkRetValOnStack(boolean retValOnStack) {
0090: if (this .retValOnStack != retValOnStack)
0091: throw new ProgrammingErrorException("retValOnStack is not "
0092: + retValOnStack);
0093: }
0094:
0095: /*=======================================================================*/
0096: /**
0097: * The loop stack is used to track nested levels of loops, and cleanup
0098: * such as JSR to finally or releasing monitors, that needs to happen
0099: * when program execution jumps out of a loop, such as in the case of
0100: * "return", "continue", or "break"
0101: */
0102: private LoopStackNode loopStack;
0103:
0104: /*=======================================================================*/
0105: /**
0106: * List of runnables to invoke after the first pass of the compiler over
0107: * the syntax-tree
0108: */
0109: private LinkedList deferredRunnableList = new LinkedList();
0110:
0111: /*=======================================================================*/
0112: /**
0113: * Create a new compiler-visitor, which generates compiled code
0114: */
0115: CompilerVisitor(CompilerContext ctx, String name, Node node) {
0116: this (ctx, name, node, null);
0117: }
0118:
0119: private CompilerVisitor(CompilerContext ctx, String name,
0120: Node node, int[] argIds) {
0121: this .ctx = ctx;
0122:
0123: il = new CompilerInstructionList();
0124:
0125: mg = new MethodGen(Constants.ACC_PRIVATE, ctx.OBJECT_TYPE,
0126: ctx.EVAL_NODE_ARG_TYPES, ctx.EVAL_NODE_ARG_NAMES, "_"
0127: + (innerNodeIdx = ctx.getNextEvalNodeIdx(name))
0128: + "_" + name, ctx.className, il, ctx.cp);
0129:
0130: scope = new CompilerScope(this , 2, argIds);
0131:
0132: ctx.addSMITs(innerNodeIdx, scope
0133: .getSharedMemberIndexTableIdxs());
0134:
0135: compileNode(node);
0136: }
0137:
0138: private int innerNodeIdx;
0139:
0140: /*=======================================================================*/
0141: /**
0142: * The entry point to compile a node.
0143: *
0144: * @param node the node in syntaxtree to compile
0145: */
0146: private void compileNode(Node node) {
0147: retValOnStack = false;
0148:
0149: loopStack = new LoopStackNode(null);
0150:
0151: node.accept(this );
0152:
0153: loopStack.pop();
0154:
0155: if (!retValOnStack)
0156: getInstanceConstant(Value.UNDEFINED);
0157:
0158: /* we may end up with two ARETURN's at the end, but that should be
0159: * ok... we need to add a return instruction at the end just in
0160: * case there isn't one, or if someone calls il.setNextAsTarget(...)
0161: */
0162: il.append(InstructionConstants.ARETURN);
0163:
0164: for (Iterator itr = deferredRunnableList.iterator(); itr
0165: .hasNext();)
0166: ((Runnable) (itr.next())).run();
0167:
0168: mg.setMaxStack();
0169: ctx.cg.addMethod(mg.getMethod());
0170: }
0171:
0172: /*=======================================================================*/
0173: CompilerScope scope;
0174:
0175: /*=======================================================================*/
0176: /**
0177: */
0178: public void visit(NodeList n) {
0179: throw new ProgrammingErrorException("unimplemented");
0180: }
0181:
0182: public void visit(NodeListOptional n) {
0183: throw new ProgrammingErrorException("unimplemented");
0184: }
0185:
0186: public void visit(NodeOptional n) {
0187: throw new ProgrammingErrorException("unimplemented");
0188: }
0189:
0190: public void visit(NodeSequence n) {
0191: throw new ProgrammingErrorException("unimplemented");
0192: }
0193:
0194: /*=======================================================================*/
0195: private NodeToken NodeToken_lastToken;
0196: private Vector NodeToken_lastSpecials;
0197: private String NodeToken_lastDesc;
0198: private int NodeToken_lastBeginLine = -1;
0199: private InstructionHandle NodeToken_lastBranchTarget = null;
0200:
0201: private CompilerScope NodeToken_lastScope = null; // for deciding which setLineNumber() to call
0202:
0203: /**
0204: * Handles storing line # info for a node-token. This should really be
0205: * called for every node-token to ensure that no line # info is lost.
0206: */
0207: void handle(NodeToken n) {
0208: NodeToken_lastToken = n;
0209:
0210: if (n.specialTokens != null)
0211: NodeToken_lastSpecials = n.specialTokens;
0212:
0213: if (true) // XXX we should be able to enable/disable inserting this extra code at runtime
0214: {
0215: // XXX I think this condition should always hold:
0216: if ((NodeToken_lastDesc != null)
0217: && !("".equals(n.desc)
0218: || "".equals(NodeToken_lastDesc) || NodeToken_lastDesc
0219: .equals(n.desc)))
0220: System.err.println("desc changed, was "
0221: + NodeToken_lastDesc + ", now is " + n.desc);
0222:
0223: // we only need to insert code to update the line # if the line # changed
0224: // or if there is a branch inst target between here and the last time we
0225: // updated the line #
0226: if ((NodeToken_lastBeginLine != n.beginLine)
0227: || (NodeToken_lastBranchTarget != il
0228: .getLastBranchTarget())) {
0229: InstructionHandle ih;
0230:
0231: if (scope != NodeToken_lastScope) {
0232: // sf.setLineNumber( scope, n.beginLine );
0233: il.append(InstructionConstants.ALOAD_1); // sf
0234: il.append(new ALOAD(scope.getSlot()));
0235: ctx.pushInt(il, n.beginLine);
0236:
0237: ih = il.append(new INVOKEVIRTUAL(ctx.methodref(
0238: "oscript.util.StackFrame", "setLineNumber",
0239: "(Loscript/data/Scope;I)V")));
0240: NodeToken_lastScope = scope;
0241: } else {
0242: // sf.setLineNumber(n.beginLine);
0243: il.append(InstructionConstants.ALOAD_1); // sf
0244: ctx.pushInt(il, n.beginLine);
0245:
0246: ih = il.append(new INVOKEVIRTUAL(ctx.methodref(
0247: "oscript.util.StackFrame", "setLineNumber",
0248: "(I)V")));
0249: }
0250:
0251: mg.addLineNumber(ih, n.beginLine);
0252: }
0253:
0254: NodeToken_lastDesc = n.desc;
0255: NodeToken_lastBeginLine = n.beginLine;
0256: NodeToken_lastBranchTarget = il.getLastBranchTarget();
0257: }
0258: }
0259:
0260: String getDebugName() {
0261: if (NodeToken_lastDesc != null)
0262: return NodeToken_lastDesc + ":" + NodeToken_lastBeginLine;
0263: return ctx.name;
0264: }
0265:
0266: /**
0267: * get the "desc" of the syntax-tree being parsed... ie. the filename
0268: */
0269: String getDesc() {
0270: return NodeToken_lastDesc;
0271: }
0272:
0273: /**
0274: */
0275: public void visit(NodeToken n) {
0276: handle(n);
0277:
0278: // XXX handle IDENTIFIER specially... it might be better to give IDENTIFIER
0279: // it's own production in the grammar
0280: if (n.kind == IDENTIFIER) {
0281: ctx.pushSymbol(il, n.tokenImage);
0282: setRetValOnStack(true);
0283: return;
0284: }
0285:
0286: if (n.cachedValue == null) {
0287: switch (n.kind) {
0288: case INTEGER_LITERAL:
0289: case HEX_LITERAL:
0290: case OCTAL_LITERAL:
0291: case DECIMAL_LITERAL:
0292: case BINARY_LITERAL:
0293: n.cachedValue = OExactNumber
0294: .makeExactNumber(n.otokenImage
0295: .castToExactNumber());
0296: break;
0297: case FLOATING_POINT_LITERAL:
0298: n.cachedValue = OInexactNumber
0299: .makeInexactNumber(n.otokenImage
0300: .castToInexactNumber());
0301: break;
0302: case STRING_LITERAL:
0303: n.cachedValue = OString.makeString(OString
0304: .chop(n.tokenImage.substring(1, n.tokenImage
0305: .length() - 1))); // should this be intern'd???
0306: break;
0307: case REGEXP_LITERAL:
0308: n.cachedValue = RegExp.createRegExp(n.otokenImage);
0309: break;
0310: case TRUE:
0311: n.cachedValue = OBoolean.TRUE;
0312: break;
0313: case FALSE:
0314: n.cachedValue = OBoolean.FALSE;
0315: break;
0316: case NULL:
0317: n.cachedValue = Value.NULL;
0318: break;
0319: case UNDEFINED:
0320: n.cachedValue = Value.UNDEFINED;
0321: break;
0322: case -1:
0323: default:
0324: // leave as null
0325: }
0326: }
0327:
0328: if (n.cachedValue != null) {
0329: getInstanceConstant(n.cachedValue);
0330: }
0331: }
0332:
0333: /**
0334: * Add a deferred runnable, which is run after the first pass over the
0335: * syntax-tree. This gives various parts of the compiler a way to defer
0336: * a decision until after the first pass.
0337: *
0338: * @param r the runnable that is invoked in an unspecified order after
0339: * the first pass
0340: */
0341: void defer(Runnable r) {
0342: deferredRunnableList.add(r);
0343: }
0344:
0345: /**
0346: * push the instance constant onto the stack, setting ret-val to true.
0347: */
0348: void getInstanceConstant(Object obj) {
0349: setRetValOnStack(true);
0350: ctx.pushInstanceConstant(il, obj);
0351: }
0352:
0353: /*=======================================================================*/
0354: /**
0355: * <PRE>
0356: * f0 -> ( <UNIX_SELF_EXECUTABLE_COMMENT> )?
0357: * f1 -> Program(false)
0358: * f2 -> <EOF>
0359: * </PRE>
0360: */
0361: public void visit(ProgramFile n) {
0362: n.f1.accept(this );
0363: }
0364:
0365: /*=======================================================================*/
0366: /**
0367: * <PRE>
0368: * f0 -> ( EvaluationUnit() )*
0369: * </PRE>
0370: */
0371: public void visit(Program n) {
0372: for (int i = 0; i < n.f0.size(); i++)
0373: n.f0.elementAt(i).accept(this );
0374: }
0375:
0376: /*=======================================================================*/
0377: /**
0378: * <PRE>
0379: * f0 -> ScopeBlock()
0380: * | VariableDeclarationBlock()
0381: * | FunctionDeclaration()
0382: * | TryStatement()
0383: * | ForLoopStatement()
0384: * | WhileLoopStatement()
0385: * | ConditionalStatement()
0386: * | SynchronizedStatement()
0387: * | ReturnStatement()
0388: * | BreakStatement()
0389: * | ContinueStatement()
0390: * | ExpressionBlock()
0391: * | ThrowBlock()
0392: * | ImportBlock()
0393: * | MixinBlock()
0394: * | EvalBlock()
0395: * </PRE>
0396: */
0397: public void visit(EvaluationUnit n) {
0398: n.f0.accept(this );
0399:
0400: if (retValOnStack) {
0401: il.append(InstructionConstants.POP);
0402: setRetValOnStack(false);
0403: }
0404: }
0405:
0406: /*=======================================================================*/
0407: /**
0408: * <PRE>
0409: * f0 -> "{"
0410: * f1 -> Program()
0411: * f2 -> "}"
0412: * </PRE>
0413: */
0414: public void visit(ScopeBlock n) {
0415: if (n.hasVarInScope)
0416: scope = new CompilerScope(this , scope, n.hasFxnInScope); // push new scope
0417: n.f1.accept(this );
0418: if (n.hasVarInScope)
0419: scope = scope.pop(); // pop scope
0420: }
0421:
0422: /*=======================================================================*/
0423: /**
0424: * <PRE>
0425: * f0 -> VariableDeclaration()
0426: * f1 -> ";"
0427: * </PRE>
0428: */
0429: public void visit(VariableDeclarationBlock n) {
0430: n.f0.accept(this );
0431: }
0432:
0433: /*=======================================================================*/
0434: /**
0435: * <PRE>
0436: * f0 -> Expression()
0437: * f1 -> ";"
0438: * </PRE>
0439: */
0440: public void visit(ExpressionBlock n) {
0441: n.f0.accept(this );
0442: }
0443:
0444: /*=======================================================================*/
0445: /**
0446: * <PRE>
0447: * f0 -> "throw"
0448: * f1 -> Expression()
0449: * f2 -> ";"
0450: * </PRE>
0451: */
0452: public void visit(ThrowBlock n) {
0453: handle(n.f0);
0454:
0455: // evaluate expression:
0456: n.f1.accept(this );
0457: setRetValOnStack(false);
0458:
0459: // check that the user isn't trying to throw (undefined)
0460: il.append(new INVOKESTATIC(ctx.methodref(
0461: "oscript.compiler.CompiledNodeEvaluator",
0462: "returnHelper",
0463: "(Loscript/data/Value;)Loscript/data/Value;")));
0464:
0465: // throw PackagedScriptObjectException.makeExceptionWrapper(retVal)
0466: il
0467: .append(new INVOKESTATIC(
0468: ctx
0469: .methodref(
0470: "oscript.exceptions.PackagedScriptObjectException",
0471: "makeExceptionWrapper2",
0472: "(Loscript/data/Value;)Loscript/exceptions/PackagedScriptObjectException;")));
0473: il.append(InstructionConstants.ATHROW);
0474: }
0475:
0476: /*=======================================================================*/
0477: /**
0478: * <PRE>
0479: * f0 -> "import"
0480: * f1 -> Expression()
0481: * f2 -> ";"
0482: * </PRE>
0483: */
0484: public void visit(ImportBlock n) {
0485: handle(n.f0);
0486:
0487: // evaluate expression:
0488: n.f1.accept(this );
0489:
0490: il.append(new INVOKEVIRTUAL(ctx.methodref("oscript.data.Value",
0491: "castToString", "()Ljava/lang/String;")));
0492:
0493: il.append(new ALOAD(scope.getSlot()));
0494:
0495: il
0496: .append(new INVOKESTATIC(
0497: ctx
0498: .methodref(
0499: "oscript.compiler.CompiledNodeEvaluator",
0500: "importHelper",
0501: "(Ljava/lang/String;Loscript/data/Scope;)Loscript/data/Value;")));
0502:
0503: scope.markOpen();
0504: }
0505:
0506: /*=======================================================================*/
0507: /**
0508: * <PRE>
0509: * f0 -> "mixin"
0510: * f1 -> Expression()
0511: * f2 -> ";"
0512: * </PRE>
0513: */
0514: public void visit(MixinBlock n) {
0515: handle(n.f0);
0516:
0517: il.append(new ALOAD(scope.getSlot()));
0518: n.f1.accept(this );
0519: setRetValOnStack(false);
0520: il.append(new INVOKEVIRTUAL(ctx.methodref("oscript.data.Scope",
0521: "mixin", "(Loscript/data/Value;)V")));
0522:
0523: scope.markOpen(); // XXX ??? need to ensure scope object is actually created, but that doesn't make it an open scope
0524: }
0525:
0526: /*=======================================================================*/
0527: /**
0528: * <PRE>
0529: * f0 -> "eval"
0530: * f1 -> Expression()
0531: * f2 -> ";"
0532: * </PRE>
0533: */
0534: public void visit(EvalBlock n) {
0535: handle(n.f0);
0536:
0537: // evaluate expression:
0538: n.f1.accept(this );
0539:
0540: il.append(new INVOKEVIRTUAL(ctx.methodref("oscript.data.Value",
0541: "castToString", "()Ljava/lang/String;")));
0542:
0543: il.append(new ALOAD(scope.getSlot()));
0544:
0545: il
0546: .append(new INVOKESTATIC(
0547: ctx
0548: .methodref(
0549: "oscript.compiler.CompiledNodeEvaluator",
0550: "evalHelper",
0551: "(Ljava/lang/String;Loscript/data/Scope;)Loscript/data/Value;")));
0552:
0553: scope.markOpen();
0554: }
0555:
0556: /*=======================================================================*/
0557: /**
0558: * <PRE>
0559: * f0 -> Permissions()
0560: * f1 -> "var"
0561: * f2 -> <IDENTIFIER>
0562: * f3 -> ( "=" Expression() )?
0563: * </PRE>
0564: */
0565: public void visit(VariableDeclaration n) {
0566: // need to handle for special tokens, before n.f3
0567: int permissions = getPermissions(n.f0, Reference.ATTR_PROTECTED);
0568:
0569: // order is important here... have to evaluate f3 before createMember
0570: // because things like:
0571: //
0572: // var foo = foo;
0573: //
0574: // should create a local which is a copy of the global with the
0575: // same name
0576: if (n.f3.present()) {
0577: ((NodeSequence) (n.f3.node)).elementAt(1).accept(this );
0578: setRetValOnStack(false);
0579: }
0580:
0581: // scope.createMember( memberName, Permissions_attr )
0582: scope.createMember(n.f2, permissions);
0583:
0584: if (n.f3.present()) {
0585: // var.opAssign(val)
0586: il.append(InstructionConstants.SWAP);
0587: il.append(new INVOKEVIRTUAL(ctx.methodref(
0588: "oscript.data.Value", "opAssign",
0589: "(Loscript/data/Value;)V")));
0590: } else {
0591: il.append(InstructionConstants.POP);
0592: }
0593: }
0594:
0595: /*=======================================================================*/
0596: /**
0597: * <PRE>
0598: * f0 -> Permissions()
0599: * f1 -> "function"
0600: * f2 -> <IDENTIFIER>
0601: * f3 -> "("
0602: * f4 -> ( Arglist() )?
0603: * f5 -> ")"
0604: * f6 -> ( "extends" PrimaryExpressionWithTrailingFxnCallExpList() FunctionCallExpressionList() )?
0605: * f7 -> "{"
0606: * f8 -> Program()
0607: * f9 -> "}"
0608: * </PRE>
0609: */
0610: public void visit(FunctionDeclaration n) {
0611: FunctionDeclarationTranslator.translate(n).accept(this );
0612: }
0613:
0614: /*=======================================================================*/
0615: private boolean Arglist_varargs;
0616:
0617: /**
0618: * <PRE>
0619: * f0 -> Permissions()
0620: * f1 -> <IDENTIFIER>
0621: * f2 -> ( "," Permissions() <IDENTIFIER> )*
0622: * f3 -> ( "..." )?
0623: * </PRE>
0624: */
0625: public void visit(Arglist n) {
0626: throw new ProgrammingErrorException("shouldn't get here!");
0627: }
0628:
0629: private int[] getArglist(Arglist n) {
0630: if (n.cachedValue == null) {
0631: int len = 2 * (n.f2.size() + 1);
0632:
0633: handle(n.f1);
0634:
0635: n.cachedValue = new int[len];
0636: n.cachedValue[0] = Symbol.getSymbol(n.f1.otokenImage)
0637: .getId();
0638: n.cachedValue[1] = getPermissions(n.f0,
0639: Reference.ATTR_PRIVATE);
0640:
0641: for (int i = 0; i < n.f2.size(); i++) {
0642: NodeToken nt = (NodeToken) (((NodeSequence) (n.f2
0643: .elementAt(i))).elementAt(2));
0644: handle(nt);
0645: n.cachedValue[2 * (i + 1)] = Symbol.getSymbol(
0646: nt.otokenImage).getId();
0647: n.cachedValue[2 * (i + 1) + 1] = getPermissions(
0648: (Permissions) (((NodeSequence) (n.f2
0649: .elementAt(i))).elementAt(1)),
0650: Reference.ATTR_PRIVATE);
0651: }
0652: }
0653:
0654: Arglist_varargs = n.f3.present();
0655:
0656: return n.cachedValue;
0657: }
0658:
0659: /*=======================================================================*/
0660: /**
0661: * <PRE>
0662: * f0 -> "try"
0663: * f1 -> EvaluationUnit()
0664: * f2 -> ( "catch" "(" Expression() <IDENTIFIER> ")" EvaluationUnit() )*
0665: * f3 -> ( "catch" "(" <IDENTIFIER> ")" EvaluationUnit() )?
0666: * f4 -> ( "finally" EvaluationUnit() )?
0667: * </PRE>
0668: */
0669: public void visit(TryStatement n) {
0670: handle(n.f0);
0671:
0672: scope.enterConditional();
0673:
0674: LinkedList gotoList = new LinkedList();
0675:
0676: final InstructionHandle[] finally_start = new InstructionHandle[1]; // array used to have ref to ref..
0677: LoopStackNode.CleanupInstructionGenerator g = null;
0678:
0679: if (n.f4.present()) {
0680: g = new LoopStackNode.CleanupInstructionGenerator() {
0681: public void generate(final CompilerInstructionList il) {
0682: final BranchInstruction JSR = new JSR(null);
0683: il.append(JSR);
0684:
0685: defer(new Runnable() {
0686: public void run() {
0687: JSR.setTarget(finally_start[0]);
0688: }
0689: });
0690: }
0691: };
0692: loopStack.addCleanupInstructionGenerator(g);
0693: }
0694:
0695: InstructionHandle try_start = il
0696: .append(InstructionConstants.NOP);
0697: n.f1.accept(this );
0698: // jump to end/finally:
0699: il.append(addToBranchInstructionList(gotoList, new GOTO(null)));
0700: InstructionHandle try_end = il.append(InstructionConstants.NOP);
0701: InstructionHandle handler_start = il
0702: .append(InstructionConstants.NOP);
0703:
0704: for (int i = 0; i < n.f2.size(); i++) {
0705: // stack: ..., e
0706:
0707: NodeSequence seq = (NodeSequence) (n.f2.elementAt(i));
0708:
0709: // store java exception on stack: ..., e -> ..., e, e
0710: il.append(InstructionConstants.DUP);
0711:
0712: // get the script exception object: ..., e, e -> ..., e, e.val
0713: il.append(new GETFIELD(ctx.fieldref(
0714: "oscript.exceptions.PackagedScriptObjectException",
0715: "val", "Loscript/data/Value;")));
0716:
0717: // check the type of the script exception: ... e, e.val -> e, e.val
0718: il.append(InstructionConstants.DUP); // ... e, e.val -> e, e.val, e.val
0719: seq.elementAt(2).accept(this ); // ... e, e.val, e.val -> e, e.val, e.val, type
0720: setRetValOnStack(false);
0721: il.append(new INVOKEVIRTUAL(ctx.methodref(
0722: "oscript.data.Value", "bopInstanceOf",
0723: "(Loscript/data/Value;)Loscript/data/Value;")));
0724: il.append(new INVOKEVIRTUAL(ctx.methodref(
0725: "oscript.data.Value", "castToBoolean", "()Z")));
0726:
0727: BranchInstruction IFEQ = new IFEQ(null); // ... e, e.val, bool -> e, e.val
0728: il.append(IFEQ);
0729:
0730: scope = new CompilerScope(this , scope, true); // push scope (XXX need to know hasFxnInScope)
0731:
0732: // createMember & opAssign: ..., e, e.val -> ..., e
0733: scope.createMember((NodeToken) (seq.elementAt(3)), 0);
0734: il.append(InstructionConstants.SWAP);
0735: il.append(new INVOKEVIRTUAL(ctx.methodref(
0736: "oscript.data.Value", "opAssign",
0737: "(Loscript/data/Value;)V")));
0738:
0739: // don't need stored java exception on stack: ..., e -> ...
0740: il.append(InstructionConstants.POP);
0741:
0742: seq.elementAt(5).accept(this );
0743:
0744: scope = scope.pop(); // pop scope
0745:
0746: // jump to end/finally:
0747: il.append(addToBranchInstructionList(gotoList, new GOTO(
0748: null)));
0749:
0750: il.setNextAsTarget(IFEQ);
0751:
0752: // don't need script exception on stack: ..., e, e.val -> ..., e
0753: il.append(InstructionConstants.POP);
0754: }
0755:
0756: if (n.f3.present()) {
0757: // stack: ..., e
0758:
0759: NodeSequence seq = (NodeSequence) (n.f3.node);
0760:
0761: // get the script exception object: ..., e -> ..., e.val
0762: il.append(new GETFIELD(ctx.fieldref(
0763: "oscript.exceptions.PackagedScriptObjectException",
0764: "val", "Loscript/data/Value;")));
0765:
0766: scope = new CompilerScope(this , scope, false); // push scope
0767:
0768: // createMember & opAssign: ..., e.val -> ...
0769: scope.createMember((NodeToken) (seq.elementAt(2)), 0);
0770: il.append(InstructionConstants.SWAP);
0771: il.append(new INVOKEVIRTUAL(ctx.methodref(
0772: "oscript.data.Value", "opAssign",
0773: "(Loscript/data/Value;)V")));
0774:
0775: seq.elementAt(4).accept(this );
0776:
0777: scope = scope.pop(); // pop scope
0778:
0779: // jump to end/finally:
0780: il.append(addToBranchInstructionList(gotoList, new GOTO(
0781: null))); // XXX ??? do I need this?
0782: } else {
0783: // don't need stored java exception on stack: ..., e -> ...
0784: il.append(InstructionConstants.ATHROW);
0785: }
0786:
0787: if ((n.f2.size() > 0) || n.f3.present())
0788: mg.addExceptionHandler(try_start, try_end, handler_start,
0789: ctx.EXCEPTION_TYPE);
0790:
0791: for (Iterator itr = gotoList.iterator(); itr.hasNext();)
0792: il.setNextAsTarget((BranchInstruction) (itr.next()));
0793:
0794: if (n.f4.present()) {
0795: BranchInstruction REG_JSR = new JSR(null);
0796: BranchInstruction GOTO_END = new GOTO(null);
0797:
0798: InstructionHandle any_exception_end = il.append(REG_JSR); // target of "try" and "catch" gotos
0799: il.append(GOTO_END); // normal execution skips exception handling glue
0800: InstructionHandle any_handler_start = il
0801: .append(InstructionConstants.NOP); // begin handler for <any>
0802:
0803: // we need to store the exception value:
0804: int exceptionSlot = mg.addLocalVariable(
0805: ctx.makeUniqueIdentifierName("e"),
0806: ctx.ANY_EXCEPTION_TYPE, null, // XXX start
0807: null // XXX end
0808: ).getIndex();
0809:
0810: BranchInstruction ANY_EXCEPTION_JSR = new JSR(null);
0811:
0812: il.append(new ASTORE(exceptionSlot));
0813: il.append(ANY_EXCEPTION_JSR);
0814: il.append(new ALOAD(exceptionSlot));
0815: il.append(InstructionConstants.ATHROW);
0816:
0817: il.setNextAsTarget(REG_JSR);
0818: il.setNextAsTarget(ANY_EXCEPTION_JSR);
0819:
0820: int retAddrSlot = mg.addLocalVariable(
0821: ctx.makeUniqueIdentifierName("retaddr"),
0822: org.apache.bcel.generic.Type.OBJECT, null, // XXX start
0823: null // XXX end
0824: ).getIndex();
0825:
0826: loopStack.removeCleanupInstructionGenerator(g);
0827: finally_start[0] = il.append(new ASTORE(retAddrSlot));
0828:
0829: ((NodeSequence) (n.f4.node)).elementAt(1).accept(this );
0830:
0831: il.append(new RET(retAddrSlot));
0832:
0833: mg.addExceptionHandler(try_start, any_exception_end,
0834: any_handler_start, ctx.ANY_EXCEPTION_TYPE);
0835:
0836: il.setNextAsTarget(GOTO_END);
0837: }
0838:
0839: scope.leaveConditional();
0840: }
0841:
0842: // XXX move this:
0843: private static final BranchInstruction addToBranchInstructionList(
0844: LinkedList list, BranchInstruction bi) {
0845: list.addFirst(bi);
0846: return bi;
0847: }
0848:
0849: /*=======================================================================*/
0850: /**
0851: * <PRE>
0852: * f0 -> "for"
0853: * f1 -> "("
0854: * f2 -> ( PreLoopStatement() )?
0855: * f3 -> ";"
0856: * f4 -> ( Expression() )?
0857: * f5 -> ";"
0858: * f6 -> ( Expression() )?
0859: * f7 -> ")"
0860: * f8 -> EvaluationUnit()
0861: * </PRE>
0862: */
0863: public void visit(ForLoopStatement n) {
0864: ForLoopStatementTranslator.translate(n).accept(this );
0865: }
0866:
0867: /*=======================================================================*/
0868: /**
0869: * <PRE>
0870: * f0 -> "for"
0871: * f1 -> "("
0872: * f2 -> PreLoopStatement()
0873: * f3 -> ":"
0874: * f4 -> Expression()
0875: * f5 -> ")"
0876: * f6 -> EvaluationUnit()
0877: * </PRE>
0878: */
0879: public void visit(CollectionForLoopStatement n) {
0880: CollectionForLoopStatementTranslator.translate(n).accept(this );
0881: }
0882:
0883: /*=======================================================================*/
0884: /**
0885: * <PRE>
0886: * f0 -> VariableDeclaration()
0887: * | Expression()
0888: * </PRE>
0889: */
0890: public void visit(PreLoopStatement n) {
0891: n.f0.accept(this );
0892: }
0893:
0894: /*=======================================================================*/
0895: /**
0896: * <PRE>
0897: * f0 -> "while"
0898: * f1 -> "("
0899: * f2 -> Expression()
0900: * f3 -> ")"
0901: * f4 -> EvaluationUnit()
0902: * </PRE>
0903: */
0904: public void visit(WhileLoopStatement n) {
0905: handle(n.f0);
0906:
0907: BranchInstruction IFEQ = new IFEQ(null);
0908: BranchInstruction GOTO = new GOTO(null);
0909:
0910: il.setNextAsTarget(GOTO);
0911: n.f2.accept(this );
0912: setRetValOnStack(false);
0913:
0914: il.append(new INVOKEVIRTUAL(ctx.methodref("oscript.data.Value",
0915: "castToBoolean", "()Z")));
0916:
0917: il.append(IFEQ);
0918:
0919: // push a new LoopStackNode:
0920: loopStack = new LoopStackNode(loopStack);
0921:
0922: scope.enterConditional();
0923: n.f4.accept(this );
0924: scope.leaveConditional();
0925:
0926: il.append(GOTO);
0927:
0928: il.setNextAsTarget(IFEQ);
0929:
0930: for (Iterator itr = loopStack.getContinueInstructions()
0931: .iterator(); itr.hasNext();)
0932: ((BranchInstruction) (itr.next())).setTarget(GOTO
0933: .getTarget());
0934:
0935: for (Iterator itr = loopStack.getBreakInstructions().iterator(); itr
0936: .hasNext();)
0937: il.setNextAsTarget((BranchInstruction) (itr.next()));
0938:
0939: // pop LoopStackNode:
0940: loopStack = loopStack.pop();
0941: }
0942:
0943: /*=======================================================================*/
0944: /**
0945: * <PRE>
0946: * f0 -> "if"
0947: * f1 -> "("
0948: * f2 -> Expression()
0949: * f3 -> ")"
0950: * f4 -> EvaluationUnit()
0951: * f5 -> ( "else" EvaluationUnit() )?
0952: * </PRE>
0953: */
0954: public void visit(ConditionalStatement n) {
0955: handle(n.f0);
0956:
0957: n.f2.accept(this );
0958: setRetValOnStack(false);
0959:
0960: il.append(new INVOKEVIRTUAL(ctx.methodref("oscript.data.Value",
0961: "castToBoolean", "()Z")));
0962:
0963: BranchInstruction IFEQ = new IFEQ(null);
0964: il.append(IFEQ);
0965:
0966: scope.enterConditional();
0967: n.f4.accept(this );
0968:
0969: if (n.f5.present()) {
0970: BranchInstruction GOTO = new GOTO(null);
0971: il.append(GOTO);
0972:
0973: il.setNextAsTarget(IFEQ);
0974: ((NodeSequence) (n.f5.node)).elementAt(1).accept(this );
0975:
0976: il.setNextAsTarget(GOTO);
0977: } else {
0978: il.setNextAsTarget(IFEQ);
0979: }
0980:
0981: scope.leaveConditional();
0982: }
0983:
0984: /*=======================================================================*/
0985: /**
0986: * <PRE>
0987: * f0 -> "synchronized"
0988: * f1 -> "("
0989: * f2 -> Expression()
0990: * f3 -> ")"
0991: * f4 -> EvaluationUnit()
0992: * </PRE>
0993: */
0994: public void visit(SynchronizedStatement n) {
0995: n.f2.accept(this );
0996: setRetValOnStack(false);
0997:
0998: il.append(new INVOKEVIRTUAL(ctx.methodref("oscript.data.Value",
0999: "getMonitor", "()Ljava/lang/Object;")));
1000:
1001: // we need to store the monitor value:
1002: LocalVariableGen monLg = mg.addLocalVariable(ctx
1003: .makeUniqueIdentifierName("monitor"), ctx.VALUE_TYPE,
1004: null, // XXX
1005: null); // XXX
1006: final int monSlot = monLg.getIndex();
1007:
1008: LoopStackNode.CleanupInstructionGenerator g = new LoopStackNode.CleanupInstructionGenerator() {
1009: public void generate(CompilerInstructionList il) {
1010: il.append(new ALOAD(monSlot));
1011: il.append(InstructionConstants.MONITOREXIT);
1012: }
1013: };
1014:
1015: loopStack.addCleanupInstructionGenerator(g);
1016:
1017: il.append(InstructionConstants.DUP);
1018: il.append(new ASTORE(monSlot));
1019: InstructionHandle try_start = il
1020: .append(InstructionConstants.MONITORENTER);
1021:
1022: n.f4.accept(this );
1023:
1024: loopStack.removeCleanupInstructionGenerator(g);
1025:
1026: il.append(new ALOAD(monSlot));
1027: InstructionHandle try_end = il
1028: .append(InstructionConstants.MONITOREXIT);
1029: BranchInstruction GOTO = new GOTO(null);
1030: il.append(GOTO);
1031:
1032: InstructionHandle handler_start = il.append(new ALOAD(monSlot));
1033: il.append(InstructionConstants.MONITOREXIT);
1034: il.append(InstructionConstants.ATHROW);
1035:
1036: il.setNextAsTarget(GOTO);
1037:
1038: mg.addExceptionHandler(try_start, try_end, handler_start,
1039: ctx.ANY_EXCEPTION_TYPE);
1040: }
1041:
1042: /*=======================================================================*/
1043: /**
1044: * <PRE>
1045: * f0 -> "return"
1046: * f1 -> ( Expression() )?
1047: * </PRE>
1048: */
1049: public void visit(ReturnStatement n) {
1050: handle(n.f0);
1051:
1052: if (n.f1.present()) {
1053: n.f1.node.accept(this );
1054: checkRetValOnStack(true);
1055:
1056: il.append(new INVOKESTATIC(ctx.methodref(
1057: "oscript.compiler.CompiledNodeEvaluator",
1058: "returnHelper",
1059: "(Loscript/data/Value;)Loscript/data/Value;")));
1060: } else {
1061: getInstanceConstant(Value.UNDEFINED);
1062: setRetValOnStack(false);
1063: }
1064:
1065: int retValSlot = mg.addLocalVariable(
1066: ctx.makeUniqueIdentifierName("retVal"), ctx.VALUE_TYPE,
1067: null, // XXX start
1068: null // XXX end
1069: ).getIndex();
1070:
1071: il.append(new ASTORE(retValSlot));
1072: loopStack.insertCleanupInstructions(il, true);
1073: il.append(new ALOAD(retValSlot));
1074:
1075: il.append(InstructionConstants.ARETURN);
1076: }
1077:
1078: /*=======================================================================*/
1079: /**
1080: * <PRE>
1081: * f0 -> "break"
1082: * f1 -> ";"
1083: * </PRE>
1084: */
1085: public void visit(BreakStatement n) {
1086: handle(n.f0);
1087:
1088: loopStack.insertCleanupInstructions(il, false);
1089:
1090: BranchInstruction GOTO = new GOTO(null);
1091: il.append(GOTO);
1092:
1093: loopStack.addBreakBranchInstruction(GOTO);
1094: }
1095:
1096: /*=======================================================================*/
1097: /**
1098: * <PRE>
1099: * f0 -> "continue"
1100: * f1 -> ";"
1101: * </PRE>
1102: */
1103: public void visit(ContinueStatement n) {
1104: handle(n.f0);
1105:
1106: loopStack.insertCleanupInstructions(il, false);
1107:
1108: BranchInstruction GOTO = new GOTO(null);
1109: il.append(GOTO);
1110:
1111: loopStack.addContinueBranchInstruction(GOTO);
1112: }
1113:
1114: /*=======================================================================*/
1115: /**
1116: * Note, <i>Expression</i> always returns a value on the stack, even
1117: * if that value is <code>Value.NULL</code>.
1118: *
1119: * <PRE>
1120: * f0 -> AssignmentExpression()
1121: * f1 -> ( "," AssignmentExpression() )*
1122: * </PRE>
1123: */
1124: public void visit(Expression n) {
1125: n.f0.accept(this );
1126:
1127: for (int i = 0; i < n.f1.size(); i++) {
1128: // get rid of previous value on stack:
1129: il.append(InstructionConstants.POP);
1130: setRetValOnStack(false);
1131:
1132: ((NodeSequence) (n.f1.elementAt(i))).elementAt(1).accept(
1133: this );
1134: }
1135:
1136: checkRetValOnStack(true);
1137: }
1138:
1139: /*=======================================================================*/
1140: /**
1141: * <PRE>
1142: * f0 -> "("
1143: * f1 -> ( FunctionCallExpressionListBody() )?
1144: * f2 -> ")"
1145: * </PRE>
1146: */
1147: public void visit(FunctionCallExpressionList n) {
1148: n.f0.accept(this ); // to record last NodeToken
1149:
1150: if (n.f1.present()) {
1151: FunctionCallExpressionList_sfIsNull = false;
1152: n.f1.node.accept(this );
1153: } else {
1154: FunctionCallExpressionList_sfIsNull = true;
1155: allocateMemberTable_allocateFromStack = false;
1156: il.append(InstructionConstants.ACONST_NULL);
1157: }
1158:
1159: setRetValOnStack(true);
1160: }
1161:
1162: /**
1163: * If there were no args, the FunctionCallExpressionList visitor will
1164: * push <code>null</code> onto the stack
1165: */
1166: private boolean FunctionCallExpressionList_sfIsNull = false;
1167:
1168: /**
1169: * Set to true before accept()ing the the {@link FunctionCallExpressionList}
1170: * (or calling {@link #allocateMemberTable}, to indicate that the member-
1171: * table should be allocated from the stack (rather than allocating an
1172: * <code>OArray</code>). This is reset back to <code>false</code> once
1173: * the <code>FunctionCallExpressionList</code> is visited.
1174: * <p>
1175: * If set to true, the code that the member-table is created for should
1176: * take care to call {@link MemberTable#free()}
1177: */
1178: private boolean allocateMemberTable_allocateFromStack = false;
1179:
1180: private void allocateMemberTable(int sz) {
1181: if (allocateMemberTable_allocateFromStack) {
1182: il.append(InstructionConstants.ALOAD_1); // sf
1183: ctx.pushInt(il, sz);
1184: il.append(new INVOKEVIRTUAL(ctx.methodref(
1185: "oscript.util.StackFrame", "allocateMemberTable",
1186: "(S)Loscript/util/MemberTable;")));
1187: allocateMemberTable_allocateFromStack = false;
1188: } else {
1189: il.append(new NEW(ctx.cp.addClass("oscript.data.OArray")));
1190: il.append(InstructionConstants.DUP);
1191: ctx.pushInt(il, sz);
1192: il.append(new INVOKESPECIAL(ctx.methodref(
1193: "oscript.data.OArray", "<init>", "(I)V")));
1194: }
1195: }
1196:
1197: /*=======================================================================*/
1198: /**
1199: * <PRE>
1200: * f0 -> AssignmentExpression()
1201: * f1 -> ( "," AssignmentExpression() )*
1202: * </PRE>
1203: */
1204: public void visit(FunctionCallExpressionListBody n) {
1205: allocateMemberTable(1 + n.f1.size());
1206:
1207: int cnt = 0;
1208:
1209: il.append(InstructionConstants.DUP);
1210: n.f0.accept(this );
1211: setRetValOnStack(false);
1212: cnt++;
1213:
1214: for (int i = 0; i < n.f1.size(); i++) {
1215: if (cnt == 4) {
1216: il.append(new INVOKEINTERFACE(ctx.ifmethodref(
1217: "oscript.util.MemberTable",
1218: PUSH_METHOD_NAMES[cnt],
1219: PUSH_METHOD_SIGNATURES[cnt]), cnt + 1));
1220: il.append(InstructionConstants.DUP);
1221: cnt = 0;
1222: }
1223:
1224: NodeSequence seq = (NodeSequence) (n.f1.elementAt(i));
1225: seq.elementAt(1).accept(this );
1226: setRetValOnStack(false);
1227: cnt++;
1228: }
1229:
1230: if (cnt > 0) {
1231: il.append(new INVOKEINTERFACE(ctx.ifmethodref(
1232: "oscript.util.MemberTable", PUSH_METHOD_NAMES[cnt],
1233: PUSH_METHOD_SIGNATURES[cnt]), cnt + 1));
1234: } else {
1235: // get rid of extra member-table reference on top of the stack
1236: il.append(InstructionConstants.POP);
1237: }
1238: }
1239:
1240: private static final String[] PUSH_METHOD_NAMES = new String[] {
1241: null, "push1", "push2", "push3", "push4" };
1242:
1243: private static final String[] PUSH_METHOD_SIGNATURES = new String[] {
1244: null,
1245: "(Loscript/data/Value;)V",
1246: "(Loscript/data/Value;Loscript/data/Value;)V",
1247: "(Loscript/data/Value;Loscript/data/Value;Loscript/data/Value;)V",
1248: "(Loscript/data/Value;Loscript/data/Value;Loscript/data/Value;Loscript/data/Value;)V" };
1249:
1250: /*=======================================================================*/
1251: /**
1252: * <PRE>
1253: * f0 -> ConditionalExpression()
1254: * f1 -> ( ( "=" | "+=" | "-=" | "*=" | "/=" | "%=" | ">>=" | "<<=" | ">>>=" | "&=" | "^=" | "|=" ) ConditionalExpression() )*
1255: * </PRE>
1256: */
1257: public void visit(AssignmentExpression n) {
1258: // the tricky part here is that things need to be evaluated backwards:
1259: int lastOp = -1;
1260:
1261: for (int i = n.f1.size() - 1; i >= -1; i--) {
1262: int op = lastOp;
1263:
1264: // evaluate <i>CondidtionalExpression</i>, should return a val on stack:
1265: if (i >= 0) {
1266: NodeSequence seq = (NodeSequence) (n.f1.elementAt(i));
1267: seq.elementAt(1).accept(this );
1268: lastOp = ((NodeToken) (((NodeChoice) (seq.elementAt(0))).choice)).kind;
1269: } else {
1270: n.f0.accept(this );
1271: }
1272:
1273: // keep the val on the stack, don't return it
1274: setRetValOnStack(false);
1275:
1276: if (op != -1) {
1277: // stack: ..., lastVal, val
1278:
1279: String methodName = null;
1280:
1281: switch (op) {
1282: case ASSIGN:
1283: // no-op
1284: break;
1285: case PLUSASSIGN:
1286: methodName = "bopPlus";
1287: break;
1288: case MINUSASSIGN:
1289: methodName = "bopMinus";
1290: break;
1291: case STARASSIGN:
1292: methodName = "bopMultiply";
1293: break;
1294: case SLASHASSIGN:
1295: methodName = "bopDivide";
1296: break;
1297: case ANDASSIGN:
1298: methodName = "bopBitwiseAnd";
1299: break;
1300: case ORASSIGN:
1301: methodName = "bopBitwiseOr";
1302: break;
1303: case XORASSIGN:
1304: methodName = "bopBitwiseXor";
1305: break;
1306: case REMASSIGN:
1307: methodName = "bopRemainder";
1308: break;
1309: case LSHIFTASSIGN:
1310: methodName = "bopLeftShift";
1311: break;
1312: case RSIGNEDSHIFTASSIGN:
1313: methodName = "bopSignedRightShift";
1314: break;
1315: case RUNSIGNEDSHIFTASSIGN:
1316: methodName = "bopUnsignedRightShift";
1317: break;
1318: default:
1319: throw new ProgrammingErrorException(
1320: "unknown operator: " + op);
1321: }
1322:
1323: if (methodName != null) {
1324: // stack: ..., lastVal, val => ..., val, val, lastVal
1325: il.append(InstructionConstants.DUP_X1);
1326: il.append(InstructionConstants.SWAP);
1327:
1328: // stack: ..., val, val, lastVal => ..., val, lastVal
1329: il
1330: .append(new INVOKEVIRTUAL(
1331: ctx
1332: .methodref(
1333: "oscript.data.Value",
1334: methodName,
1335: "(Loscript/data/Value;)Loscript/data/Value;")));
1336: } else {
1337: // stack: ..., lastVal, val => ..., val, lastVal
1338: il.append(InstructionConstants.SWAP);
1339: }
1340:
1341: // stack: ..., val, lastVal => ..., lastVal, val, lastVal:
1342: il.append(InstructionConstants.DUP_X1);
1343:
1344: // stack: ..., lastVal, val, lastVal => ..., lastVal
1345: il.append(new INVOKEVIRTUAL(ctx.methodref(
1346: "oscript.data.Value", "opAssign",
1347: "(Loscript/data/Value;)V")));
1348: }
1349: }
1350:
1351: setRetValOnStack(true);
1352: }
1353:
1354: /*=======================================================================*/
1355: /**
1356: * <PRE>
1357: * f0 -> LogicalOrExpression()
1358: * f1 -> ( "?" LogicalOrExpression() ":" LogicalOrExpression() )?
1359: * </PRE>
1360: */
1361: public void visit(ConditionalExpression n) {
1362: n.f0.accept(this );
1363:
1364: if (n.f1.present()) {
1365: setRetValOnStack(false);
1366:
1367: il.append(new INVOKEVIRTUAL(ctx.methodref(
1368: "oscript.data.Value", "castToBoolean", "()Z")));
1369:
1370: scope.enterConditional();
1371:
1372: BranchInstruction IFEQ = new IFEQ(null);
1373: il.append(IFEQ);
1374:
1375: ((NodeSequence) (n.f1.node)).elementAt(1).accept(this );
1376: setRetValOnStack(false);
1377:
1378: BranchInstruction GOTO = new GOTO(null);
1379: il.append(GOTO);
1380:
1381: il.setNextAsTarget(IFEQ);
1382:
1383: ((NodeSequence) (n.f1.node)).elementAt(3).accept(this );
1384:
1385: il.setNextAsTarget(GOTO);
1386:
1387: scope.leaveConditional();
1388: }
1389: }
1390:
1391: /*=======================================================================*/
1392: /**
1393: * <PRE>
1394: * f0 -> LogicalAndExpression()
1395: * f1 -> ( "||" LogicalAndExpression() )*
1396: * </PRE>
1397: */
1398: public void visit(LogicalOrExpression n) {
1399: n.f0.accept(this );
1400:
1401: if (n.f1.present()) {
1402: LinkedList branchInstructionList = new LinkedList();
1403:
1404: scope.enterConditional();
1405:
1406: for (int i = 0; i < n.f1.size(); i++) {
1407: setRetValOnStack(false);
1408:
1409: il.append(InstructionConstants.DUP);
1410: il.append(new INVOKEVIRTUAL(ctx.methodref(
1411: "oscript.data.Value", "castToBoolean", "()Z")));
1412:
1413: BranchInstruction IFNE = new IFNE(null);
1414: branchInstructionList.add(IFNE);
1415: il.append(IFNE);
1416:
1417: il.append(InstructionConstants.POP);
1418:
1419: ((NodeSequence) (n.f1.elementAt(i))).elementAt(1)
1420: .accept(this );
1421: }
1422:
1423: for (Iterator itr = branchInstructionList.iterator(); itr
1424: .hasNext();) {
1425: il.setNextAsTarget((BranchInstruction) (itr.next()));
1426: }
1427:
1428: scope.leaveConditional();
1429: }
1430: }
1431:
1432: /*=======================================================================*/
1433: /**
1434: * <PRE>
1435: * f0 -> BitwiseOrExpression()
1436: * f1 -> ( "&&" BitwiseOrExpression() )*
1437: * </PRE>
1438: */
1439: public void visit(LogicalAndExpression n) {
1440: n.f0.accept(this );
1441:
1442: if (n.f1.present()) {
1443: LinkedList branchInstructionList = new LinkedList();
1444:
1445: scope.enterConditional();
1446:
1447: for (int i = 0; i < n.f1.size(); i++) {
1448: setRetValOnStack(false);
1449:
1450: il.append(InstructionConstants.DUP);
1451: il.append(new INVOKEVIRTUAL(ctx.methodref(
1452: "oscript.data.Value", "castToBoolean", "()Z")));
1453:
1454: BranchInstruction IFEQ = new IFEQ(null);
1455: branchInstructionList.add(IFEQ);
1456: il.append(IFEQ);
1457:
1458: il.append(InstructionConstants.POP);
1459:
1460: ((NodeSequence) (n.f1.elementAt(i))).elementAt(1)
1461: .accept(this );
1462: }
1463:
1464: for (Iterator itr = branchInstructionList.iterator(); itr
1465: .hasNext();) {
1466: il.setNextAsTarget((BranchInstruction) (itr.next()));
1467: }
1468:
1469: scope.leaveConditional();
1470: }
1471: }
1472:
1473: /*=======================================================================*/
1474: /**
1475: * <PRE>
1476: * f0 -> BitwiseXorExpression()
1477: * f1 -> ( "|" BitwiseXorExpression() )*
1478: * </PRE>
1479: */
1480: public void visit(BitwiseOrExpression n) {
1481: n.f0.accept(this );
1482:
1483: for (int i = 0; i < n.f1.size(); i++) {
1484: setRetValOnStack(false);
1485:
1486: ((NodeSequence) (n.f1.elementAt(i))).elementAt(1).accept(
1487: this );
1488: checkRetValOnStack(true);
1489:
1490: il.append(new INVOKEVIRTUAL(ctx.methodref(
1491: "oscript.data.Value", "bopBitwiseOr",
1492: "(Loscript/data/Value;)Loscript/data/Value;")));
1493: }
1494: }
1495:
1496: /*=======================================================================*/
1497: /**
1498: * <PRE>
1499: * f0 -> BitwiseAndExpression()
1500: * f1 -> ( "^" BitwiseAndExpression() )*
1501: * </PRE>
1502: */
1503: public void visit(BitwiseXorExpression n) {
1504: n.f0.accept(this );
1505:
1506: for (int i = 0; i < n.f1.size(); i++) {
1507: setRetValOnStack(false);
1508:
1509: ((NodeSequence) (n.f1.elementAt(i))).elementAt(1).accept(
1510: this );
1511: checkRetValOnStack(true);
1512:
1513: il.append(new INVOKEVIRTUAL(ctx.methodref(
1514: "oscript.data.Value", "bopBitwiseXor",
1515: "(Loscript/data/Value;)Loscript/data/Value;")));
1516: }
1517: }
1518:
1519: /*=======================================================================*/
1520: /**
1521: * <PRE>
1522: * f0 -> EqualityExpression()
1523: * f1 -> ( "&" EqualityExpression() )*
1524: * </PRE>
1525: */
1526: public void visit(BitwiseAndExpression n) {
1527: n.f0.accept(this );
1528:
1529: for (int i = 0; i < n.f1.size(); i++) {
1530: setRetValOnStack(false);
1531:
1532: ((NodeSequence) (n.f1.elementAt(i))).elementAt(1).accept(
1533: this );
1534: checkRetValOnStack(true);
1535:
1536: il.append(new INVOKEVIRTUAL(ctx.methodref(
1537: "oscript.data.Value", "bopBitwiseAnd",
1538: "(Loscript/data/Value;)Loscript/data/Value;")));
1539: }
1540: }
1541:
1542: /*=======================================================================*/
1543: /**
1544: * <PRE>
1545: * f0 -> RelationalExpression()
1546: * f1 -> ( ( "==" | "!=" ) RelationalExpression() )*
1547: * </PRE>
1548: */
1549: public void visit(EqualityExpression n) {
1550: n.f0.accept(this );
1551:
1552: for (int i = 0; i < n.f1.size(); i++) {
1553: setRetValOnStack(false);
1554:
1555: NodeSequence seq = (NodeSequence) (n.f1.elementAt(i));
1556: NodeToken op = (NodeToken) (((NodeChoice) (seq.elementAt(0))).choice);
1557:
1558: seq.elementAt(1).accept(this );
1559: checkRetValOnStack(true);
1560:
1561: String methodName = null;
1562: switch (op.kind) {
1563: case EQ:
1564: methodName = "bopEquals";
1565: break;
1566: case NE:
1567: methodName = "bopNotEquals";
1568: break;
1569: default:
1570: throw new ProgrammingErrorException("bad binary op: "
1571: + OscriptParser.getTokenString(op.kind));
1572: }
1573:
1574: il.append(new INVOKEVIRTUAL(ctx.methodref(
1575: "oscript.data.Value", methodName,
1576: "(Loscript/data/Value;)Loscript/data/Value;")));
1577: }
1578: }
1579:
1580: /*=======================================================================*/
1581: /**
1582: * <PRE>
1583: * f0 -> ShiftExpression()
1584: * f1 -> ( ( "<" | ">" | ">=" | "<=" | "instanceof" ) ShiftExpression() )*
1585: * </PRE>
1586: */
1587: public void visit(RelationalExpression n) {
1588: n.f0.accept(this );
1589:
1590: for (int i = 0; i < n.f1.size(); i++) {
1591: setRetValOnStack(false);
1592:
1593: NodeSequence seq = (NodeSequence) (n.f1.elementAt(i));
1594: NodeToken op = (NodeToken) (((NodeChoice) (seq.elementAt(0))).choice);
1595:
1596: seq.elementAt(1).accept(this );
1597: checkRetValOnStack(true);
1598:
1599: String methodName = null;
1600: switch (op.kind) {
1601: case LT:
1602: methodName = "bopLessThan";
1603: break;
1604: case GT:
1605: methodName = "bopGreaterThan";
1606: break;
1607: case LE:
1608: methodName = "bopLessThanOrEquals";
1609: break;
1610: case GE:
1611: methodName = "bopGreaterThanOrEquals";
1612: break;
1613: case INSTANCEOF:
1614: methodName = "bopInstanceOf";
1615: break;
1616: default:
1617: throw new ProgrammingErrorException("bad binary op: "
1618: + OscriptParser.getTokenString(op.kind));
1619: }
1620:
1621: il.append(new INVOKEVIRTUAL(ctx.methodref(
1622: "oscript.data.Value", methodName,
1623: "(Loscript/data/Value;)Loscript/data/Value;")));
1624: }
1625: }
1626:
1627: /*=======================================================================*/
1628: /**
1629: * <PRE>
1630: * f0 -> AdditiveExpression()
1631: * f1 -> ( ( "<<" | ">>" | ">>>" ) AdditiveExpression() )*
1632: * </PRE>
1633: */
1634: public void visit(ShiftExpression n) {
1635: n.f0.accept(this );
1636:
1637: for (int i = 0; i < n.f1.size(); i++) {
1638: setRetValOnStack(false);
1639:
1640: NodeSequence seq = (NodeSequence) (n.f1.elementAt(i));
1641: NodeToken op = (NodeToken) (((NodeChoice) (seq.elementAt(0))).choice);
1642:
1643: seq.elementAt(1).accept(this );
1644: checkRetValOnStack(true);
1645:
1646: String methodName = null;
1647: switch (op.kind) {
1648: case LSHIFT:
1649: methodName = "bopLeftShift";
1650: break;
1651: case RSIGNEDSHIFT:
1652: methodName = "bopSignedRightShift";
1653: break;
1654: case RUNSIGNEDSHIFT:
1655: methodName = "bopUnsignedRightShift";
1656: break;
1657: default:
1658: throw new ProgrammingErrorException("bad binary op: "
1659: + OscriptParser.getTokenString(op.kind));
1660: }
1661:
1662: il.append(new INVOKEVIRTUAL(ctx.methodref(
1663: "oscript.data.Value", methodName,
1664: "(Loscript/data/Value;)Loscript/data/Value;")));
1665: }
1666: }
1667:
1668: /*=======================================================================*/
1669: /**
1670: * <PRE>
1671: * f0 -> MultiplicativeExpression()
1672: * f1 -> ( ( "+" | "-" ) MultiplicativeExpression() )*
1673: * </PRE>
1674: */
1675: public void visit(AdditiveExpression n) {
1676: n.f0.accept(this );
1677:
1678: for (int i = 0; i < n.f1.size(); i++) {
1679: setRetValOnStack(false);
1680:
1681: NodeSequence seq = (NodeSequence) (n.f1.elementAt(i));
1682: NodeToken op = (NodeToken) (((NodeChoice) (seq.elementAt(0))).choice);
1683:
1684: seq.elementAt(1).accept(this );
1685: checkRetValOnStack(true);
1686:
1687: String methodName = null;
1688: switch (op.kind) {
1689: case PLUS:
1690: methodName = "bopPlus";
1691: break;
1692: case MINUS:
1693: methodName = "bopMinus";
1694: break;
1695: default:
1696: throw new ProgrammingErrorException("bad binary op: "
1697: + OscriptParser.getTokenString(op.kind));
1698: }
1699:
1700: il.append(new INVOKEVIRTUAL(ctx.methodref(
1701: "oscript.data.Value", methodName,
1702: "(Loscript/data/Value;)Loscript/data/Value;")));
1703: }
1704: }
1705:
1706: /*=======================================================================*/
1707: /**
1708: * <PRE>
1709: * f0 -> UnaryExpression()
1710: * f1 -> ( ( "*" | "/" | "%" ) UnaryExpression() )*
1711: * </PRE>
1712: */
1713: public void visit(MultiplicativeExpression n) {
1714: n.f0.accept(this );
1715:
1716: for (int i = 0; i < n.f1.size(); i++) {
1717: setRetValOnStack(false);
1718:
1719: NodeSequence seq = (NodeSequence) (n.f1.elementAt(i));
1720: NodeToken op = (NodeToken) (((NodeChoice) (seq.elementAt(0))).choice);
1721:
1722: seq.elementAt(1).accept(this );
1723: checkRetValOnStack(true);
1724:
1725: String methodName = null;
1726: switch (op.kind) {
1727: case STAR:
1728: methodName = "bopMultiply";
1729: break;
1730: case SLASH:
1731: methodName = "bopDivide";
1732: break;
1733: case REM:
1734: methodName = "bopRemainder";
1735: break;
1736: default:
1737: throw new ProgrammingErrorException("bad binary op: "
1738: + OscriptParser.getTokenString(op.kind));
1739: }
1740:
1741: il.append(new INVOKEVIRTUAL(ctx.methodref(
1742: "oscript.data.Value", methodName,
1743: "(Loscript/data/Value;)Loscript/data/Value;")));
1744: }
1745: }
1746:
1747: /*=======================================================================*/
1748: /**
1749: * <PRE>
1750: * f0 -> ( ( "++" | "--" | "+" | "-" | "~" | "!" ) )?
1751: * f1 -> PostfixExpression()
1752: * </PRE>
1753: */
1754: public void visit(UnaryExpression n) {
1755: n.f1.accept(this );
1756:
1757: if (n.f0.present()) {
1758: checkRetValOnStack(true);
1759: NodeToken op = (NodeToken) (((NodeChoice) (n.f0.node)).choice);
1760:
1761: String methodName = null;
1762: boolean doOpAssign = false;
1763:
1764: switch (op.kind) {
1765: case INCR:
1766: doOpAssign = true;
1767: methodName = "uopIncrement";
1768: break;
1769: case DECR:
1770: doOpAssign = true;
1771: methodName = "uopDecrement";
1772: break;
1773: case PLUS:
1774: methodName = "uopPlus";
1775: break;
1776: case MINUS:
1777: methodName = "uopMinus";
1778: break;
1779: case TILDE:
1780: methodName = "uopBitwiseNot";
1781: break;
1782: case BANG:
1783: methodName = "uopLogicalNot";
1784: break;
1785: default:
1786: throw new ProgrammingErrorException("bad unary op: "
1787: + OscriptParser.getTokenString(op.kind));
1788: }
1789:
1790: if (doOpAssign) {
1791: il.append(InstructionConstants.DUP);
1792: }
1793:
1794: il.append(new INVOKEVIRTUAL(ctx.methodref(
1795: "oscript.data.Value", methodName,
1796: "()Loscript/data/Value;")));
1797:
1798: if (doOpAssign) {
1799: il.append(InstructionConstants.DUP_X1);
1800: il.append(new INVOKEVIRTUAL(ctx.methodref(
1801: "oscript.data.Value", "opAssign",
1802: "(Loscript/data/Value;)V")));
1803: }
1804: }
1805: }
1806:
1807: /*=======================================================================*/
1808: /**
1809: * <PRE>
1810: * f0 -> TypeExpression()
1811: * f1 -> ( "++" | "--" )?
1812: * </PRE>
1813: */
1814: public void visit(PostfixExpression n) {
1815: n.f0.accept(this );
1816:
1817: if (n.f1.present()) {
1818: checkRetValOnStack(true);
1819: NodeToken op = (NodeToken) (((NodeChoice) (n.f1.node)).choice);
1820:
1821: String methodName = null;
1822:
1823: switch (op.kind) {
1824: case INCR:
1825: methodName = "uopIncrement";
1826: break;
1827: case DECR:
1828: methodName = "uopDecrement";
1829: break;
1830: default:
1831: throw new ProgrammingErrorException("bad unary op: "
1832: + OscriptParser.getTokenString(op.kind));
1833: }
1834:
1835: // the result value is the original value... since you can't assign to it,
1836: // unhand() works fine to get the original value:
1837: il.append(InstructionConstants.DUP);
1838: il.append(new INVOKEVIRTUAL(ctx.methodref(
1839: "oscript.data.Value", "unhand",
1840: "()Loscript/data/Value;")));
1841: il.append(InstructionConstants.SWAP);
1842:
1843: // now invoke the operation and assign it to the reference:
1844: il.append(InstructionConstants.DUP);
1845: il.append(new INVOKEVIRTUAL(ctx.methodref(
1846: "oscript.data.Value", methodName,
1847: "()Loscript/data/Value;")));
1848: il.append(new INVOKEVIRTUAL(ctx.methodref(
1849: "oscript.data.Value", "opAssign",
1850: "(Loscript/data/Value;)V")));
1851: }
1852: }
1853:
1854: /*=======================================================================*/
1855: /**
1856: * <PRE>
1857: * f0 -> AllocationExpression()
1858: * | CastExpression()
1859: * | PrimaryExpression()
1860: * </PRE>
1861: */
1862: public void visit(TypeExpression n) {
1863: n.f0.accept(this );
1864: }
1865:
1866: /*=======================================================================*/
1867: /**
1868: * <PRE>
1869: * f0 -> "new"
1870: * f1 -> PrimaryExpressionWithTrailingFxnCallExpList()
1871: * f2 -> FunctionCallExpressionList()
1872: * </PRE>
1873: */
1874: public void visit(AllocationExpression n) {
1875: handle(n.f0);
1876:
1877: n.f1.accept(this );
1878: setRetValOnStack(false);
1879:
1880: il.append(InstructionConstants.ALOAD_1); // sf
1881:
1882: n.f2.accept(this );
1883: checkRetValOnStack(true);
1884:
1885: il
1886: .append(new INVOKEVIRTUAL(
1887: ctx
1888: .methodref("oscript.data.Value",
1889: "callAsConstructor",
1890: "(Loscript/util/StackFrame;Loscript/util/MemberTable;)Loscript/data/Value;")));
1891: }
1892:
1893: /*=======================================================================*/
1894: /**
1895: * <PRE>
1896: * f0 -> "("
1897: * f1 -> PrimaryExpressionNotFunction()
1898: * f2 -> ")"
1899: * f3 -> PrimaryExpression()
1900: * </PRE>
1901: */
1902: public void visit(CastExpression n) {
1903: handle(n.f0);
1904:
1905: n.f1.accept(this );
1906: setRetValOnStack(false);
1907:
1908: n.f3.accept(this );
1909: checkRetValOnStack(true);
1910:
1911: il.append(new INVOKEVIRTUAL(ctx
1912: .methodref("oscript.data.Value", "bopCast",
1913: "(Loscript/data/Value;)Loscript/data/Value;")));
1914: }
1915:
1916: /*=======================================================================*/
1917: /**
1918: * <PRE>
1919: * f0 -> PrimaryPrefix()
1920: * f1 -> ( PrimaryPostfix() )*
1921: * </PRE>
1922: */
1923: public void visit(PrimaryExpression n) {
1924: n.f0.accept(this );
1925:
1926: for (int i = 0; i < n.f1.size(); i++) {
1927: checkRetValOnStack(true);
1928: n.f1.elementAt(i).accept(this );
1929: }
1930:
1931: checkRetValOnStack(true);
1932: }
1933:
1934: /*=======================================================================*/
1935: /**
1936: * <PRE>
1937: * f0 -> PrimaryPrefix()
1938: * f1 -> ( PrimaryPostfix() )*
1939: * </PRE>
1940: */
1941: public void visit(PrimaryExpressionNotFunction n) {
1942: n.f0.accept(this );
1943:
1944: for (int i = 0; i < n.f1.size(); i++) {
1945: checkRetValOnStack(true);
1946: n.f1.elementAt(i).accept(this );
1947: }
1948:
1949: checkRetValOnStack(true);
1950: }
1951:
1952: /*=======================================================================*/
1953: /**
1954: * <PRE>
1955: * f0 -> PrimaryPrefix()
1956: * f1 -> ( PrimaryPostfixWithTrailingFxnCallExpList() )*
1957: * </PRE>
1958: */
1959: public void visit(PrimaryExpressionWithTrailingFxnCallExpList n) {
1960: n.f0.accept(this );
1961:
1962: for (int i = 0; i < n.f1.size(); i++) {
1963: checkRetValOnStack(true);
1964: n.f1.elementAt(i).accept(this );
1965: }
1966:
1967: checkRetValOnStack(true);
1968: }
1969:
1970: /*=======================================================================*/
1971: /**
1972: * <PRE>
1973: * f0 -> PrimaryPrefixNotFunction()
1974: * | FunctionPrimaryPrefix()
1975: * | ShorthandFunctionPrimaryPrefix()
1976: * </PRE>
1977: */
1978: public void visit(PrimaryPrefix n) {
1979: n.f0.accept(this );
1980: }
1981:
1982: /*=======================================================================*/
1983: /**
1984: * <PRE>
1985: * f0 -> ThisPrimaryPrefix()
1986: * | SuperPrimaryPrefix()
1987: * | CalleePrimaryPrefix()
1988: * | IdentifierPrimaryPrefix()
1989: * | ParenPrimaryPrefix()
1990: * | ArrayDeclarationPrimaryPrefix()
1991: * | Literal()
1992: * </PRE>
1993: */
1994: public void visit(PrimaryPrefixNotFunction n) {
1995: n.f0.accept(this );
1996: }
1997:
1998: /*=======================================================================*/
1999: /**
2000: * <PRE>
2001: * f0 -> "this"
2002: * </PRE>
2003: */
2004: public void visit(ThisPrimaryPrefix n) {
2005: handle(n.f0);
2006:
2007: if (this Slot == -1) {
2008: LocalVariableGen lg = mg.addLocalVariable(ctx
2009: .makeUniqueIdentifierName("this"), ctx.VALUE_TYPE,
2010: null, null);
2011: this Slot = lg.getIndex();
2012:
2013: // insert at head in reverse order
2014: il.insert(new ASTORE(this Slot));
2015: il.insert(new INVOKEVIRTUAL(ctx.methodref(
2016: "oscript.data.Scope", "getThis",
2017: "()Loscript/data/Value;")));
2018: il.insert(InstructionConstants.ALOAD_2); // scope
2019: }
2020:
2021: il.append(new ALOAD(this Slot));
2022: setRetValOnStack(true);
2023: }
2024:
2025: private int this Slot = -1;
2026:
2027: /*=======================================================================*/
2028: /**
2029: * <PRE>
2030: * f0 -> "super"
2031: * </PRE>
2032: */
2033: public void visit(SuperPrimaryPrefix n) {
2034: handle(n.f0);
2035:
2036: if (super Slot == -1) {
2037: LocalVariableGen lg = mg.addLocalVariable(ctx
2038: .makeUniqueIdentifierName("super"), ctx.VALUE_TYPE,
2039: null, null);
2040: super Slot = lg.getIndex();
2041:
2042: // insert at head in reverse order
2043: il.insert(new ASTORE(super Slot));
2044: il.insert(new INVOKEVIRTUAL(ctx.methodref(
2045: "oscript.data.Scope", "getSuper",
2046: "()Loscript/data/Value;")));
2047: il.insert(InstructionConstants.ALOAD_2); // scope
2048: }
2049:
2050: il.append(new ALOAD(super Slot));
2051: setRetValOnStack(true);
2052: }
2053:
2054: private int super Slot = -1;
2055:
2056: /*=======================================================================*/
2057: /**
2058: * <PRE>
2059: * f0 -> "callee"
2060: * </PRE>
2061: */
2062: public void visit(CalleePrimaryPrefix n) {
2063: handle(n.f0);
2064:
2065: if (calleeSlot == -1) {
2066: LocalVariableGen lg = mg.addLocalVariable(ctx
2067: .makeUniqueIdentifierName("callee"),
2068: ctx.VALUE_TYPE, null, null);
2069: calleeSlot = lg.getIndex();
2070:
2071: // insert at head in reverse order
2072: il.insert(new ASTORE(calleeSlot));
2073: il.insert(new INVOKEVIRTUAL(ctx.methodref(
2074: "oscript.data.Scope", "getCallee",
2075: "()Loscript/data/Value;")));
2076: il.insert(InstructionConstants.ALOAD_2); // scope
2077: }
2078:
2079: il.append(new ALOAD(calleeSlot));
2080: setRetValOnStack(true);
2081: }
2082:
2083: private int calleeSlot = -1;
2084:
2085: /*=======================================================================*/
2086: /**
2087: * <PRE>
2088: * f0 -> <IDENTIFIER>
2089: * </PRE>
2090: */
2091: public void visit(IdentifierPrimaryPrefix n) {
2092: scope.lookupInScope(this , n.f0);
2093: setRetValOnStack(true);
2094: }
2095:
2096: /*=======================================================================*/
2097: /**
2098: * <PRE>
2099: * f0 -> "("
2100: * f1 -> Expression()
2101: * f2 -> ")"
2102: * </PRE>
2103: */
2104: public void visit(ParenPrimaryPrefix n) {
2105: n.f1.accept(this );
2106: }
2107:
2108: /*=======================================================================*/
2109: /**
2110: * <PRE>
2111: * f0 -> "function"
2112: * f1 -> "("
2113: * f2 -> ( Arglist() )?
2114: * f3 -> ")"
2115: * f4 -> ( "extends" PrimaryExpressionWithTrailingFxnCallExpList() FunctionCallExpressionList() )?
2116: * f5 -> "{"
2117: * f6 -> Program()
2118: * f7 -> "}"
2119: * </PRE>
2120: */
2121: public void visit(FunctionPrimaryPrefix n) {
2122: handle(n.f0);
2123: // new Function( scope, superFxn, n.fd )
2124: il.append(new NEW(ctx.cp.addClass("oscript.data.Function")));
2125: il.append(InstructionConstants.DUP);
2126: il.append(new ALOAD(scope.getSlot())); // scope
2127:
2128: if (n.f4.present()) {
2129: // superFxn
2130: ((NodeSequence) (n.f4.node)).elementAt(1).accept(this );
2131: setRetValOnStack(false);
2132: il.append(new INVOKEVIRTUAL(ctx.methodref(
2133: "oscript.data.Value", "unhand",
2134: "()Loscript/data/Value;")));
2135: } else {
2136: il.append(InstructionConstants.ACONST_NULL); // superFxn
2137: }
2138:
2139: // fd
2140: {
2141: Value oname = Symbol.getSymbol(n.id);
2142: String name = oname.castToString();
2143:
2144: int[] argIds;
2145: boolean varargs;
2146:
2147: // get arglist:
2148: if (n.f2.present()) {
2149: argIds = getArglist((Arglist) (n.f2.node));
2150: varargs = Arglist_varargs;
2151: } else {
2152: argIds = ctx.EMPTY_ARG_IDS;
2153: varargs = false;
2154: }
2155:
2156: // get extends evaluator:
2157: int extendsIdx = -1;
2158: if (n.f4.present()) {
2159: FunctionCallExpressionList fcel = (FunctionCallExpressionList) (((NodeSequence) (n.f4.node))
2160: .elementAt(2));
2161:
2162: extendsIdx = (new CompilerVisitor(ctx, name
2163: + "$extends", fcel)).innerNodeIdx;
2164: }
2165:
2166: int fxnIdx = (new CompilerVisitor(ctx, name, n.f6, argIds)).innerNodeIdx;
2167: int staticIdx = -1;
2168: if (n.f6.staticNodes != null)
2169: staticIdx = (new CompilerVisitor(ctx, name + "$static",
2170: n.f6.staticNodes)).innerNodeIdx;
2171:
2172: // just in case, to get the specials...
2173: handle(n.f0);
2174:
2175: // the syntaxtree won't change, so we only need to parse the comment once:
2176: synchronized (n) {
2177: if (!n.commentParsed) {
2178: n.commentParsed = true;
2179: if (NodeToken_lastSpecials != null)
2180: n.comment = Function.extractJavadocComment(
2181: NodeToken_lastSpecials, oname, argIds);
2182: }
2183: }
2184:
2185: ctx.pushFunctionData(il, Symbol.getSymbol(name).getId(),
2186: argIds, varargs, extendsIdx, fxnIdx, staticIdx,
2187: n.hasVarInScope, n.hasFxnInScope, n.comment);
2188: }
2189:
2190: il.append(new INVOKESPECIAL(ctx.methodref(
2191: "oscript.data.Function", "<init>",
2192: "(Loscript/data/Scope;" + "Loscript/data/Value;"
2193: + "Loscript/data/Function$FunctionData;)V")));
2194:
2195: setRetValOnStack(true);
2196: }
2197:
2198: /*=======================================================================*/
2199: /**
2200: * <PRE>
2201: * f0 -> "'{"
2202: * f1 -> Program(true)
2203: * f2 -> "}"
2204: * </PRE>
2205: */
2206: public void visit(ShorthandFunctionPrimaryPrefix n) {
2207: ShorthandFunctionPrimaryPrefixTranslator.translate(n).accept(
2208: this );
2209: }
2210:
2211: /*=======================================================================*/
2212: /**
2213: * <PRE>
2214: * f0 -> "["
2215: * f1 -> (FunctionCallExpressionListBody())?
2216: * f2 -> "]"
2217: * </PRE>
2218: */
2219: public void visit(ArrayDeclarationPrimaryPrefix n) {
2220: if (n.f1.present())
2221: n.f1.node.accept(this );
2222: else
2223: allocateMemberTable(0);
2224:
2225: setRetValOnStack(true);
2226: }
2227:
2228: /*=======================================================================*/
2229: /**
2230: * <PRE>
2231: * f0 -> FunctionCallPrimaryPostfix()
2232: * | ArraySubscriptPrimaryPostfix()
2233: * | ThisScopeQualifierPrimaryPostfix()
2234: * | PropertyIdentifierPrimaryPostfix()
2235: * </PRE>
2236: */
2237: public void visit(PrimaryPostfix n) {
2238: n.f0.accept(this );
2239: }
2240:
2241: /*=======================================================================*/
2242: /**
2243: * <PRE>
2244: * f0 -> ArraySubscriptPrimaryPostfix()
2245: * | ThisScopeQualifierPrimaryPostfix()
2246: * | PropertyIdentifierPrimaryPostfix()
2247: * </PRE>
2248: */
2249: public void visit(PrimaryPostfixWithTrailingFxnCallExpList n) {
2250: n.f0.accept(this );
2251: }
2252:
2253: /*=======================================================================*/
2254: /**
2255: * <PRE>
2256: * f0 -> FunctionCallExpressionList()
2257: * </PRE>
2258: */
2259: public void visit(FunctionCallPrimaryPostfix n) {
2260: setRetValOnStack(false);
2261:
2262: il.append(InstructionConstants.ALOAD_1); // sf
2263:
2264: allocateMemberTable_allocateFromStack = true;
2265: n.f0.accept(this );
2266: boolean sfIsNull = FunctionCallExpressionList_sfIsNull;
2267: checkRetValOnStack(true);
2268:
2269: // save mt: ..., val, sf, mt => ..., [mt,] val, sf, mt
2270: if (!sfIsNull)
2271: il.append(InstructionConstants.DUP_X2);
2272:
2273: // call: ..., [mt,] val, sf, mt => ..., mt, rval
2274: il
2275: .append(new INVOKEVIRTUAL(
2276: ctx
2277: .methodref("oscript.data.Value",
2278: "callAsFunction",
2279: "(Loscript/util/StackFrame;Loscript/util/MemberTable;)Loscript/data/Value;")));
2280:
2281: if (!sfIsNull) {
2282: // swap: ..., mt, rval => ..., rval, mt
2283: il.append(InstructionConstants.SWAP);
2284:
2285: // mt.free(): ..., rval, mt => ..., rval
2286: il.append(new INVOKEINTERFACE(ctx.ifmethodref(
2287: "oscript.util.MemberTable", "free", "()V"), 1));
2288: }
2289: }
2290:
2291: /*=======================================================================*/
2292: /**
2293: * <PRE>
2294: * <PRE>
2295: * f0 -> "["
2296: * f1 -> Expression()
2297: * f2 -> ( ".." Expression() )?
2298: * f3 -> "]"
2299: * </PRE>
2300: */
2301: public void visit(ArraySubscriptPrimaryPostfix n) {
2302: setRetValOnStack(false);
2303:
2304: n.f1.accept(this );
2305:
2306: if (n.f2.present()) {
2307: setRetValOnStack(false);
2308: ((NodeSequence) (n.f2.node)).elementAt(1).accept(this );
2309:
2310: checkRetValOnStack(true);
2311: il
2312: .append(new INVOKEVIRTUAL(
2313: ctx
2314: .methodref("oscript.data.Value",
2315: "elementsAt",
2316: "(Loscript/data/Value;Loscript/data/Value;)Loscript/data/Value;")));
2317: } else {
2318: checkRetValOnStack(true);
2319: il.append(new INVOKEVIRTUAL(ctx.methodref(
2320: "oscript.data.Value", "elementAt",
2321: "(Loscript/data/Value;)Loscript/data/Value;")));
2322: }
2323: }
2324:
2325: /*=======================================================================*/
2326: /**
2327: * <PRE>
2328: * f0 -> "."
2329: * f1 -> <IDENTIFIER>
2330: * </PRE>
2331: */
2332: public void visit(PropertyIdentifierPrimaryPostfix n) {
2333: setRetValOnStack(false);
2334:
2335: n.f1.accept(this );
2336: checkRetValOnStack(true);
2337:
2338: il.append(new INVOKEVIRTUAL(ctx.methodref("oscript.data.Value",
2339: "getMember", "(I)Loscript/data/Value;")));
2340: }
2341:
2342: /*=======================================================================*/
2343: /**
2344: * <PRE>
2345: * f0 -> "."
2346: * f1 -> "this"
2347: * </PRE>
2348: */
2349: public void visit(ThisScopeQualifierPrimaryPostfix n) {
2350: checkRetValOnStack(true);
2351:
2352: il.append(InstructionConstants.ALOAD_2); // scope
2353: il.append(InstructionConstants.SWAP);
2354: il.append(new INVOKEVIRTUAL(ctx
2355: .methodref("oscript.data.Scope", "getThis",
2356: "(Loscript/data/Value;)Loscript/data/Value;")));
2357: }
2358:
2359: /*=======================================================================*/
2360: /**
2361: * <PRE>
2362: * f0 -> <INTEGER_LITERAL>
2363: * | <FLOATING_POINT_LITERAL>
2364: * | <STRING_LITERAL>
2365: * | <REGEXP_LITERAL>
2366: * | "true"
2367: * | "false"
2368: * | "null"
2369: * | "undefined"
2370: * </PRE>
2371: */
2372: public void visit(Literal n) {
2373: n.f0.accept(this );
2374: }
2375:
2376: /*=======================================================================*/
2377: /**
2378: * <PRE>
2379: * f0 -> ( "static" | "const" | "private" | "protected" | "public" )*
2380: * </PRE>
2381: */
2382: public void visit(Permissions n) {
2383: throw new ProgrammingErrorException("shouldn't get here!");
2384: }
2385:
2386: /**
2387: * Get the permissions mask...
2388: *
2389: * @param n the permissions syntaxtree node
2390: * @param attr the default permissions value
2391: * @return the permissions mask
2392: */
2393: private int getPermissions(Permissions n, int attr) {
2394: for (int i = 0; i < n.f0.size(); i++) {
2395: n.f0.elementAt(i).accept(this );
2396:
2397: switch (NodeToken_lastToken.kind) {
2398: case PRIVATE:
2399: attr = (attr & 0xf0) | Reference.ATTR_PRIVATE;
2400: break;
2401: case PROTECTED:
2402: attr = (attr & 0xf0) | Reference.ATTR_PROTECTED;
2403: break;
2404: case PUBLIC:
2405: attr = (attr & 0xf0) | Reference.ATTR_PUBLIC;
2406: break;
2407: case STATIC:
2408: attr |= Reference.ATTR_STATIC;
2409: break;
2410: case CONST:
2411: attr |= Reference.ATTR_CONST;
2412: break;
2413: default:
2414: throw new ProgrammingErrorException(
2415: "bad kind: "
2416: + OscriptParser
2417: .getTokenString(NodeToken_lastToken.kind));
2418: }
2419: }
2420:
2421: return attr;
2422: }
2423:
2424: public String toString() {
2425: return mg.getName();
2426: }
2427: }
2428:
2429: /*
2430: * Local Variables:
2431: * tab-width: 2
2432: * indent-tabs-mode: nil
2433: * mode: java
2434: * c-indentation-style: java
2435: * c-basic-offset: 2
2436: * eval: (c-set-offset 'substatement-open '0)
2437: * eval: (c-set-offset 'case-label '+)
2438: * eval: (c-set-offset 'inclass '+)
2439: * eval: (c-set-offset 'inline-open '0)
2440: * End:
2441: */
|