package migl.lisp; import java.math.BigInteger; import java.util.Map; import migl.util.Cons; import java.util.HashMap; /** * Class pour gérer les élément des expressions Lisp * * @author Arthur Brandao */ public class LispElement { /** * Garde en cache les elements deja créer pour eviter de recreer plusieurs fois les meme elements */ private static Map cache = new HashMap<>(); /** * La valeur de l'element */ private final Object value; /** * Constructeur privée pour construire un element à partir de valueOf * * @param val */ private LispElement(Object val) { this.value = val; cache.put(val, this); } /** * Retourne la valeur de l'element lisp * @return */ public Object getValue() { return this.value; } /** * Retourne la valeur d'un element sous forme d'entier * * @throws IllegalStateException Si l'element ne peut pas être converti en BigInteger * @return */ public BigInteger toInt() { if(this.isInt()) { return (BigInteger) this.value; } throw new IllegalStateException("Not an integer"); } /** * Retourne la valeur d'un element sous forme de nombre * * @throws IllegalStateException Si l'element ne peut pas être converti en Double * @return */ public double toNumber() { if(this.value.getClass() == BigInteger.class) { BigInteger bi = (BigInteger) this.value; return bi.doubleValue(); } else if(this.value.getClass() == Double.class) { return (Double) this.value; } throw new IllegalStateException("Not a number"); } /** * Retourne la valeur d'un element sous forme de boolean * * @throws IllegalStateException Si l'element ne peut pas être converti en boolean * @return */ public boolean toBoolean() { if(this.isBoolean()) { LispBoolean lb = (LispBoolean) this.value; return lb.value(); } throw new IllegalStateException("Not a Boolean"); } /** * Retourne la valeur d'un element sous forme de string * * @throws IllegalStateException Si l'element ne peut pas être converti en String * @return */ public String toStr() { if(this.isStr()) { return (String) this.value; } throw new IllegalStateException("Not a String"); } /** * Retourne la valeur d'un element sous forme d'une liste * * @throws IllegalStateException * @return */ public LispList toList() { if(this.isList()) { return (LispList) this.value; } throw new IllegalStateException("Not a List"); } /** * Retourne la valeur d'un element sous forme d'une cons * * @throws IllegalStateException * @return */ public Cons toCons() { if(this.isCons()) { return (Cons) this.value; } throw new IllegalStateException("Not a Cons"); } /** * Indique si l'element est un entier * @return */ public boolean isInt() { return this.value.getClass() == BigInteger.class; } /** * Indique si l'element est nombre (BigInteger ou Double) * @return */ public boolean isNumber() { return this.isInt() || (this.value.getClass() == Double.class); } /** * Indique si l'element est boolean * @return */ public boolean isBoolean() { return this.value.getClass() == LispBoolean.class; } /** * Indique si l'element est un String * @return */ public boolean isStr() { return this.value.getClass() == String.class; } /** * Indique si l'element est une liste * @return */ public boolean isList() { return this.value.getClass() == LispList.class; } /** * Indique si l'element est une Cons * @return */ public boolean isCons() { return this.value.getClass() == Cons.class; } @Override public int hashCode() { return this.value.hashCode(); } @Override public boolean equals(Object obj) { if(obj == null) { return false; } else if(this == obj) { return true; } else if(obj instanceof LispElement) { LispElement other = (LispElement) obj; return this.value.equals(other.value); } return false; } @Override public String toString() { return this.value.toString(); } /** * Indique le nombre actuel d'element en cache * @return */ public static int getCacheSize() { return cache.size(); } /** * Supprime le cache */ public static void clear() { cache.clear(); } /** * Parse un element * * @param elt L'element à parser * @return Un LispElement contenant la valeur extraite */ public static LispElement valueOf(String elt) { try { return generate(new BigInteger(elt)); } catch(NumberFormatException ex) { //Rien } try { return generate(Double.valueOf(elt)); } catch(NumberFormatException ex) { //Rien } try { return generate(LispBoolean.valueOf(elt)); } catch(IllegalArgumentException ex) { //Rien } return generate(elt); } /** * Genere un LispElement correspondant à l'objet * * @param elt * @return */ public static LispElement generate(Object elt) { if(elt == null) { return new LispElement(null); } else if(elt.getClass() == LispElement.class) { return (LispElement) elt; } else if(elt.getClass() == Integer.class) { elt = BigInteger.valueOf((Integer) elt); } else if(elt.getClass() == Boolean.class) { elt = LispBoolean.valueOf((boolean) elt); } else if(elt.getClass() == Long.class) { elt = BigInteger.valueOf((long) elt); } else if( elt.getClass() != BigInteger.class && elt.getClass() != Double.class && elt.getClass() != LispBoolean.class && elt.getClass() != String.class && elt.getClass() != LispList.class && elt.getClass() != Cons.class ) { throw new IllegalArgumentException("Object class is not a Lisp element"); } if(cache.containsKey(elt)) { return cache.get(elt); } return new LispElement(elt); } }