001: /*****************************************************************************
002: * *
003: * This file is part of the BeanShell Java Scripting distribution. *
004: * Documentation and updates may be found at http://www.beanshell.org/ *
005: * *
006: * Sun Public License Notice: *
007: * *
008: * The contents of this file are subject to the Sun Public License Version *
009: * 1.0 (the "License"); you may not use this file except in compliance with *
010: * the License. A copy of the License is available at http://www.sun.com *
011: * *
012: * The Original Code is BeanShell. The Initial Developer of the Original *
013: * Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright *
014: * (C) 2000. All Rights Reserved. *
015: * *
016: * GNU Public License Notice: *
017: * *
018: * Alternatively, the contents of this file may be used under the terms of *
019: * the GNU Lesser General Public License (the "LGPL"), in which case the *
020: * provisions of LGPL are applicable instead of those above. If you wish to *
021: * allow use of your version of this file only under the terms of the LGPL *
022: * and not to allow others to use your version of this file under the SPL, *
023: * indicate your decision by deleting the provisions above and replace *
024: * them with the notice and other provisions required by the LGPL. If you *
025: * do not delete the provisions above, a recipient may use your version of *
026: * this file under either the SPL or the LGPL. *
027: * *
028: * Patrick Niemeyer (pat@pat.net) *
029: * Author of Learning Java, O'Reilly & Associates *
030: * http://www.pat.net/~pat/ *
031: * *
032: *****************************************************************************/package bsh;
033:
034: /**
035: Implementation of the for(;;) statement.
036: */
037: class BSHForStatement extends SimpleNode implements ParserConstants {
038: public boolean hasForInit;
039: public boolean hasExpression;
040: public boolean hasForUpdate;
041:
042: private SimpleNode forInit;
043: private SimpleNode expression;
044: private SimpleNode forUpdate;
045: private SimpleNode statement;
046:
047: private boolean parsed;
048:
049: BSHForStatement(int id) {
050: super (id);
051: }
052:
053: public Object eval(CallStack callstack, Interpreter interpreter)
054: throws EvalError {
055: int i = 0;
056: if (hasForInit)
057: forInit = ((SimpleNode) jjtGetChild(i++));
058: if (hasExpression)
059: expression = ((SimpleNode) jjtGetChild(i++));
060: if (hasForUpdate)
061: forUpdate = ((SimpleNode) jjtGetChild(i++));
062: if (i < jjtGetNumChildren()) // should normally be
063: statement = ((SimpleNode) jjtGetChild(i));
064:
065: NameSpace enclosingNameSpace = callstack.top();
066: BlockNameSpace forNameSpace = new BlockNameSpace(
067: enclosingNameSpace);
068:
069: /*
070: Note: some interesting things are going on here.
071:
072: 1) We swap instead of push... The primary mode of operation
073: acts like we are in the enclosing namespace... (super must be
074: preserved, etc.)
075:
076: 2) We do *not* call the body block eval with the namespace
077: override. Instead we allow it to create a second subordinate
078: BlockNameSpace child of the forNameSpace. Variable propogation
079: still works through the chain, but the block's child cleans the
080: state between iteration.
081: (which is correct Java behavior... see forscope4.bsh)
082: */
083:
084: // put forNameSpace it on the top of the stack
085: // Note: it's important that there is only one exit point from this
086: // method so that we can swap back the namespace.
087: callstack.swap(forNameSpace);
088:
089: // Do the for init
090: if (hasForInit)
091: forInit.eval(callstack, interpreter);
092:
093: Object returnControl = Primitive.VOID;
094: while (true) {
095: if (hasExpression) {
096: boolean cond = BSHIfStatement.evaluateCondition(
097: expression, callstack, interpreter);
098:
099: if (!cond)
100: break;
101: }
102:
103: boolean breakout = false; // switch eats a multi-level break here?
104: if (statement != null) // not empty statement
105: {
106: // do *not* invoke special override for block... (see above)
107: Object ret = statement.eval(callstack, interpreter);
108:
109: if (ret instanceof ReturnControl) {
110: switch (((ReturnControl) ret).kind) {
111: case RETURN:
112: returnControl = ret;
113: breakout = true;
114: break;
115:
116: case CONTINUE:
117: break;
118:
119: case BREAK:
120: breakout = true;
121: break;
122: }
123: }
124: }
125:
126: if (breakout)
127: break;
128:
129: if (hasForUpdate)
130: forUpdate.eval(callstack, interpreter);
131: }
132:
133: callstack.swap(enclosingNameSpace); // put it back
134: return returnControl;
135: }
136:
137: }
|