diff options
| author | Joel Martin <github@martintribe.org> | 2014-04-02 22:23:37 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-04-02 22:23:37 -0500 |
| commit | ea81a8087bcd7953b083a2be9db447f75e7ebf56 (patch) | |
| tree | 6cf47a2dbd55d42efc4a901eaabdec952f40ce89 /java | |
| parent | 1617910ad342a55762f3ddabb975849d843cff85 (diff) | |
| download | mal-ea81a8087bcd7953b083a2be9db447f75e7ebf56.tar.gz mal-ea81a8087bcd7953b083a2be9db447f75e7ebf56.zip | |
All: split types into types, env, printer, core.
- types: low-level mapping to the implementation language.
- core: functions on types that are exposed directly to mal.
- printer: implementation called by pr-str, str, prn, println.
- env: the environment implementation
- Also, unindent all TCO while loops so that the diff of step4 and
step5 are minimized.
Diffstat (limited to 'java')
| -rw-r--r-- | java/Makefile | 6 | ||||
| -rw-r--r-- | java/src/main/java/mal/core.java | 470 | ||||
| -rw-r--r-- | java/src/main/java/mal/env.java | 57 | ||||
| -rw-r--r-- | java/src/main/java/mal/printer.java | 50 | ||||
| -rw-r--r-- | java/src/main/java/mal/step1_read_print.java | 5 | ||||
| -rw-r--r-- | java/src/main/java/mal/step2_eval.java | 20 | ||||
| -rw-r--r-- | java/src/main/java/mal/step3_env.java | 27 | ||||
| -rw-r--r-- | java/src/main/java/mal/step4_if_fn_do.java | 23 | ||||
| -rw-r--r-- | java/src/main/java/mal/step5_tco.java | 27 | ||||
| -rw-r--r-- | java/src/main/java/mal/step6_file.java | 25 | ||||
| -rw-r--r-- | java/src/main/java/mal/step7_quote.java | 29 | ||||
| -rw-r--r-- | java/src/main/java/mal/step8_macros.java | 33 | ||||
| -rw-r--r-- | java/src/main/java/mal/stepA_more.java | 35 | ||||
| -rw-r--r-- | java/src/main/java/mal/types.java | 654 |
14 files changed, 768 insertions, 693 deletions
diff --git a/java/Makefile b/java/Makefile index 8559a05..e6312a3 100644 --- a/java/Makefile +++ b/java/Makefile @@ -2,8 +2,10 @@ TESTS = -SOURCES = src/main/java/mal/types.java src/main/java/mal/readline.java \ - src/main/java/mal/reader.java src/main/java/mal/stepA_more.java +SOURCES = src/main/java/mal/readline.java src/main/java/mal/types.java \ + src/main/java/mal/reader.java src/main/java/mal/printer.java \ + src/main/java/mal/env.java src/main/java/mal/core.java \ + src/main/java/mal/stepA_more.java #.PHONY: stats tests $(TESTS) .PHONY: stats diff --git a/java/src/main/java/mal/core.java b/java/src/main/java/mal/core.java new file mode 100644 index 0000000..3200c0e --- /dev/null +++ b/java/src/main/java/mal/core.java @@ -0,0 +1,470 @@ +package mal; + +import java.util.List; +import java.util.ArrayList; +import java.util.Set; +import java.util.Map; +import java.util.HashMap; +import com.google.common.collect.ImmutableMap; + +import mal.types.*; +import mal.printer; + +public class core { + // Local references for convenience + static MalConstant Nil = mal.types.Nil; + static MalConstant True = mal.types.True; + static MalConstant False = mal.types.False; + + + // Errors/Exceptions + static MalFunction mal_throw = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + throw new MalException(a.nth(0)); + } + }; + + + // Scalar functions + static MalFunction nil_Q = new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + return args.nth(0) == Nil ? True : False; + } + }; + + static MalFunction true_Q = new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + return args.nth(0) == True ? True : False; + } + }; + + static MalFunction false_Q = new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + return args.nth(0) == False ? True : False; + } + }; + static MalFunction symbol_Q = new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + return args.nth(0) instanceof MalSymbol ? True : False; + } + }; + + + // String functions + static MalFunction pr_str = new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + return new MalString(printer._pr_str_args(args, " ", true)); + } + }; + + static MalFunction str = new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + return new MalString(printer._pr_str_args(args, "", false)); + } + }; + + static MalFunction prn = new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + System.out.println(printer._pr_str_args(args, " ", true)); + return Nil; + } + }; + + static MalFunction println = new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + System.out.println(printer._pr_str_args(args, " ", false)); + return Nil; + } + }; + + + static MalFunction equal_Q = new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + return types._equal_Q(args.nth(0), args.nth(1)) ? True : False; + } + }; + + + // Number functions + static MalFunction add = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return ((MalInteger)a.nth(0)).add((MalInteger)a.nth(1)); + } + }; + static MalFunction subtract = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return ((MalInteger)a.nth(0)).subtract((MalInteger)a.nth(1)); + } + }; + static MalFunction multiply = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return ((MalInteger)a.nth(0)).multiply((MalInteger)a.nth(1)); + } + }; + static MalFunction divide = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return ((MalInteger)a.nth(0)).divide((MalInteger)a.nth(1)); + } + }; + + static MalFunction lt = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return ((MalInteger)a.nth(0)).lt((MalInteger)a.nth(1)); + } + }; + static MalFunction lte = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return ((MalInteger)a.nth(0)).lte((MalInteger)a.nth(1)); + } + }; + static MalFunction gt = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return ((MalInteger)a.nth(0)).gt((MalInteger)a.nth(1)); + } + }; + static MalFunction gte = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return ((MalInteger)a.nth(0)).gte((MalInteger)a.nth(1)); + } + }; + + + // List functions + static MalFunction new_list = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return new MalList(a.value); + } + }; + + static public Boolean _list_Q(MalVal mv) { + return mv.getClass().equals(MalList.class); + } + static MalFunction list_Q = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return _list_Q(a.nth(0)) ? True : False; + } + }; + + + // Vector functions + static MalFunction new_vector = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return new MalVector(a.value); + } + }; + + static public Boolean _vector_Q(MalVal mv) { + return mv.getClass().equals(MalVector.class); + } + static MalFunction vector_Q = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return _vector_Q(a.nth(0)) ? True : False; + } + }; + + // + // Hash map operations + // + static MalFunction new_hash_map = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return new MalHashMap(a); + } + }; + static MalFunction hash_map_Q = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return a.nth(0) instanceof MalHashMap ? True : False; + } + }; + + static MalFunction contains_Q = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + String key = ((MalString)a.nth(1)).getValue(); + MalHashMap mhm = (MalHashMap)a.nth(0); + HashMap<String,MalVal> hm = (HashMap<String,MalVal>)mhm.value; + return hm.containsKey(key) ? True : False; + } + }; + + static MalFunction assoc = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + MalHashMap mhm = (MalHashMap)a.nth(0); + HashMap<String,MalVal> hm = (HashMap<String,MalVal>)mhm.value; + MalHashMap new_mhm = new MalHashMap((Map)hm.clone()); + new_mhm.assoc_BANG((MalList)a.slice(1)); + return new_mhm; + } + }; + + static MalFunction dissoc = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + MalHashMap mhm = (MalHashMap)a.nth(0); + HashMap<String,MalVal> hm = (HashMap<String,MalVal>)mhm.value; + MalHashMap new_mhm = new MalHashMap((Map)hm.clone()); + new_mhm.dissoc_BANG((MalList)a.slice(1)); + return new_mhm; + } + }; + + static MalFunction get = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + String key = ((MalString)a.nth(1)).getValue(); + MalHashMap mhm = (MalHashMap)a.nth(0); + HashMap<String,MalVal> hm = (HashMap<String,MalVal>)mhm.value; + if (hm.containsKey(key)) { + return hm.get(key); + } else { + return Nil; + } + } + }; + + static MalFunction keys = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + MalHashMap mhm = (MalHashMap)a.nth(0); + HashMap<String,MalVal> hm = (HashMap<String,MalVal>)mhm.value; + MalList key_lst = new MalList(); + for (String key : hm.keySet()) { + key_lst.conj_BANG(new MalString(key)); + } + return key_lst; + } + }; + + static MalFunction vals = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + MalHashMap mhm = (MalHashMap)a.nth(0); + HashMap<String,MalVal> hm = (HashMap<String,MalVal>)mhm.value; + //return new ArrayList<MalVal>(((HashMap<String,MalVal>)hm).values()); + MalList val_lst = new MalList(); + for (MalVal val : hm.values()) { + val_lst.conj_BANG(val); + } + return val_lst; + } + }; + + + // Sequence functions + static MalFunction sequential_Q = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return a.nth(0) instanceof MalList ? True : False; + } + }; + + static MalFunction count = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return new MalInteger(((MalList)a.nth(0)).size()); + } + }; + + static MalFunction empty_Q = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + MalVal exp = a.nth(0); + if (exp == Nil || (exp instanceof MalList && + ((MalList)exp).size() == 0)) { + return True; + } else { + return False; + } + } + }; + + static MalFunction cons = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + MalList lst = new MalList(); + lst.value.addAll(((MalList)a.nth(1)).value); + lst.value.add(0, a.nth(0)); + return (MalVal) lst; + } + }; + + static MalFunction concat = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + if (a.size() == 0) { return new MalList(); } + MalList lst = new MalList(); + lst.value.addAll(((MalList)a.nth(0)).value); + for(Integer i=1; i<a.size(); i++) { + lst.value.addAll(((MalList)a.nth(i)).value); + } + return (MalVal) lst; + } + }; + + static MalFunction conj = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + MalList src_seq = (MalList)a.nth(0), new_seq; + if (a.nth(0) instanceof MalVector) { + new_seq = new MalVector(); + new_seq.value.addAll(src_seq.value); + for(Integer i=1; i<a.size(); i++) { + new_seq.value.add(a.nth(i)); + } + } else { + new_seq = new MalList(); + new_seq.value.addAll(src_seq.value); + for(Integer i=1; i<a.size(); i++) { + new_seq.value.add(0, a.nth(i)); + } + } + return (MalVal) new_seq; + } + }; + + static MalFunction first = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + MalList ml = ((MalList)a.nth(0)); + return ml.size() > 0 ? ml.nth(0) : Nil; + } + }; + + static MalFunction rest = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + MalList ml = ((MalList)a.nth(0)); + return ml.rest(); + } + }; + + 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); + } + }; + + // General list related functions + static MalFunction apply = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + MalFunction f = (MalFunction)a.nth(0); + MalList args = a.slice(1,a.size()-1); + args.value.addAll( ((MalList)a.nth(a.size()-1)).value); + return f.apply(args); + } + }; + + static MalFunction map = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + MalFunction f = (MalFunction) a.nth(0); + MalList src_lst = (MalList) a.nth(1); + MalList new_lst = new MalList(); + for(Integer i=0; i<src_lst.size(); i++) { + new_lst.value.add( + f.apply(new MalList(src_lst.nth(i)))); + } + return new_lst; + } + }; + + + // Metadata functions + + static MalFunction meta = new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + return args.nth(0).getMeta(); + } + }; + + static MalFunction with_meta = new MalFunction() { + public MalVal apply(MalList args) throws MalThrowable { + MalVal new_mv = ((MalVal)args.nth(0)).copy(); + new_mv.setMeta(args.nth(1)); + return new_mv; + } + }; + + + // Atom functions + static MalFunction new_atom = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return new MalAtom(a.nth(0)); + } + }; + + static MalFunction atom_Q = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return a.nth(0) instanceof MalAtom ? True : False; + } + }; + + static MalFunction deref = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return ((MalAtom)a.nth(0)).value; + } + }; + + static MalFunction reset_BANG = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + return ((MalAtom)a.nth(0)).value = a.nth(1); + } + }; + + static MalFunction swap_BANG = new MalFunction() { + public MalVal apply(MalList a) throws MalThrowable { + MalAtom atm = (MalAtom)a.nth(0); + MalFunction f = (MalFunction)a.nth(1); + MalList new_args = new MalList(); + new_args.value.addAll(((MalList)a.slice(2)).value); + new_args.value.add(0, atm.value); + atm.value = f.apply(new_args); + return atm.value; + } + }; + + + + + + // types_ns is namespace of type functions + static Map<String, MalVal> ns = ImmutableMap.<String, MalVal>builder() + .put("=", equal_Q) + .put("throw", mal_throw) + .put("nil?", nil_Q) + .put("true?", true_Q) + .put("false?", false_Q) + .put("symbol?", symbol_Q) + .put("pr-str", pr_str) + .put("str", str) + .put("prn", prn) + .put("println", println) + .put("<", lt) + .put("<=", lte) + .put(">", gt) + .put(">=", gte) + .put("+", add) + .put("-", subtract) + .put("*", multiply) + .put("/", divide) + + .put("list", new_list) + .put("list?", list_Q) + .put("vector", new_vector) + .put("vector?", vector_Q) + .put("hash-map", new_hash_map) + .put("map?", hash_map_Q) + .put("assoc", assoc) + .put("dissoc", dissoc) + .put("contains?", contains_Q) + .put("get", get) + .put("keys", keys) + .put("vals", vals) + + .put("sequential?", sequential_Q) + .put("cons", cons) + .put("concat", concat) + .put("nth", nth) + .put("first", first) + .put("rest", rest) + .put("empty?", empty_Q) + .put("count", count) + .put("conj", conj) + .put("apply", apply) + .put("map", map) + + .put("with-meta", with_meta) + .put("meta", meta) + .put("atom", new_atom) + .put("atom?", atom_Q) + .put("deref", deref) + .put("reset!", reset_BANG) + .put("swap!", swap_BANG) + .build(); +} diff --git a/java/src/main/java/mal/env.java b/java/src/main/java/mal/env.java new file mode 100644 index 0000000..8a1913e --- /dev/null +++ b/java/src/main/java/mal/env.java @@ -0,0 +1,57 @@ +package mal; + +import java.util.HashMap; + +import mal.types.MalThrowable; +import mal.types.MalException; +import mal.types.MalVal; +import mal.types.MalSymbol; +import mal.types.MalList; + +public class env { + public static class Env { + Env outer = null; + HashMap<String,MalVal> data = new HashMap<String,MalVal>(); + + public Env(Env outer) { + this.outer = outer; + } + public Env(Env outer, MalList binds, MalList exprs) { + this.outer = outer; + for (Integer i=0; i<binds.size(); i++) { + String sym = ((MalSymbol)binds.nth(i)).getName(); + if (sym.equals("&")) { + data.put(((MalSymbol)binds.nth(i+1)).getName(), + exprs.slice(i)); + break; + } else { + data.put(sym, exprs.nth(i)); + } + } + } + + public Env find(String key) { + if (data.containsKey(key)) { + return this; + } else if (outer != null) { + return outer.find(key); + } else { + return null; + } + } + + public MalVal get(String key) throws MalThrowable { + Env e = find(key); + if (e == null) { + throw new MalException("'" + key + "' not found"); + } else { + return e.data.get(key); + } + } + + public Env set(String key, MalVal value) { + data.put(key, value); + return this; + } + } +} diff --git a/java/src/main/java/mal/printer.java b/java/src/main/java/mal/printer.java new file mode 100644 index 0000000..73dfca3 --- /dev/null +++ b/java/src/main/java/mal/printer.java @@ -0,0 +1,50 @@ +package mal; + +import java.util.List; +import java.util.ArrayList; +import com.google.common.base.Joiner; +import java.util.Map; +import org.apache.commons.lang3.StringEscapeUtils; + +import mal.types.MalVal; +import mal.types.MalList; + +public class printer { + + public static String join(List<MalVal> value, + String delim, Boolean print_readably) { + ArrayList<String> strs = new ArrayList<String>(); + for (MalVal mv : value) { + strs.add(mv.toString(print_readably)); + } + return Joiner.on(delim).join(strs); + } + + public static String join(Map<String,MalVal> value, + String delim, Boolean print_readably) { + ArrayList<String> strs = new ArrayList<String>(); + for (Map.Entry<String, MalVal> entry : value.entrySet()) { + if (print_readably) { + strs.add("\"" + entry.getKey().toString() + "\""); + } else { + strs.add(entry.getKey().toString()); + } + strs.add(entry.getValue().toString(print_readably)); + } + return Joiner.on(" ").join(strs); + } + + public static String _pr_str(MalVal mv, + Boolean print_readably) { + return mv.toString(print_readably); + } + + public static String _pr_str_args(MalList args, + String sep, Boolean print_readably) { + return join(args.getList(), sep, print_readably); + } + + public static String escapeString(String value) { + return StringEscapeUtils.escapeJson(value); + } +} diff --git a/java/src/main/java/mal/step1_read_print.java b/java/src/main/java/mal/step1_read_print.java index 447afc5..3f7e3fb 100644 --- a/java/src/main/java/mal/step1_read_print.java +++ b/java/src/main/java/mal/step1_read_print.java @@ -5,6 +5,7 @@ import java.io.IOException; import mal.types.*; import mal.readline; import mal.reader; +import mal.printer; public class step1_read_print { // read @@ -19,7 +20,7 @@ public class step1_read_print { // print public static String PRINT(MalVal exp) { - return types._pr_str(exp, true); + return printer._pr_str(exp, true); } // REPL @@ -30,7 +31,7 @@ public class step1_read_print { public static void main(String[] args) throws MalThrowable { String prompt = "user> "; - if (args[0].equals("--raw")) { + if (args.length > 0 && args[0].equals("--raw")) { readline.mode = readline.Mode.JAVA; } while (true) { diff --git a/java/src/main/java/mal/step2_eval.java b/java/src/main/java/mal/step2_eval.java index e1b30a9..3d425db 100644 --- a/java/src/main/java/mal/step2_eval.java +++ b/java/src/main/java/mal/step2_eval.java @@ -9,6 +9,7 @@ import java.util.Iterator; import mal.types.*; import mal.readline; import mal.reader; +import mal.printer; public class step2_eval { // read @@ -23,8 +24,8 @@ public class step2_eval { return (MalVal)env.get(sym.getName()); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; - MalList new_lst = types._list_Q(ast) ? new MalList() - : (MalList)new MalVector(); + MalList new_lst = ast.list_Q() ? new MalList() + : (MalList)new MalVector(); for (MalVal mv : (List<MalVal>)old_lst.value) { new_lst.conj_BANG(EVAL(mv, env)); } @@ -44,8 +45,8 @@ public class step2_eval { public static MalVal EVAL(MalVal orig_ast, HashMap env) throws MalThrowable { MalVal a0; - //System.out.println("EVAL: " + types._pr_str(orig_ast, true)); - if (!(types._list_Q(orig_ast))) { + //System.out.println("EVAL: " + printer._pr_str(orig_ast, true)); + if (!orig_ast.list_Q()) { return eval_ast(orig_ast, env); } @@ -55,17 +56,20 @@ public class step2_eval { a0 = ast.nth(0); if (!(a0 instanceof MalSymbol)) { throw new MalError("attempt to apply on non-symbol '" - + types._pr_str(a0,true) + "'"); + + printer._pr_str(a0,true) + "'"); } - MalVal args = eval_ast(types._rest(ast), env); + MalVal args = eval_ast(ast.rest(), env); MalSymbol fsym = (MalSymbol)a0; ILambda f = (ILambda)env.get(fsym.getName()); + if (f == null) { + throw new MalError("'" + fsym.getName() + "' not found"); + } return f.apply((MalList)args); } // print public static String PRINT(MalVal exp) { - return types._pr_str(exp, true); + return printer._pr_str(exp, true); } // REPL @@ -110,7 +114,7 @@ public class step2_eval { repl_env.put("*", new multiply()); repl_env.put("/", new divide()); - if (args[0].equals("--raw")) { + if (args.length > 0 && args[0].equals("--raw")) { readline.mode = readline.Mode.JAVA; } while (true) { diff --git a/java/src/main/java/mal/step3_env.java b/java/src/main/java/mal/step3_env.java index 867dba1..690469e 100644 --- a/java/src/main/java/mal/step3_env.java +++ b/java/src/main/java/mal/step3_env.java @@ -9,6 +9,9 @@ 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 step3_env { // read @@ -23,8 +26,8 @@ public class step3_env { return env.get(sym.getName()); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; - MalList new_lst = types._list_Q(ast) ? new MalList() - : (MalList)new MalVector(); + MalList new_lst = ast.list_Q() ? new MalList() + : (MalList)new MalVector(); for (MalVal mv : (List<MalVal>)old_lst.value) { new_lst.conj_BANG(EVAL(mv, env)); } @@ -44,8 +47,8 @@ public class step3_env { public static MalVal EVAL(MalVal orig_ast, Env env) throws MalThrowable { MalVal a0, a1,a2, res; - //System.out.println("EVAL: " + types._pr_str(orig_ast, true)); - if (!(types._list_Q(orig_ast))) { + //System.out.println("EVAL: " + printer._pr_str(orig_ast, true)); + if (!orig_ast.list_Q()) { return eval_ast(orig_ast, env); } @@ -55,7 +58,7 @@ public class step3_env { a0 = ast.nth(0); if (!(a0 instanceof MalSymbol)) { throw new MalError("attempt to apply on non-symbol '" - + types._pr_str(a0,true) + "'"); + + printer._pr_str(a0,true) + "'"); } switch (((MalSymbol)a0).getName()) { @@ -78,7 +81,7 @@ public class step3_env { } return EVAL(a2, let_env); default: - MalVal args = eval_ast(types._rest(ast), env); + MalVal args = eval_ast(ast.rest(), env); MalSymbol fsym = (MalSymbol)a0; ILambda f = (ILambda)env.get(fsym.getName()); return f.apply((MalList)args); @@ -87,7 +90,7 @@ public class step3_env { // print public static String PRINT(MalVal exp) { - return types._pr_str(exp, true); + return printer._pr_str(exp, true); } // REPL @@ -102,12 +105,12 @@ public class step3_env { String prompt = "user> "; Env repl_env = new Env(null); - _ref(repl_env, "+", types.add); - _ref(repl_env, "-", types.subtract); - _ref(repl_env, "*", types.multiply); - _ref(repl_env, "/", types.divide); + _ref(repl_env, "+", core.add); + _ref(repl_env, "-", core.subtract); + _ref(repl_env, "*", core.multiply); + _ref(repl_env, "/", core.divide); - if (args[0].equals("--raw")) { + if (args.length > 0 && args[0].equals("--raw")) { readline.mode = readline.Mode.JAVA; } while (true) { 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 7501b50..4d064cf 100644 --- a/java/src/main/java/mal/step4_if_fn_do.java +++ b/java/src/main/java/mal/step4_if_fn_do.java @@ -9,6 +9,9 @@ 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 step4_if_fn_do { // read @@ -23,8 +26,8 @@ public class step4_if_fn_do { return env.get(sym.getName()); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; - MalList new_lst = types._list_Q(ast) ? new MalList() - : (MalList)new MalVector(); + MalList new_lst = ast.list_Q() ? new MalList() + : (MalList)new MalVector(); for (MalVal mv : (List<MalVal>)old_lst.value) { new_lst.conj_BANG(EVAL(mv, env)); } @@ -45,8 +48,8 @@ public class step4_if_fn_do { public static MalVal EVAL(MalVal orig_ast, Env env) throws MalThrowable { MalVal a0, a1,a2, a3, res; MalList el; - //System.out.println("EVAL: " + types._pr_str(orig_ast, true)); - if (!(types._list_Q(orig_ast))) { + //System.out.println("EVAL: " + printer._pr_str(orig_ast, true)); + if (!orig_ast.list_Q()) { return eval_ast(orig_ast, env); } @@ -76,7 +79,7 @@ public class step4_if_fn_do { } return EVAL(a2, let_env); case "do": - el = (MalList)eval_ast(types._rest(ast), env); + el = (MalList)eval_ast(ast.rest(), env); return el.nth(el.size()-1); case "if": a1 = ast.nth(1); @@ -106,13 +109,13 @@ public class step4_if_fn_do { default: el = (MalList)eval_ast(ast, env); MalFunction f = (MalFunction)el.nth(0); - return f.apply(types._rest(el)); + return f.apply(el.rest()); } } // print public static String PRINT(MalVal exp) { - return types._pr_str(exp, true); + return printer._pr_str(exp, true); } // REPL @@ -127,13 +130,13 @@ public class step4_if_fn_do { String prompt = "user> "; Env repl_env = new Env(null); - for (String key : types.types_ns.keySet()) { - _ref(repl_env, key, types.types_ns.get(key)); + for (String key : core.ns.keySet()) { + _ref(repl_env, key, core.ns.get(key)); } RE(repl_env, "(def! not (fn* (a) (if a false true)))"); - if (args[0].equals("--raw")) { + if (args.length > 0 && args[0].equals("--raw")) { readline.mode = readline.Mode.JAVA; } while (true) { diff --git a/java/src/main/java/mal/step5_tco.java b/java/src/main/java/mal/step5_tco.java index 41b295b..43b93c6 100644 --- a/java/src/main/java/mal/step5_tco.java +++ b/java/src/main/java/mal/step5_tco.java @@ -9,6 +9,9 @@ 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 step5_tco { // read @@ -23,8 +26,8 @@ public class step5_tco { return env.get(sym.getName()); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; - MalList new_lst = types._list_Q(ast) ? new MalList() - : (MalList)new MalVector(); + MalList new_lst = ast.list_Q() ? new MalList() + : (MalList)new MalVector(); for (MalVal mv : (List<MalVal>)old_lst.value) { new_lst.conj_BANG(EVAL(mv, env)); } @@ -43,20 +46,20 @@ public class step5_tco { } public static MalVal EVAL(MalVal orig_ast, Env env) throws MalThrowable { - MalVal a1,a2, a3, res; + MalVal a0, a1,a2, a3, res; MalList el; while (true) { - //System.out.println("EVAL: " + types._pr_str(orig_ast, true)); - if (!(types._list_Q(orig_ast))) { + //System.out.println("EVAL: " + printer._pr_str(orig_ast, true)); + if (!orig_ast.list_Q()) { return eval_ast(orig_ast, env); } // apply list MalList ast = (MalList)orig_ast; if (ast.size() == 0) { return ast; } - MalVal a0 = ast.nth(0); + a0 = ast.nth(0); String a0sym = a0 instanceof MalSymbol ? ((MalSymbol)a0).getName() : "__<*fn*>__"; switch (a0sym) { @@ -101,7 +104,7 @@ public class step5_tco { final MalList a1f = (MalList)ast.nth(1); final MalVal a2f = ast.nth(2); final Env cur_env = env; - return new MalFunction (a2f, (mal.types.Env)env, a1f) { + 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)); } @@ -114,7 +117,7 @@ public class step5_tco { orig_ast = fnast; env = new Env(f.getEnv(), f.getParams(), el.slice(1)); } else { - return f.apply(types._rest(el)); + return f.apply(el.rest()); } } @@ -123,7 +126,7 @@ public class step5_tco { // print public static String PRINT(MalVal exp) { - return types._pr_str(exp, true); + return printer._pr_str(exp, true); } // REPL @@ -138,13 +141,13 @@ public class step5_tco { String prompt = "user> "; Env repl_env = new Env(null); - for (String key : types.types_ns.keySet()) { - _ref(repl_env, key, types.types_ns.get(key)); + for (String key : core.ns.keySet()) { + _ref(repl_env, key, core.ns.get(key)); } RE(repl_env, "(def! not (fn* (a) (if a false true)))"); - if (args[0].equals("--raw")) { + if (args.length > 0 && args[0].equals("--raw")) { readline.mode = readline.Mode.JAVA; } while (true) { diff --git a/java/src/main/java/mal/step6_file.java b/java/src/main/java/mal/step6_file.java index 65d9d38..0a1a99b 100644 --- a/java/src/main/java/mal/step6_file.java +++ b/java/src/main/java/mal/step6_file.java @@ -12,6 +12,9 @@ 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 step6_file { // read @@ -26,8 +29,8 @@ public class step6_file { return env.get(sym.getName()); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; - MalList new_lst = types._list_Q(ast) ? new MalList() - : (MalList)new MalVector(); + MalList new_lst = ast.list_Q() ? new MalList() + : (MalList)new MalVector(); for (MalVal mv : (List<MalVal>)old_lst.value) { new_lst.conj_BANG(EVAL(mv, env)); } @@ -46,20 +49,20 @@ public class step6_file { } public static MalVal EVAL(MalVal orig_ast, Env env) throws MalThrowable { - MalVal a1,a2, a3, res; + MalVal a0, a1,a2, a3, res; MalList el; while (true) { - //System.out.println("EVAL: " + types._pr_str(orig_ast, true)); - if (!(types._list_Q(orig_ast))) { + //System.out.println("EVAL: " + printer._pr_str(orig_ast, true)); + if (!orig_ast.list_Q()) { return eval_ast(orig_ast, env); } // apply list MalList ast = (MalList)orig_ast; if (ast.size() == 0) { return ast; } - MalVal a0 = ast.nth(0); + a0 = ast.nth(0); String a0sym = a0 instanceof MalSymbol ? ((MalSymbol)a0).getName() : "__<*fn*>__"; switch (a0sym) { @@ -104,7 +107,7 @@ public class step6_file { final MalList a1f = (MalList)ast.nth(1); final MalVal a2f = ast.nth(2); final Env cur_env = env; - return new MalFunction (a2f, (mal.types.Env)env, a1f) { + 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)); } @@ -117,7 +120,7 @@ public class step6_file { orig_ast = fnast; env = new Env(f.getEnv(), f.getParams(), el.slice(1)); } else { - return f.apply(types._rest(el)); + return f.apply(el.rest()); } } @@ -126,7 +129,7 @@ public class step6_file { // print public static String PRINT(MalVal exp) { - return types._pr_str(exp, true); + return printer._pr_str(exp, true); } // REPL @@ -149,8 +152,8 @@ public class step6_file { String prompt = "user> "; final Env repl_env = new Env(null); - for (String key : types.types_ns.keySet()) { - _ref(repl_env, key, types.types_ns.get(key)); + for (String key : core.ns.keySet()) { + _ref(repl_env, key, core.ns.get(key)); } _ref(repl_env, "read-string", new MalFunction() { public MalVal apply(MalList args) throws MalThrowable { diff --git a/java/src/main/java/mal/step7_quote.java b/java/src/main/java/mal/step7_quote.java index 2a09d3e..7105671 100644 --- a/java/src/main/java/mal/step7_quote.java +++ b/java/src/main/java/mal/step7_quote.java @@ -12,6 +12,9 @@ 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 step7_quote { // read @@ -38,12 +41,12 @@ public class step7_quote { (((MalSymbol)a00).getName() == "splice-unquote")) { return new MalList(new MalSymbol("concat"), ((MalList)a0).nth(1), - quasiquote(types._rest((MalList)ast))); + quasiquote(((MalList)ast).rest())); } } return new MalList(new MalSymbol("cons"), quasiquote(a0), - quasiquote(types._rest((MalList)ast))); + quasiquote(((MalList)ast).rest())); } } @@ -53,8 +56,8 @@ public class step7_quote { return env.get(sym.getName()); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; - MalList new_lst = types._list_Q(ast) ? new MalList() - : (MalList)new MalVector(); + MalList new_lst = ast.list_Q() ? new MalList() + : (MalList)new MalVector(); for (MalVal mv : (List<MalVal>)old_lst.value) { new_lst.conj_BANG(EVAL(mv, env)); } @@ -73,20 +76,20 @@ public class step7_quote { } public static MalVal EVAL(MalVal orig_ast, Env env) throws MalThrowable { - MalVal a1,a2, a3, res; + MalVal a0, a1,a2, a3, res; MalList el; while (true) { - //System.out.println("EVAL: " + types._pr_str(orig_ast, true)); - if (!(types._list_Q(orig_ast))) { + //System.out.println("EVAL: " + printer._pr_str(orig_ast, true)); + if (!orig_ast.list_Q()) { return eval_ast(orig_ast, env); } // apply list MalList ast = (MalList)orig_ast; if (ast.size() == 0) { return ast; } - MalVal a0 = ast.nth(0); + a0 = ast.nth(0); String a0sym = a0 instanceof MalSymbol ? ((MalSymbol)a0).getName() : "__<*fn*>__"; switch (a0sym) { @@ -135,7 +138,7 @@ public class step7_quote { final MalList a1f = (MalList)ast.nth(1); final MalVal a2f = ast.nth(2); final Env cur_env = env; - return new MalFunction (a2f, (mal.types.Env)env, a1f) { + 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)); } @@ -148,7 +151,7 @@ public class step7_quote { orig_ast = fnast; env = new Env(f.getEnv(), f.getParams(), el.slice(1)); } else { - return f.apply(types._rest(el)); + return f.apply(el.rest()); } } @@ -157,7 +160,7 @@ public class step7_quote { // print public static String PRINT(MalVal exp) { - return types._pr_str(exp, true); + return printer._pr_str(exp, true); } // REPL @@ -180,8 +183,8 @@ public class step7_quote { String prompt = "user> "; final Env repl_env = new Env(null); - for (String key : types.types_ns.keySet()) { - _ref(repl_env, key, types.types_ns.get(key)); + for (String key : core.ns.keySet()) { + _ref(repl_env, key, core.ns.get(key)); } _ref(repl_env, "read-string", new MalFunction() { public MalVal apply(MalList args) throws MalThrowable { diff --git a/java/src/main/java/mal/step8_macros.java b/java/src/main/java/mal/step8_macros.java index 47732dd..c834119 100644 --- a/java/src/main/java/mal/step8_macros.java +++ b/java/src/main/java/mal/step8_macros.java @@ -12,6 +12,9 @@ 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 step8_macros { // read @@ -38,12 +41,12 @@ public class step8_macros { (((MalSymbol)a00).getName() == "splice-unquote")) { return new MalList(new MalSymbol("concat"), ((MalList)a0).nth(1), - quasiquote(types._rest((MalList)ast))); + quasiquote(((MalList)ast).rest())); } } return new MalList(new MalSymbol("cons"), quasiquote(a0), - quasiquote(types._rest((MalList)ast))); + quasiquote(((MalList)ast).rest())); } } @@ -68,7 +71,7 @@ public class step8_macros { while (is_macro_call(ast, env)) { MalSymbol a0 = (MalSymbol)((MalList)ast).nth(0); MalFunction mac = (MalFunction) env.get(a0.getName()); - ast = mac.apply(types._rest((MalList)ast)); + ast = mac.apply(((MalList)ast).rest()); } return ast; } @@ -79,8 +82,8 @@ public class step8_macros { return env.get(sym.getName()); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; - MalList new_lst = types._list_Q(ast) ? new MalList() - : (MalList)new MalVector(); + MalList new_lst = ast.list_Q() ? new MalList() + : (MalList)new MalVector(); for (MalVal mv : (List<MalVal>)old_lst.value) { new_lst.conj_BANG(EVAL(mv, env)); } @@ -99,22 +102,22 @@ public class step8_macros { } public static MalVal EVAL(MalVal orig_ast, Env env) throws MalThrowable { - MalVal a1,a2, a3, res; + MalVal a0, a1,a2, a3, res; MalList el; while (true) { - //System.out.println("EVAL: " + types._pr_str(orig_ast, true)); - if (!(types._list_Q(orig_ast))) { + //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 (!types._list_Q(expanded)) { return expanded; } + if (!expanded.list_Q()) { return expanded; } MalList ast = (MalList) expanded; if (ast.size() == 0) { return ast; } - MalVal a0 = ast.nth(0); + a0 = ast.nth(0); String a0sym = a0 instanceof MalSymbol ? ((MalSymbol)a0).getName() : "__<*fn*>__"; switch (a0sym) { @@ -173,7 +176,7 @@ public class step8_macros { final MalList a1f = (MalList)ast.nth(1); final MalVal a2f = ast.nth(2); final Env cur_env = env; - return new MalFunction (a2f, (mal.types.Env)env, a1f) { + 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)); } @@ -186,7 +189,7 @@ public class step8_macros { orig_ast = fnast; env = new Env(f.getEnv(), f.getParams(), el.slice(1)); } else { - return f.apply(types._rest(el)); + return f.apply(el.rest()); } } @@ -195,7 +198,7 @@ public class step8_macros { // print public static String PRINT(MalVal exp) { - return types._pr_str(exp, true); + return printer._pr_str(exp, true); } // REPL @@ -218,8 +221,8 @@ public class step8_macros { String prompt = "user> "; final Env repl_env = new Env(null); - for (String key : types.types_ns.keySet()) { - _ref(repl_env, key, types.types_ns.get(key)); + for (String key : core.ns.keySet()) { + _ref(repl_env, key, core.ns.get(key)); } _ref(repl_env, "read-string", new MalFunction() { public MalVal apply(MalList args) throws MalThrowable { diff --git a/java/src/main/java/mal/stepA_more.java b/java/src/main/java/mal/stepA_more.java index d3bb161..9f4fb07 100644 --- a/java/src/main/java/mal/stepA_more.java +++ b/java/src/main/java/mal/stepA_more.java @@ -14,6 +14,9 @@ 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 @@ -40,12 +43,12 @@ public class stepA_more { (((MalSymbol)a00).getName() == "splice-unquote")) { return new MalList(new MalSymbol("concat"), ((MalList)a0).nth(1), - quasiquote(types._rest((MalList)ast))); + quasiquote(((MalList)ast).rest())); } } return new MalList(new MalSymbol("cons"), quasiquote(a0), - quasiquote(types._rest((MalList)ast))); + quasiquote(((MalList)ast).rest())); } } @@ -70,7 +73,7 @@ public class stepA_more { while (is_macro_call(ast, env)) { MalSymbol a0 = (MalSymbol)((MalList)ast).nth(0); MalFunction mac = (MalFunction) env.get(a0.getName()); - ast = mac.apply(types._rest((MalList)ast)); + ast = mac.apply(((MalList)ast).rest()); } return ast; } @@ -81,8 +84,8 @@ public class stepA_more { return env.get(sym.getName()); } else if (ast instanceof MalList) { MalList old_lst = (MalList)ast; - MalList new_lst = types._list_Q(ast) ? new MalList() - : (MalList)new MalVector(); + MalList new_lst = ast.list_Q() ? new MalList() + : (MalList)new MalVector(); for (MalVal mv : (List<MalVal>)old_lst.value) { new_lst.conj_BANG(EVAL(mv, env)); } @@ -101,22 +104,22 @@ public class stepA_more { } public static MalVal EVAL(MalVal orig_ast, Env env) throws MalThrowable { - MalVal a1,a2, a3, res; + MalVal a0, a1,a2, a3, res; MalList el; while (true) { - //System.out.println("EVAL: " + types._pr_str(orig_ast, true)); - if (!(types._list_Q(orig_ast))) { + //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 (!types._list_Q(expanded)) { return expanded; } + if (!expanded.list_Q()) { return expanded; } MalList ast = (MalList) expanded; if (ast.size() == 0) { return ast; } - MalVal a0 = ast.nth(0); + a0 = ast.nth(0); String a0sym = a0 instanceof MalSymbol ? ((MalSymbol)a0).getName() : "__<*fn*>__"; switch (a0sym) { @@ -199,7 +202,7 @@ public class stepA_more { final MalList a1f = (MalList)ast.nth(1); final MalVal a2f = ast.nth(2); final Env cur_env = env; - return new MalFunction (a2f, (mal.types.Env)env, a1f) { + 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)); } @@ -212,7 +215,7 @@ public class stepA_more { orig_ast = fnast; env = new Env(f.getEnv(), f.getParams(), el.slice(1)); } else { - return f.apply(types._rest(el)); + return f.apply(el.rest()); } } @@ -221,7 +224,7 @@ public class stepA_more { // print public static String PRINT(MalVal exp) { - return types._pr_str(exp, true); + return printer._pr_str(exp, true); } // REPL @@ -244,8 +247,8 @@ public class stepA_more { String prompt = "user> "; final Env repl_env = new Env(null); - for (String key : types.types_ns.keySet()) { - _ref(repl_env, key, types.types_ns.get(key)); + for (String key : core.ns.keySet()) { + _ref(repl_env, key, core.ns.get(key)); } _ref(repl_env, "readline", new MalFunction() { public MalVal apply(MalList args) throws MalThrowable { @@ -315,7 +318,7 @@ public class stepA_more { System.out.println(e.getMessage()); continue; } catch (MalException e) { - System.out.println("Error: " + types._pr_str(e.getValue(), false)); + System.out.println("Error: " + printer._pr_str(e.getValue(), false)); continue; } catch (MalThrowable t) { System.out.println("Error: " + t.getMessage()); diff --git a/java/src/main/java/mal/types.java b/java/src/main/java/mal/types.java index 8a4910b..a53c0e9 100644 --- a/java/src/main/java/mal/types.java +++ b/java/src/main/java/mal/types.java @@ -2,12 +2,12 @@ package mal; import java.util.List; import java.util.ArrayList; -import com.google.common.base.Joiner; import java.util.Set; import java.util.Map; import java.util.HashMap; -import com.google.common.collect.ImmutableMap; -import org.apache.commons.lang3.StringEscapeUtils; + +import mal.printer; +import mal.env.Env; public class types { // @@ -34,6 +34,41 @@ public class types { public MalVal getValue() { return value; } } + // + // General functions + // + + public static Boolean _equal_Q(MalVal a, MalVal b) { + Class ota = a.getClass(), otb = b.getClass(); + if (!((ota == otb) || + (a instanceof MalList && b instanceof MalList))) { + return false; + } else { + if (a instanceof MalInteger) { + return ((MalInteger)a).getValue() == + ((MalInteger)b).getValue(); + } else if (a instanceof MalSymbol) { + return ((MalSymbol)a).getName().equals( + ((MalSymbol)b).getName()); + } else if (a instanceof MalString) { + return ((MalString)a).getValue().equals( + ((MalString)b).getValue()); + } else if (a instanceof MalList) { + if (((MalList)a).size() != ((MalList)b).size()) { + return false; + } + for (Integer i=0; i<((MalList)a).size(); i++) { + if (! _equal_Q(((MalList)a).nth(i), + ((MalList)b).nth(i))) { + return false; + } + } + return true; + } else { + return a == b; + } + } + } // // Mal boxed types @@ -48,6 +83,7 @@ public class types { } public MalVal getMeta() { return meta; } public void setMeta(MalVal m) { meta = m; } + public Boolean list_Q() { return false; } } public static class MalConstant extends MalVal { String value; @@ -56,9 +92,9 @@ public class types { public String toString() { return value; } } - static MalConstant Nil = new MalConstant("nil"); - static MalConstant True = new MalConstant("true"); - static MalConstant False = new MalConstant("false"); + public static MalConstant Nil = new MalConstant("nil"); + public static MalConstant True = new MalConstant("true"); + public static MalConstant False = new MalConstant("false"); public static class MalInteger extends MalVal { Integer value; @@ -117,7 +153,7 @@ public class types { } public String toString(Boolean print_readably) { if (print_readably) { - return "\"" + StringEscapeUtils.escapeJson(value) + "\""; + return "\"" + printer.escapeString(value) + "\""; } else { return value; } @@ -141,19 +177,15 @@ public class types { return new_ml; } - String _join(String delim, Boolean print_readably) { - ArrayList<String> strs = new ArrayList<String>(); - for (MalVal mv : (List<MalVal>)value) { - strs.add(mv.toString(print_readably)); - } - return Joiner.on(delim).join(strs); - } @Override public String toString() { - return start + _join(" ", true) + end; + return start + printer.join(value, " ", true) + end; } public String toString(Boolean print_readably) { - return start + _join(" ", print_readably) + end; + return start + printer.join(value, " ", print_readably) + end; } + + public List getList() { return value; } + public Boolean list_Q() { return true; } public MalList conj_BANG(MalVal... mvs) { for (MalVal mv : mvs) { @@ -169,6 +201,14 @@ public class types { public MalVal nth(Integer idx) { return (MalVal)value.get(idx); } + public MalList rest () { + if (size() > 0) { + return new MalList(value.subList(1, value.size())); + } else { + return new MalList(); + } + } + public MalList slice(Integer start, Integer end) { return new MalList(value.subList(start, end)); @@ -197,6 +237,8 @@ public class types { return new_mv; } + public Boolean list_Q() { return false; } + public MalVector slice(Integer start, Integer end) { return new MalVector(value.subList(start, end)); } @@ -223,24 +265,11 @@ public class types { return new_hm; } - String _join(Boolean print_readably) { - ArrayList<String> strs = new ArrayList<String>(); - for (Map.Entry<String, MalVal> entry : - ((Map<String,MalVal>)value).entrySet()) { - if (print_readably) { - strs.add("\"" + entry.getKey().toString() + "\""); - } else { - strs.add(entry.getKey().toString()); - } - strs.add(entry.getValue().toString(print_readably)); - } - return Joiner.on(" ").join(strs); - } @Override public String toString() { - return "{" + _join(true) + "}"; + return "{" + printer.join(value, " ", true) + "}"; } public String toString(Boolean print_readably) { - return "{" + _join(print_readably) + "}"; + return "{" + printer.join(value, " ", print_readably) + "}"; } public Set _entries() { @@ -280,10 +309,10 @@ public class types { public MalAtom(MalVal value) { this.value = value; } public MalAtom copy() throws MalThrowable { return new MalAtom(value); } @Override public String toString() { - return "(atom " + _pr_str(value, true) + ")"; + return "(atom " + printer._pr_str(value, true) + ")"; } public String toString(Boolean print_readably) { - return "(atom " + _pr_str(value, print_readably) + ")"; + return "(atom " + printer._pr_str(value, print_readably) + ")"; } } @@ -329,563 +358,4 @@ public class types { public Boolean isMacro() { return macro; } public void setMacro() { macro = true; } } - - - // - // General functions - // - public static String _pr_str(MalVal mv, Boolean print_readably) { - return mv.toString(print_readably); - } - - public static String _pr_str_args(MalList args, String sep, Boolean print_readably) { - return args._join(sep, print_readably); - } - - static MalFunction pr_str = new MalFunction() { - public MalVal apply(MalList args) throws MalThrowable { - return new MalString(_pr_str_args(args, " ", true)); - } - }; - - static MalFunction str = new MalFunction() { - public MalVal apply(MalList args) throws MalThrowable { - return new MalString(_pr_str_args(args, "", false)); - } - }; - - static MalFunction prn = new MalFunction() { - public MalVal apply(MalList args) throws MalThrowable { - System.out.println(_pr_str_args(args, " ", true)); - return Nil; - } - }; - - static MalFunction println = new MalFunction() { - public MalVal apply(MalList args) throws MalThrowable { - System.out.println(_pr_str_args(args, " ", false)); - return Nil; - } - }; - - - static MalFunction meta = new MalFunction() { - public MalVal apply(MalList args) throws MalThrowable { - return args.nth(0).getMeta(); - } - }; - - static MalFunction with_meta = new MalFunction() { - public MalVal apply(MalList args) throws MalThrowable { - MalVal new_mv = ((MalVal)args.nth(0)).copy(); - new_mv.setMeta(args.nth(1)); - return new_mv; - } - }; - - - public static Boolean _equal_Q(MalVal a, MalVal b) { - Class ota = a.getClass(), otb = b.getClass(); - if (!((ota == otb) || - (a instanceof MalList && b instanceof MalList))) { - return false; - } else { - if (a instanceof MalInteger) { - return ((MalInteger)a).getValue() == - ((MalInteger)b).getValue(); - } else if (a instanceof MalSymbol) { - return ((MalSymbol)a).getName().equals( - ((MalSymbol)b).getName()); - } else if (a instanceof MalString) { - return ((MalString)a).getValue().equals( - ((MalString)b).getValue()); - } else if (a instanceof MalList) { - if (((MalList)a).size() != ((MalList)b).size()) { - return false; - } - for (Integer i=0; i<((MalList)a).size(); i++) { - if (! _equal_Q(((MalList)a).nth(i), - ((MalList)b).nth(i))) { - return false; - } - } - return true; - } else { - return a == b; - } - } - } - - static MalFunction equal_Q = new MalFunction() { - public MalVal apply(MalList args) throws MalThrowable { - return _equal_Q(args.nth(0), args.nth(1)) ? True : False; - } - }; - - - // - // Constants operations - // - static MalFunction symbol_Q = new MalFunction() { - public MalVal apply(MalList args) throws MalThrowable { - return args.nth(0) instanceof MalSymbol ? True : False; - } - }; - - static MalFunction nil_Q = new MalFunction() { - public MalVal apply(MalList args) throws MalThrowable { - return args.nth(0) == Nil ? True : False; - } - }; - - static MalFunction true_Q = new MalFunction() { - public MalVal apply(MalList args) throws MalThrowable { - return args.nth(0) == True ? True : False; - } - }; - - static MalFunction false_Q = new MalFunction() { - public MalVal apply(MalList args) throws MalThrowable { - return args.nth(0) == False ? True : False; - } - }; - - - // - // Number operations - // - static MalFunction add = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return ((MalInteger)a.nth(0)).add((MalInteger)a.nth(1)); - } - }; - static MalFunction subtract = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return ((MalInteger)a.nth(0)).subtract((MalInteger)a.nth(1)); - } - }; - static MalFunction multiply = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return ((MalInteger)a.nth(0)).multiply((MalInteger)a.nth(1)); - } - }; - static MalFunction divide = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return ((MalInteger)a.nth(0)).divide((MalInteger)a.nth(1)); - } - }; - - static MalFunction lt = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return ((MalInteger)a.nth(0)).lt((MalInteger)a.nth(1)); - } - }; - static MalFunction lte = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return ((MalInteger)a.nth(0)).lte((MalInteger)a.nth(1)); - } - }; - static MalFunction gt = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return ((MalInteger)a.nth(0)).gt((MalInteger)a.nth(1)); - } - }; - static MalFunction gte = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return ((MalInteger)a.nth(0)).gte((MalInteger)a.nth(1)); - } - }; - - // - // Errors/Exceptions - // - static MalFunction mal_throw = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - throw new MalException(a.nth(0)); - } - }; - - // - // List operations - // - static MalFunction new_list = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return new MalList(a.value); - } - }; - - static public Boolean _list_Q(MalVal mv) { - return mv.getClass().equals(MalList.class); - } - static MalFunction list_Q = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return _list_Q(a.nth(0)) ? True : False; - } - }; - - // - // Vector operations - // - static MalFunction new_vector = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return new MalVector(a.value); - } - }; - - static public Boolean _vector_Q(MalVal mv) { - return mv.getClass().equals(MalVector.class); - } - static MalFunction vector_Q = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return _vector_Q(a.nth(0)) ? True : False; - } - }; - - // - // Hash map operations - // - static MalFunction new_hash_map = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return new MalHashMap(a); - } - }; - - static MalFunction hash_map_Q = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return a.nth(0) instanceof MalHashMap ? True : False; - } - }; - - static MalFunction contains_Q = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - String key = ((MalString)a.nth(1)).getValue(); - MalHashMap mhm = (MalHashMap)a.nth(0); - HashMap<String,MalVal> hm = (HashMap<String,MalVal>)mhm.value; - return hm.containsKey(key) ? True : False; - } - }; - - static MalFunction assoc = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - MalHashMap mhm = (MalHashMap)a.nth(0); - HashMap<String,MalVal> hm = (HashMap<String,MalVal>)mhm.value; - MalHashMap new_mhm = new MalHashMap((Map)hm.clone()); - new_mhm.assoc_BANG((MalList)a.slice(1)); - return new_mhm; - } - }; - - static MalFunction dissoc = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - MalHashMap mhm = (MalHashMap)a.nth(0); - HashMap<String,MalVal> hm = (HashMap<String,MalVal>)mhm.value; - MalHashMap new_mhm = new MalHashMap((Map)hm.clone()); - new_mhm.dissoc_BANG((MalList)a.slice(1)); - return new_mhm; - } - }; - - static MalFunction get = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - String key = ((MalString)a.nth(1)).getValue(); - MalHashMap mhm = (MalHashMap)a.nth(0); - HashMap<String,MalVal> hm = (HashMap<String,MalVal>)mhm.value; - if (hm.containsKey(key)) { - return hm.get(key); - } else { - return Nil; - } - } - }; - - static MalFunction keys = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - MalHashMap mhm = (MalHashMap)a.nth(0); - HashMap<String,MalVal> hm = (HashMap<String,MalVal>)mhm.value; - MalList key_lst = new MalList(); - for (String key : hm.keySet()) { - key_lst.conj_BANG(new MalString(key)); - } - return key_lst; - } - }; - - static MalFunction vals = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - MalHashMap mhm = (MalHashMap)a.nth(0); - HashMap<String,MalVal> hm = (HashMap<String,MalVal>)mhm.value; - //return new ArrayList<MalVal>(((HashMap<String,MalVal>)hm).values()); - MalList val_lst = new MalList(); - for (MalVal val : hm.values()) { - val_lst.conj_BANG(val); - } - return val_lst; - } - }; - - - // - // Atoms - // - static MalFunction new_atom = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return new MalAtom(a.nth(0)); - } - }; - - static MalFunction atom_Q = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return a.nth(0) instanceof MalAtom ? True : False; - } - }; - - static MalFunction deref = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return ((MalAtom)a.nth(0)).value; - } - }; - - static MalFunction reset_BANG = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return ((MalAtom)a.nth(0)).value = a.nth(1); - } - }; - - static MalFunction swap_BANG = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - MalAtom atm = (MalAtom)a.nth(0); - MalFunction f = (MalFunction)a.nth(1); - MalList new_args = new MalList(); - new_args.value.addAll(((MalList)a.slice(2)).value); - new_args.value.add(0, atm.value); - atm.value = f.apply(new_args); - return atm.value; - } - }; - - - - - // - // Sequence operations - // - static MalFunction sequential_Q = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return a.nth(0) instanceof MalList ? True : False; - } - }; - - static MalFunction count = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - return new MalInteger(((MalList)a.nth(0)).size()); - } - }; - - static MalFunction empty_Q = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - MalVal exp = a.nth(0); - if (exp == Nil || (exp instanceof MalList && - ((MalList)exp).size() == 0)) { - return True; - } else { - return False; - } - } - }; - - static MalFunction cons = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - MalList lst = new MalList(); - lst.value.addAll(((MalList)a.nth(1)).value); - lst.value.add(0, a.nth(0)); - return (MalVal) lst; - } - }; - - static MalFunction concat = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - if (a.size() == 0) { return new MalList(); } - MalList lst = new MalList(); - lst.value.addAll(((MalList)a.nth(0)).value); - for(Integer i=1; i<a.size(); i++) { - lst.value.addAll(((MalList)a.nth(i)).value); - } - return (MalVal) lst; - } - }; - - static MalFunction conj = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - MalList src_seq = (MalList)a.nth(0), new_seq; - if (a.nth(0) instanceof MalVector) { - new_seq = new MalVector(); - new_seq.value.addAll(src_seq.value); - for(Integer i=1; i<a.size(); i++) { - new_seq.value.add(a.nth(i)); - } - } else { - new_seq = new MalList(); - new_seq.value.addAll(src_seq.value); - for(Integer i=1; i<a.size(); i++) { - new_seq.value.add(0, a.nth(i)); - } - } - return (MalVal) new_seq; - } - }; - - static MalFunction first = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - MalList ml = ((MalList)a.nth(0)); - return ml.size() > 0 ? ml.nth(0) : Nil; - } - }; - - static MalList _rest (MalList ml) { - if (ml.size() > 0) { - return new MalList(ml.value.subList(1, ml.value.size())); - } else { - return new MalList(); - } - } - - static MalFunction rest = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - MalList ml = ((MalList)a.nth(0)); - return _rest(ml); - } - }; - - 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); - } - }; - - // General list related functions - static MalFunction apply = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - MalFunction f = (MalFunction)a.nth(0); - MalList args = a.slice(1,a.size()-1); - args.value.addAll( ((MalList)a.nth(a.size()-1)).value); - return f.apply(args); - } - }; - - static MalFunction map = new MalFunction() { - public MalVal apply(MalList a) throws MalThrowable { - MalFunction f = (MalFunction) a.nth(0); - MalList src_lst = (MalList) a.nth(1); - MalList new_lst = new MalList(); - for(Integer i=0; i<src_lst.size(); i++) { - new_lst.value.add( - f.apply(new MalList(src_lst.nth(i)))); - } - return new_lst; - } - }; - - - - // - // Env implementation - // - public static class Env { - Env outer = null; - HashMap<String,MalVal> data = new HashMap<String,MalVal>(); - - public Env(Env outer) { - this.outer = outer; - } - public Env(Env outer, MalList binds, MalList exprs) { - this.outer = outer; - for (Integer i=0; i<binds.size(); i++) { - String sym = ((MalSymbol)binds.nth(i)).getName(); - if (sym.equals("&")) { - data.put(((MalSymbol)binds.nth(i+1)).getName(), - exprs.slice(i)); - break; - } else { - data.put(sym, exprs.nth(i)); - } - } - } - - public Env find(String key) { - if (data.containsKey(key)) { - return this; - } else if (outer != null) { - return outer.find(key); - } else { - return null; - } - } - - public MalVal get(String key) throws MalThrowable { - Env e = find(key); - if (e == null) { - throw new MalException("'" + key + "' not found"); - } else { - return e.data.get(key); - } - } - - public Env set(String key, MalVal value) { - data.put(key, value); - return this; - } - } - - // types_ns is namespace of type functions - static Map<String, MalVal> types_ns = ImmutableMap.<String, MalVal>builder() - .put("pr-str", pr_str) - .put("str", str) - .put("prn", prn) - .put("println", println) - .put("meta", meta) - .put("with-meta", with_meta) - .put("=", equal_Q) - .put("symbol?", symbol_Q) - .put("nil?", nil_Q) - .put("true?", true_Q) - .put("false?", false_Q) - .put("<", lt) - .put("<=", lte) - .put(">", gt) - .put(">=", gte) - .put("+", add) - .put("-", subtract) - .put("*", multiply) - .put("/", divide) - .put("throw", mal_throw) - .put("list", new_list) - .put("list?", list_Q) - .put("vector", new_vector) - .put("vector?", vector_Q) - .put("hash-map", new_hash_map) - .put("map?", hash_map_Q) - .put("assoc", assoc) - .put("dissoc", dissoc) - .put("contains?", contains_Q) - .put("get", get) - .put("keys", keys) - .put("vals", vals) - .put("atom", new_atom) - .put("atom?", atom_Q) - .put("deref", deref) - .put("reset!", reset_BANG) - .put("swap!", swap_BANG) - .put("sequential?", sequential_Q) - .put("cons", cons) - .put("concat", concat) - .put("conj", conj) - .put("first", first) - .put("rest", rest) - .put("nth", nth) - .put("count", count) - .put("empty?", empty_Q) - .put("apply", apply) - .put("map", map) - .build(); } |
