diff --git a/zero-compiler/pom.xml b/zero-compiler/pom.xml
index a46968b..6fe08f4 100644
--- a/zero-compiler/pom.xml
+++ b/zero-compiler/pom.xml
@@ -19,6 +19,11 @@
guava
11.0.2
+
+ org.functionaljava
+ functionaljava
+ 3.0
+
diff --git a/zero-compiler/src/main/java/zero/compiler/Main.java b/zero-compiler/src/main/java/zero/compiler/Main.java
index 0b21ea2..c9efd2c 100644
--- a/zero-compiler/src/main/java/zero/compiler/Main.java
+++ b/zero-compiler/src/main/java/zero/compiler/Main.java
@@ -5,8 +5,9 @@
import java.io.InputStream;
import java.io.FileInputStream;
-import zero.lang.Version;
+import zero.lang.*;
import zero.compiler.parser.*;
+import zero.interp.ast.*;
public final class Main {
static final Console C = System.console();
@@ -16,6 +17,8 @@ public final class Main {
public static void main(final String[] args) throws Exception {
C.printf(welcome());
+ Scope scope = Pervasives.addAll(Scope.EMPTY);
+
if(args.length > 0) {
for(final String file : args) {
final Expression expr = read(new FileInputStream(file));
diff --git a/zero-compiler/src/main/java/zero/compiler/parser/AExpression.java b/zero-compiler/src/main/java/zero/compiler/parser/AExpression.java
new file mode 100644
index 0000000..4b7a2b3
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/compiler/parser/AExpression.java
@@ -0,0 +1,9 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.compiler.parser;
+
+public abstract class AExpression implements Expression {
+ @Override
+ public String toString() {
+ return toString(new StringBuilder()).toString();
+ }
+}
diff --git a/zero-compiler/src/main/java/zero/compiler/parser/ApplyExpression.java b/zero-compiler/src/main/java/zero/compiler/parser/ApplyExpression.java
new file mode 100644
index 0000000..98a5351
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/compiler/parser/ApplyExpression.java
@@ -0,0 +1,30 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.compiler.parser;
+
+public class ApplyExpression extends AExpression {
+ public final Expression fn;
+ public final Expression[] params;
+
+ public ApplyExpression(final Expression fn, final Expression... params) {
+ this.fn = fn;
+ this.params = params == null ? new Expression[0] : params;
+ }
+
+ @Override
+ public R accept(ExpressionVisitor v, C c) {
+ return v.visit(this, c);
+ }
+
+ @Override
+ public StringBuilder toString(final StringBuilder b) {
+ b.append("((");
+ fn.toString(b);
+ b.append(')');
+ for(final Expression param : params) {
+ b.append(' ');
+ param.toString(b);
+ }
+ b.append(')');
+ return b;
+ }
+}
diff --git a/zero-compiler/src/main/java/zero/compiler/parser/CaseExpression.java b/zero-compiler/src/main/java/zero/compiler/parser/CaseExpression.java
new file mode 100644
index 0000000..82f2427
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/compiler/parser/CaseExpression.java
@@ -0,0 +1,30 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.compiler.parser;
+
+public class CaseExpression extends AExpression {
+ public final PatternExpression bind;
+ public final Expression result;
+
+ public CaseExpression(final PatternExpression bind, final Expression result) {
+ this.bind = bind;
+ this.result = result;
+ }
+
+ @Override
+ public R accept(ExpressionVisitor v, C c) {
+ return v.visit(this, c);
+ }
+
+ @Override
+ public StringBuilder toString(final StringBuilder b) {
+ if(bind.isWildcard()) {
+ b.append("else ");
+ } else {
+ b.append("| ");
+ bind.toString(b);
+ b.append(" -> ");
+ }
+ result.toString(b);
+ return b;
+ }
+}
diff --git a/zero-compiler/src/main/java/zero/compiler/parser/Expression.java b/zero-compiler/src/main/java/zero/compiler/parser/Expression.java
index ebe8671..d6f9f5d 100644
--- a/zero-compiler/src/main/java/zero/compiler/parser/Expression.java
+++ b/zero-compiler/src/main/java/zero/compiler/parser/Expression.java
@@ -5,206 +5,3 @@ public interface Expression {
R accept(ExpressionVisitor v, C c);
StringBuilder toString(StringBuilder b);
}
-
-abstract class AExpression implements Expression {
- @Override
- public String toString() {
- return toString(new StringBuilder()).toString();
- }
-}
-
-class NameExpression extends AExpression {
- final String name;
-
- public NameExpression(final Token token) {
- this.name = token.getText();
- }
-
- @Override
- public R accept(ExpressionVisitor v, C c) {
- return v.visit(this, c);
- }
-
- @Override
- public StringBuilder toString(final StringBuilder b) {
- return b.append(name);
- }
-}
-
-class IntegerExpression extends AExpression {
- final int val;
-
- public IntegerExpression(final Token token) {
- this.val = Integer.parseInt(token.getText());
- }
-
- @Override
- public R accept(ExpressionVisitor v, C c) {
- return v.visit(this, c);
- }
-
- @Override
- public StringBuilder toString(final StringBuilder b) {
- return b.append(val);
- }
-}
-
-class ValDeclExpression extends AExpression {
- private final NameExpression name;
- private final Expression val;
-
- public ValDeclExpression(final NameExpression name, final Expression val) {
- this.name = name;
- this.val = val;
- }
-
- @Override
- public R accept(ExpressionVisitor v, C c) {
- return v.visit(this, c);
- }
-
- @Override
- public StringBuilder toString(final StringBuilder b) {
- b.append("val ");
- name.toString(b);
- b.append(" = ");
- val.toString(b);
- return b;
- }
-}
-
-class FnExpression extends AExpression {
- private final NameExpression[] params;
- private final Expression body;
-
- public FnExpression(final Expression body, final NameExpression... params) {
- this.params = params == null ? new NameExpression[0] : params;
- this.body = body;
- }
-
- @Override
- public R accept(ExpressionVisitor v, C c) {
- return v.visit(this, c);
- }
-
- @Override
- public StringBuilder toString(final StringBuilder b) {
- b.append("fn ");
- for(final NameExpression name : params) {
- name.toString(b).append(' ');
- }
- b.append("-> ");
- body.toString(b);
- return b;
- }
-}
-
-class ApplyExpression extends AExpression {
- private final Expression fn;
- private final Expression[] params;
-
- public ApplyExpression(final Expression fn, final Expression... params) {
- this.fn = fn;
- this.params = params == null ? new Expression[0] : params;
- }
-
- @Override
- public R accept(ExpressionVisitor v, C c) {
- return v.visit(this, c);
- }
-
- @Override
- public StringBuilder toString(final StringBuilder b) {
- b.append("((");
- fn.toString(b);
- b.append(')');
- for(final Expression param : params) {
- b.append(' ');
- param.toString(b);
- }
- b.append(')');
- return b;
- }
-}
-
-class MatchExpression extends AExpression {
- private final Expression val;
- private final CaseExpression[] cases;
-
- public MatchExpression(final Expression val, final CaseExpression... cases) {
- this.val = val;
- this.cases = cases == null ? new CaseExpression[0] : cases;
- }
-
- @Override
- public R accept(ExpressionVisitor v, C c) {
- return v.visit(this, c);
- }
-
- @Override
- public StringBuilder toString(final StringBuilder b) {
- b.append("match ");
- val.toString(b);
- b.append(" with ");
- for(final CaseExpression c : cases) {
- c.toString(b);
- b.append(' ');
- }
- b.append("end");
- return b;
- }
-}
-
-class CaseExpression extends AExpression {
- private final PatternExpression bind;
- private final Expression result;
-
- public CaseExpression(final PatternExpression bind, final Expression result) {
- this.bind = bind;
- this.result = result;
- }
-
- @Override
- public R accept(ExpressionVisitor v, C c) {
- return v.visit(this, c);
- }
-
- @Override
- public StringBuilder toString(final StringBuilder b) {
- if(bind.isWildcard()) {
- b.append("else ");
- } else {
- b.append("| ");
- bind.toString(b);
- b.append(" -> ");
- }
- result.toString(b);
- return b;
- }
-}
-
-class PatternExpression extends AExpression {
- public static final PatternExpression WILDCARD = new PatternExpression(new NameExpression(new Token(Token.Type.NAME, "_")));
-
- private final Expression pattern;
-
- public PatternExpression(final Expression pattern) {
- this.pattern = pattern;
- }
-
- @Override
- public R accept(ExpressionVisitor v, C c) {
- return v.visit(this, c);
- }
-
- @Override
- public StringBuilder toString(final StringBuilder b) {
- pattern.toString(b);
- return b;
- }
-
- public boolean isWildcard() {
- return pattern.getClass() == NameExpression.class
- && ((NameExpression) pattern).name.equals("_");
- }
-}
diff --git a/zero-compiler/src/main/java/zero/compiler/parser/FnExpression.java b/zero-compiler/src/main/java/zero/compiler/parser/FnExpression.java
new file mode 100644
index 0000000..3f6a348
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/compiler/parser/FnExpression.java
@@ -0,0 +1,28 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.compiler.parser;
+
+public class FnExpression extends AExpression {
+ public final NameExpression[] params;
+ public final Expression body;
+
+ public FnExpression(final Expression body, final NameExpression... params) {
+ this.params = params == null ? new NameExpression[0] : params;
+ this.body = body;
+ }
+
+ @Override
+ public R accept(ExpressionVisitor v, C c) {
+ return v.visit(this, c);
+ }
+
+ @Override
+ public StringBuilder toString(final StringBuilder b) {
+ b.append("fn ");
+ for(final NameExpression name : params) {
+ name.toString(b).append(' ');
+ }
+ b.append("-> ");
+ body.toString(b);
+ return b;
+ }
+}
diff --git a/zero-compiler/src/main/java/zero/compiler/parser/IntegerExpression.java b/zero-compiler/src/main/java/zero/compiler/parser/IntegerExpression.java
new file mode 100644
index 0000000..cd78a53
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/compiler/parser/IntegerExpression.java
@@ -0,0 +1,20 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.compiler.parser;
+
+public class IntegerExpression extends AExpression {
+ public final int val;
+
+ public IntegerExpression(final Token token) {
+ this.val = Integer.parseInt(token.getText());
+ }
+
+ @Override
+ public R accept(ExpressionVisitor v, C c) {
+ return v.visit(this, c);
+ }
+
+ @Override
+ public StringBuilder toString(final StringBuilder b) {
+ return b.append(val);
+ }
+}
diff --git a/zero-compiler/src/main/java/zero/compiler/parser/MatchExpression.java b/zero-compiler/src/main/java/zero/compiler/parser/MatchExpression.java
new file mode 100644
index 0000000..2438251
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/compiler/parser/MatchExpression.java
@@ -0,0 +1,30 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.compiler.parser;
+
+public class MatchExpression extends AExpression {
+ public final Expression val;
+ public final CaseExpression[] cases;
+
+ public MatchExpression(final Expression val, final CaseExpression... cases) {
+ this.val = val;
+ this.cases = cases == null ? new CaseExpression[0] : cases;
+ }
+
+ @Override
+ public R accept(ExpressionVisitor v, C c) {
+ return v.visit(this, c);
+ }
+
+ @Override
+ public StringBuilder toString(final StringBuilder b) {
+ b.append("match ");
+ val.toString(b);
+ b.append(" with ");
+ for(final CaseExpression c : cases) {
+ c.toString(b);
+ b.append(' ');
+ }
+ b.append("end");
+ return b;
+ }
+}
diff --git a/zero-compiler/src/main/java/zero/compiler/parser/NameExpression.java b/zero-compiler/src/main/java/zero/compiler/parser/NameExpression.java
new file mode 100644
index 0000000..f9b5f23
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/compiler/parser/NameExpression.java
@@ -0,0 +1,20 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.compiler.parser;
+
+public class NameExpression extends AExpression {
+ public final String name;
+
+ public NameExpression(final Token token) {
+ this.name = token.getText();
+ }
+
+ @Override
+ public R accept(ExpressionVisitor v, C c) {
+ return v.visit(this, c);
+ }
+
+ @Override
+ public StringBuilder toString(final StringBuilder b) {
+ return b.append(name);
+ }
+}
diff --git a/zero-compiler/src/main/java/zero/compiler/parser/PatternExpression.java b/zero-compiler/src/main/java/zero/compiler/parser/PatternExpression.java
new file mode 100644
index 0000000..038b89a
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/compiler/parser/PatternExpression.java
@@ -0,0 +1,28 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.compiler.parser;
+
+public class PatternExpression extends AExpression {
+ public static final PatternExpression WILDCARD = new PatternExpression(new NameExpression(new Token(Token.Type.NAME, "_")));
+
+ public final Expression pattern;
+
+ public PatternExpression(final Expression pattern) {
+ this.pattern = pattern;
+ }
+
+ @Override
+ public R accept(ExpressionVisitor v, C c) {
+ return v.visit(this, c);
+ }
+
+ @Override
+ public StringBuilder toString(final StringBuilder b) {
+ pattern.toString(b);
+ return b;
+ }
+
+ public boolean isWildcard() {
+ return pattern.getClass() == NameExpression.class
+ && ((NameExpression) pattern).name.equals("_");
+ }
+}
diff --git a/zero-compiler/src/main/java/zero/compiler/parser/ValDeclExpression.java b/zero-compiler/src/main/java/zero/compiler/parser/ValDeclExpression.java
new file mode 100644
index 0000000..2455b2d
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/compiler/parser/ValDeclExpression.java
@@ -0,0 +1,26 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.compiler.parser;
+
+public class ValDeclExpression extends AExpression {
+ public final NameExpression name;
+ public final Expression val;
+
+ public ValDeclExpression(final NameExpression name, final Expression val) {
+ this.name = name;
+ this.val = val;
+ }
+
+ @Override
+ public R accept(ExpressionVisitor v, C c) {
+ return v.visit(this, c);
+ }
+
+ @Override
+ public StringBuilder toString(final StringBuilder b) {
+ b.append("val ");
+ name.toString(b);
+ b.append(" = ");
+ val.toString(b);
+ return b;
+ }
+}
diff --git a/zero-compiler/src/main/java/zero/interp/ast/Interpreter.java b/zero-compiler/src/main/java/zero/interp/ast/Interpreter.java
index d4c37e3..b34a2d4 100644
--- a/zero-compiler/src/main/java/zero/interp/ast/Interpreter.java
+++ b/zero-compiler/src/main/java/zero/interp/ast/Interpreter.java
@@ -1,24 +1,60 @@
/* Copyright (C) 2012 Matt O'Connor */
package zero.interp.ast;
+import zero.lang.*;
import zero.compiler.parser.*;
import java.util.Map;
public class Interpreter {
- // with pervasives
- // without
-
- Result eval(Expression e, Scope in) {
+ public Result eval(final Expression e, final Scope in) {
return null;
}
}
-class Scope {
- Map defs;
-}
+class AstWalk implements ExpressionVisitor {
+ @Override
+ public Result visit(NameExpression expr, Scope scope) {
+ return new Result(scope.get(expr.name), scope);
+ }
+
+ @Override
+ public Result visit(IntegerExpression expr, Scope scope) {
+ return new Result(new Val(expr.val), scope);
+ }
+
+ @Override
+ public Result visit(ValDeclExpression expr, Scope scope) {
+ scope = scope.add(expr.name, new Val(expr.val));
+ return new Result(scope);
+ }
+
+ @Override
+ public Result visit(FnExpression expr, Scope scope) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Result visit(ApplyExpression expr, Scope scope) {
-class Result {
- Expression val;
- Scope updated;
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Result visit(MatchExpression expr, Scope scope) {
+
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Result visit(CaseExpression expr, Scope scope) {
+
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Result visit(PatternExpression expr, Scope scope) {
+
+ throw new UnsupportedOperationException();
+ }
}
\ No newline at end of file
diff --git a/zero-compiler/src/main/java/zero/interp/ast/Result.java b/zero-compiler/src/main/java/zero/interp/ast/Result.java
new file mode 100644
index 0000000..f1c7850
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/interp/ast/Result.java
@@ -0,0 +1,25 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.interp.ast;
+
+import zero.lang.*;
+import zero.compiler.parser.*;
+
+import java.util.Map;
+
+public class Result {
+ public final Val val;
+ public final Scope newScope;
+
+ public Result(final Val val) {
+ this(val, null);
+ }
+
+ public Result(final Scope newScope) {
+ this(null, newScope);
+ }
+
+ public Result(final Val val, final Scope newScope) {
+ this.val = val;
+ this.newScope = newScope;
+ }
+}
diff --git a/zero-compiler/src/main/java/zero/interp/ast/Scope.java b/zero-compiler/src/main/java/zero/interp/ast/Scope.java
new file mode 100644
index 0000000..e09900a
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/interp/ast/Scope.java
@@ -0,0 +1,26 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.interp.ast;
+
+import zero.lang.*;
+import zero.compiler.parser.*;
+import zero.util.*;
+
+import java.util.Map;
+
+public class Scope {
+ public static final Scope EMPTY = new Scope(Nil.get());
+
+ private final Associative defs;
+
+ private Scope(final Associative defs) {
+ this.defs = defs;
+ }
+
+ public Scope add(final String name, final Val val) {
+ return new Scope(defs.add(name, val));
+ }
+
+ public Val get(final String name) {
+ return defs.get(name);
+ }
+}
diff --git a/zero-compiler/src/main/java/zero/lang/Fn0.java b/zero-compiler/src/main/java/zero/lang/Fn0.java
new file mode 100644
index 0000000..60bb2d1
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/lang/Fn0.java
@@ -0,0 +1,6 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.lang;
+
+public interface Fn0 {
+ R apply();
+}
diff --git a/zero-compiler/src/main/java/zero/lang/Fn1.java b/zero-compiler/src/main/java/zero/lang/Fn1.java
new file mode 100644
index 0000000..2d7b658
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/lang/Fn1.java
@@ -0,0 +1,6 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.lang;
+
+public interface Fn1 {
+ R apply(A a);
+}
diff --git a/zero-compiler/src/main/java/zero/lang/Fn2.java b/zero-compiler/src/main/java/zero/lang/Fn2.java
new file mode 100644
index 0000000..2520107
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/lang/Fn2.java
@@ -0,0 +1,6 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.lang;
+
+public interface Fn2 {
+ R apply(A a, B b);
+}
diff --git a/zero-compiler/src/main/java/zero/lang/Pervasives.java b/zero-compiler/src/main/java/zero/lang/Pervasives.java
index dbdfde3..8f5750c 100644
--- a/zero-compiler/src/main/java/zero/lang/Pervasives.java
+++ b/zero-compiler/src/main/java/zero/lang/Pervasives.java
@@ -1,7 +1,31 @@
/* Copyright (C) 2012 Matt O'Connor */
package zero.lang;
+import zero.interp.ast.Scope;
+
public final class Pervasives {
- // + - *
+ public static final Val plus = new Val(new Fn2() {
+ @Override
+ public Integer apply(final Integer a, final Integer b) {
+ return a + b;
+ }
+ });
+ public static final Val minus = new Val(new Fn2() {
+ @Override
+ public Integer apply(final Integer a, final Integer b) {
+ return a - b;
+ }
+ });
+ public static final Val times = new Val(new Fn2() {
+ @Override
+ public Integer apply(final Integer a, final Integer b) {
+ return a * b;
+ }
+ });
+
+ public static Scope addAll(final Scope scope) {
+ return scope.add("+", plus).add("-", minus).add("*", times);
+ }
+
private Pervasives() {}
-}
\ No newline at end of file
+}
diff --git a/zero-compiler/src/main/java/zero/lang/Val.java b/zero-compiler/src/main/java/zero/lang/Val.java
new file mode 100644
index 0000000..21eb84c
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/lang/Val.java
@@ -0,0 +1,24 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.lang;
+
+import zero.compiler.parser.Expression;
+
+public class Val {
+ final Object val;
+
+ public Val(final Object val) {
+ this.val = val;
+ }
+
+ public Fn2 asFn2() {
+ return (Fn2) val;
+ }
+
+ public Integer asInteger() {
+ return (Integer) val;
+ }
+
+ public Expression asExpression() {
+ return (Expression) val;
+ }
+}
diff --git a/zero-compiler/src/main/java/zero/util/Associative.java b/zero-compiler/src/main/java/zero/util/Associative.java
new file mode 100644
index 0000000..9ac27d4
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/util/Associative.java
@@ -0,0 +1,7 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.util;
+
+public interface Associative {
+ Associative add(K k, V v);
+ V get(K k);
+}
diff --git a/zero-compiler/src/main/java/zero/util/AssociativeList.java b/zero-compiler/src/main/java/zero/util/AssociativeList.java
new file mode 100644
index 0000000..0c1ae22
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/util/AssociativeList.java
@@ -0,0 +1,26 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.util;
+
+public class AssociativeList implements Associative {
+ private final K k;
+ private final V v;
+ private final Associative tl;
+
+ public AssociativeList(final K k, final V v, final Associative tl) {
+ this.k = k;
+ this.v = v;
+ this.tl = tl;
+ }
+
+ public Associative add(K k, V v) {
+ return new AssociativeList<>(k, v, this);
+ }
+
+ public V get(K k) {
+ if(k.equals(this.k)) {
+ return v;
+ } else {
+ return tl.get(k);
+ }
+ }
+}
diff --git a/zero-compiler/src/main/java/zero/util/Nil.java b/zero-compiler/src/main/java/zero/util/Nil.java
new file mode 100644
index 0000000..2c43c72
--- /dev/null
+++ b/zero-compiler/src/main/java/zero/util/Nil.java
@@ -0,0 +1,19 @@
+/* Copyright (C) 2012 Matt O'Connor */
+package zero.util;
+
+public class Nil implements Associative {
+ private static final Associative, ?> NIL = new Nil<>();
+ private Nil() {}
+
+ public static Associative get() {
+ return (Associative) NIL;
+ }
+
+ public Associative add(K k, V v) {
+ return new AssociativeList<>(k, v, this);
+ }
+
+ public V get(K k) {
+ return null;
+ }
+}