├── gradle.properties
├── .gitignore
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── src
├── main
│ ├── java
│ │ └── org
│ │ │ └── toylisp
│ │ │ ├── IMacro.java
│ │ │ ├── IFunc.java
│ │ │ ├── Macro.java
│ │ │ ├── Symbol.java
│ │ │ ├── Env.java
│ │ │ ├── Func.java
│ │ │ ├── Cons.java
│ │ │ ├── Main.java
│ │ │ ├── Reader.java
│ │ │ └── Runtime.java
│ └── resources
│ │ └── core.lisp
└── test
│ └── java
│ └── org
│ └── toylisp
│ ├── TestUtil.java
│ ├── ConsTests.java
│ ├── RuntimeTests.java
│ └── ReaderTests.java
├── examples
└── map.lisp
├── README.md
├── gradlew.bat
└── gradlew
/gradle.properties:
--------------------------------------------------------------------------------
1 | version=0.1.0-SNAPSHOT
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | .idea
3 | *.iml
4 | build
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jerrypnz/toylisp4j/master/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/src/main/java/org/toylisp/IMacro.java:
--------------------------------------------------------------------------------
1 | package org.toylisp;
2 |
3 | /**
4 | * Marker interface for macros.
5 | * @author jerry created 18/02/15
6 | */
7 | public interface IMacro {}
8 |
--------------------------------------------------------------------------------
/src/main/java/org/toylisp/IFunc.java:
--------------------------------------------------------------------------------
1 | package org.toylisp;
2 |
3 | /**
4 | * @author jerry created 14/11/29
5 | */
6 | public interface IFunc {
7 |
8 | Object invoke(Object... args);
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Nov 30 10:45:12 CST 2014
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-bin.zip
7 |
--------------------------------------------------------------------------------
/examples/map.lisp:
--------------------------------------------------------------------------------
1 | ; Example map function.
2 | (def map
3 | (lambda (f x)
4 | (cond
5 | x (cons (f (car x)) (map f (cdr x)))
6 | t nil)))
7 |
8 | ; Double
9 | (def double (lambda (n) (* n 2)))
10 |
11 | ; For testing comment
12 | (prn "Double: " (map double '(0 1 2 3 4 5 6)))
13 |
--------------------------------------------------------------------------------
/src/main/java/org/toylisp/Macro.java:
--------------------------------------------------------------------------------
1 | package org.toylisp;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Macro is essentially a function with an IMacro marker
7 | *
8 | * @author jerry created 18/02/15
9 | */
10 | public class Macro extends Func implements IMacro {
11 |
12 | public Macro(List argNames, Object body, Env env) {
13 | super(argNames, body, env);
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/test/java/org/toylisp/TestUtil.java:
--------------------------------------------------------------------------------
1 | package org.toylisp;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * TestUtil
7 | *
8 | * @author jerry created 14/11/29
9 | */
10 | public class TestUtil {
11 |
12 | /**
13 | * Short method to easily construct cons cells
14 | */
15 | public static Cons _(Object... args) {
16 | return Cons.fromList(Arrays.asList(args));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/org/toylisp/Symbol.java:
--------------------------------------------------------------------------------
1 | package org.toylisp;
2 |
3 | import java.util.concurrent.ConcurrentHashMap;
4 | import java.util.concurrent.ConcurrentMap;
5 |
6 | /**
7 | * Symbol
8 | *
9 | * @author jerry created 14/11/26
10 | */
11 | public class Symbol {
12 |
13 | private static ConcurrentMap allSymbols = new ConcurrentHashMap<>(128);
14 |
15 | private final String name;
16 |
17 | private Symbol(String name) {this.name = name;}
18 |
19 | public static Symbol intern(String name) {
20 | Symbol sym = allSymbols.get(name);
21 | if (sym == null) {
22 | Symbol newSymbol = new Symbol(name);
23 | if ((sym = allSymbols.putIfAbsent(name, newSymbol)) == null) {
24 | sym = newSymbol;
25 | }
26 | }
27 | return sym;
28 | }
29 |
30 | @Override
31 | public String toString() {
32 | return name;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/resources/core.lisp:
--------------------------------------------------------------------------------
1 | (defmacro defun (name args & body)
2 | `(def ,name (lambda ,args ,@body)))
3 |
4 | (defmacro if (pred then else)
5 | `(cond
6 | (,pred ,then)
7 | (t ,else)))
8 |
9 | (defmacro when (pred & body)
10 | `(cond
11 | (,pred (do ,@body))))
12 |
13 | (defun cadr (lst) (car (cdr lst)))
14 | (defun caar (lst) (car (car lst)))
15 | (defun cddr (lst) (cdr (cdr lst)))
16 |
17 | (defun caddr (lst) (car (cdr (cdr lst))))
18 | (defun caadr (lst) (car (car (cdr lst))))
19 | (defun cadar (lst) (car (cdr (car lst))))
20 |
21 | (defun map (f x)
22 | (cond
23 | (x (cons (f (car x)) (map f (cdr x))))
24 | (t nil)))
25 |
26 | (defmacro let (bindings & body)
27 | `((lambda ,(map car bindings)
28 | ,@body)
29 | ,@(map cadr bindings)))
30 |
31 | (defun -let-helper (bindings body)
32 | (if bindings
33 | `(((lambda (,(caar bindings))
34 | ,@(-let-helper (cdr bindings) body))
35 | ,(cadar bindings)))
36 | body))
37 |
38 | (defmacro let* (bindings & body)
39 | (car (-let-helper bindings body)))
40 |
--------------------------------------------------------------------------------
/src/main/java/org/toylisp/Env.java:
--------------------------------------------------------------------------------
1 | package org.toylisp;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | /**
7 | * Environment
8 | *
9 | * @author jerry created 14/11/26
10 | */
11 | public class Env {
12 |
13 | private final Env parent;
14 | private final Map bindings = new HashMap<>();
15 |
16 | private Env(Env parent) {this.parent = parent;}
17 |
18 | public static Env createRoot() {
19 | return new Env(null);
20 | }
21 |
22 | public Env push() {
23 | return new Env(this);
24 | }
25 |
26 | public Env pop() {
27 | return this.parent;
28 | }
29 |
30 | public Env set(Symbol name, Object val) {
31 | bindings.put(name, val);
32 | return this;
33 | }
34 |
35 | public Object get(Symbol name) {
36 | if (bindings.containsKey(name)) {
37 | return bindings.get(name);
38 | } else if (parent != null) {
39 | return parent.get(name);
40 | }
41 | throw new IllegalStateException("No value bound to symbol " + name);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/org/toylisp/ConsTests.java:
--------------------------------------------------------------------------------
1 | package org.toylisp;
2 |
3 | import java.util.Arrays;
4 | import org.junit.Test;
5 |
6 | import static org.junit.Assert.*;
7 | import static org.toylisp.Runtime.cons;
8 | import static org.toylisp.TestUtil._;
9 |
10 | public class ConsTests {
11 |
12 | @Test
13 | public void testConsToString() {
14 | Cons test = cons(cons("a", cons("b", null)), cons(1, cons(2, cons(3, null))));
15 | assertEquals("((a b) 1 2 3)", test.toString());
16 | }
17 |
18 | @Test
19 | public void testToList() {
20 | Cons cons = _("1", "2", "3", 4, 5, 6);
21 | assertEquals(Arrays.