001: // Copyright (c) 2001 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: * This class represents a conditional.
011: * @author Per Bothner
012: */
013:
014: public class IfExp extends Expression {
015: Expression test;
016: Expression then_clause;
017: Expression else_clause;
018:
019: public IfExp(Expression i, Expression t, Expression e) {
020: test = i;
021: then_clause = t;
022: else_clause = e;
023: }
024:
025: protected final Language getLanguage() {
026: return Language.getDefaultLanguage(); // FIXME
027: }
028:
029: protected boolean mustCompile() {
030: return false;
031: }
032:
033: public void apply(CallContext ctx) throws Throwable {
034: if (getLanguage().isTrue(test.eval(ctx)))
035: then_clause.apply(ctx);
036: else if (else_clause != null)
037: else_clause.apply(ctx);
038: }
039:
040: public void compile(Compilation comp, Target target) {
041: compile(test, then_clause,
042: else_clause == null ? QuoteExp.voidExp : else_clause,
043: comp, target);
044: }
045:
046: public static void compile(Expression test, Expression then_clause,
047: Expression else_clause, Compilation comp, Target target) {
048: Language language = comp.getLanguage();
049: gnu.bytecode.CodeAttr code = comp.getCode();
050: Label trueLabel, falseLabel;
051: boolean trueInherited, falseInherited;
052: // A constant else_clause results from the expansion of (and ...),
053: // and also if the else_clause if elided, so we optimize this case.
054: if (target instanceof ConditionalTarget
055: && else_clause instanceof QuoteExp) {
056: falseInherited = true;
057: Object value = ((QuoteExp) else_clause).getValue();
058: if (language.isTrue(value))
059: falseLabel = ((ConditionalTarget) target).ifTrue;
060: else
061: falseLabel = ((ConditionalTarget) target).ifFalse;
062: } else if (else_clause instanceof ExitExp
063: && ((ExitExp) else_clause).result instanceof QuoteExp
064: && ((ExitExp) else_clause).block.subTarget instanceof IgnoreTarget) {
065: falseInherited = true;
066: falseLabel = ((ExitExp) else_clause).block.exitLabel;
067: } else {
068: falseInherited = false;
069: falseLabel = new Label(code);
070: }
071: // The expansion of "or" creates an IfExp with test==then_clause.
072: // In that case, we know that the then_clause must be true.
073: // Let's optimize that case.
074: if (test == then_clause && target instanceof ConditionalTarget
075: && then_clause instanceof ReferenceExp) {
076: trueInherited = true;
077: trueLabel = ((ConditionalTarget) target).ifTrue;
078: } else {
079: trueInherited = false;
080: trueLabel = new Label(code);
081: }
082: ConditionalTarget ctarget = new ConditionalTarget(trueLabel,
083: falseLabel, language);
084: if (trueInherited)
085: ctarget.trueBranchComesFirst = false;
086: test.compile(comp, ctarget);
087: code.emitIfThen();
088: if (!trueInherited /* && trueLabel.hasFixups()*/) {
089: trueLabel.define(code);
090: // An alternative to saving and restoring callContextVar
091: // would be to surround the compile with a pushScope and popScope.
092: // That would also release any "dangling" callContextVar.
093: Variable callContextSave = comp.callContextVar;
094: then_clause.compileWithPosition(comp, target);
095: comp.callContextVar = callContextSave;
096: }
097: if (!falseInherited /* && falseLabel.hasFixups()*/) {
098: code.emitElse();
099: falseLabel.define(code);
100: // See note above for then_clause.
101: Variable callContextSave = comp.callContextVar;
102: if (else_clause == null)
103: comp.compileConstant(Values.empty, target);
104: else
105: else_clause.compileWithPosition(comp, target);
106: comp.callContextVar = callContextSave;
107: } else
108: code.setUnreachable();
109: code.emitFi();
110: }
111:
112: protected Expression walk(ExpWalker walker) {
113: return walker.walkIfExp(this );
114: }
115:
116: protected void walkChildren(ExpWalker walker) {
117: test = test.walk(walker);
118: if (walker.exitValue == null)
119: then_clause = walker.walk(then_clause);
120: if (walker.exitValue == null && else_clause != null)
121: else_clause = walker.walk(else_clause);
122: }
123:
124: public gnu.bytecode.Type getType() {
125: Type t1 = then_clause.getType();
126: Type t2 = else_clause == null ? Type.void_type : else_clause
127: .getType();
128: if (t1 == t2)
129: return t1;
130: // FIXME - implement union types
131: return Type.pointer_type;
132: }
133:
134: public void print(OutPort out) {
135: out.startLogicalBlock("(If ", false, ")");
136: out.setIndentation(-2, false);
137: test.print(out);
138: out.writeSpaceLinear();
139: then_clause.print(out);
140: if (else_clause != null) {
141: out.writeSpaceLinear();
142: else_clause.print(out);
143: }
144: out.endLogicalBlock(")");
145: }
146: }
|