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 reference operators.
019: */
020: public class ReferenceOp extends Procedure2 implements Branchable,
021: bossa.syntax.Macro {
022: private final static int Eq = 1, Ne = 2;
023:
024: public static ReferenceOp create(String param) {
025: int kind = 0;
026: if ("==".equals(param))
027: kind = Eq;
028: else if ("!=".equals(param))
029: kind = Ne;
030: else
031: bossa.util.User.error("Unknown inlined boolean operator "
032: + param);
033: return new ReferenceOp(kind);
034: }
035:
036: private ReferenceOp(int kind) {
037: this .kind = kind;
038: }
039:
040: private final int kind;
041:
042: public void compile(ApplyExp exp, Compilation comp, Target target) {
043: Expression[] args = exp.getArgs();
044: compile(args, comp, target);
045: }
046:
047: void compile(Expression[] args, Compilation comp, Target target) {
048: CodeAttr code = comp.getCode();
049: Target stack = Target.pushObject;
050: Label _else = new Label(code);
051: Label _end = new Label(code);
052:
053: boolean prim0 = args[0].getType() instanceof PrimType;
054: boolean prim1 = args[1].getType() instanceof PrimType;
055:
056: if (prim1 && !prim0) {
057: compilePrimitive(false, args[0], args[1], comp);
058: return;
059: } else if (prim0 && !prim1) {
060: compilePrimitive(true, args[1], args[0], comp);
061: return;
062: } else if (args[0] instanceof QuoteExp
063: && ((QuoteExp) args[0]).getType() == Type.nullType) {
064: args[1].compile(comp, stack);
065: if (kind == Eq)
066: code.emitGotoIfNotNull(_else);
067: else
068: code.emitGotoIfNull(_else);
069: } else if (args[1] instanceof QuoteExp
070: && ((QuoteExp) args[1]).getType() == Type.nullType) {
071: args[0].compile(comp, stack);
072: if (kind == Eq)
073: code.emitGotoIfNotNull(_else);
074: else
075: code.emitGotoIfNull(_else);
076: } else {
077: args[0].compile(comp, stack);
078: args[1].compile(comp, stack);
079: if (kind == Eq)
080: code.emitGotoIfNE(_else);
081: else
082: code.emitGotoIfEq(_else);
083:
084: }
085: code.emitPushBoolean(true);
086: code.emitGoto(_end);
087: code.popType(); // simulate 'else' otherwise gnu.bytecode doesn't like it
088: _else.define(code);
089: code.emitPushBoolean(false);
090: _end.define(code);
091:
092: target.compileFromStack(comp, retType);
093: }
094:
095: private void compilePrimitive(boolean primFirst,
096: Expression nonPrimArg, Expression primArg, Compilation comp) {
097: CodeAttr code = comp.getCode();
098: Target stack = Target.pushObject;
099: Target primTarget = new StackTarget(primArg.getType());
100: boolean eq = kind == Eq;
101:
102: if (primFirst)
103: primArg.compile(comp, primTarget);
104: nonPrimArg.compile(comp, stack);
105: code.emitDup();
106:
107: code.emitIfNotNull();
108: primTarget.compileFromStack(comp, code.topType());
109: if (!primFirst)
110: primArg.compile(comp, primTarget);
111: code.emitIfEq();
112: code.emitPushBoolean(eq);
113: code.emitElse();
114: code.emitPushBoolean(!eq);
115: code.emitFi();
116: code.emitElse();
117: code.emitPop(primFirst ? 2 : 1);
118: code.emitPushBoolean(!eq);
119: code.emitFi();
120: }
121:
122: public void compileJump(Compilation comp, Expression[] args,
123: Label to) {
124: compileJump(comp, args, to, false);
125: }
126:
127: public void compileJumpNot(Compilation comp, Expression[] args,
128: Label to) {
129: compileJump(comp, args, to, true);
130: }
131:
132: private void compileJump(Compilation comp, Expression[] args,
133: Label to, boolean not) {
134: CodeAttr code = comp.getCode();
135: Target stack = Target.pushObject;
136:
137: boolean prim0 = args[0].getType() instanceof PrimType;
138: boolean prim1 = args[1].getType() instanceof PrimType;
139:
140: if (prim1 && !prim0 || prim0 && !prim1) {
141: compile(args, comp, StackTarget
142: .getInstance(Type.boolean_type));
143: if (not)
144: code.emitGotoIfIntEqZero(to);
145: else
146: code.emitGotoIfIntNeZero(to);
147: }
148:
149: else if (args[0] instanceof QuoteExp
150: && ((QuoteExp) args[0]).getType() == Type.nullType) {
151: if (args[1].getType() instanceof PrimType) {
152: if (not ^ kind == Ne)
153: code.emitGoto(to);
154:
155: return;
156: }
157:
158: args[1].compile(comp, stack);
159: if (not ^ kind == Eq)
160: code.emitGotoIfNull(to);
161: else
162: code.emitGotoIfNotNull(to);
163: } else if (args[1] instanceof QuoteExp
164: && ((QuoteExp) args[1]).getType() == Type.nullType) {
165: if (args[0].getType() instanceof PrimType) {
166: if (not ^ kind == Ne)
167: code.emitGoto(to);
168:
169: return;
170: }
171:
172: args[0].compile(comp, stack);
173: if (not ^ kind == Eq)
174: code.emitGotoIfNull(to);
175: else
176: code.emitGotoIfNotNull(to);
177: } else {
178: args[0].compile(comp, stack);
179: args[1].compile(comp, stack);
180: if (not ^ kind == Eq)
181: code.emitGotoIfEq(to);
182: else
183: code.emitGotoIfNE(to);
184: }
185: }
186:
187: private static final Type retType = Type.boolean_type;
188:
189: public Type getReturnType(Expression[] args) {
190: return retType;
191: }
192:
193: public void checkSpecialRequirements(
194: bossa.syntax.Expression[] arguments) {
195: bossa.syntax.Expression exp = null;
196: if (arguments[0].isNull())
197: exp = arguments[1];
198: else if (arguments[1].isNull())
199: exp = arguments[0];
200:
201: if (exp != null
202: && nice.tools.typing.Types.isSure(exp.getType()
203: .getMonotype()))
204: bossa.util.User.warning(exp,
205: "Comparing a non-null value with null");
206: }
207:
208: // Interpretation
209:
210: public Object apply2(Object arg1, Object arg2) {
211: throw new Error("Not implemented");
212: }
213: }
|