From e4731931589d6313988337a921747f9caf6fc3e7 Mon Sep 17 00:00:00 2001 From: paltherr Date: Sun, 1 Feb 2004 03:15:00 +0000 Subject: - Generalized use of AConstant to represent con... - Generalized use of AConstant to represent constant values --- sources/scalac/typechecker/Analyzer.java | 52 +- sources/scalac/typechecker/ConstantFolder.java | 631 +++++++++++++------------ 2 files changed, 350 insertions(+), 333 deletions(-) (limited to 'sources/scalac/typechecker') 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; + } + } + + //######################################################################## +} -- cgit v1.2.3