// Copyright (c) 2011, David J. Pearce (djp@ecs.vuw.ac.nz) // All rights reserved. // // This software may be modified and distributed under the terms // of the BSD license. See the LICENSE file for details. package wyil.lang; import java.math.BigInteger; import java.util.*; import wybs.lang.NameID; import wycc.util.Pair; public abstract class Constant implements Comparable<Constant> { /** * The Null constant value */ public static final Null Null = new Null(); /** * The Bool true constant */ public static final Bool True = new Constant.Bool(true); /** * The Bool false constant */ public static final Bool False = new Constant.Bool(false); /** * Get the appropriate Bool constant corresponding to a Java boolean. * * @param f * @return */ public static final Bool Bool(boolean f) { return f ? True : False; } public abstract wyil.lang.Type type(); public static final class Null extends Constant { @Override public wyil.lang.Type type() { return wyil.lang.Type.T_NULL; } @Override public int hashCode() { return 0; } @Override public boolean equals(Object o) { return o instanceof Null; } @Override public String toString() { return "null"; } @Override public int compareTo(Constant v) { if(v instanceof Null) { return 0; } else { return 1; // everything is above null } } } public static final class Bool extends Constant { private final boolean value; private Bool(boolean value) { this.value = value; } @Override public wyil.lang.Type type() { return wyil.lang.Type.T_BOOL; } @Override public int hashCode() { return value ? 1 : 0; } @Override public boolean equals(Object o) { if(o instanceof Bool) { Bool i = (Bool) o; return value == i.value; } return false; } @Override public int compareTo(Constant v) { if(v instanceof Bool) { Bool b = (Bool) v; if(value == b.value) { return 0; } else if(value) { return 1; } } else if(v instanceof Null) { return 1; } return -1; } @Override public String toString() { if(value) { return "true"; } else { return "false"; } } public boolean value() { return value; } } public static final class Byte extends Constant { private final byte value; public Byte(byte value) { this.value = value; } @Override public wyil.lang.Type type() { return wyil.lang.Type.T_BYTE; } @Override public int hashCode() { return value; } @Override public boolean equals(Object o) { if(o instanceof Byte) { Byte i = (Byte) o; return value == i.value; } return false; } @Override public int compareTo(Constant v) { if(v instanceof Byte) { Byte i = (Byte) v; if(value < i.value) { return -1; } else if(value > i.value) { return 1; } else { return 0; } } else if(v instanceof Null || v instanceof Bool) { return 1; } return -1; } @Override public String toString() { String r = "b"; byte v = value; for(int i=0;i!=8;++i) { if((v&0x1) == 1) { r = "1" + r; } else { r = "0" + r; } v = (byte) (v >>> 1); } return r; } public byte value() { return value; } } public static final class Integer extends Constant { private final BigInteger value; public Integer(BigInteger value) { this.value = value; } @Override public wyil.lang.Type type() { return wyil.lang.Type.T_INT; } @Override public int hashCode() { return value.hashCode(); } @Override public boolean equals(Object o) { if(o instanceof Integer) { Integer i = (Integer) o; return value.equals(i.value); } return false; } @Override public int compareTo(Constant v) { if(v instanceof Integer) { Integer i = (Integer) v; return value.compareTo(i.value); } else if(v instanceof Null || v instanceof Byte || v instanceof Bool) { return 1; } return -1; } @Override public String toString() { return value.toString(); } public BigInteger value() { return value; } } public static final class Array extends Constant { private final ArrayList<Constant> values; public Array(Collection<Constant> value) { this.values = new ArrayList<Constant>(value); } @Override public wyil.lang.Type type() { wyil.lang.Type t = wyil.lang.Type.T_VOID; for(Constant arg : values) { t = wyil.lang.Type.Union(t,arg.type()); } return wyil.lang.Type.Array(t); } @Override public int hashCode() { return values.hashCode(); } @Override public boolean equals(Object o) { if(o instanceof Array) { Array i = (Array) o; return values.equals(i.values); } return false; } @Override public int compareTo(Constant v) { if(v instanceof Array) { Array l = (Array) v; if(values.size() < l.values.size()) { return -1; } else if(values.size() > l.values.size()) { return 1; } else { for(int i=0;i!=values.size();++i) { Constant v1 = values.get(i); Constant v2 = l.values.get(i); int c = v1.compareTo(v2); if(c != 0) { return c; } } return 0; } } else if (v instanceof Null || v instanceof Bool || v instanceof Byte || v instanceof Integer) { return 1; } return -1; } @Override public String toString() { String r = "["; boolean firstTime=true; for(Constant v : values) { if(!firstTime) { r += ","; } firstTime=false; r += v; } return r + "]"; } public ArrayList<Constant> values() { return values; } } public static final class Record extends Constant { private final HashMap<String,Constant> values; public Record(java.util.Map<String,Constant> value) { this.values = new HashMap<String,Constant>(value); } @Override public wyil.lang.Type type() { ArrayList<Pair<wyil.lang.Type,String>> types = new ArrayList<Pair<wyil.lang.Type,String>>(); for (java.util.Map.Entry<String, Constant> e : values.entrySet()) { types.add(new Pair<>(e.getValue().type(),e.getKey())); } return wyil.lang.Type.Record(false,types); } @Override public int hashCode() { return values.hashCode(); } @Override public boolean equals(Object o) { if(o instanceof Record) { Record i = (Record) o; return values.equals(i.values); } return false; } @Override public int compareTo(Constant v) { if(v instanceof Record) { Record l = (Record) v; if(values.size() < l.values.size()) { return -1; } else if(values.size() > l.values.size()) { return 1; } else { ArrayList<String> vs1 = new ArrayList<String>(values.keySet()); ArrayList<String> vs2 = new ArrayList<String>(l.values.keySet()); Collections.sort(vs1); Collections.sort(vs2); for(int i=0;i!=values.size();++i) { String s1 = vs1.get(i); String s2 = vs2.get(i); int c = s1.compareTo(s2); if(c != 0) { return c; } Constant v1 = values.get(s1); Constant v2 = l.values.get(s1); c = v1.compareTo(v2); if(c != 0) { return c; } } return 0; } } else if (v instanceof Null || v instanceof Bool || v instanceof Byte || v instanceof Integer || v instanceof Set || v instanceof Array) { return 1; } return -1; } @Override public String toString() { String r = "{"; boolean firstTime=true; ArrayList<String> keys = new ArrayList<String>(values.keySet()); Collections.sort(keys); for(String key : keys) { if(!firstTime) { r += ","; } firstTime=false; r += key + ":=" + values.get(key); } return r + "}"; } public HashMap<String,Constant> values() { return values; } } public static final class Type extends Constant { private final wyil.lang.Type value; public Type(wyil.lang.Type type) { this.value = type; } @Override public wyil.lang.Type type() { return wyil.lang.Type.T_META; } @Override public int hashCode() { return value.hashCode(); } @Override public boolean equals(Object o) { if(o instanceof Type) { Type i = (Type) o; return value == i.value; } return false; } @Override public int compareTo(Constant v) { if(v instanceof Type) { Type t = (Type) v; // FIXME: following is an ugly hack! return value.toString().compareTo(t.toString()); } else { return 1; // everything is above a type constant } } @Override public String toString() { return value.toString(); } public wyil.lang.Type value() { return value; } } /** * Represents a named function or method. This is used when taking the * address of a function or method. * * @author David J. Pearce * */ public static final class FunctionOrMethod extends Constant { private final NameID name; private final wyil.lang.Type.FunctionOrMethod type; private final ArrayList<Constant> arguments; public FunctionOrMethod(NameID name, wyil.lang.Type.FunctionOrMethod type, Constant... arguments) { this.name = name; this.type = type; this.arguments = new ArrayList<Constant>(); for(int i=0;i!=arguments.length;++i) { this.arguments.add(arguments[i]); } } public FunctionOrMethod(NameID name, wyil.lang.Type.FunctionOrMethod type, Collection<Constant> arguments) { this.name = name; this.type = type; this.arguments = new ArrayList<Constant>(arguments); } @Override public wyil.lang.Type.FunctionOrMethod type() { return type; } @Override public int hashCode() { if(type != null) { return type.hashCode() + name.hashCode() + arguments.hashCode(); } else { return name.hashCode(); } } @Override public boolean equals(Object o) { if(o instanceof FunctionOrMethod) { FunctionOrMethod i = (FunctionOrMethod) o; return name.equals(i.name) && (type == i.type || (type != null && type .equals(i.type))) && arguments.equals(i.arguments); } return false; } @Override public int compareTo(Constant v) { if(v instanceof FunctionOrMethod) { FunctionOrMethod t = (FunctionOrMethod) v; // FIXME: following is an ugly hack! return type.toString().compareTo(t.toString()); } else { return 1; // everything is above a type constant } } @Override public String toString() { String args = ""; boolean firstTime=true; for(Constant arg : arguments) { if(!firstTime) { args += ","; } firstTime=false; if(arg == null) { args += "_"; } else { args += arg.toString(); } } return "&" + name.toString() + "(" + args + "):" + type.toString(); } public NameID name() { return name; } public ArrayList<Constant> arguments() { return arguments; } } }