summaryrefslogtreecommitdiff
path: root/sources/scalac/typechecker
diff options
context:
space:
mode:
authorpaltherr <paltherr@epfl.ch>2004-02-01 03:15:00 +0000
committerpaltherr <paltherr@epfl.ch>2004-02-01 03:15:00 +0000
commite4731931589d6313988337a921747f9caf6fc3e7 (patch)
tree92c7298118201c435ef42d99d6b6d6c00a70c64a /sources/scalac/typechecker
parentc9e045f5c67d44313e9e2436ec107e514548272e (diff)
downloadscala-e4731931589d6313988337a921747f9caf6fc3e7.tar.gz
scala-e4731931589d6313988337a921747f9caf6fc3e7.tar.bz2
scala-e4731931589d6313988337a921747f9caf6fc3e7.zip
- Generalized use of AConstant to represent con...
- Generalized use of AConstant to represent constant values
Diffstat (limited to 'sources/scalac/typechecker')
-rw-r--r--sources/scalac/typechecker/Analyzer.java52
-rw-r--r--sources/scalac/typechecker/ConstantFolder.java631
2 files changed, 350 insertions, 333 deletions
diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java
index 9c7b5fbaf0..7099163995 100644
--- a/sources/scalac/typechecker/Analyzer.java
+++ b/sources/scalac/typechecker/Analyzer.java
@@ -20,6 +20,7 @@ import ch.epfl.lamp.util.Pair;
import scalac.*;
import scalac.util.*;
import scalac.ast.*;
+import scalac.atree.AConstant;
import scalac.ast.printer.*;
import scalac.symtab.*;
import scalac.symtab.classfile.*;
@@ -41,7 +42,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
this.definitions = global.definitions;
this.descr = descr;
this.infer = new Infer(this);
- this.constfold = new ConstantFolder(this);
+ this.constfold = new ConstantFolder(global);
this.desugarize = new DeSugarize(this, global);
}
@@ -1209,13 +1210,13 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
*/
Tree mkStable(Tree tree, Type pre, int mode, Type pt) {
switch (tree.type) {
- case ConstantType(_, Object value):
- return make.Literal(tree.pos, value).setType(tree.type);
+ case ConstantType(_, AConstant value):
+ return gen.Literal(tree.pos, value);
case PolyType(Symbol[] tparams, Type restp):
if (tparams.length == 0) {
switch (restp) {
- case ConstantType(_, Object value):
- return make.Literal(tree.pos, value).setType(tree.type);
+ case ConstantType(_, AConstant value):
+ return gen.Literal(tree.pos, value);
}
}
}
@@ -1386,25 +1387,24 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
}
if (!(owntype instanceof Type.PolyType || owntype.isSubType(pt))) {
switch (tree) {
- case Literal(Object value):
+ case Literal(AConstant constant):
int n = Integer.MAX_VALUE;
- if (value instanceof Integer)
- n = ((Integer) value).intValue();
- else if (value instanceof Character)
- n = ((Character) value).charValue();
- Object value1 = null;
+ switch (constant) {
+ case INT(int value): n = value; break;
+ case CHAR(char value): n = value; break;
+ }
+ AConstant value1 = null;
if (pt.symbol() == definitions.BYTE_CLASS &&
-128 <= n && n <= 127)
- value1 = new Byte((byte) n);
+ value1 = AConstant.BYTE((byte) n);
else if (pt.symbol() == definitions.SHORT_CLASS &&
-32768 <= n && n <= 32767)
- value1 = new Short((short) n);
+ value1 = AConstant.SHORT((short) n);
else if (pt.symbol() == definitions.CHAR_CLASS &&
0 <= n && n <= 65535)
- value1 = new Character((char) n);
+ value1 = AConstant.CHAR((char) n);
if (value1 != null)
- return make.Literal(tree.pos, value1)
- .setType(Type.ConstantType(pt, value1));
+ return gen.Literal(tree.pos, value1);
break;
}
if ((mode & EXPRmode) != 0) {
@@ -2286,17 +2286,13 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
// constant fold asInstanceOf calls.
switch (fn1) {
case Select(Tree qual, Name name):
- if (fn1.symbol() == definitions.ANY_AS &&
- qual.type instanceof Type.ConstantType) {
- Type restp1 = constfold.foldAsInstanceOf(
- tree.pos,
- (Type.ConstantType)qual.type,
- argtypes[0]);
- switch (restp1) {
- case ConstantType(_, Object value):
- return make.Literal(tree.pos, value)
- .setType(restp1);
- }
+ if (fn1.symbol() == definitions.ANY_AS) {
+ switch (qual.type()) {
+ case ConstantType(_, AConstant value):
+ value = constfold.cast(value, argtypes[0]);
+ if (value != null)
+ return gen.Literal(tree.pos, value);
+ }
}
}
return constfold.tryToFold(
@@ -2592,7 +2588,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds {
return transformIdent(tree, name);
}
- case Literal(Object value):
+ case Literal(AConstant value):
return tree.setType(Type.constantType(value));
case LabelDef(Name name, Ident[] params, Tree body):
diff --git a/sources/scalac/typechecker/ConstantFolder.java b/sources/scalac/typechecker/ConstantFolder.java
index 46d33b702f..20b37323eb 100644
--- a/sources/scalac/typechecker/ConstantFolder.java
+++ b/sources/scalac/typechecker/ConstantFolder.java
@@ -12,331 +12,352 @@
package scalac.typechecker;
-import scalac.util.*;
-import scalac.ast.*;
-import scalac.symtab.*;
-import scalac.symtab.Type.*;
+import scalac.Global;
+import scalac.ast.Tree;
+import scalac.ast.TreeGen;
+import scalac.atree.AConstant;
+import scalac.atree.ATypeKind;
+import scalac.symtab.Definitions;
+import scalac.symtab.Type;
+import scalac.util.Name;
+import scalac.util.Names;
-class ConstantFolder implements /*imports*/ TypeTags {
+public class ConstantFolder {
- private final Analyzer ana;
+ //########################################################################
+ // Private Fields
- ConstantFolder(Analyzer ana) {
- this.ana = ana;
+ /** The global definitions */
+ private final Definitions definitions;
+
+ /** The tree generator */
+ private final TreeGen gen;
+
+ //########################################################################
+ // Public Constructors
+
+ /** Initializes this instance. */
+ public ConstantFolder(Global global) {
+ this.definitions = global.definitions;
+ this.gen = global.treeGen;
}
- /** fold binary operation.
+ //########################################################################
+ // Public Methods
+
+ /**
+ * Attempts to constant fold given tree. Returns the input tree if
+ * constant folding fails.
*/
- Type foldBinary(int pos, ConstantType left, ConstantType right, Name op) {
- try {
- Type ltype = left.deconst();
- Symbol lsymbol = left.symbol();
- if (lsymbol == ana.definitions.BYTE_CLASS ||
- lsymbol == ana.definitions.CHAR_CLASS ||
- lsymbol == ana.definitions.SHORT_CLASS) {
- ltype = ana.definitions.INT_TYPE();
- lsymbol = ana.definitions.INT_CLASS;
- }
- Type rtype = right.deconst();
- Symbol rsymbol = right.symbol();
- if (rsymbol == ana.definitions.BYTE_CLASS ||
- rsymbol == ana.definitions.CHAR_CLASS ||
- rsymbol == ana.definitions.SHORT_CLASS) {
- rtype = ana.definitions.INT_TYPE();
- rsymbol = ana.definitions.INT_CLASS;
- }
- Type optype;
- if (ltype.isSameAs(rtype))
- optype = ltype;
- else if (lsymbol == ana.definitions.JAVA_STRING_CLASS)
- optype = ltype;
- else if (rsymbol == ana.definitions.JAVA_STRING_CLASS)
- optype = rtype;
- else if (lsymbol == ana.definitions.INT_CLASS)
- optype = rtype;
- else if (rsymbol == ana.definitions.INT_CLASS)
- optype = ltype;
- else if (lsymbol == ana.definitions.LONG_CLASS)
- optype = rtype;
- else if (rsymbol == ana.definitions.LONG_CLASS)
- optype = ltype;
- else if (lsymbol == ana.definitions.FLOAT_CLASS)
- optype = rtype;
- else if (rsymbol == ana.definitions.FLOAT_CLASS)
- optype = ltype;
- else
- throw Debug.abort("illegal case", ltype + " - " + rtype);
- Object value = null;
- switch (optype.unbox()) {
- case UnboxedType(INT):
- if (op == Names.ADD)
- value = new Integer(left.intValue() + right.intValue());
- else if (op == Names.SUB)
- value = new Integer(left.intValue() - right.intValue());
- else if (op == Names.MUL)
- value = new Integer(left.intValue() * right.intValue());
- else if (op == Names.DIV)
- value = new Integer(left.intValue() / right.intValue());
- else if (op == Names.MOD)
- value = new Integer(left.intValue() % right.intValue());
- else if (op == Names.EQ)
- value = new Boolean(left.intValue() == right.intValue());
- else if (op == Names.NE)
- value = new Boolean(left.intValue() != right.intValue());
- else if (op == Names.LT)
- value = new Boolean(left.intValue() < right.intValue());
- else if (op == Names.GT)
- value = new Boolean(left.intValue() > right.intValue());
- else if (op == Names.LE)
- value = new Boolean(left.intValue() <= right.intValue());
- else if (op == Names.GE)
- value = new Boolean(left.intValue() >= right.intValue());
- else if (op == Names.OR)
- value = new Integer(left.intValue() | right.intValue());
- else if (op == Names.AND)
- value = new Integer(left.intValue() & right.intValue());
- else if (op == Names.XOR)
- value = new Integer(left.intValue() ^ right.intValue());
- else if (op == Names.LSL)
- value = new Integer(left.intValue() << right.intValue());
- else if (op == Names.LSR)
- value = new Integer(left.intValue() >>> right.intValue());
- else if (op == Names.ASR)
- value = new Integer(left.intValue() >> right.intValue());
- break;
- case UnboxedType(LONG):
- if (op == Names.ADD)
- value = new Long(left.longValue() + right.longValue());
- else if (op == Names.SUB)
- value = new Long(left.longValue() - right.longValue());
- else if (op == Names.MUL)
- value = new Long(left.longValue() * right.longValue());
- else if (op == Names.DIV)
- value = new Long(left.longValue() / right.longValue());
- else if (op == Names.MOD)
- value = new Long(left.longValue() % right.longValue());
- else if (op == Names.EQ)
- value = new Boolean(left.longValue() == right.longValue());
- else if (op == Names.NE)
- value = new Boolean(left.longValue() != right.longValue());
- else if (op == Names.LT)
- value = new Boolean(left.longValue() < right.longValue());
- else if (op == Names.GT)
- value = new Boolean(left.longValue() > right.longValue());
- else if (op == Names.LE)
- value = new Boolean(left.longValue() <= right.longValue());
- else if (op == Names.GE)
- value = new Boolean(left.longValue() >= right.longValue());
- else if (op == Names.OR)
- value = new Long(left.longValue() | right.longValue());
- else if (op == Names.AND)
- value = new Long(left.longValue() & right.longValue());
- else if (op == Names.XOR)
- value = new Long(left.longValue() ^ right.longValue());
- else if (op == Names.LSL)
- value = new Long(left.longValue() << right.intValue());
- else if (op == Names.LSR)
- value = new Long(left.longValue() >>> right.intValue());
- else if (op == Names.ASR)
- value = new Long(left.longValue() >> right.intValue());
- break;
- case UnboxedType(FLOAT):
- if (op == Names.ADD)
- value = new Float(left.floatValue() + right.floatValue());
- else if (op == Names.SUB)
- value = new Float(left.floatValue() - right.floatValue());
- else if (op == Names.MUL)
- value = new Float(left.floatValue() * right.floatValue());
- else if (op == Names.DIV)
- value = new Float(left.floatValue() / right.floatValue());
- else if (op == Names.MOD)
- value = new Float(left.floatValue() % right.floatValue());
- else if (op == Names.EQ)
- value = new Boolean(left.floatValue() == right.floatValue());
- else if (op == Names.NE)
- value = new Boolean(left.floatValue() != right.floatValue());
- else if (op == Names.LT)
- value = new Boolean(left.floatValue() < right.floatValue());
- else if (op == Names.GT)
- value = new Boolean(left.floatValue() > right.floatValue());
- else if (op == Names.LE)
- value = new Boolean(left.floatValue() <= right.floatValue());
- else if (op == Names.GE)
- value = new Boolean(left.floatValue() >= right.floatValue());
- break;
- case UnboxedType(DOUBLE):
- if (op == Names.ADD)
- value = new Double(left.doubleValue() + right.doubleValue());
- else if (op == Names.SUB)
- value = new Double(left.doubleValue() - right.doubleValue());
- else if (op == Names.MUL)
- value = new Double(left.doubleValue() * right.doubleValue());
- else if (op == Names.DIV)
- value = new Double(left.doubleValue() / right.doubleValue());
- else if (op == Names.MOD)
- value = new Double(left.doubleValue() % right.doubleValue());
- else if (op == Names.EQ)
- value = new Boolean(left.doubleValue() == right.doubleValue());
- else if (op == Names.NE)
- value = new Boolean(left.doubleValue() != right.doubleValue());
- else if (op == Names.LT)
- value = new Boolean(left.doubleValue() < right.doubleValue());
- else if (op == Names.GT)
- value = new Boolean(left.doubleValue() > right.doubleValue());
- else if (op == Names.LE)
- value = new Boolean(left.doubleValue() <= right.doubleValue());
- else if (op == Names.GE)
- value = new Boolean(left.doubleValue() >= right.doubleValue());
- break;
- case UnboxedType(BOOLEAN):
- if (op == Names.EQ)
- value = new Boolean(left.booleanValue() == right.booleanValue());
- else if (op == Names.NE)
- value = new Boolean(left.booleanValue() != right.booleanValue());
- else if (op == Names.OR || op == Names.ZOR)
- value = new Boolean(left.booleanValue() | right.booleanValue());
- else if (op == Names.AND || op == Names.ZAND)
- value = new Boolean(left.booleanValue() & right.booleanValue());
- else if (op == Names.XOR)
- value = new Boolean(left.booleanValue() ^ right.booleanValue());
- break;
- default:
- if (optype.symbol() == ana.definitions.JAVA_STRING_CLASS &&
- op == Names.ADD)
- value = left.stringValue() + right.stringValue();
- }
- return (value != null) ? Type.constantType(value) : Type.NoType;
- } catch (ArithmeticException e) {
- ana.unit.warning(pos, e.toString());
- return Type.NoType;
- }
+ public Tree tryToFold(Tree tree) {
+ AConstant value = evaluate(tree);
+ return value != null ? gen.Literal(tree.pos, value) : tree;
}
- /** fold unary operation.
+ /**
+ * Evaluates the expression represented by the tree and returns
+ * the resulting value. Returns null if the evaluation can't be
+ * performed.
*/
- Type foldUnary(int pos, ConstantType od, Name op) {
- try {
- Object value = null;
- switch (od.deconst().unbox()) {
- case UnboxedType(INT):
- if (op == Names.ADD)
- value = new Integer(od.intValue());
- else if (op == Names.SUB)
- value = new Integer(-od.intValue());
- else if (op == Names.NOT)
- value = new Integer(~od.intValue());
- break;
- case UnboxedType(LONG):
- if (op == Names.ADD)
- value = new Long(od.longValue());
- else if (op == Names.SUB)
- value = new Long(-od.longValue());
- else if (op == Names.NOT)
- value = new Long(~od.longValue());
- break;
- case UnboxedType(FLOAT):
- if (op == Names.ADD)
- value = new Float(od.floatValue());
- else if (op == Names.SUB)
- value = new Float(-od.floatValue());
- break;
- case UnboxedType(DOUBLE):
- if (op == Names.ADD)
- value = new Double(od.doubleValue());
- else if (op == Names.SUB)
- value = new Double(-od.doubleValue());
- break;
- case UnboxedType(BOOLEAN):
- if (op == Names.ZNOT)
- value = new Boolean(!od.booleanValue());
- break;
- }
- return (value != null) ? Type.constantType(value) : Type.NoType;
- } catch (ArithmeticException e) {
- ana.unit.warning(pos, e.toString());
- return Type.NoType;
+ public AConstant evaluate(Tree tree) {
+ switch (tree) {
+ case TypeApply(Select(Tree qualifier, Name op), Tree[] args):
+ switch (qualifier.type()) {
+ case ConstantType(_, AConstant lvalue):
+ if (args.length == 1 && op == Names.asInstanceOf)
+ return cast(lvalue, args[0].type());
+ return null;
+ default:
+ return null;
+ }
+ case Apply(Select(Tree qualifier, Name op), Tree[] args):
+ switch (qualifier.type()) {
+ case ConstantType(_, AConstant lvalue):
+ switch (args.length) {
+ case 0:
+ return evaluate(op, lvalue);
+ case 1:
+ switch (args[0].type()) {
+ case ConstantType(_, AConstant rvalue):
+ return evaluate(op, lvalue, rvalue);
+ default:
+ return null;
+ }
+ default:
+ return null;
+ }
+ default:
+ return null;
+ }
+ default:
+ return null;
}
}
- /** fold cast operation
+ /**
+ * Evaluates the unary operation and returns the resulting value.
+ * Returns null if the evaluation can't be performed.
*/
- Type foldAsInstanceOf(int pos, ConstantType od, Type argtype) {
- try {
- Object value = null;
- switch (argtype.unbox()) {
- case UnboxedType(BYTE):
- value = new Byte((byte)od.intValue());
- break;
- case UnboxedType(CHAR):
- value = new Character((char)od.intValue());
- break;
- case UnboxedType(SHORT):
- value = new Short((short)od.intValue());
- break;
- case UnboxedType(INT):
- value = new Integer(od.intValue());
- break;
- case UnboxedType(LONG):
- value = new Long(od.longValue());
- break;
- case UnboxedType(FLOAT):
- value = new Float(od.longValue());
- break;
- case UnboxedType(DOUBLE):
- value = new Double(od.doubleValue());
- break;
- case UnboxedType(BOOLEAN):
- value = new Boolean(od.booleanValue());
- break;
- }
- return (value != null) ? new ConstantType(argtype, value)
- : Type.NoType;
- } catch (ClassCastException e) {
- ana.unit.warning(pos, e.toString());
- return Type.NoType;
- }
+ public AConstant evaluate(Name op, AConstant value) {
+ switch (kind(value)) {
+ case ATypeKind.BOOL:
+ boolean v = value.booleanValue();
+ if (op == Names.ZNOT) return AConstant.BOOLEAN(!v);
+ return null;
+ case ATypeKind.I4:
+ int v = value.intValue();
+ if (op == Names.ADD) return AConstant.INT(+v);
+ if (op == Names.SUB) return AConstant.INT(-v);
+ if (op == Names.NOT) return AConstant.INT(~v);
+ return null;
+ case ATypeKind.I8:
+ long v = value.longValue();
+ if (op == Names.ADD) return AConstant.LONG(+v);
+ if (op == Names.SUB) return AConstant.LONG(-v);
+ if (op == Names.NOT) return AConstant.LONG(~v);
+ return null;
+ case ATypeKind.R4:
+ float v = value.floatValue();
+ if (op == Names.ADD) return AConstant.FLOAT(+v);
+ if (op == Names.SUB) return AConstant.FLOAT(-v);
+ return null;
+ case ATypeKind.R8:
+ double v = value.doubleValue();
+ if (op == Names.ADD) return AConstant.DOUBLE(+v);
+ if (op == Names.SUB) return AConstant.DOUBLE(-v);
+ return null;
+ default:
+ return null;
+ }
}
- /** attempt to constant fold tree.
+ /**
+ * Evaluates the binary operation and returns the resulting value.
+ * Returns null if the evaluation can't be performed.
*/
- Tree tryToFold(Tree tree) {
- Type ctp = Type.NoType;
- switch (tree) {
- case Apply(Select(Tree qual, Name op), Tree[] args):
- if (qual.type instanceof ConstantType) {
- if (args.length == 0)
- ctp = foldUnary(
- tree.pos, (ConstantType)qual.type, op);
- else if (args.length == 1 &&
- args[0].type instanceof ConstantType)
- ctp = foldBinary(
- tree.pos,
- (ConstantType)qual.type,
- (ConstantType)(args[0].type),
- op);
- }
- break;
- case TypeApply(Select(Tree qual, Name op), Tree[] targs):
- if (qual.type instanceof Type.ConstantType &&
- op == Names.asInstanceOf)
- ctp = foldAsInstanceOf(
- tree.pos,
- (ConstantType)qual.type,
- targs[0].type);
- break;
- }
- switch (ctp) {
- case ConstantType(Type base, Object value):
- return ana.make.Literal(tree.pos, value).setType(ctp);
- default:
- return tree;
- }
- }
+ public AConstant evaluate(Name op, AConstant lvalue, AConstant rvalue) {
+ ATypeKind kind = kind(lvalue, rvalue);
+ if (kind == null) return null;
+ switch (kind) {
-}
+ case ATypeKind.I4:
+ int l = lvalue.intValue();
+ int r = rvalue.intValue();
+ if (op == Names.OR ) return AConstant.INT(l | r);
+ if (op == Names.AND) return AConstant.INT(l & r);
+ if (op == Names.XOR) return AConstant.INT(l ^ r);
+ if (op == Names.ADD) return AConstant.INT(l + r);
+ if (op == Names.SUB) return AConstant.INT(l - r);
+ if (op == Names.MUL) return AConstant.INT(l * r);
+ if (op == Names.DIV) return r == 0 ? null : AConstant.INT(l / r);
+ if (op == Names.MOD) return r == 0 ? null : AConstant.INT(l % r);
+ if (op == Names.EQ ) return AConstant.BOOLEAN(l == r);
+ if (op == Names.NE ) return AConstant.BOOLEAN(l != r);
+ if (op == Names.LT ) return AConstant.BOOLEAN(l < r);
+ if (op == Names.GT ) return AConstant.BOOLEAN(l > r);
+ if (op == Names.LE ) return AConstant.BOOLEAN(l <= r);
+ if (op == Names.GE ) return AConstant.BOOLEAN(l >= r);
+ if (op == Names.LSL) return AConstant.INT(l << r);
+ if (op == Names.LSR) return AConstant.INT(l >>> r);
+ if (op == Names.ASR) return AConstant.INT(l >> r);
+ return null;
+ case ATypeKind.I8:
+ long l = lvalue.longValue();
+ long r = rvalue.longValue();
+ if (op == Names.OR ) return AConstant.LONG(l | r);
+ if (op == Names.AND) return AConstant.LONG(l & r);
+ if (op == Names.XOR) return AConstant.LONG(l ^ r);
+ if (op == Names.ADD) return AConstant.LONG(l + r);
+ if (op == Names.SUB) return AConstant.LONG(l - r);
+ if (op == Names.MUL) return AConstant.LONG(l * r);
+ if (op == Names.DIV) return r == 0 ? null : AConstant.LONG(l / r);
+ if (op == Names.MOD) return r == 0 ? null : AConstant.LONG(l % r);
+ if (op == Names.EQ ) return AConstant.BOOLEAN(l == r);
+ if (op == Names.NE ) return AConstant.BOOLEAN(l != r);
+ if (op == Names.LT ) return AConstant.BOOLEAN(l < r);
+ if (op == Names.GT ) return AConstant.BOOLEAN(l > r);
+ if (op == Names.LE ) return AConstant.BOOLEAN(l <= r);
+ if (op == Names.GE ) return AConstant.BOOLEAN(l >= r);
+ if (kind(lvalue) == ATypeKind.I4) {
+ int li = lvalue.intValue();
+ if (op == Names.LSL) return AConstant.INT(li << r);
+ if (op == Names.LSR) return AConstant.INT(li >>> r);
+ if (op == Names.ASR) return AConstant.INT(li >> r);
+ } else {
+ if (op == Names.LSL) return AConstant.LONG(l << r);
+ if (op == Names.LSR) return AConstant.LONG(l >>> r);
+ if (op == Names.ASR) return AConstant.LONG(l >> r);
+ }
+ return null;
+ case ATypeKind.R4:
+ float l = lvalue.floatValue();
+ float r = rvalue.floatValue();
+ if (op == Names.ADD) return AConstant.FLOAT(l + r);
+ if (op == Names.SUB) return AConstant.FLOAT(l - r);
+ if (op == Names.MUL) return AConstant.FLOAT(l * r);
+ if (op == Names.DIV) return AConstant.FLOAT(l / r);
+ if (op == Names.MOD) return AConstant.FLOAT(l % r);
+ if (op == Names.EQ ) return AConstant.BOOLEAN(l == r);
+ if (op == Names.NE ) return AConstant.BOOLEAN(l != r);
+ if (op == Names.LT ) return AConstant.BOOLEAN(l < r);
+ if (op == Names.GT ) return AConstant.BOOLEAN(l > r);
+ if (op == Names.LE ) return AConstant.BOOLEAN(l <= r);
+ if (op == Names.GE ) return AConstant.BOOLEAN(l >= r);
+ return null;
+ case ATypeKind.R8:
+ double l = lvalue.doubleValue();
+ double r = rvalue.doubleValue();
+ if (op == Names.ADD) return AConstant.DOUBLE(l + r);
+ if (op == Names.SUB) return AConstant.DOUBLE(l - r);
+ if (op == Names.MUL) return AConstant.DOUBLE(l * r);
+ if (op == Names.DIV) return AConstant.DOUBLE(l / r);
+ if (op == Names.MOD) return AConstant.DOUBLE(l % r);
+ if (op == Names.EQ ) return AConstant.BOOLEAN(l == r);
+ if (op == Names.NE ) return AConstant.BOOLEAN(l != r);
+ if (op == Names.LT ) return AConstant.BOOLEAN(l < r);
+ if (op == Names.GT ) return AConstant.BOOLEAN(l > r);
+ if (op == Names.LE ) return AConstant.BOOLEAN(l <= r);
+ if (op == Names.GE ) return AConstant.BOOLEAN(l >= r);
+ return null;
+ case ATypeKind.BOOL:
+ boolean l = lvalue.booleanValue();
+ boolean r = rvalue.booleanValue();
+ if (op == Names.ZOR ) return AConstant.BOOLEAN(l | r);
+ if (op == Names.OR ) return AConstant.BOOLEAN(l | r);
+ if (op == Names.ZAND) return AConstant.BOOLEAN(l & r);
+ if (op == Names.AND ) return AConstant.BOOLEAN(l & r);
+ if (op == Names.XOR ) return AConstant.BOOLEAN(l ^ r);
+ if (op == Names.EQ ) return AConstant.BOOLEAN(l == r);
+ if (op == Names.NE ) return AConstant.BOOLEAN(l != r);
+ return null;
+ case ATypeKind.STR:
+ if (op == Names.ADD)
+ return AConstant.STRING(lvalue.stringValue()+rvalue.stringValue());
+ return null;
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Casts the value to given type and returns the resulting value.
+ * Returns null if the cast can't be performed.
+ */
+ public AConstant cast(AConstant value, Type type) {
+ switch (value.kind()) {
+ case UNIT:
+ if (type.isSameAs(definitions.UNIT_CLASS.type()))
+ return value;
+ return null;
+ case BOOL:
+ if (type.isSameAs(definitions.BOOLEAN_TYPE()))
+ return value;
+ return null;
+ case U1:
+ case U2:
+ case U4:
+ case U8:
+ case I1:
+ case I2:
+ case I4:
+ case I8:
+ case R4:
+ case R8:
+ if (type.isSameAs(definitions.BYTE_TYPE()))
+ return AConstant.BYTE(value.byteValue());
+ if (type.isSameAs(definitions.SHORT_TYPE()))
+ return AConstant.SHORT(value.shortValue());
+ if (type.isSameAs(definitions.CHAR_TYPE()))
+ return AConstant.CHAR(value.charValue());
+ if (type.isSameAs(definitions.INT_TYPE()))
+ return AConstant.INT(value.intValue());
+ if (type.isSameAs(definitions.LONG_TYPE()))
+ return AConstant.LONG(value.longValue());
+ if (type.isSameAs(definitions.FLOAT_TYPE()))
+ return AConstant.FLOAT(value.floatValue());
+ if (type.isSameAs(definitions.DOUBLE_TYPE()))
+ return AConstant.DOUBLE(value.doubleValue());
+ return null;
+ case STR:
+ if (type.isSameAs(definitions.JAVA_STRING_TYPE()))
+ return value;
+ return null;
+ default:
+ return null;
+ }
+ }
+
+ //########################################################################
+ // Private Methods
+
+ /** Returns the kind of given value. */
+ private ATypeKind kind(AConstant value) {
+ ATypeKind kind = value.kind();
+ switch (kind) {
+ case I1:
+ case I2:
+ case U2:
+ return ATypeKind.I4;
+ default:
+ return kind;
+ }
+ }
+
+ /**
+ * Returns the combined kind of given values or null if the values
+ * can't be combined.
+ */
+ private ATypeKind kind(AConstant lvalue, AConstant rvalue) {
+ ATypeKind lkind = kind(lvalue);
+ ATypeKind rkind = kind(rvalue);
+ if (lkind == rkind) return lkind;
+ if (lkind == ATypeKind.ZERO) return null;
+ if (rkind == ATypeKind.ZERO) return null;
+ if (lkind == ATypeKind.STR) return lkind;
+ if (rkind == ATypeKind.STR) return rkind;
+ switch (lkind) {
+ case I4:
+ switch (rkind) {
+ case I4: return lkind;
+ case I8: return rkind;
+ case R4: return rkind;
+ case R8: return rkind;
+ default: return null;
+ }
+ case I8:
+ switch (rkind) {
+ case I4: return lkind;
+ case I8: return lkind;
+ case R4: return rkind;
+ case R8: return rkind;
+ default: return null;
+ }
+ case R4:
+ switch (rkind) {
+ case I4: return lkind;
+ case I8: return lkind;
+ case R4: return lkind;
+ case R8: return rkind;
+ default: return null;
+ }
+ case R8:
+ switch (rkind) {
+ case I4: return lkind;
+ case I8: return lkind;
+ case R4: return lkind;
+ case R8: return lkind;
+ default: return null;
+ }
+ default:
+ return null;
+ }
+ }
+
+ //########################################################################
+}