From 92474a1bef0daaa37187f6e9871bfe9ce63b4779 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Sat, 10 May 2014 15:46:15 -0500 Subject: Java, Make: return nil from core readline function on EOF. --- java/src/main/java/mal/core.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'java/src') diff --git a/java/src/main/java/mal/core.java b/java/src/main/java/mal/core.java index 0f1d226..7af2f72 100644 --- a/java/src/main/java/mal/core.java +++ b/java/src/main/java/mal/core.java @@ -98,7 +98,7 @@ public class core { } catch (IOException e) { throw new MalException(new MalString(e.getMessage())); } catch (readline.EOFException e) { - throw new MalException(new MalString(e.getMessage())); + return Nil; } } }; -- cgit v1.2.3 From 01c9731649a7ed97fad0bdeac9cb75b7323c0ad6 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Thu, 9 Oct 2014 23:48:47 -0500 Subject: All: swap step9,A. Fixes for bash, C, perl. step9_interop -> stepA_interop stepA_more -> step9_try C: fix glib headers bash: behavior change of declare -A and pattern replacement. perl: squelch new 5.18 warnings related to switch/given statement. Also, include some in-progress interop related files. --- java/src/main/java/mal/step9_try.java | 302 ++++++++++++++++++++++++++++++ java/src/main/java/mal/stepA_interop.java | 302 ++++++++++++++++++++++++++++++ java/src/main/java/mal/stepA_more.java | 302 ------------------------------ 3 files changed, 604 insertions(+), 302 deletions(-) create mode 100644 java/src/main/java/mal/step9_try.java create mode 100644 java/src/main/java/mal/stepA_interop.java delete mode 100644 java/src/main/java/mal/stepA_more.java (limited to 'java/src') diff --git a/java/src/main/java/mal/step9_try.java b/java/src/main/java/mal/step9_try.java new file mode 100644 index 0000000..c3b0e9f --- /dev/null +++ b/java/src/main/java/mal/step9_try.java @@ -0,0 +1,302 @@ +package mal; + +import java.io.IOException; + +import java.io.StringWriter; +import java.io.PrintWriter; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Iterator; +import mal.types.*; +import mal.readline; +import mal.reader; +import mal.printer; +import mal.env.Env; +import mal.core; + +public class step9_try { + // read + public static MalVal READ(String str) throws MalThrowable { + return reader.read_str(str); + } + + // eval + public static Boolean is_pair(MalVal x) { + return x instanceof MalList && ((MalList)x).size() > 0; + } + + public static MalVal quasiquote(MalVal ast) { + if (!is_pair(ast)) { + return new MalList(new MalSymbol("quote"), ast); + } else { + MalVal a0 = ((MalList)ast).nth(0); + if ((a0 instanceof MalSymbol) && + (((MalSymbol)a0).getName() == "unquote")) { + return ((MalList)ast).nth(1); + } else if (is_pair(a0)) { + MalVal a00 = ((MalList)a0).nth(0); + if ((a00 instanceof MalSymbol) && + (((MalSymbol)a00).getName() == "splice-unquote")) { + return new MalList(new MalSymbol("concat"), + ((MalList)a0).nth(1), + quasiquote(((MalList)ast).rest())); + } + } + return new MalList(new MalSymbol("cons"), + quasiquote(a0), + quasiquote(((MalList)ast).rest())); + } + } + + public static Boolean is_macro_call(MalVal ast, Env env) + throws MalThrowable { + if (ast instanceof MalList) { + MalVal a0 = ((MalList)ast).nth(0); + if (a0 instanceof MalSymbol && + env.find(((MalSymbol)a0).getName()) != null) { + MalVal mac = env.get(((MalSymbol)a0).getName()); + if (mac instanceof MalFunction && + ((MalFunction)mac).isMacro()) { + return true; + } + } + } + return false; + } + + public static MalVal macroexpand(MalVal ast, Env env) + throws MalThrowable { + while (is_macro_call(ast, env)) { + MalSymbol a0 = (MalSymbol)((MalList)ast).nth(0); + MalFunction mac = (MalFunction) env.get(a0.getName()); + ast = mac.apply(((MalList)ast).rest()); + } + return ast; + } + + public static MalVal eval_ast(MalVal ast, Env env) throws MalThrowable { + if (ast instanceof MalSymbol) { + MalSymbol sym = (MalSymbol)ast; + return env.get(sym.getName()); + } else if (ast instanceof MalList) { + MalList old_lst = (MalList)ast; + MalList new_lst = ast.list_Q() ? new MalList() + : (MalList)new MalVector(); + for (MalVal mv : (List)old_lst.value) { + new_lst.conj_BANG(EVAL(mv, env)); + } + return new_lst; + } else if (ast instanceof MalHashMap) { + MalHashMap new_hm = new MalHashMap(); + Iterator it = ((MalHashMap)ast).value.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = (Map.Entry)it.next(); + new_hm.value.put(entry.getKey(), EVAL((MalVal)entry.getValue(), env)); + } + return new_hm; + } else { + return ast; + } + } + + public static MalVal EVAL(MalVal orig_ast, Env env) throws MalThrowable { + MalVal a0, a1,a2, a3, res; + MalList el; + + while (true) { + + //System.out.println("EVAL: " + printer._pr_str(orig_ast, true)); + if (!orig_ast.list_Q()) { + return eval_ast(orig_ast, env); + } + + // apply list + MalVal expanded = macroexpand(orig_ast, env); + if (!expanded.list_Q()) { return expanded; } + MalList ast = (MalList) expanded; + if (ast.size() == 0) { return ast; } + a0 = ast.nth(0); + String a0sym = a0 instanceof MalSymbol ? ((MalSymbol)a0).getName() + : "__<*fn*>__"; + switch (a0sym) { + case "def!": + a1 = ast.nth(1); + a2 = ast.nth(2); + res = EVAL(a2, env); + env.set(((MalSymbol)a1).getName(), res); + return res; + case "let*": + a1 = ast.nth(1); + a2 = ast.nth(2); + MalSymbol key; + MalVal val; + Env let_env = new Env(env); + for(int i=0; i<((MalList)a1).size(); i+=2) { + key = (MalSymbol)((MalList)a1).nth(i); + val = ((MalList)a1).nth(i+1); + let_env.set(key.getName(), EVAL(val, let_env)); + } + orig_ast = a2; + env = let_env; + break; + case "quote": + return ast.nth(1); + case "quasiquote": + orig_ast = quasiquote(ast.nth(1)); + break; + case "defmacro!": + a1 = ast.nth(1); + a2 = ast.nth(2); + res = EVAL(a2, env); + ((MalFunction)res).setMacro(); + env.set(((MalSymbol)a1).getName(), res); + return res; + case "macroexpand": + a1 = ast.nth(1); + return macroexpand(a1, env); + case "try*": + try { + return EVAL(ast.nth(1), env); + } catch (Throwable t) { + if (ast.size() > 2) { + MalVal exc; + a2 = ast.nth(2); + MalVal a20 = ((MalList)a2).nth(0); + if (((MalSymbol)a20).getName().equals("catch*")) { + if (t instanceof MalException) { + exc = ((MalException)t).getValue(); + } else { + StringWriter sw = new StringWriter(); + t.printStackTrace(new PrintWriter(sw)); + String tstr = sw.toString(); + exc = new MalString(t.getMessage() + ": " + tstr); + } + return EVAL(((MalList)a2).nth(2), + new Env(env, ((MalList)a2).slice(1,2), + new MalList(exc))); + } + } + throw t; + } + case "do": + eval_ast(ast.slice(1, ast.size()-1), env); + orig_ast = ast.nth(ast.size()-1); + break; + case "if": + a1 = ast.nth(1); + MalVal cond = EVAL(a1, env); + if (cond == types.Nil || cond == types.False) { + // eval false slot form + if (ast.size() > 3) { + orig_ast = ast.nth(3); + } else { + return types.Nil; + } + } else { + // eval true slot form + orig_ast = ast.nth(2); + } + break; + case "fn*": + final MalList a1f = (MalList)ast.nth(1); + final MalVal a2f = ast.nth(2); + final Env cur_env = env; + return new MalFunction (a2f, (mal.env.Env)env, a1f) { + public MalVal apply(MalList args) throws MalThrowable { + return EVAL(a2f, new Env(cur_env, a1f, args)); + } + }; + default: + el = (MalList)eval_ast(ast, env); + MalFunction f = (MalFunction)el.nth(0); + MalVal fnast = f.getAst(); + if (fnast != null) { + orig_ast = fnast; + env = f.genEnv(el.slice(1)); + } else { + return f.apply(el.rest()); + } + } + + } + } + + // print + public static String PRINT(MalVal exp) { + return printer._pr_str(exp, true); + } + + // repl + public static MalVal RE(Env env, String str) throws MalThrowable { + return EVAL(READ(str), env); + } + + public static void main(String[] args) throws MalThrowable { + String prompt = "user> "; + + final Env repl_env = new Env(null); + + // core.java: defined using Java + for (String key : core.ns.keySet()) { + repl_env.set(key, core.ns.get(key)); + } + repl_env.set("eval", new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + return EVAL(args.nth(0), repl_env); + } + }); + MalList _argv = new MalList(); + for (Integer i=1; i < args.length; i++) { + _argv.conj_BANG(new MalString(args[i])); + } + repl_env.set("*ARGV*", _argv); + + + // core.mal: defined using the language itself + RE(repl_env, "(def! *host-language* \"java\")"); + RE(repl_env, "(def! not (fn* (a) (if a false true)))"); + RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"); + RE(repl_env, "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))"); + RE(repl_env, "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))"); + + Integer fileIdx = 0; + if (args.length > 0 && args[0].equals("--raw")) { + readline.mode = readline.Mode.JAVA; + fileIdx = 1; + } + if (args.length > fileIdx) { + RE(repl_env, "(load-file \"" + args[fileIdx] + "\")"); + return; + } + + // repl loop + RE(repl_env, "(println (str \"Mal [\" *host-language* \"]\"))"); + while (true) { + String line; + try { + line = readline.readline(prompt); + if (line == null) { continue; } + } catch (readline.EOFException e) { + break; + } catch (IOException e) { + System.out.println("IOException: " + e.getMessage()); + break; + } + try { + System.out.println(PRINT(RE(repl_env, line))); + } catch (MalContinue e) { + continue; + } catch (MalException e) { + System.out.println("Error: " + printer._pr_str(e.getValue(), false)); + continue; + } catch (MalThrowable t) { + System.out.println("Error: " + t.getMessage()); + continue; + } catch (Throwable t) { + System.out.println("Uncaught " + t + ": " + t.getMessage()); + continue; + } + } + } +} diff --git a/java/src/main/java/mal/stepA_interop.java b/java/src/main/java/mal/stepA_interop.java new file mode 100644 index 0000000..75c0402 --- /dev/null +++ b/java/src/main/java/mal/stepA_interop.java @@ -0,0 +1,302 @@ +package mal; + +import java.io.IOException; + +import java.io.StringWriter; +import java.io.PrintWriter; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Iterator; +import mal.types.*; +import mal.readline; +import mal.reader; +import mal.printer; +import mal.env.Env; +import mal.core; + +public class stepA_interop { + // read + public static MalVal READ(String str) throws MalThrowable { + return reader.read_str(str); + } + + // eval + public static Boolean is_pair(MalVal x) { + return x instanceof MalList && ((MalList)x).size() > 0; + } + + public static MalVal quasiquote(MalVal ast) { + if (!is_pair(ast)) { + return new MalList(new MalSymbol("quote"), ast); + } else { + MalVal a0 = ((MalList)ast).nth(0); + if ((a0 instanceof MalSymbol) && + (((MalSymbol)a0).getName() == "unquote")) { + return ((MalList)ast).nth(1); + } else if (is_pair(a0)) { + MalVal a00 = ((MalList)a0).nth(0); + if ((a00 instanceof MalSymbol) && + (((MalSymbol)a00).getName() == "splice-unquote")) { + return new MalList(new MalSymbol("concat"), + ((MalList)a0).nth(1), + quasiquote(((MalList)ast).rest())); + } + } + return new MalList(new MalSymbol("cons"), + quasiquote(a0), + quasiquote(((MalList)ast).rest())); + } + } + + public static Boolean is_macro_call(MalVal ast, Env env) + throws MalThrowable { + if (ast instanceof MalList) { + MalVal a0 = ((MalList)ast).nth(0); + if (a0 instanceof MalSymbol && + env.find(((MalSymbol)a0).getName()) != null) { + MalVal mac = env.get(((MalSymbol)a0).getName()); + if (mac instanceof MalFunction && + ((MalFunction)mac).isMacro()) { + return true; + } + } + } + return false; + } + + public static MalVal macroexpand(MalVal ast, Env env) + throws MalThrowable { + while (is_macro_call(ast, env)) { + MalSymbol a0 = (MalSymbol)((MalList)ast).nth(0); + MalFunction mac = (MalFunction) env.get(a0.getName()); + ast = mac.apply(((MalList)ast).rest()); + } + return ast; + } + + public static MalVal eval_ast(MalVal ast, Env env) throws MalThrowable { + if (ast instanceof MalSymbol) { + MalSymbol sym = (MalSymbol)ast; + return env.get(sym.getName()); + } else if (ast instanceof MalList) { + MalList old_lst = (MalList)ast; + MalList new_lst = ast.list_Q() ? new MalList() + : (MalList)new MalVector(); + for (MalVal mv : (List)old_lst.value) { + new_lst.conj_BANG(EVAL(mv, env)); + } + return new_lst; + } else if (ast instanceof MalHashMap) { + MalHashMap new_hm = new MalHashMap(); + Iterator it = ((MalHashMap)ast).value.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = (Map.Entry)it.next(); + new_hm.value.put(entry.getKey(), EVAL((MalVal)entry.getValue(), env)); + } + return new_hm; + } else { + return ast; + } + } + + public static MalVal EVAL(MalVal orig_ast, Env env) throws MalThrowable { + MalVal a0, a1,a2, a3, res; + MalList el; + + while (true) { + + //System.out.println("EVAL: " + printer._pr_str(orig_ast, true)); + if (!orig_ast.list_Q()) { + return eval_ast(orig_ast, env); + } + + // apply list + MalVal expanded = macroexpand(orig_ast, env); + if (!expanded.list_Q()) { return expanded; } + MalList ast = (MalList) expanded; + if (ast.size() == 0) { return ast; } + a0 = ast.nth(0); + String a0sym = a0 instanceof MalSymbol ? ((MalSymbol)a0).getName() + : "__<*fn*>__"; + switch (a0sym) { + case "def!": + a1 = ast.nth(1); + a2 = ast.nth(2); + res = EVAL(a2, env); + env.set(((MalSymbol)a1).getName(), res); + return res; + case "let*": + a1 = ast.nth(1); + a2 = ast.nth(2); + MalSymbol key; + MalVal val; + Env let_env = new Env(env); + for(int i=0; i<((MalList)a1).size(); i+=2) { + key = (MalSymbol)((MalList)a1).nth(i); + val = ((MalList)a1).nth(i+1); + let_env.set(key.getName(), EVAL(val, let_env)); + } + orig_ast = a2; + env = let_env; + break; + case "quote": + return ast.nth(1); + case "quasiquote": + orig_ast = quasiquote(ast.nth(1)); + break; + case "defmacro!": + a1 = ast.nth(1); + a2 = ast.nth(2); + res = EVAL(a2, env); + ((MalFunction)res).setMacro(); + env.set(((MalSymbol)a1).getName(), res); + return res; + case "macroexpand": + a1 = ast.nth(1); + return macroexpand(a1, env); + case "try*": + try { + return EVAL(ast.nth(1), env); + } catch (Throwable t) { + if (ast.size() > 2) { + MalVal exc; + a2 = ast.nth(2); + MalVal a20 = ((MalList)a2).nth(0); + if (((MalSymbol)a20).getName().equals("catch*")) { + if (t instanceof MalException) { + exc = ((MalException)t).getValue(); + } else { + StringWriter sw = new StringWriter(); + t.printStackTrace(new PrintWriter(sw)); + String tstr = sw.toString(); + exc = new MalString(t.getMessage() + ": " + tstr); + } + return EVAL(((MalList)a2).nth(2), + new Env(env, ((MalList)a2).slice(1,2), + new MalList(exc))); + } + } + throw t; + } + case "do": + eval_ast(ast.slice(1, ast.size()-1), env); + orig_ast = ast.nth(ast.size()-1); + break; + case "if": + a1 = ast.nth(1); + MalVal cond = EVAL(a1, env); + if (cond == types.Nil || cond == types.False) { + // eval false slot form + if (ast.size() > 3) { + orig_ast = ast.nth(3); + } else { + return types.Nil; + } + } else { + // eval true slot form + orig_ast = ast.nth(2); + } + break; + case "fn*": + final MalList a1f = (MalList)ast.nth(1); + final MalVal a2f = ast.nth(2); + final Env cur_env = env; + return new MalFunction (a2f, (mal.env.Env)env, a1f) { + public MalVal apply(MalList args) throws MalThrowable { + return EVAL(a2f, new Env(cur_env, a1f, args)); + } + }; + default: + el = (MalList)eval_ast(ast, env); + MalFunction f = (MalFunction)el.nth(0); + MalVal fnast = f.getAst(); + if (fnast != null) { + orig_ast = fnast; + env = f.genEnv(el.slice(1)); + } else { + return f.apply(el.rest()); + } + } + + } + } + + // print + public static String PRINT(MalVal exp) { + return printer._pr_str(exp, true); + } + + // repl + public static MalVal RE(Env env, String str) throws MalThrowable { + return EVAL(READ(str), env); + } + + public static void main(String[] args) throws MalThrowable { + String prompt = "user> "; + + final Env repl_env = new Env(null); + + // core.java: defined using Java + for (String key : core.ns.keySet()) { + repl_env.set(key, core.ns.get(key)); + } + repl_env.set("eval", new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + return EVAL(args.nth(0), repl_env); + } + }); + MalList _argv = new MalList(); + for (Integer i=1; i < args.length; i++) { + _argv.conj_BANG(new MalString(args[i])); + } + repl_env.set("*ARGV*", _argv); + + + // core.mal: defined using the language itself + RE(repl_env, "(def! *host-language* \"java\")"); + RE(repl_env, "(def! not (fn* (a) (if a false true)))"); + RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"); + RE(repl_env, "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))"); + RE(repl_env, "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))"); + + Integer fileIdx = 0; + if (args.length > 0 && args[0].equals("--raw")) { + readline.mode = readline.Mode.JAVA; + fileIdx = 1; + } + if (args.length > fileIdx) { + RE(repl_env, "(load-file \"" + args[fileIdx] + "\")"); + return; + } + + // repl loop + RE(repl_env, "(println (str \"Mal [\" *host-language* \"]\"))"); + while (true) { + String line; + try { + line = readline.readline(prompt); + if (line == null) { continue; } + } catch (readline.EOFException e) { + break; + } catch (IOException e) { + System.out.println("IOException: " + e.getMessage()); + break; + } + try { + System.out.println(PRINT(RE(repl_env, line))); + } catch (MalContinue e) { + continue; + } catch (MalException e) { + System.out.println("Error: " + printer._pr_str(e.getValue(), false)); + continue; + } catch (MalThrowable t) { + System.out.println("Error: " + t.getMessage()); + continue; + } catch (Throwable t) { + System.out.println("Uncaught " + t + ": " + t.getMessage()); + continue; + } + } + } +} diff --git a/java/src/main/java/mal/stepA_more.java b/java/src/main/java/mal/stepA_more.java deleted file mode 100644 index 7e869e6..0000000 --- a/java/src/main/java/mal/stepA_more.java +++ /dev/null @@ -1,302 +0,0 @@ -package mal; - -import java.io.IOException; - -import java.io.StringWriter; -import java.io.PrintWriter; -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.Iterator; -import mal.types.*; -import mal.readline; -import mal.reader; -import mal.printer; -import mal.env.Env; -import mal.core; - -public class stepA_more { - // read - public static MalVal READ(String str) throws MalThrowable { - return reader.read_str(str); - } - - // eval - public static Boolean is_pair(MalVal x) { - return x instanceof MalList && ((MalList)x).size() > 0; - } - - public static MalVal quasiquote(MalVal ast) { - if (!is_pair(ast)) { - return new MalList(new MalSymbol("quote"), ast); - } else { - MalVal a0 = ((MalList)ast).nth(0); - if ((a0 instanceof MalSymbol) && - (((MalSymbol)a0).getName() == "unquote")) { - return ((MalList)ast).nth(1); - } else if (is_pair(a0)) { - MalVal a00 = ((MalList)a0).nth(0); - if ((a00 instanceof MalSymbol) && - (((MalSymbol)a00).getName() == "splice-unquote")) { - return new MalList(new MalSymbol("concat"), - ((MalList)a0).nth(1), - quasiquote(((MalList)ast).rest())); - } - } - return new MalList(new MalSymbol("cons"), - quasiquote(a0), - quasiquote(((MalList)ast).rest())); - } - } - - public static Boolean is_macro_call(MalVal ast, Env env) - throws MalThrowable { - if (ast instanceof MalList) { - MalVal a0 = ((MalList)ast).nth(0); - if (a0 instanceof MalSymbol && - env.find(((MalSymbol)a0).getName()) != null) { - MalVal mac = env.get(((MalSymbol)a0).getName()); - if (mac instanceof MalFunction && - ((MalFunction)mac).isMacro()) { - return true; - } - } - } - return false; - } - - public static MalVal macroexpand(MalVal ast, Env env) - throws MalThrowable { - while (is_macro_call(ast, env)) { - MalSymbol a0 = (MalSymbol)((MalList)ast).nth(0); - MalFunction mac = (MalFunction) env.get(a0.getName()); - ast = mac.apply(((MalList)ast).rest()); - } - return ast; - } - - public static MalVal eval_ast(MalVal ast, Env env) throws MalThrowable { - if (ast instanceof MalSymbol) { - MalSymbol sym = (MalSymbol)ast; - return env.get(sym.getName()); - } else if (ast instanceof MalList) { - MalList old_lst = (MalList)ast; - MalList new_lst = ast.list_Q() ? new MalList() - : (MalList)new MalVector(); - for (MalVal mv : (List)old_lst.value) { - new_lst.conj_BANG(EVAL(mv, env)); - } - return new_lst; - } else if (ast instanceof MalHashMap) { - MalHashMap new_hm = new MalHashMap(); - Iterator it = ((MalHashMap)ast).value.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = (Map.Entry)it.next(); - new_hm.value.put(entry.getKey(), EVAL((MalVal)entry.getValue(), env)); - } - return new_hm; - } else { - return ast; - } - } - - public static MalVal EVAL(MalVal orig_ast, Env env) throws MalThrowable { - MalVal a0, a1,a2, a3, res; - MalList el; - - while (true) { - - //System.out.println("EVAL: " + printer._pr_str(orig_ast, true)); - if (!orig_ast.list_Q()) { - return eval_ast(orig_ast, env); - } - - // apply list - MalVal expanded = macroexpand(orig_ast, env); - if (!expanded.list_Q()) { return expanded; } - MalList ast = (MalList) expanded; - if (ast.size() == 0) { return ast; } - a0 = ast.nth(0); - String a0sym = a0 instanceof MalSymbol ? ((MalSymbol)a0).getName() - : "__<*fn*>__"; - switch (a0sym) { - case "def!": - a1 = ast.nth(1); - a2 = ast.nth(2); - res = EVAL(a2, env); - env.set(((MalSymbol)a1).getName(), res); - return res; - case "let*": - a1 = ast.nth(1); - a2 = ast.nth(2); - MalSymbol key; - MalVal val; - Env let_env = new Env(env); - for(int i=0; i<((MalList)a1).size(); i+=2) { - key = (MalSymbol)((MalList)a1).nth(i); - val = ((MalList)a1).nth(i+1); - let_env.set(key.getName(), EVAL(val, let_env)); - } - orig_ast = a2; - env = let_env; - break; - case "quote": - return ast.nth(1); - case "quasiquote": - orig_ast = quasiquote(ast.nth(1)); - break; - case "defmacro!": - a1 = ast.nth(1); - a2 = ast.nth(2); - res = EVAL(a2, env); - ((MalFunction)res).setMacro(); - env.set(((MalSymbol)a1).getName(), res); - return res; - case "macroexpand": - a1 = ast.nth(1); - return macroexpand(a1, env); - case "try*": - try { - return EVAL(ast.nth(1), env); - } catch (Throwable t) { - if (ast.size() > 2) { - MalVal exc; - a2 = ast.nth(2); - MalVal a20 = ((MalList)a2).nth(0); - if (((MalSymbol)a20).getName().equals("catch*")) { - if (t instanceof MalException) { - exc = ((MalException)t).getValue(); - } else { - StringWriter sw = new StringWriter(); - t.printStackTrace(new PrintWriter(sw)); - String tstr = sw.toString(); - exc = new MalString(t.getMessage() + ": " + tstr); - } - return EVAL(((MalList)a2).nth(2), - new Env(env, ((MalList)a2).slice(1,2), - new MalList(exc))); - } - } - throw t; - } - case "do": - eval_ast(ast.slice(1, ast.size()-1), env); - orig_ast = ast.nth(ast.size()-1); - break; - case "if": - a1 = ast.nth(1); - MalVal cond = EVAL(a1, env); - if (cond == types.Nil || cond == types.False) { - // eval false slot form - if (ast.size() > 3) { - orig_ast = ast.nth(3); - } else { - return types.Nil; - } - } else { - // eval true slot form - orig_ast = ast.nth(2); - } - break; - case "fn*": - final MalList a1f = (MalList)ast.nth(1); - final MalVal a2f = ast.nth(2); - final Env cur_env = env; - return new MalFunction (a2f, (mal.env.Env)env, a1f) { - public MalVal apply(MalList args) throws MalThrowable { - return EVAL(a2f, new Env(cur_env, a1f, args)); - } - }; - default: - el = (MalList)eval_ast(ast, env); - MalFunction f = (MalFunction)el.nth(0); - MalVal fnast = f.getAst(); - if (fnast != null) { - orig_ast = fnast; - env = f.genEnv(el.slice(1)); - } else { - return f.apply(el.rest()); - } - } - - } - } - - // print - public static String PRINT(MalVal exp) { - return printer._pr_str(exp, true); - } - - // repl - public static MalVal RE(Env env, String str) throws MalThrowable { - return EVAL(READ(str), env); - } - - public static void main(String[] args) throws MalThrowable { - String prompt = "user> "; - - final Env repl_env = new Env(null); - - // core.java: defined using Java - for (String key : core.ns.keySet()) { - repl_env.set(key, core.ns.get(key)); - } - repl_env.set("eval", new MalFunction() { - public MalVal apply(MalList args) throws MalThrowable { - return EVAL(args.nth(0), repl_env); - } - }); - MalList _argv = new MalList(); - for (Integer i=1; i < args.length; i++) { - _argv.conj_BANG(new MalString(args[i])); - } - repl_env.set("*ARGV*", _argv); - - - // core.mal: defined using the language itself - RE(repl_env, "(def! *host-language* \"java\")"); - RE(repl_env, "(def! not (fn* (a) (if a false true)))"); - RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"); - RE(repl_env, "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))"); - RE(repl_env, "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))"); - - Integer fileIdx = 0; - if (args.length > 0 && args[0].equals("--raw")) { - readline.mode = readline.Mode.JAVA; - fileIdx = 1; - } - if (args.length > fileIdx) { - RE(repl_env, "(load-file \"" + args[fileIdx] + "\")"); - return; - } - - // repl loop - RE(repl_env, "(println (str \"Mal [\" *host-language* \"]\"))"); - while (true) { - String line; - try { - line = readline.readline(prompt); - if (line == null) { continue; } - } catch (readline.EOFException e) { - break; - } catch (IOException e) { - System.out.println("IOException: " + e.getMessage()); - break; - } - try { - System.out.println(PRINT(RE(repl_env, line))); - } catch (MalContinue e) { - continue; - } catch (MalException e) { - System.out.println("Error: " + printer._pr_str(e.getValue(), false)); - continue; - } catch (MalThrowable t) { - System.out.println("Error: " + t.getMessage()); - continue; - } catch (Throwable t) { - System.out.println("Uncaught " + t + ": " + t.getMessage()); - continue; - } - } - } -} -- cgit v1.2.3 From b8ee29b22fbaa7a01f2754b4d6dd9af52e02017c Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Thu, 18 Dec 2014 20:33:49 -0600 Subject: All: add keywords. Also, fix nth and count to match cloure. --- java/src/main/java/mal/core.java | 36 ++++++++++++++++++++++++++++-- java/src/main/java/mal/env.java | 15 +++++++------ java/src/main/java/mal/printer.java | 5 ++++- java/src/main/java/mal/reader.java | 6 +++-- java/src/main/java/mal/step3_env.java | 18 +++++++-------- java/src/main/java/mal/step4_if_fn_do.java | 9 ++++---- java/src/main/java/mal/step5_tco.java | 9 ++++---- java/src/main/java/mal/step6_file.java | 13 +++++------ java/src/main/java/mal/step7_quote.java | 13 +++++------ java/src/main/java/mal/step8_macros.java | 21 +++++++++-------- java/src/main/java/mal/step9_try.java | 23 +++++++++---------- java/src/main/java/mal/stepA_interop.java | 21 +++++++++-------- java/src/main/java/mal/types.java | 5 ++++- 13 files changed, 112 insertions(+), 82 deletions(-) (limited to 'java/src') diff --git a/java/src/main/java/mal/core.java b/java/src/main/java/mal/core.java index 7af2f72..facaeb1 100644 --- a/java/src/main/java/mal/core.java +++ b/java/src/main/java/mal/core.java @@ -49,11 +49,32 @@ public class core { return args.nth(0) == False ? True : False; } }; + static MalFunction symbol = new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + return new MalSymbol((MalString)args.nth(0)); + } + }; static MalFunction symbol_Q = new MalFunction() { public MalVal apply(MalList args) throws MalThrowable { return args.nth(0) instanceof MalSymbol ? True : False; } }; + static MalFunction keyword = new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + return new MalString( + "\u029e" + ((MalString)args.nth(0)).getValue()); + } + }; + static MalFunction keyword_Q = new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + if (args.nth(0) instanceof MalString && + (((MalString)args.nth(0)).getValue().charAt(0) == '\u029e')) { + return True; + } else { + return False; + } + } + }; // String functions @@ -304,7 +325,11 @@ public class core { static MalFunction count = new MalFunction() { public MalVal apply(MalList a) throws MalThrowable { - return new MalInteger(((MalList)a.nth(0)).size()); + if (a.nth(0) == Nil) { + return new MalInteger(0); + } else { + return new MalInteger(((MalList)a.nth(0)).size()); + } } }; @@ -358,7 +383,11 @@ public class core { static MalFunction nth = new MalFunction() { public MalVal apply(MalList a) throws MalThrowable { Integer idx = ((MalInteger)a.nth(1)).getValue(); - return ((MalList)a.nth(0)).nth(idx); + if (idx < ((MalList)a.nth(0)).size()) { + return ((MalList)a.nth(0)).nth(idx); + } else { + throw new MalError("nth: index out of range"); + } } }; @@ -471,7 +500,10 @@ public class core { .put("nil?", nil_Q) .put("true?", true_Q) .put("false?", false_Q) + .put("symbol", symbol) .put("symbol?", symbol_Q) + .put("keyword", keyword) + .put("keyword?", keyword_Q) .put("pr-str", pr_str) .put("str", str) diff --git a/java/src/main/java/mal/env.java b/java/src/main/java/mal/env.java index 8a1913e..711a9ee 100644 --- a/java/src/main/java/mal/env.java +++ b/java/src/main/java/mal/env.java @@ -30,8 +30,8 @@ public class env { } } - public Env find(String key) { - if (data.containsKey(key)) { + public Env find(MalSymbol key) { + if (data.containsKey(key.getName())) { return this; } else if (outer != null) { return outer.find(key); @@ -40,17 +40,18 @@ public class env { } } - public MalVal get(String key) throws MalThrowable { + public MalVal get(MalSymbol key) throws MalThrowable { Env e = find(key); if (e == null) { - throw new MalException("'" + key + "' not found"); + throw new MalException( + "'" + key.getName() + "' not found"); } else { - return e.data.get(key); + return e.data.get(key.getName()); } } - public Env set(String key, MalVal value) { - data.put(key, value); + public Env set(MalSymbol key, MalVal value) { + data.put(key.getName(), value); return this; } } diff --git a/java/src/main/java/mal/printer.java b/java/src/main/java/mal/printer.java index 73dfca3..fe3c5c4 100644 --- a/java/src/main/java/mal/printer.java +++ b/java/src/main/java/mal/printer.java @@ -24,7 +24,10 @@ public class printer { String delim, Boolean print_readably) { ArrayList strs = new ArrayList(); for (Map.Entry entry : value.entrySet()) { - if (print_readably) { + if (entry.getKey().length() > 0 && + entry.getKey().charAt(0) == '\u029e') { + strs.add(":" + entry.getKey().substring(1)); + } else if (print_readably) { strs.add("\"" + entry.getKey().toString() + "\""); } else { strs.add(entry.getKey().toString()); diff --git a/java/src/main/java/mal/reader.java b/java/src/main/java/mal/reader.java index 6bae506..7c9d3aa 100644 --- a/java/src/main/java/mal/reader.java +++ b/java/src/main/java/mal/reader.java @@ -51,7 +51,7 @@ public class reader { public static MalVal read_atom(Reader rdr) throws ParseError { String token = rdr.next(); - Pattern pattern = Pattern.compile("(^-?[0-9]+$)|(^-?[0-9][0-9.]*$)|(^nil$)|(^true$)|(^false$)|^\"(.*)\"$|(^[^\"]*$)"); + Pattern pattern = Pattern.compile("(^-?[0-9]+$)|(^-?[0-9][0-9.]*$)|(^nil$)|(^true$)|(^false$)|^\"(.*)\"$|:(.*)|(^[^\"]*$)"); Matcher matcher = pattern.matcher(token); if (!matcher.find()) { throw new ParseError("unrecognized token '" + token + "'"); @@ -67,7 +67,9 @@ public class reader { } else if (matcher.group(6) != null) { return new MalString(StringEscapeUtils.unescapeJson(matcher.group(6))); } else if (matcher.group(7) != null) { - return new MalSymbol(matcher.group(7)); + return new MalString("\u029e" + matcher.group(7)); + } else if (matcher.group(8) != null) { + return new MalSymbol(matcher.group(8)); } else { throw new ParseError("unrecognized '" + matcher.group(0) + "'"); } diff --git a/java/src/main/java/mal/step3_env.java b/java/src/main/java/mal/step3_env.java index a88dc13..d3e221b 100644 --- a/java/src/main/java/mal/step3_env.java +++ b/java/src/main/java/mal/step3_env.java @@ -21,8 +21,7 @@ public class step3_env { // eval public static MalVal eval_ast(MalVal ast, Env env) throws MalThrowable { if (ast instanceof MalSymbol) { - MalSymbol sym = (MalSymbol)ast; - return env.get(sym.getName()); + return env.get((MalSymbol)ast); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; MalList new_lst = ast.list_Q() ? new MalList() @@ -65,7 +64,7 @@ public class step3_env { a1 = ast.nth(1); a2 = ast.nth(2); res = EVAL(a2, env); - env.set(((MalSymbol)a1).getName(), res); + env.set(((MalSymbol)a1), res); return res; case "let*": a1 = ast.nth(1); @@ -76,13 +75,12 @@ public class step3_env { for(int i=0; i<((MalList)a1).size(); i+=2) { key = (MalSymbol)((MalList)a1).nth(i); val = ((MalList)a1).nth(i+1); - let_env.set(key.getName(), EVAL(val, let_env)); + let_env.set(key, EVAL(val, let_env)); } return EVAL(a2, let_env); default: MalVal args = eval_ast(ast.rest(), env); - MalSymbol fsym = (MalSymbol)a0; - ILambda f = (ILambda)env.get(fsym.getName()); + ILambda f = (ILambda)env.get((MalSymbol)a0); return f.apply((MalList)args); } } @@ -123,10 +121,10 @@ public class step3_env { String prompt = "user> "; Env repl_env = new Env(null); - repl_env.set("+", add); - repl_env.set("-", subtract); - repl_env.set("*", multiply); - repl_env.set("/", divide); + repl_env.set(new MalSymbol("+"), add); + repl_env.set(new MalSymbol("-"), subtract); + repl_env.set(new MalSymbol("*"), multiply); + repl_env.set(new MalSymbol("/"), divide); if (args.length > 0 && args[0].equals("--raw")) { readline.mode = readline.Mode.JAVA; diff --git a/java/src/main/java/mal/step4_if_fn_do.java b/java/src/main/java/mal/step4_if_fn_do.java index ce9043d..ff15709 100644 --- a/java/src/main/java/mal/step4_if_fn_do.java +++ b/java/src/main/java/mal/step4_if_fn_do.java @@ -22,8 +22,7 @@ public class step4_if_fn_do { // eval public static MalVal eval_ast(MalVal ast, Env env) throws MalThrowable { if (ast instanceof MalSymbol) { - MalSymbol sym = (MalSymbol)ast; - return env.get(sym.getName()); + return env.get((MalSymbol)ast); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; MalList new_lst = ast.list_Q() ? new MalList() @@ -64,7 +63,7 @@ public class step4_if_fn_do { a1 = ast.nth(1); a2 = ast.nth(2); res = EVAL(a2, env); - env.set(((MalSymbol)a1).getName(), res); + env.set(((MalSymbol)a1), res); return res; case "let*": a1 = ast.nth(1); @@ -75,7 +74,7 @@ public class step4_if_fn_do { for(int i=0; i<((MalList)a1).size(); i+=2) { key = (MalSymbol)((MalList)a1).nth(i); val = ((MalList)a1).nth(i+1); - let_env.set(key.getName(), EVAL(val, let_env)); + let_env.set(key, EVAL(val, let_env)); } return EVAL(a2, let_env); case "do": @@ -130,7 +129,7 @@ public class step4_if_fn_do { // core.java: defined using Java for (String key : core.ns.keySet()) { - repl_env.set(key, core.ns.get(key)); + repl_env.set(new MalSymbol(key), core.ns.get(key)); } // core.mal: defined using the language itself diff --git a/java/src/main/java/mal/step5_tco.java b/java/src/main/java/mal/step5_tco.java index ef56083..43c87b7 100644 --- a/java/src/main/java/mal/step5_tco.java +++ b/java/src/main/java/mal/step5_tco.java @@ -22,8 +22,7 @@ public class step5_tco { // eval public static MalVal eval_ast(MalVal ast, Env env) throws MalThrowable { if (ast instanceof MalSymbol) { - MalSymbol sym = (MalSymbol)ast; - return env.get(sym.getName()); + return env.get((MalSymbol)ast); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; MalList new_lst = ast.list_Q() ? new MalList() @@ -67,7 +66,7 @@ public class step5_tco { a1 = ast.nth(1); a2 = ast.nth(2); res = EVAL(a2, env); - env.set(((MalSymbol)a1).getName(), res); + env.set(((MalSymbol)a1), res); return res; case "let*": a1 = ast.nth(1); @@ -78,7 +77,7 @@ public class step5_tco { for(int i=0; i<((MalList)a1).size(); i+=2) { key = (MalSymbol)((MalList)a1).nth(i); val = ((MalList)a1).nth(i+1); - let_env.set(key.getName(), EVAL(val, let_env)); + let_env.set(key, EVAL(val, let_env)); } orig_ast = a2; env = let_env; @@ -143,7 +142,7 @@ public class step5_tco { // core.java: defined using Java for (String key : core.ns.keySet()) { - repl_env.set(key, core.ns.get(key)); + repl_env.set(new MalSymbol(key), core.ns.get(key)); } // core.mal: defined using the language itself diff --git a/java/src/main/java/mal/step6_file.java b/java/src/main/java/mal/step6_file.java index 56bcdf7..19c4c1c 100644 --- a/java/src/main/java/mal/step6_file.java +++ b/java/src/main/java/mal/step6_file.java @@ -22,8 +22,7 @@ public class step6_file { // eval public static MalVal eval_ast(MalVal ast, Env env) throws MalThrowable { if (ast instanceof MalSymbol) { - MalSymbol sym = (MalSymbol)ast; - return env.get(sym.getName()); + return env.get((MalSymbol)ast); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; MalList new_lst = ast.list_Q() ? new MalList() @@ -67,7 +66,7 @@ public class step6_file { a1 = ast.nth(1); a2 = ast.nth(2); res = EVAL(a2, env); - env.set(((MalSymbol)a1).getName(), res); + env.set(((MalSymbol)a1), res); return res; case "let*": a1 = ast.nth(1); @@ -78,7 +77,7 @@ public class step6_file { for(int i=0; i<((MalList)a1).size(); i+=2) { key = (MalSymbol)((MalList)a1).nth(i); val = ((MalList)a1).nth(i+1); - let_env.set(key.getName(), EVAL(val, let_env)); + let_env.set(key, EVAL(val, let_env)); } orig_ast = a2; env = let_env; @@ -143,9 +142,9 @@ public class step6_file { // core.java: defined using Java for (String key : core.ns.keySet()) { - repl_env.set(key, core.ns.get(key)); + repl_env.set(new MalSymbol(key), core.ns.get(key)); } - repl_env.set("eval", new MalFunction() { + repl_env.set(new MalSymbol("eval"), new MalFunction() { public MalVal apply(MalList args) throws MalThrowable { return EVAL(args.nth(0), repl_env); } @@ -154,7 +153,7 @@ public class step6_file { for (Integer i=1; i < args.length; i++) { _argv.conj_BANG(new MalString(args[i])); } - repl_env.set("*ARGV*", _argv); + repl_env.set(new MalSymbol("*ARGV*"), _argv); // core.mal: defined using the language itself diff --git a/java/src/main/java/mal/step7_quote.java b/java/src/main/java/mal/step7_quote.java index 8c3766a..6d015b4 100644 --- a/java/src/main/java/mal/step7_quote.java +++ b/java/src/main/java/mal/step7_quote.java @@ -49,8 +49,7 @@ public class step7_quote { public static MalVal eval_ast(MalVal ast, Env env) throws MalThrowable { if (ast instanceof MalSymbol) { - MalSymbol sym = (MalSymbol)ast; - return env.get(sym.getName()); + return env.get((MalSymbol)ast); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; MalList new_lst = ast.list_Q() ? new MalList() @@ -94,7 +93,7 @@ public class step7_quote { a1 = ast.nth(1); a2 = ast.nth(2); res = EVAL(a2, env); - env.set(((MalSymbol)a1).getName(), res); + env.set(((MalSymbol)a1), res); return res; case "let*": a1 = ast.nth(1); @@ -105,7 +104,7 @@ public class step7_quote { for(int i=0; i<((MalList)a1).size(); i+=2) { key = (MalSymbol)((MalList)a1).nth(i); val = ((MalList)a1).nth(i+1); - let_env.set(key.getName(), EVAL(val, let_env)); + let_env.set(key, EVAL(val, let_env)); } orig_ast = a2; env = let_env; @@ -175,9 +174,9 @@ public class step7_quote { // core.java: defined using Java for (String key : core.ns.keySet()) { - repl_env.set(key, core.ns.get(key)); + repl_env.set(new MalSymbol(key), core.ns.get(key)); } - repl_env.set("eval", new MalFunction() { + repl_env.set(new MalSymbol("eval"), new MalFunction() { public MalVal apply(MalList args) throws MalThrowable { return EVAL(args.nth(0), repl_env); } @@ -186,7 +185,7 @@ public class step7_quote { for (Integer i=1; i < args.length; i++) { _argv.conj_BANG(new MalString(args[i])); } - repl_env.set("*ARGV*", _argv); + repl_env.set(new MalSymbol("*ARGV*"), _argv); // core.mal: defined using the language itself diff --git a/java/src/main/java/mal/step8_macros.java b/java/src/main/java/mal/step8_macros.java index 4c89356..38a4aef 100644 --- a/java/src/main/java/mal/step8_macros.java +++ b/java/src/main/java/mal/step8_macros.java @@ -52,8 +52,8 @@ public class step8_macros { if (ast instanceof MalList) { MalVal a0 = ((MalList)ast).nth(0); if (a0 instanceof MalSymbol && - env.find(((MalSymbol)a0).getName()) != null) { - MalVal mac = env.get(((MalSymbol)a0).getName()); + env.find(((MalSymbol)a0)) != null) { + MalVal mac = env.get(((MalSymbol)a0)); if (mac instanceof MalFunction && ((MalFunction)mac).isMacro()) { return true; @@ -67,7 +67,7 @@ public class step8_macros { throws MalThrowable { while (is_macro_call(ast, env)) { MalSymbol a0 = (MalSymbol)((MalList)ast).nth(0); - MalFunction mac = (MalFunction) env.get(a0.getName()); + MalFunction mac = (MalFunction) env.get(a0); ast = mac.apply(((MalList)ast).rest()); } return ast; @@ -75,8 +75,7 @@ public class step8_macros { public static MalVal eval_ast(MalVal ast, Env env) throws MalThrowable { if (ast instanceof MalSymbol) { - MalSymbol sym = (MalSymbol)ast; - return env.get(sym.getName()); + return env.get((MalSymbol)ast); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; MalList new_lst = ast.list_Q() ? new MalList() @@ -122,7 +121,7 @@ public class step8_macros { a1 = ast.nth(1); a2 = ast.nth(2); res = EVAL(a2, env); - env.set(((MalSymbol)a1).getName(), res); + env.set(((MalSymbol)a1), res); return res; case "let*": a1 = ast.nth(1); @@ -133,7 +132,7 @@ public class step8_macros { for(int i=0; i<((MalList)a1).size(); i+=2) { key = (MalSymbol)((MalList)a1).nth(i); val = ((MalList)a1).nth(i+1); - let_env.set(key.getName(), EVAL(val, let_env)); + let_env.set(key, EVAL(val, let_env)); } orig_ast = a2; env = let_env; @@ -148,7 +147,7 @@ public class step8_macros { a2 = ast.nth(2); res = EVAL(a2, env); ((MalFunction)res).setMacro(); - env.set(((MalSymbol)a1).getName(), res); + env.set((MalSymbol)a1, res); return res; case "macroexpand": a1 = ast.nth(1); @@ -213,9 +212,9 @@ public class step8_macros { // core.java: defined using Java for (String key : core.ns.keySet()) { - repl_env.set(key, core.ns.get(key)); + repl_env.set(new MalSymbol(key), core.ns.get(key)); } - repl_env.set("eval", new MalFunction() { + repl_env.set(new MalSymbol("eval"), new MalFunction() { public MalVal apply(MalList args) throws MalThrowable { return EVAL(args.nth(0), repl_env); } @@ -224,7 +223,7 @@ public class step8_macros { for (Integer i=1; i < args.length; i++) { _argv.conj_BANG(new MalString(args[i])); } - repl_env.set("*ARGV*", _argv); + repl_env.set(new MalSymbol("*ARGV*"), _argv); // core.mal: defined using the language itself diff --git a/java/src/main/java/mal/step9_try.java b/java/src/main/java/mal/step9_try.java index c3b0e9f..ceeff27 100644 --- a/java/src/main/java/mal/step9_try.java +++ b/java/src/main/java/mal/step9_try.java @@ -54,8 +54,8 @@ public class step9_try { if (ast instanceof MalList) { MalVal a0 = ((MalList)ast).nth(0); if (a0 instanceof MalSymbol && - env.find(((MalSymbol)a0).getName()) != null) { - MalVal mac = env.get(((MalSymbol)a0).getName()); + env.find(((MalSymbol)a0)) != null) { + MalVal mac = env.get(((MalSymbol)a0)); if (mac instanceof MalFunction && ((MalFunction)mac).isMacro()) { return true; @@ -69,7 +69,7 @@ public class step9_try { throws MalThrowable { while (is_macro_call(ast, env)) { MalSymbol a0 = (MalSymbol)((MalList)ast).nth(0); - MalFunction mac = (MalFunction) env.get(a0.getName()); + MalFunction mac = (MalFunction) env.get(a0); ast = mac.apply(((MalList)ast).rest()); } return ast; @@ -77,8 +77,7 @@ public class step9_try { public static MalVal eval_ast(MalVal ast, Env env) throws MalThrowable { if (ast instanceof MalSymbol) { - MalSymbol sym = (MalSymbol)ast; - return env.get(sym.getName()); + return env.get((MalSymbol)ast); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; MalList new_lst = ast.list_Q() ? new MalList() @@ -124,7 +123,7 @@ public class step9_try { a1 = ast.nth(1); a2 = ast.nth(2); res = EVAL(a2, env); - env.set(((MalSymbol)a1).getName(), res); + env.set(((MalSymbol)a1), res); return res; case "let*": a1 = ast.nth(1); @@ -135,7 +134,7 @@ public class step9_try { for(int i=0; i<((MalList)a1).size(); i+=2) { key = (MalSymbol)((MalList)a1).nth(i); val = ((MalList)a1).nth(i+1); - let_env.set(key.getName(), EVAL(val, let_env)); + let_env.set(key, EVAL(val, let_env)); } orig_ast = a2; env = let_env; @@ -150,7 +149,7 @@ public class step9_try { a2 = ast.nth(2); res = EVAL(a2, env); ((MalFunction)res).setMacro(); - env.set(((MalSymbol)a1).getName(), res); + env.set((MalSymbol)a1, res); return res; case "macroexpand": a1 = ast.nth(1); @@ -239,9 +238,9 @@ public class step9_try { // core.java: defined using Java for (String key : core.ns.keySet()) { - repl_env.set(key, core.ns.get(key)); + repl_env.set(new MalSymbol(key), core.ns.get(key)); } - repl_env.set("eval", new MalFunction() { + repl_env.set(new MalSymbol("eval"), new MalFunction() { public MalVal apply(MalList args) throws MalThrowable { return EVAL(args.nth(0), repl_env); } @@ -250,11 +249,10 @@ public class step9_try { for (Integer i=1; i < args.length; i++) { _argv.conj_BANG(new MalString(args[i])); } - repl_env.set("*ARGV*", _argv); + repl_env.set(new MalSymbol("*ARGV*"), _argv); // core.mal: defined using the language itself - RE(repl_env, "(def! *host-language* \"java\")"); RE(repl_env, "(def! not (fn* (a) (if a false true)))"); RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"); RE(repl_env, "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))"); @@ -271,7 +269,6 @@ public class step9_try { } // repl loop - RE(repl_env, "(println (str \"Mal [\" *host-language* \"]\"))"); while (true) { String line; try { diff --git a/java/src/main/java/mal/stepA_interop.java b/java/src/main/java/mal/stepA_interop.java index 75c0402..1fa1125 100644 --- a/java/src/main/java/mal/stepA_interop.java +++ b/java/src/main/java/mal/stepA_interop.java @@ -54,8 +54,8 @@ public class stepA_interop { if (ast instanceof MalList) { MalVal a0 = ((MalList)ast).nth(0); if (a0 instanceof MalSymbol && - env.find(((MalSymbol)a0).getName()) != null) { - MalVal mac = env.get(((MalSymbol)a0).getName()); + env.find(((MalSymbol)a0)) != null) { + MalVal mac = env.get(((MalSymbol)a0)); if (mac instanceof MalFunction && ((MalFunction)mac).isMacro()) { return true; @@ -69,7 +69,7 @@ public class stepA_interop { throws MalThrowable { while (is_macro_call(ast, env)) { MalSymbol a0 = (MalSymbol)((MalList)ast).nth(0); - MalFunction mac = (MalFunction) env.get(a0.getName()); + MalFunction mac = (MalFunction) env.get(a0); ast = mac.apply(((MalList)ast).rest()); } return ast; @@ -77,8 +77,7 @@ public class stepA_interop { public static MalVal eval_ast(MalVal ast, Env env) throws MalThrowable { if (ast instanceof MalSymbol) { - MalSymbol sym = (MalSymbol)ast; - return env.get(sym.getName()); + return env.get((MalSymbol)ast); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; MalList new_lst = ast.list_Q() ? new MalList() @@ -124,7 +123,7 @@ public class stepA_interop { a1 = ast.nth(1); a2 = ast.nth(2); res = EVAL(a2, env); - env.set(((MalSymbol)a1).getName(), res); + env.set(((MalSymbol)a1), res); return res; case "let*": a1 = ast.nth(1); @@ -135,7 +134,7 @@ public class stepA_interop { for(int i=0; i<((MalList)a1).size(); i+=2) { key = (MalSymbol)((MalList)a1).nth(i); val = ((MalList)a1).nth(i+1); - let_env.set(key.getName(), EVAL(val, let_env)); + let_env.set(key, EVAL(val, let_env)); } orig_ast = a2; env = let_env; @@ -150,7 +149,7 @@ public class stepA_interop { a2 = ast.nth(2); res = EVAL(a2, env); ((MalFunction)res).setMacro(); - env.set(((MalSymbol)a1).getName(), res); + env.set((MalSymbol)a1, res); return res; case "macroexpand": a1 = ast.nth(1); @@ -239,9 +238,9 @@ public class stepA_interop { // core.java: defined using Java for (String key : core.ns.keySet()) { - repl_env.set(key, core.ns.get(key)); + repl_env.set(new MalSymbol(key), core.ns.get(key)); } - repl_env.set("eval", new MalFunction() { + repl_env.set(new MalSymbol("eval"), new MalFunction() { public MalVal apply(MalList args) throws MalThrowable { return EVAL(args.nth(0), repl_env); } @@ -250,7 +249,7 @@ public class stepA_interop { for (Integer i=1; i < args.length; i++) { _argv.conj_BANG(new MalString(args[i])); } - repl_env.set("*ARGV*", _argv); + repl_env.set(new MalSymbol("*ARGV*"), _argv); // core.mal: defined using the language itself diff --git a/java/src/main/java/mal/types.java b/java/src/main/java/mal/types.java index 7ad419a..a8a2dfa 100644 --- a/java/src/main/java/mal/types.java +++ b/java/src/main/java/mal/types.java @@ -134,6 +134,7 @@ public class types { public static class MalSymbol extends MalVal { String value; public MalSymbol(String v) { value = v; } + public MalSymbol(MalString v) { value = v.getValue(); } public MalSymbol copy() throws MalThrowable { return this; } public String getName() { return value; } @@ -152,7 +153,9 @@ public class types { return "\"" + value + "\""; } public String toString(Boolean print_readably) { - if (print_readably) { + if (value.length() > 0 && value.charAt(0) == '\u029e') { + return ":" + value.substring(1); + } else if (print_readably) { return "\"" + printer.escapeString(value) + "\""; } else { return value; -- cgit v1.2.3 From 90f618cbe7ac7740accf501a75be6972bd95be1a Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Sat, 28 Feb 2015 11:09:54 -0600 Subject: All: rename stepA_interop to stepA_mal Also, add missed postscript interop tests. --- java/src/main/java/mal/stepA_interop.java | 301 ------------------------------ java/src/main/java/mal/stepA_mal.java | 301 ++++++++++++++++++++++++++++++ 2 files changed, 301 insertions(+), 301 deletions(-) delete mode 100644 java/src/main/java/mal/stepA_interop.java create mode 100644 java/src/main/java/mal/stepA_mal.java (limited to 'java/src') diff --git a/java/src/main/java/mal/stepA_interop.java b/java/src/main/java/mal/stepA_interop.java deleted file mode 100644 index 1fa1125..0000000 --- a/java/src/main/java/mal/stepA_interop.java +++ /dev/null @@ -1,301 +0,0 @@ -package mal; - -import java.io.IOException; - -import java.io.StringWriter; -import java.io.PrintWriter; -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.Iterator; -import mal.types.*; -import mal.readline; -import mal.reader; -import mal.printer; -import mal.env.Env; -import mal.core; - -public class stepA_interop { - // read - public static MalVal READ(String str) throws MalThrowable { - return reader.read_str(str); - } - - // eval - public static Boolean is_pair(MalVal x) { - return x instanceof MalList && ((MalList)x).size() > 0; - } - - public static MalVal quasiquote(MalVal ast) { - if (!is_pair(ast)) { - return new MalList(new MalSymbol("quote"), ast); - } else { - MalVal a0 = ((MalList)ast).nth(0); - if ((a0 instanceof MalSymbol) && - (((MalSymbol)a0).getName() == "unquote")) { - return ((MalList)ast).nth(1); - } else if (is_pair(a0)) { - MalVal a00 = ((MalList)a0).nth(0); - if ((a00 instanceof MalSymbol) && - (((MalSymbol)a00).getName() == "splice-unquote")) { - return new MalList(new MalSymbol("concat"), - ((MalList)a0).nth(1), - quasiquote(((MalList)ast).rest())); - } - } - return new MalList(new MalSymbol("cons"), - quasiquote(a0), - quasiquote(((MalList)ast).rest())); - } - } - - public static Boolean is_macro_call(MalVal ast, Env env) - throws MalThrowable { - if (ast instanceof MalList) { - MalVal a0 = ((MalList)ast).nth(0); - if (a0 instanceof MalSymbol && - env.find(((MalSymbol)a0)) != null) { - MalVal mac = env.get(((MalSymbol)a0)); - if (mac instanceof MalFunction && - ((MalFunction)mac).isMacro()) { - return true; - } - } - } - return false; - } - - public static MalVal macroexpand(MalVal ast, Env env) - throws MalThrowable { - while (is_macro_call(ast, env)) { - MalSymbol a0 = (MalSymbol)((MalList)ast).nth(0); - MalFunction mac = (MalFunction) env.get(a0); - ast = mac.apply(((MalList)ast).rest()); - } - return ast; - } - - public static MalVal eval_ast(MalVal ast, Env env) throws MalThrowable { - if (ast instanceof MalSymbol) { - return env.get((MalSymbol)ast); - } else if (ast instanceof MalList) { - MalList old_lst = (MalList)ast; - MalList new_lst = ast.list_Q() ? new MalList() - : (MalList)new MalVector(); - for (MalVal mv : (List)old_lst.value) { - new_lst.conj_BANG(EVAL(mv, env)); - } - return new_lst; - } else if (ast instanceof MalHashMap) { - MalHashMap new_hm = new MalHashMap(); - Iterator it = ((MalHashMap)ast).value.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = (Map.Entry)it.next(); - new_hm.value.put(entry.getKey(), EVAL((MalVal)entry.getValue(), env)); - } - return new_hm; - } else { - return ast; - } - } - - public static MalVal EVAL(MalVal orig_ast, Env env) throws MalThrowable { - MalVal a0, a1,a2, a3, res; - MalList el; - - while (true) { - - //System.out.println("EVAL: " + printer._pr_str(orig_ast, true)); - if (!orig_ast.list_Q()) { - return eval_ast(orig_ast, env); - } - - // apply list - MalVal expanded = macroexpand(orig_ast, env); - if (!expanded.list_Q()) { return expanded; } - MalList ast = (MalList) expanded; - if (ast.size() == 0) { return ast; } - a0 = ast.nth(0); - String a0sym = a0 instanceof MalSymbol ? ((MalSymbol)a0).getName() - : "__<*fn*>__"; - switch (a0sym) { - case "def!": - a1 = ast.nth(1); - a2 = ast.nth(2); - res = EVAL(a2, env); - env.set(((MalSymbol)a1), res); - return res; - case "let*": - a1 = ast.nth(1); - a2 = ast.nth(2); - MalSymbol key; - MalVal val; - Env let_env = new Env(env); - for(int i=0; i<((MalList)a1).size(); i+=2) { - key = (MalSymbol)((MalList)a1).nth(i); - val = ((MalList)a1).nth(i+1); - let_env.set(key, EVAL(val, let_env)); - } - orig_ast = a2; - env = let_env; - break; - case "quote": - return ast.nth(1); - case "quasiquote": - orig_ast = quasiquote(ast.nth(1)); - break; - case "defmacro!": - a1 = ast.nth(1); - a2 = ast.nth(2); - res = EVAL(a2, env); - ((MalFunction)res).setMacro(); - env.set((MalSymbol)a1, res); - return res; - case "macroexpand": - a1 = ast.nth(1); - return macroexpand(a1, env); - case "try*": - try { - return EVAL(ast.nth(1), env); - } catch (Throwable t) { - if (ast.size() > 2) { - MalVal exc; - a2 = ast.nth(2); - MalVal a20 = ((MalList)a2).nth(0); - if (((MalSymbol)a20).getName().equals("catch*")) { - if (t instanceof MalException) { - exc = ((MalException)t).getValue(); - } else { - StringWriter sw = new StringWriter(); - t.printStackTrace(new PrintWriter(sw)); - String tstr = sw.toString(); - exc = new MalString(t.getMessage() + ": " + tstr); - } - return EVAL(((MalList)a2).nth(2), - new Env(env, ((MalList)a2).slice(1,2), - new MalList(exc))); - } - } - throw t; - } - case "do": - eval_ast(ast.slice(1, ast.size()-1), env); - orig_ast = ast.nth(ast.size()-1); - break; - case "if": - a1 = ast.nth(1); - MalVal cond = EVAL(a1, env); - if (cond == types.Nil || cond == types.False) { - // eval false slot form - if (ast.size() > 3) { - orig_ast = ast.nth(3); - } else { - return types.Nil; - } - } else { - // eval true slot form - orig_ast = ast.nth(2); - } - break; - case "fn*": - final MalList a1f = (MalList)ast.nth(1); - final MalVal a2f = ast.nth(2); - final Env cur_env = env; - return new MalFunction (a2f, (mal.env.Env)env, a1f) { - public MalVal apply(MalList args) throws MalThrowable { - return EVAL(a2f, new Env(cur_env, a1f, args)); - } - }; - default: - el = (MalList)eval_ast(ast, env); - MalFunction f = (MalFunction)el.nth(0); - MalVal fnast = f.getAst(); - if (fnast != null) { - orig_ast = fnast; - env = f.genEnv(el.slice(1)); - } else { - return f.apply(el.rest()); - } - } - - } - } - - // print - public static String PRINT(MalVal exp) { - return printer._pr_str(exp, true); - } - - // repl - public static MalVal RE(Env env, String str) throws MalThrowable { - return EVAL(READ(str), env); - } - - public static void main(String[] args) throws MalThrowable { - String prompt = "user> "; - - final Env repl_env = new Env(null); - - // core.java: defined using Java - for (String key : core.ns.keySet()) { - repl_env.set(new MalSymbol(key), core.ns.get(key)); - } - repl_env.set(new MalSymbol("eval"), new MalFunction() { - public MalVal apply(MalList args) throws MalThrowable { - return EVAL(args.nth(0), repl_env); - } - }); - MalList _argv = new MalList(); - for (Integer i=1; i < args.length; i++) { - _argv.conj_BANG(new MalString(args[i])); - } - repl_env.set(new MalSymbol("*ARGV*"), _argv); - - - // core.mal: defined using the language itself - RE(repl_env, "(def! *host-language* \"java\")"); - RE(repl_env, "(def! not (fn* (a) (if a false true)))"); - RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"); - RE(repl_env, "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))"); - RE(repl_env, "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))"); - - Integer fileIdx = 0; - if (args.length > 0 && args[0].equals("--raw")) { - readline.mode = readline.Mode.JAVA; - fileIdx = 1; - } - if (args.length > fileIdx) { - RE(repl_env, "(load-file \"" + args[fileIdx] + "\")"); - return; - } - - // repl loop - RE(repl_env, "(println (str \"Mal [\" *host-language* \"]\"))"); - while (true) { - String line; - try { - line = readline.readline(prompt); - if (line == null) { continue; } - } catch (readline.EOFException e) { - break; - } catch (IOException e) { - System.out.println("IOException: " + e.getMessage()); - break; - } - try { - System.out.println(PRINT(RE(repl_env, line))); - } catch (MalContinue e) { - continue; - } catch (MalException e) { - System.out.println("Error: " + printer._pr_str(e.getValue(), false)); - continue; - } catch (MalThrowable t) { - System.out.println("Error: " + t.getMessage()); - continue; - } catch (Throwable t) { - System.out.println("Uncaught " + t + ": " + t.getMessage()); - continue; - } - } - } -} diff --git a/java/src/main/java/mal/stepA_mal.java b/java/src/main/java/mal/stepA_mal.java new file mode 100644 index 0000000..f8d4056 --- /dev/null +++ b/java/src/main/java/mal/stepA_mal.java @@ -0,0 +1,301 @@ +package mal; + +import java.io.IOException; + +import java.io.StringWriter; +import java.io.PrintWriter; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Iterator; +import mal.types.*; +import mal.readline; +import mal.reader; +import mal.printer; +import mal.env.Env; +import mal.core; + +public class stepA_mal { + // read + public static MalVal READ(String str) throws MalThrowable { + return reader.read_str(str); + } + + // eval + public static Boolean is_pair(MalVal x) { + return x instanceof MalList && ((MalList)x).size() > 0; + } + + public static MalVal quasiquote(MalVal ast) { + if (!is_pair(ast)) { + return new MalList(new MalSymbol("quote"), ast); + } else { + MalVal a0 = ((MalList)ast).nth(0); + if ((a0 instanceof MalSymbol) && + (((MalSymbol)a0).getName() == "unquote")) { + return ((MalList)ast).nth(1); + } else if (is_pair(a0)) { + MalVal a00 = ((MalList)a0).nth(0); + if ((a00 instanceof MalSymbol) && + (((MalSymbol)a00).getName() == "splice-unquote")) { + return new MalList(new MalSymbol("concat"), + ((MalList)a0).nth(1), + quasiquote(((MalList)ast).rest())); + } + } + return new MalList(new MalSymbol("cons"), + quasiquote(a0), + quasiquote(((MalList)ast).rest())); + } + } + + public static Boolean is_macro_call(MalVal ast, Env env) + throws MalThrowable { + if (ast instanceof MalList) { + MalVal a0 = ((MalList)ast).nth(0); + if (a0 instanceof MalSymbol && + env.find(((MalSymbol)a0)) != null) { + MalVal mac = env.get(((MalSymbol)a0)); + if (mac instanceof MalFunction && + ((MalFunction)mac).isMacro()) { + return true; + } + } + } + return false; + } + + public static MalVal macroexpand(MalVal ast, Env env) + throws MalThrowable { + while (is_macro_call(ast, env)) { + MalSymbol a0 = (MalSymbol)((MalList)ast).nth(0); + MalFunction mac = (MalFunction) env.get(a0); + ast = mac.apply(((MalList)ast).rest()); + } + return ast; + } + + public static MalVal eval_ast(MalVal ast, Env env) throws MalThrowable { + if (ast instanceof MalSymbol) { + return env.get((MalSymbol)ast); + } else if (ast instanceof MalList) { + MalList old_lst = (MalList)ast; + MalList new_lst = ast.list_Q() ? new MalList() + : (MalList)new MalVector(); + for (MalVal mv : (List)old_lst.value) { + new_lst.conj_BANG(EVAL(mv, env)); + } + return new_lst; + } else if (ast instanceof MalHashMap) { + MalHashMap new_hm = new MalHashMap(); + Iterator it = ((MalHashMap)ast).value.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = (Map.Entry)it.next(); + new_hm.value.put(entry.getKey(), EVAL((MalVal)entry.getValue(), env)); + } + return new_hm; + } else { + return ast; + } + } + + public static MalVal EVAL(MalVal orig_ast, Env env) throws MalThrowable { + MalVal a0, a1,a2, a3, res; + MalList el; + + while (true) { + + //System.out.println("EVAL: " + printer._pr_str(orig_ast, true)); + if (!orig_ast.list_Q()) { + return eval_ast(orig_ast, env); + } + + // apply list + MalVal expanded = macroexpand(orig_ast, env); + if (!expanded.list_Q()) { return expanded; } + MalList ast = (MalList) expanded; + if (ast.size() == 0) { return ast; } + a0 = ast.nth(0); + String a0sym = a0 instanceof MalSymbol ? ((MalSymbol)a0).getName() + : "__<*fn*>__"; + switch (a0sym) { + case "def!": + a1 = ast.nth(1); + a2 = ast.nth(2); + res = EVAL(a2, env); + env.set(((MalSymbol)a1), res); + return res; + case "let*": + a1 = ast.nth(1); + a2 = ast.nth(2); + MalSymbol key; + MalVal val; + Env let_env = new Env(env); + for(int i=0; i<((MalList)a1).size(); i+=2) { + key = (MalSymbol)((MalList)a1).nth(i); + val = ((MalList)a1).nth(i+1); + let_env.set(key, EVAL(val, let_env)); + } + orig_ast = a2; + env = let_env; + break; + case "quote": + return ast.nth(1); + case "quasiquote": + orig_ast = quasiquote(ast.nth(1)); + break; + case "defmacro!": + a1 = ast.nth(1); + a2 = ast.nth(2); + res = EVAL(a2, env); + ((MalFunction)res).setMacro(); + env.set((MalSymbol)a1, res); + return res; + case "macroexpand": + a1 = ast.nth(1); + return macroexpand(a1, env); + case "try*": + try { + return EVAL(ast.nth(1), env); + } catch (Throwable t) { + if (ast.size() > 2) { + MalVal exc; + a2 = ast.nth(2); + MalVal a20 = ((MalList)a2).nth(0); + if (((MalSymbol)a20).getName().equals("catch*")) { + if (t instanceof MalException) { + exc = ((MalException)t).getValue(); + } else { + StringWriter sw = new StringWriter(); + t.printStackTrace(new PrintWriter(sw)); + String tstr = sw.toString(); + exc = new MalString(t.getMessage() + ": " + tstr); + } + return EVAL(((MalList)a2).nth(2), + new Env(env, ((MalList)a2).slice(1,2), + new MalList(exc))); + } + } + throw t; + } + case "do": + eval_ast(ast.slice(1, ast.size()-1), env); + orig_ast = ast.nth(ast.size()-1); + break; + case "if": + a1 = ast.nth(1); + MalVal cond = EVAL(a1, env); + if (cond == types.Nil || cond == types.False) { + // eval false slot form + if (ast.size() > 3) { + orig_ast = ast.nth(3); + } else { + return types.Nil; + } + } else { + // eval true slot form + orig_ast = ast.nth(2); + } + break; + case "fn*": + final MalList a1f = (MalList)ast.nth(1); + final MalVal a2f = ast.nth(2); + final Env cur_env = env; + return new MalFunction (a2f, (mal.env.Env)env, a1f) { + public MalVal apply(MalList args) throws MalThrowable { + return EVAL(a2f, new Env(cur_env, a1f, args)); + } + }; + default: + el = (MalList)eval_ast(ast, env); + MalFunction f = (MalFunction)el.nth(0); + MalVal fnast = f.getAst(); + if (fnast != null) { + orig_ast = fnast; + env = f.genEnv(el.slice(1)); + } else { + return f.apply(el.rest()); + } + } + + } + } + + // print + public static String PRINT(MalVal exp) { + return printer._pr_str(exp, true); + } + + // repl + public static MalVal RE(Env env, String str) throws MalThrowable { + return EVAL(READ(str), env); + } + + public static void main(String[] args) throws MalThrowable { + String prompt = "user> "; + + final Env repl_env = new Env(null); + + // core.java: defined using Java + for (String key : core.ns.keySet()) { + repl_env.set(new MalSymbol(key), core.ns.get(key)); + } + repl_env.set(new MalSymbol("eval"), new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + return EVAL(args.nth(0), repl_env); + } + }); + MalList _argv = new MalList(); + for (Integer i=1; i < args.length; i++) { + _argv.conj_BANG(new MalString(args[i])); + } + repl_env.set(new MalSymbol("*ARGV*"), _argv); + + + // core.mal: defined using the language itself + RE(repl_env, "(def! *host-language* \"java\")"); + RE(repl_env, "(def! not (fn* (a) (if a false true)))"); + RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"); + RE(repl_env, "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))"); + RE(repl_env, "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))"); + + Integer fileIdx = 0; + if (args.length > 0 && args[0].equals("--raw")) { + readline.mode = readline.Mode.JAVA; + fileIdx = 1; + } + if (args.length > fileIdx) { + RE(repl_env, "(load-file \"" + args[fileIdx] + "\")"); + return; + } + + // repl loop + RE(repl_env, "(println (str \"Mal [\" *host-language* \"]\"))"); + while (true) { + String line; + try { + line = readline.readline(prompt); + if (line == null) { continue; } + } catch (readline.EOFException e) { + break; + } catch (IOException e) { + System.out.println("IOException: " + e.getMessage()); + break; + } + try { + System.out.println(PRINT(RE(repl_env, line))); + } catch (MalContinue e) { + continue; + } catch (MalException e) { + System.out.println("Error: " + printer._pr_str(e.getValue(), false)); + continue; + } catch (MalThrowable t) { + System.out.println("Error: " + t.getMessage()); + continue; + } catch (Throwable t) { + System.out.println("Uncaught " + t + ": " + t.getMessage()); + continue; + } + } + } +} -- cgit v1.2.3