001: // Copyright (c) 1999, 2006 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.expr;
005:
006: import gnu.bytecode.*;
007: import gnu.mapping.*;
008:
009: /**
010: * Class used to implement a block that can be exited.
011: * @author Per Bothner
012: */
013:
014: public class BlockExp extends Expression {
015: Declaration label;
016: Expression body;
017:
018: /** If non-null, evaluate this, but only if non-normal exit. */
019: Expression exitBody;
020:
021: public void setBody(Expression body) {
022: this .body = body;
023: }
024:
025: public void setBody(Expression body, Expression exitBody) {
026: this .body = body;
027: this .exitBody = exitBody;
028: }
029:
030: /* Target used to evaluate body. Temporary only used during compilation. */
031: Target subTarget;
032: /* Label to exit to. Temporary only used during compilation. */
033: Label exitLabel;
034: /* Current TryState when we start compiling the. Temporary. */
035: TryState oldTryState;
036:
037: protected boolean mustCompile() {
038: return false;
039: }
040:
041: public void apply(CallContext ctx) throws Throwable {
042: Object result;
043: try {
044: result = body.eval(ctx);
045: } catch (BlockExitException ex) {
046: if (ex.exit.block != this )
047: throw ex;
048: result = ex.exit.result;
049: if (exitBody != null)
050: result = exitBody.eval(ctx);
051: }
052: ctx.writeValue(result);
053: }
054:
055: public void compile(Compilation comp, Target target) {
056: Target subTarget;
057: if (target instanceof IgnoreTarget
058: || target == Target.pushObject)
059: subTarget = target;
060: else {
061: // We can probably do better - and this is probably
062: // wrong for TailTargets. FIXME.
063: subTarget = new StackTarget(getType());
064: }
065: gnu.bytecode.CodeAttr code = comp.getCode();
066: oldTryState = code.getCurrentTry();
067: exitLabel = new Label(code);
068: this .subTarget = exitBody == null ? subTarget : Target.Ignore;
069: body.compileWithPosition(comp, subTarget);
070: if (exitBody != null) {
071: Label doneLabel = new Label(code);
072: code.emitGoto(doneLabel);
073: exitLabel.define(code);
074: exitBody.compileWithPosition(comp, subTarget);
075: doneLabel.define(code);
076: } else
077: exitLabel.define(code);
078: if (subTarget != target)
079: target.compileFromStack(comp, subTarget.getType());
080: oldTryState = null;
081: }
082:
083: protected Expression walk(ExpWalker walker) {
084: return walker.walkBlockExp(this );
085: }
086:
087: protected void walkChildren(ExpWalker walker) {
088: body = walker.walk(body);
089: if (walker.exitValue == null && exitBody != null)
090: exitBody = walker.walk(exitBody);
091: }
092:
093: public void print(OutPort out) {
094: out.startLogicalBlock("(Block", ")", 2);
095: if (label != null)
096: out.print(label.getName());
097: out.writeSpaceLinear();
098: body.print(out);
099: if (exitBody != null) {
100: out.writeSpaceLinear();
101: out.print("else ");
102: exitBody.print(out);
103: }
104: out.endLogicalBlock(")");
105: }
106: }
107:
108: class BlockExitException extends RuntimeException {
109: ExitExp exit;
110: Object result;
111:
112: public BlockExitException(ExitExp exit, Object result) {
113: this.exit = exit;
114: this.result = result;
115: }
116: }
|