فهرست منبع

code pour le TDD3

Daniel Le Berre 6 سال پیش
والد
کامیت
1567312e96
5فایلهای تغییر یافته به همراه251 افزوده شده و 0 حذف شده
  1. 45 0
      src/migl/lisp/Lisp.java
  2. 90 0
      src/migl/lisp/LispBoolean.java
  3. 49 0
      src/migl/lisp/LispError.java
  4. 23 0
      src/migl/lisp/LispFactory.java
  5. 44 0
      src/migl/lisp/REPL.java

+ 45 - 0
src/migl/lisp/Lisp.java

@@ -0,0 +1,45 @@
+package migl.lisp;
+
+/**
+ * A simple abstraction for a lisp interpreter.
+ * 
+ * @author leberre
+ *
+ */
+public interface Lisp {
+
+    /**
+     * Parse a textual lisp expression and cut it into operator and operands for
+     * further evaluation.
+     * 
+     * @param expr
+     * @return a single object or a list of elements
+     * @throws LispError
+     *             if the expression is not a valid Lisp/scheme expression
+     */
+    Object parse(String expr) throws LispError;
+
+    /**
+     * Evaluate the expression returned by the {@link #parse(String)} method.
+     * 
+     * @param ex
+     *            the result of the {@link #parse(String)} method
+     * @return a lisp evaluation of the parameter
+     * @throws LispError
+     *             if the expression cannot be evaluated
+     */
+    Object evaluate(Object ex) throws LispError;
+
+    /**
+     * Evaluate a lisp expression.
+     * 
+     * @param expr
+     *            a lisp expression
+     * @return a
+     * @throws LispError
+     *             if the expression is malformed or cannot be evaluated.
+     */
+    default Object eval(String expr) throws LispError {
+        return evaluate(parse(expr));
+    }
+}

+ 90 - 0
src/migl/lisp/LispBoolean.java

@@ -0,0 +1,90 @@
+package migl.lisp;
+
+/**
+ * Simple Boolean type for our lisp interpreter.
+ * 
+ * We do not use the classical boolean operators in order to have an easy
+ * translation to and from the lisp representation of Booleans.
+ * 
+ * The Boolean operators are not implemented. They must be applied on the
+ * {@link #value()} of the object.
+ * 
+ * @author leberre
+ *
+ */
+public final class LispBoolean {
+
+    /**
+     * The object representing the true Boolean value.
+     */
+    public static final LispBoolean TRUE = new LispBoolean(true);
+
+    /**
+     * The object representing the false Boolean value.
+     */
+    public static final LispBoolean FALSE = new LispBoolean(false);
+
+    private final boolean value;
+
+    private LispBoolean(boolean value) {
+        this.value = value;
+    }
+
+    /**
+     * Retrieve a Java primitive Boolean value for Boolean reasoning in Java code.
+     * 
+     * @return the corresponding Java's Boolean value.
+     */
+    public boolean value() {
+        return this.value;
+    }
+
+    @Override
+    public int hashCode() {
+        return Boolean.hashCode(value);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof LispBoolean) {
+            return ((LispBoolean) obj).value == value;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return value ? "#t" : "#f";
+    }
+
+    /**
+     * Retrieve a {@link LispBoolean} from a Java primitive Boolean.
+     * 
+     * @param b
+     *            a Boolean value
+     * @return the corresponding {@link LispBoolean} object.
+     */
+    public static LispBoolean valueOf(boolean b) {
+        return b ? TRUE : FALSE;
+    }
+
+    /**
+     * Retrieve a {@link LispBoolean} from its textual representation.
+     * 
+     * @param s
+     *            a textual representation of the boolean value (#t or #f)
+     * @return the corresponding {@link LispBoolean} object.
+     * @throws IllegalArgumentException
+     *             if s does not correspond to a valid textual representation.
+     */
+    public static LispBoolean valueOf(String s) {
+        switch (s.toLowerCase()) {
+        case "#t":
+            return TRUE;
+        case "#f":
+            return FALSE;
+        default:
+            throw new IllegalArgumentException("Not a Boolean");
+        }
+    }
+}

+ 49 - 0
src/migl/lisp/LispError.java

@@ -0,0 +1,49 @@
+package migl.lisp;
+
+/**
+ * Generic exception for our lisp interpreter.
+ * 
+ * @author leberre
+ *
+ */
+public class LispError extends Exception {
+
+    /**
+     * Fake serial version UID
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Create a new exception with a message and a cause.
+     * 
+     * @param message
+     *            a detailed message intended to the end user.
+     * @param cause
+     *            the reason of the exception (e.g another exception).
+     */
+    public LispError(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Create a new exception with a message.
+     * 
+     * @param message
+     *            a detailed message intended to the end user.
+     */
+    public LispError(String message) {
+        super(message);
+    }
+
+    /**
+     * Encapsulate a throwable as a LispError.
+     * 
+     * @param cause
+     *            the cause of the issue. The message of the exception will be
+     *            the message of the root cause.
+     */
+    public LispError(Throwable cause) {
+        super(cause);
+    }
+
+}

+ 23 - 0
src/migl/lisp/LispFactory.java

@@ -0,0 +1,23 @@
+package migl.lisp;
+
+/**
+ * Simple factory to access the interpreter implementation.
+ * 
+ * @author leberre
+ *
+ */
+public class LispFactory {
+
+    private LispFactory() {
+        // do nothing
+    }
+
+    /**
+     * Create a new instance of the interpreter.
+     * 
+     * @return a new lisp interpreter.
+     */
+    public static Lisp makeIntepreter() {
+        throw new UnsupportedOperationException();
+    }
+}

+ 44 - 0
src/migl/lisp/REPL.java

@@ -0,0 +1,44 @@
+package migl.lisp;
+
+import java.util.Scanner;
+
+/**
+ * A very basic Read Eval Print Loop for your interpreter.
+ * 
+ * It is made available to let you play with your work and even to try running
+ * real lisp program with it.
+ * 
+ * @author leberre
+ *
+ */
+public class REPL {
+
+    private REPL() {
+        // to prevent instantiation
+    }
+
+    public static void main(String[] args) {
+        // It would be nice to support expression history as in most common shells.
+        // However, it appears that it is not that simple to implement. MR welcome.
+
+        Lisp lisp = LispFactory.makeIntepreter();
+        try (Scanner scanner = new Scanner(System.in, "UTF8")) {
+            System.out.println("My super own Lisp/Scheme interpreter 2018");
+            System.out.println("Enter a valid Lisp expression followed by Enter. type 'quit' to exit.");
+            System.out.print("> ");
+            while (scanner.hasNext()) {
+                String line = scanner.nextLine();
+                if ("quit".equalsIgnoreCase(line)) {
+                    System.out.println("Bye.");
+                    return;
+                }
+                try {
+                    System.out.println(lisp.eval(line));
+                } catch (LispError le) {
+                    System.out.println("Error: " + le.getMessage());
+                }
+                System.out.print("> ");
+            }
+        }
+    }
+}