001: // Copyright (c) 1999 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.OutPort;
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 BlockExp() {
022: }
023:
024: public BlockExp(Expression body) {
025: setBody(body);
026: }
027:
028: public void setBody(Expression body) {
029: this .body = body;
030: }
031:
032: public void setBody(Expression body, Expression exitBody) {
033: this .body = body;
034: this .exitBody = exitBody;
035: }
036:
037: /* Target used to evaluate body. Temporary only used during compilation. */
038: Target subTarget;
039: /* Label to exit to. Temporary only used during compilation. */
040: Label exitLabel;
041:
042: public void compile(Compilation comp, Target target) {
043: Target subTarget;
044: if (target instanceof IgnoreTarget
045: || target == Target.pushObject)
046: subTarget = target;
047: else {
048: // We can probably do better - and this is probably
049: // wrong for TailTargets. FIXME.
050: subTarget = new StackTarget(getType());
051: }
052: gnu.bytecode.CodeAttr code = comp.getCode();
053: exitLabel = new Label(code);
054: this .subTarget = exitBody == null ? subTarget : Target.Ignore;
055:
056: initialTryState = code.getTryStack();
057: body.compileWithPosition(comp, subTarget);
058:
059: if (exitBody != null) {
060: Label doneLabel = new Label(code);
061: code.emitGoto(doneLabel);
062: exitLabel.define(code);
063: exitBody.compileWithPosition(comp, subTarget);
064: doneLabel.define(code);
065: } else
066: exitLabel.define(code);
067: if (subTarget != target)
068: target.compileFromStack(comp, subTarget.getType());
069: }
070:
071: // The try state in place at the beginning of the block
072: TryState initialTryState;
073:
074: void exit(CodeAttr code) {
075: // Run enclosing finally clauses
076: for (TryState st = code.getTryStack(); st != initialTryState; st = st.previous) {
077: if (st.finally_subr != null)
078: code.emitJsr(st.finally_subr);
079: }
080:
081: code.emitGoto(exitLabel);
082: }
083:
084: protected Expression walk(ExpWalker walker) {
085: return walker.walkBlockExp(this );
086: }
087:
088: protected void walkChildren(ExpWalker walker) {
089: body = body.walk(walker);
090: if (walker.exitValue == null && exitBody != null)
091: exitBody = exitBody.walk(walker);
092: }
093:
094: public void print(OutPort out) {
095: out.startLogicalBlock("(Block", ")", 2);
096: if (label != null)
097: out.print(label.getName());
098: out.writeSpaceLinear();
099: body.print(out);
100: if (exitBody != null) {
101: out.writeSpaceLinear();
102: out.print("else ");
103: exitBody.print(out);
104: }
105: out.endLogicalBlock(")");
106: }
107: }
|