Selaa lähdekoodia

Class poue evaluer les expressions lisp

Arthur Brandao 6 vuotta sitten
vanhempi
sitoutus
a411c6e995
1 muutettua tiedostoa jossa 165 lisäystä ja 0 poistoa
  1. 165 0
      src/migl/lisp/LispEval.java

+ 165 - 0
src/migl/lisp/LispEval.java

@@ -0,0 +1,165 @@
+package migl.lisp;
+
+import java.util.Map;
+import java.math.BigInteger;
+import java.util.HashMap;
+
+import migl.util.ConsList;
+import migl.util.ConsListFactory;
+
+@SuppressWarnings("unchecked")
+public class LispEval {
+	
+	/*
+	 * Utilisé LispElement.generate pour tous ce qui est retour ou quand la valeur doit être un element précis
+	 * Sinon utiliser getElement pour pour voir gerer les souslistes et les variables
+	 */
+	
+	private static Map<String, LispOperator> operators = new HashMap<>();
+	
+	public static void setupOperators() {
+		operators.put("not", (lisp) -> {
+			if(lisp.size() != 1) {
+				throw new LispError("Incorrect number of argument");
+			}
+			boolean result = !getElement(lisp.car()).getBool();
+			return LispElement.generate(result);
+		});
+		operators.put("and", (lisp) -> {
+			if(lisp.size() != 2) {
+				throw new LispError("Incorrect number of argument");
+			}
+			boolean result = getElement(lisp.car()).getBool() && getElement(lisp.cdr().car()).getBool();
+			return LispElement.generate(result);
+		});
+		operators.put("or", (lisp) -> {
+			if(lisp.size() != 2) {
+				throw new LispError("Incorrect number of argument");
+			}
+			boolean result = getElement(lisp.car()).getBool() || getElement(lisp.cdr().car()).getBool();
+			return LispElement.generate(result);
+		});
+		operators.put(">", (lisp) -> {
+			if(lisp.size() != 2) {
+				throw new LispError("Incorrect number of argument");
+			}
+			boolean result = getElement(lisp.car()).getNumber() > getElement(lisp.cdr().car()).getNumber();
+			return LispElement.generate(result);
+		});
+		operators.put(">=", (lisp) -> {
+			if(lisp.size() != 2) {
+				throw new LispError("Incorrect number of argument");
+			}
+			boolean result = getElement(lisp.car()).getNumber() >= getElement(lisp.cdr().car()).getNumber();
+			return LispElement.generate(result);
+		});
+		operators.put("<", (lisp) -> {
+			if(lisp.size() != 2) {
+				throw new LispError("Incorrect number of argument");
+			}
+			boolean result = getElement(lisp.car()).getNumber() < getElement(lisp.cdr().car()).getNumber();
+			return LispElement.generate(result);
+		});
+		operators.put("<=", (lisp) -> {
+			if(lisp.size() != 2) {
+				throw new LispError("Incorrect number of argument");
+			}
+			boolean result = getElement(lisp.car()).getNumber() <= getElement(lisp.cdr().car()).getNumber();
+			return LispElement.generate(result);
+		});
+		operators.put("=", (lisp) -> {
+			if(lisp.size() != 2) {
+				throw new LispError("Incorrect number of argument");
+			}
+			boolean result = getElement(lisp.car()).getNumber() == getElement(lisp.cdr().car()).getNumber();
+			return LispElement.generate(result);
+		});
+		operators.put("+", (lisp) -> {
+			boolean isInt = true;
+			double result = 0;
+			while(!lisp.isEmpty()) {
+				LispElement<?> elt = getElement(lisp.car());
+				result += elt.getNumber();
+				isInt = isInt && elt.value.getClass() == BigInteger.class;
+				lisp = lisp.cdr();
+			}
+			if(isInt) {
+				return LispElement.generate((int) result);
+			}
+			return LispElement.generate(result);
+		});
+		operators.put("*", (lisp) -> {
+			boolean isInt = true;
+			double result = 1;
+			while(!lisp.isEmpty()) {
+				LispElement<?> elt = getElement(lisp.car());
+				result *= elt.getNumber();
+				isInt = isInt && elt.value.getClass() == BigInteger.class;
+				lisp = lisp.cdr();
+			}
+			if(isInt) {
+				return LispElement.generate((int) result);
+			}
+			return LispElement.generate(result);
+		});
+		operators.put("-", (lisp) -> {
+			switch(lisp.size()) {				
+				case 1:
+					LispElement<?> elt = getElement(lisp.car());
+					if(elt.value.getClass() == Double.class) {
+						return LispElement.generate(elt.getNumber() * -1);
+					}
+					return LispElement.generate(elt.getInt().multiply(new BigInteger("-1")));
+				case 2:
+					LispElement<?> elt1 = getElement(lisp.car());
+					LispElement<?> elt2 = getElement(lisp.cdr().car());
+					if(elt1.value.getClass() == Double.class || elt2.value.getClass() == Double.class) {
+						return LispElement.generate(elt1.getNumber() - elt2.getNumber());
+					}
+					return LispElement.generate(elt1.getInt().subtract(elt2.getInt()));
+				default:
+					throw new LispError("Incorrect number of argument");
+			}
+		});
+		operators.put("/", (lisp) -> {
+			if(lisp.size() != 2) {
+				throw new LispError("Incorrect number of argument");
+			}
+			LispElement<?> elt1 = getElement(lisp.car());
+			LispElement<?> elt2 = getElement(lisp.cdr().car());
+			if(elt1.value.getClass() == Double.class || elt2.value.getClass() == Double.class) {
+				return LispElement.generate(elt1.getNumber() / elt2.getNumber());
+			}
+			return LispElement.generate(elt1.getInt().divide(elt2.getInt()));
+		});
+	}
+	
+	public static LispElement<?> evaluate(Object elt) throws LispError {
+		if(elt instanceof ConsList) {
+			return evaluate((ConsList<Object>) elt);
+		}
+		return evaluate(ConsListFactory.singleton(elt));
+	}
+
+	public static LispElement<?> evaluate(ConsList<Object> lisp) throws LispError {
+		LispOperator op = operators.get(lisp.car().toString());
+		if(op == null) {
+			throw new LispError(new UnsupportedOperationException("Unknow expression"));
+		}
+		try {
+			return op.apply(lisp.cdr());
+		} catch (IllegalStateException ex) {
+			throw new LispError(ex.getMessage(), ex);
+		}
+	}
+	
+	/* --- Recuperation des elements --- */
+	
+	private static LispElement<?> getElement(Object elt) throws LispError {
+		if(elt instanceof ConsList) {
+			return evaluate((ConsList<Object>) elt);
+		}
+		return LispElement.generate(elt);
+	}
+
+}