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: class BSHSwitchStatement extends SimpleNode implements ParserConstants {
035:
036: public BSHSwitchStatement(int id) {
037: super (id);
038: }
039:
040: public Object eval(CallStack callstack, Interpreter interpreter)
041: throws EvalError {
042: int numchild = jjtGetNumChildren();
043: int child = 0;
044: SimpleNode switchExp = ((SimpleNode) jjtGetChild(child++));
045: Object switchVal = switchExp.eval(callstack, interpreter);
046:
047: /*
048: Note: this could be made clearer by adding an inner class for the
049: cases and an object context for the child traversal.
050: */
051: // first label
052: BSHSwitchLabel label;
053: Object node;
054: ReturnControl returnControl = null;
055:
056: // get the first label
057: if (child >= numchild)
058: throw new EvalError("Empty switch statement.", this ,
059: callstack);
060: label = ((BSHSwitchLabel) jjtGetChild(child++));
061:
062: // while more labels or blocks and haven't hit return control
063: while (child < numchild && returnControl == null) {
064: // if label is default or equals switchVal
065: if (label.isDefault
066: || primitiveEquals(switchVal, label.eval(callstack,
067: interpreter), callstack, switchExp)) {
068: // execute nodes, skipping labels, until a break or return
069: while (child < numchild) {
070: node = jjtGetChild(child++);
071: if (node instanceof BSHSwitchLabel)
072: continue;
073: // eval it
074: Object value = ((SimpleNode) node).eval(callstack,
075: interpreter);
076:
077: // should check to disallow continue here?
078: if (value instanceof ReturnControl) {
079: returnControl = (ReturnControl) value;
080: break;
081: }
082: }
083: } else {
084: // skip nodes until next label
085: while (child < numchild) {
086: node = jjtGetChild(child++);
087: if (node instanceof BSHSwitchLabel) {
088: label = (BSHSwitchLabel) node;
089: break;
090: }
091: }
092: }
093: }
094:
095: if (returnControl != null && returnControl.kind == RETURN)
096: return returnControl;
097: else
098: return Primitive.VOID;
099: }
100:
101: /**
102: Helper method for testing equals on two primitive or boxable objects.
103: yuck: factor this out into Primitive.java
104: */
105: private boolean primitiveEquals(Object switchVal, Object targetVal,
106: CallStack callstack, SimpleNode switchExp) throws EvalError {
107: if (switchVal instanceof Primitive
108: || targetVal instanceof Primitive)
109: try {
110: // binaryOperation can return Primitive or wrapper type
111: Object result = Primitive.binaryOperation(switchVal,
112: targetVal, ParserConstants.EQ);
113: result = Primitive.unwrap(result);
114: return result.equals(Boolean.TRUE);
115: } catch (UtilEvalError e) {
116: throw e.toEvalError("Switch value: "
117: + switchExp.getText() + ": ", this, callstack);
118: }
119: else
120: return switchVal.equals(targetVal);
121: }
122: }
|