|
@@ -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);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|