Permalink
Browse files

Implement values and receive.

Can use (values 1 2 3) and (receive (x y z) (values ...) body...).
Fix #18
  • Loading branch information...
mokehehe
mokehehe committed Jul 12, 2012
1 parent e296bc3 commit 0ccc777827b2cbc5328f5d37e230a37304919d6d
Showing with 81 additions and 0 deletions.
  1. +2 −0 src/lsp/core/Util.java
  2. +32 −0 src/lsp/eval/Compiler.java
  3. +30 −0 src/lsp/eval/Vm.java
  4. +2 −0 src/lsp/eval/VmConst.java
  5. +15 −0 src/lsp/tests/EvalTest.java
View
@@ -20,6 +20,8 @@
public static Symbol unquote = Symbol.intern("unquote");
public static Symbol unquoteSplicing = Symbol.intern("unquote-splicing");
public static Symbol callcc = Symbol.intern("call/cc");
public static Symbol values = Symbol.intern("values");
public static Symbol receive = Symbol.intern("receive");
public static Symbol falseValue = nil;
public static Symbol trueValue = t;
public static Sexp emptyList = nil;
View
@@ -96,6 +96,10 @@ private Sexp compile(Sexp x, Sexp e, Sexp next) throws LspException {
Sexp body = Util.cddr(rest);
return Util.list(DEFMACRO, symbol, createVarsInfo(vars),
compileBodies(body, extend(e, vars), RETURN_LIST), next, debugInfo(vars));
} else if (op.eq(Util.values)) {
return compileValues(rest, e, next);
} else if (op.eq(Util.receive)) {
return compileReceive(rest, e, next);
} else {
return compileApply(op, rest, e, next);
}
@@ -170,6 +174,34 @@ private Sexp compileApply(Sexp op, Sexp params, Sexp e, Sexp next) throws LspExc
}
}
private Sexp compileValues(Sexp params, Sexp e, Sexp next) throws LspException {
boolean tail = isTail(next);
Sexp c;
if (tail) {
// Tail case: directly go to next command.
c = Util.list(VALUES, next);
} else {
// Non-tail case: implicit return.
c = Util.list(VALUES);
}
for (Sexp args = Util.reverse(params); Util.isClass(args, Cell.class); args = Util.cdr(args)) {
c = compile(Util.car(args), e, Util.list(ARGUMENT, c));
}
if (tail) {
return c;
} else {
return Util.list(FRAME, next, c);
}
}
private Sexp compileReceive(Sexp params, Sexp e, Sexp next) throws LspException {
Sexp vars = Util.car(params);
Sexp vals = Util.cadr(params);
Sexp bodies = Util.cddr(params);
return compile(vals, e,
Util.list(RECEIVE, compileBodies(bodies, extend(e, vars), next)));
}
/**
* Expands macro 1 level.
*/
View
@@ -31,6 +31,10 @@ public Env(Env e, ArrayList<Sexp> r) {
this.e = e;
this.r = r;
}
@Override public String toString() {
return this.r + (this.e != null ? " > " + this.e : "");
}
}
/**
@@ -68,6 +72,7 @@ public CallFrame pop() {
public Sexp x;
public Env e;
public ArrayList<Sexp> r;
public ArrayList<Sexp> restValues;
public CallFrame s;
public State(Map<Sexp, Sexp> globalEnvironment, CallStack callStack, Sexp x) {
@@ -78,6 +83,7 @@ public State(Map<Sexp, Sexp> globalEnvironment, CallStack callStack, Sexp x) {
this.e = Env.emptyEnv;
this.r = new ArrayList<Sexp>();
this.s = new CallFrame(null, null, null, null);
this.restValues = null;
}
}
@@ -417,6 +423,30 @@ private static Sexp referGlobal(Map<Sexp, Sexp> globalEnvironment, Sexp symbol)
return true;
}
});
opTable.put(VALUES, new OpAction() {
@Override public boolean run(Sexp rest, State state, Lsp lsp) {
state.restValues = state.r;
state.a = state.restValues.isEmpty() ? Util.nil : state.restValues.get(0);
if (Util.isNull(rest)) {
// Non-tail case: implicit return. We don't call function so trick call stack.
state.callStack.push(null, -1, null);
state.x = RETURN_LIST;
} else {
// Tail case: move to next command.
state.x = Util.car(rest);
}
return true;
}
});
opTable.put(RECEIVE, new OpAction() {
@Override public boolean run(Sexp rest, State state, Lsp lsp) {
state.x = Util.car(rest);
state.e = extend(state.e, state.restValues);
state.r = new ArrayList<Sexp>();
state.callStack.push(null, -1, null);
return true;
}
});
}
/**
@@ -21,6 +21,8 @@
public static final Symbol NUATE = Symbol.intern("nuate");
public static final Symbol DEFINE = Symbol.intern("define");
public static final Symbol DEFMACRO = Symbol.intern("defmacro");
public static final Symbol VALUES = Symbol.intern("values");
public static final Symbol RECEIVE = Symbol.intern("receive");
public static final Symbol POPCALLSTACK = Symbol.intern("popcallstack");
public static final Sexp HALT_LIST = Util.list(HALT);
@@ -155,4 +155,19 @@ public void testDefMacro() throws LspException {
"(nil! abc)\n" +
"abc");
}
public void testValues() throws LspException {
evalTest("nil", "(values)");
evalTest("1", "(values 1 2 3)");
evalTest("1", "(define x (values 1 2 3)) x");
evalTest("(1 2 3)",
"(define (list . rest) rest)\n" +
"(list 1 (values 2 4 6) 3)");
}
public void testReceive() throws LspException {
readEvalAll(reader, new Reader.LspInputStream("(define (list . rest) rest)", null), vm);
evalTest("(1 2 3)",
"(receive (x y z) (values 1 2 3) (list x y z))");
}
}

0 comments on commit 0ccc777

Please sign in to comment.