001: /**************************************************************************/
002: /* N I C E */
003: /* A simple imperative object-oriented research language */
004: /* (c) Daniel Bonniot 2000 */
005: /* */
006: /* This program is free software; you can redistribute it and/or modify */
007: /* it under the terms of the GNU General Public License as published by */
008: /* the Free Software Foundation; either version 2 of the License, or */
009: /* (at your option) any later version. */
010: /* */
011: /**************************************************************************/package nice.lang.inline;
012:
013: import gnu.mapping.Procedure2;
014: import gnu.expr.*;
015: import gnu.bytecode.*;
016:
017: /**
018: Inlining of native short-circuit operators.
019:
020: @author Daniel Bonniot
021: */
022: public class ShortCircuitOp extends Procedure2 implements Inlineable,
023: Branchable {
024: private final static int And = 2, Or = 3;
025:
026: public static ShortCircuitOp create(String param) {
027: int kind;
028: if ("&&".equals(param))
029: kind = And;
030: else if ("||".equals(param))
031: kind = Or;
032: else
033: throw bossa.util.User
034: .error("Unknown inlined short-circuit operator "
035: + param);
036: return new ShortCircuitOp(kind);
037: }
038:
039: private ShortCircuitOp(int kind) {
040: this .kind = kind;
041: }
042:
043: private final int kind;
044:
045: public void compile(ApplyExp exp, Compilation comp, Target target) {
046: Expression[] args = exp.getArgs();
047:
048: // Optimize some trivial cases
049: if (kind == And) {
050: if (args[0] == QuoteExp.trueExp) {
051: args[1].compile(comp, target);
052: return;
053: }
054: if (args[1] == QuoteExp.trueExp) {
055: args[0].compile(comp, target);
056: return;
057: }
058: }
059:
060: CodeAttr code = comp.getCode();
061: Target stack = new StackTarget(Type.boolean_type);
062:
063: Branchable branchOp = args[0].getBranchable();
064: Branchable branchOp2 = args[1].getBranchable();
065: Label _else = new Label(code);
066: Label _end = new Label(code);
067:
068: if (branchOp != null) {
069: Expression[] brArgs = ((ApplyExp) args[0]).getArgs();
070: if (kind == And)
071: branchOp.compileJumpNot(comp, brArgs, _else);
072: else
073: branchOp.compileJump(comp, brArgs, _else);
074: } else {
075: args[0].compile(comp, stack);
076: if (kind == And)
077: code.emitGotoIfIntEqZero(_else);
078: else
079: code.emitGotoIfIntNeZero(_else);
080: }
081: if (branchOp2 != null) {
082: Expression[] brArgs = ((ApplyExp) args[1]).getArgs();
083: if (kind == And)
084: branchOp2.compileJumpNot(comp, brArgs, _else);
085: else
086: branchOp2.compileJump(comp, brArgs, _else);
087:
088: code.emitPushBoolean(kind == And);
089: } else
090: args[1].compile(comp, stack);
091:
092: code.emitGoto(_end);
093: code.popType(); //simulate 'else' otherwise gnu.bytecode don't like it
094: _else.define(code);
095: code.emitPushBoolean(kind != And);
096: _end.define(code);
097:
098: target.compileFromStack(comp, retType);
099: }
100:
101: /**
102: Jump to label if the expression yields true.
103: */
104: public void compileJump(Compilation comp, Expression[] args,
105: Label to) {
106: CodeAttr code = comp.getCode();
107: Target stack = new StackTarget(Type.boolean_type);
108:
109: Branchable branchOp = args[0].getBranchable();
110: Branchable branchOp2 = args[1].getBranchable();
111: Label _end = new Label(code);
112:
113: if (branchOp != null) {
114: Expression[] brArgs = ((ApplyExp) args[0]).getArgs();
115: if (kind == And)
116: branchOp.compileJumpNot(comp, brArgs, _end);
117: else
118: branchOp.compileJump(comp, brArgs, to);
119: } else {
120: args[0].compile(comp, stack);
121: if (kind == And)
122: code.emitGotoIfIntEqZero(_end);
123: else
124: code.emitGotoIfIntNeZero(to);
125: }
126: if (branchOp2 != null) {
127: Expression[] brArgs = ((ApplyExp) args[1]).getArgs();
128: branchOp2.compileJump(comp, brArgs, to);
129: } else {
130: args[1].compile(comp, stack);
131: code.emitGotoIfIntNeZero(to);
132: }
133: _end.define(code);
134: }
135:
136: /**
137: Jump to label if the expression yields false.
138: */
139: public void compileJumpNot(Compilation comp, Expression[] args,
140: Label to) {
141: CodeAttr code = comp.getCode();
142: Target stack = new StackTarget(Type.boolean_type);
143:
144: Branchable branchOp = args[0].getBranchable();
145: Branchable branchOp2 = args[1].getBranchable();
146: Label _end = new Label(code);
147:
148: if (branchOp != null) {
149: Expression[] brArgs = ((ApplyExp) args[0]).getArgs();
150: if (kind == And)
151: branchOp.compileJumpNot(comp, brArgs, to);
152: else
153: branchOp.compileJump(comp, brArgs, _end);
154: } else if (kind == And && args[0] == QuoteExp.trueExp) {
155: // Optim: do nothing, this argument cannot make the expression false.
156: } else {
157: args[0].compile(comp, stack);
158: if (kind == And)
159: code.emitGotoIfIntEqZero(to);
160: else
161: code.emitGotoIfIntNeZero(_end);
162: }
163: if (branchOp2 != null) {
164: Expression[] brArgs = ((ApplyExp) args[1]).getArgs();
165: branchOp2.compileJumpNot(comp, brArgs, to);
166: } else if (kind == And && args[1] == QuoteExp.trueExp) {
167: // Optim: do nothing, this argument cannot make the expression false.
168: } else {
169: args[1].compile(comp, stack);
170: code.emitGotoIfIntEqZero(to);
171: }
172: _end.define(code);
173: }
174:
175: private static final Type retType = Type.boolean_type;
176:
177: public Type getReturnType(Expression[] args) {
178: return retType;
179: }
180:
181: // Interpretation
182:
183: public Object apply2(Object arg1, Object arg2) {
184: throw new Error("Not implemented");
185: }
186: }
|