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