diff options
| author | Joel Martin <github@martintribe.org> | 2014-04-07 00:17:13 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-04-07 00:17:13 -0500 |
| commit | afdf531eba459a7a7b6505b037dbe48a363c2c79 (patch) | |
| tree | b899e21b373ac8338756140eaf7afcb399d46bb9 /cs | |
| parent | b18969c0b8d47d67d4b73b5b20742a0bc3179e72 (diff) | |
| download | mal-afdf531eba459a7a7b6505b037dbe48a363c2c79.tar.gz mal-afdf531eba459a7a7b6505b037dbe48a363c2c79.zip | |
CS: add step4_if_fn_do
Diffstat (limited to 'cs')
| -rw-r--r-- | cs/Makefile | 5 | ||||
| -rw-r--r-- | cs/core.cs | 83 | ||||
| -rw-r--r-- | cs/printer.cs | 9 | ||||
| -rw-r--r-- | cs/reader.cs | 9 | ||||
| -rw-r--r-- | cs/step1_read_print.cs | 2 | ||||
| -rw-r--r-- | cs/step2_eval.cs | 43 | ||||
| -rw-r--r-- | cs/step3_env.cs | 23 | ||||
| -rw-r--r-- | cs/step4_if_fn_do.cs | 166 | ||||
| -rw-r--r-- | cs/types.cs | 92 |
9 files changed, 341 insertions, 91 deletions
diff --git a/cs/Makefile b/cs/Makefile index bf8a8ef..61835cf 100644 --- a/cs/Makefile +++ b/cs/Makefile @@ -3,13 +3,14 @@ TESTS = SOURCES = readline.cs types.cs reader.cs printer.cs env.cs core.cs \ - step3_env.cs + step4_if_fn_do.cs OTHER_SOURCES = getline.cs ##################### -SRCS = step0_repl.cs step1_read_print.cs step2_eval.cs step3_env.cs +SRCS = step0_repl.cs step1_read_print.cs step2_eval.cs step3_env.cs \ + step4_if_fn_do.cs LIB_SRCS = $(filter-out step%,$(OTHER_SOURCES) $(SOURCES)) @@ -1,33 +1,68 @@ +using System; +using System.Collections.Generic; using MalVal = Mal.types.MalVal; +using MalConstant = Mal.types.MalConstant; using MalInteger = Mal.types.MalInteger; +using MalString = Mal.types.MalString; using MalList = Mal.types.MalList; using MalFunction = Mal.types.MalFunction; namespace Mal { public class core { - public class plus : MalFunction { - public override MalVal apply(MalList args) { - return ((MalInteger)args.nth(0)).add( - ((MalInteger)args.nth(1))); - } - } - public class minus : MalFunction { - public override MalVal apply(MalList args) { - return ((MalInteger)args.nth(0)).subtract( - ((MalInteger)args.nth(1))); - } - } - public class multiply : MalFunction { - public override MalVal apply(MalList args) { - return ((MalInteger)args.nth(0)).multiply( - ((MalInteger)args.nth(1))); - } - } - public class divide : MalFunction { - public override MalVal apply(MalList args) { - return ((MalInteger)args.nth(0)).divide( - ((MalInteger)args.nth(1))); - } - } + static MalConstant Nil = Mal.types.Nil; + static MalConstant True = Mal.types.True; + static MalConstant False = Mal.types.False; + + // String functions + static public MalFunction pr_str = new MalFunction( + a => new MalString(printer._pr_str_args(a, " ", true)) ); + + static public MalFunction str = new MalFunction( + a => new MalString(printer._pr_str_args(a, "", false)) ); + + static public MalFunction prn = new MalFunction( + a => { + Console.WriteLine(printer._pr_str_args(a, " ", true)); + return Nil; + } ); + + static public MalFunction println = new MalFunction( + a => { + Console.WriteLine(printer._pr_str_args(a, " ", false)); + return Nil; + } ); + + // Sequence functions + static public MalFunction list_Q = new MalFunction( + a => a[0].GetType() == typeof(MalList) ? True : False); + + + + static public Dictionary<string, MalVal> ns = + new Dictionary<string, MalVal> { + {"=", new MalFunction( + a => Mal.types._equal_Q(a[0], a[1]) ? True : False)}, + {"pr-str", pr_str}, + {"str", str}, + {"prn", prn}, + {"println", println}, + {"<", new MalFunction(a => (MalInteger)a[0] < (MalInteger)a[1])}, + {"<=", new MalFunction(a => (MalInteger)a[0] <= (MalInteger)a[1])}, + {">", new MalFunction(a => (MalInteger)a[0] > (MalInteger)a[1])}, + {">=", new MalFunction(a => (MalInteger)a[0] >= (MalInteger)a[1])}, + {"+", new MalFunction(a => (MalInteger)a[0] + (MalInteger)a[1])}, + {"-", new MalFunction(a => (MalInteger)a[0] - (MalInteger)a[1])}, + {"*", new MalFunction(a => (MalInteger)a[0] * (MalInteger)a[1])}, + {"/", new MalFunction(a => (MalInteger)a[0] / (MalInteger)a[1])}, + + {"list", new MalFunction(a => new MalList(a.getValue()))}, + {"list?", list_Q}, + {"first", new MalFunction(a => ((MalList)a[0]).nth(0))}, + {"rest", new MalFunction(a => ((MalList)a[0]).rest())}, + {"count", new MalFunction( + a => new MalInteger(((MalList)a[0]).size()))}, + {"empty?", new MalFunction( + a => ((MalList)a[0]).size() == 0 ? True : False)}, + }; } } diff --git a/cs/printer.cs b/cs/printer.cs index 7ee5c03..b5e8c63 100644 --- a/cs/printer.cs +++ b/cs/printer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Text.RegularExpressions; using Mal; using MalVal = Mal.types.MalVal; using MalList = Mal.types.MalList; @@ -33,12 +34,14 @@ namespace Mal { return mv.ToString(print_readably); } - /* public static string _pr_str_args(MalList args, String sep, bool print_readably) { - return join(args.getList(), sep, print_readably); + return join(args.getValue(), sep, print_readably); + } + + public static string escapeString(string str) { + return Regex.Escape(str); } - */ } } diff --git a/cs/reader.cs b/cs/reader.cs index 5e38136..a6d22c5 100644 --- a/cs/reader.cs +++ b/cs/reader.cs @@ -52,7 +52,7 @@ namespace Mal { public static MalVal read_atom(Reader rdr) { string token = rdr.next(); - string pattern = @"(^-?[0-9]+$)|(^-?[0-9][0-9.]*$)|(^nil$)|(^true$)|(^false$)|^""(.*)""$|(^[^""]*$)"; + string pattern = @"(^-?[0-9]+$)|(^-?[0-9][0-9.]*$)|(^nil$)|(^true$)|(^false$)|^("".*"")$|(^[^""]*$)"; Regex regex = new Regex(pattern); Match match = regex.Match(token); //Console.WriteLine("token: ^" + token + "$"); @@ -68,8 +68,11 @@ namespace Mal { } else if (match.Groups[5].Value != String.Empty) { return Mal.types.False; } else if (match.Groups[6].Value != String.Empty) { - //return new MalString(StringEscapeUtils.unescapeJson(match.Groups[6])); - return new Mal.types.MalString(match.Groups[6].Value); + string str = match.Groups[6].Value; + str = str.Substring(1, str.Length-2) + .Replace("\\\"", "\"") + .Replace("\\n", "\n"); + return new Mal.types.MalString(str); } else if (match.Groups[7].Value != String.Empty) { return new Mal.types.MalSymbol(match.Groups[7].Value); } else { diff --git a/cs/step1_read_print.cs b/cs/step1_read_print.cs index d06071c..92a8b65 100644 --- a/cs/step1_read_print.cs +++ b/cs/step1_read_print.cs @@ -4,7 +4,7 @@ using Mal; using MalVal = Mal.types.MalVal; namespace Mal { - class step1_repl { + class step1_read_print { // read static MalVal READ(string str) { return reader.read_str(str); diff --git a/cs/step2_eval.cs b/cs/step2_eval.cs index 5b49916..09bf36d 100644 --- a/cs/step2_eval.cs +++ b/cs/step2_eval.cs @@ -12,7 +12,7 @@ using MalHashMap = Mal.types.MalHashMap; using MalFunction = Mal.types.MalFunction; namespace Mal { - class step1_repl { + class step1_eval { // read static MalVal READ(string str) { return reader.read_str(str); @@ -74,40 +74,23 @@ namespace Mal { return EVAL(READ(str), env); } - class plus : MalFunction { - public override MalVal apply(MalList args) { - return ((MalInteger)args.nth(0)).add( - ((MalInteger)args.nth(1))); - } - } - class minus : MalFunction { - public override MalVal apply(MalList args) { - return ((MalInteger)args.nth(0)).subtract( - ((MalInteger)args.nth(1))); - } - } - class multiply : MalFunction { - public override MalVal apply(MalList args) { - return ((MalInteger)args.nth(0)).multiply( - ((MalInteger)args.nth(1))); - } - } - class divide : MalFunction { - public override MalVal apply(MalList args) { - return ((MalInteger)args.nth(0)).divide( - ((MalInteger)args.nth(1))); - } - } - + static public MalFunction plus = new MalFunction( + a => (MalInteger)a[0] + (MalInteger)a[1] ); + static public MalFunction minus = new MalFunction( + a => (MalInteger)a[0] - (MalInteger)a[1] ); + static public MalFunction multiply = new MalFunction( + a => (MalInteger)a[0] * (MalInteger)a[1] ); + static public MalFunction divide = new MalFunction( + a => (MalInteger)a[0] / (MalInteger)a[1] ); static void Main(string[] args) { string prompt = "user> "; var repl_env = new Dictionary<string, MalVal> { - { "+", new plus() }, - { "-", new minus() }, - { "*", new multiply() }, - { "/", new divide() }, + {"+", plus}, + {"-", minus}, + {"*", multiply}, + {"/", divide}, }; if (args.Length > 0 && args[0] == "--raw") { Mal.readline.mode = Mal.readline.Mode.Raw; diff --git a/cs/step3_env.cs b/cs/step3_env.cs index 0fbbda7..032fadd 100644 --- a/cs/step3_env.cs +++ b/cs/step3_env.cs @@ -13,7 +13,7 @@ using MalFunction = Mal.types.MalFunction; using Env = Mal.env.Env; namespace Mal { - class step1_repl { + class step3_env { // read static MalVal READ(string str) { return reader.read_str(str); @@ -46,6 +46,7 @@ namespace Mal { static MalVal EVAL(MalVal orig_ast, Env env) { MalVal a0, a1, a2, res; + MalList el; //System.out.println("EVAL: " + printer._pr_str(orig_ast, true)); if (!orig_ast.list_Q()) { return eval_ast(orig_ast, env); @@ -80,7 +81,7 @@ namespace Mal { } return EVAL(a2, let_env); default: - var el = (MalList)eval_ast(ast, env); + el = (MalList)eval_ast(ast, env); var f = (MalFunction)el.nth(0); return f.apply(el.rest()); } @@ -99,14 +100,24 @@ namespace Mal { return env.set(name, mv); } + static public MalFunction plus = new MalFunction( + a => (MalInteger)a[0] + (MalInteger)a[1] ); + static public MalFunction minus = new MalFunction( + a => (MalInteger)a[0] - (MalInteger)a[1] ); + static public MalFunction multiply = new MalFunction( + a => (MalInteger)a[0] * (MalInteger)a[1] ); + static public MalFunction divide = new MalFunction( + a => (MalInteger)a[0] / (MalInteger)a[1] ); + + static void Main(string[] args) { string prompt = "user> "; var repl_env = new Mal.env.Env(null); - _ref(repl_env, "+", new Mal.core.plus() ); - _ref(repl_env, "-", new Mal.core.minus() ); - _ref(repl_env, "*", new Mal.core.multiply() ); - _ref(repl_env, "/", new Mal.core.divide() ); + _ref(repl_env, "+", plus); + _ref(repl_env, "-", minus); + _ref(repl_env, "*", multiply); + _ref(repl_env, "/", divide); if (args.Length > 0 && args[0] == "--raw") { Mal.readline.mode = Mal.readline.Mode.Raw; diff --git a/cs/step4_if_fn_do.cs b/cs/step4_if_fn_do.cs new file mode 100644 index 0000000..d0ca882 --- /dev/null +++ b/cs/step4_if_fn_do.cs @@ -0,0 +1,166 @@ +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Mal; +using MalVal = Mal.types.MalVal; +using MalSymbol = Mal.types.MalSymbol; +using MalInteger = Mal.types.MalInteger; +using MalList = Mal.types.MalList; +using MalVector = Mal.types.MalVector; +using MalHashMap = Mal.types.MalHashMap; +using MalFunction = Mal.types.MalFunction; +using Env = Mal.env.Env; + +namespace Mal { + class step4_if_fn_do { + // read + static MalVal READ(string str) { + return reader.read_str(str); + } + + // eval + static MalVal eval_ast(MalVal ast, Env env) { + if (ast is MalSymbol) { + MalSymbol sym = (MalSymbol)ast; + return env.get(sym.getName()); + } else if (ast is MalList) { + MalList old_lst = (MalList)ast; + MalList new_lst = ast.list_Q() ? new MalList() + : (MalList)new MalVector(); + foreach (MalVal mv in old_lst.getValue()) { + new_lst.conj_BANG(EVAL(mv, env)); + } + return new_lst; + } else if (ast is MalHashMap) { + var new_dict = new Dictionary<string, MalVal>(); + foreach (var entry in ((MalHashMap)ast).getValue()) { + new_dict.Add(entry.Key, EVAL((MalVal)entry.Value, env)); + } + return new MalHashMap(new_dict); + } else { + return ast; + } + } + + + static MalVal EVAL(MalVal orig_ast, Env env) { + MalVal a0, a1, a2, a3, res; + MalList el; + //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; } + a0 = ast.nth(0); + + String a0sym = a0 is 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)); + } + return EVAL(a2, let_env); + case "do": + el = (MalList)eval_ast(ast.rest(), env); + return el.nth(el.size()-1); + case "if": + a1 = ast.nth(1); + MalVal cond = EVAL(a1, env); + if (cond == Mal.types.Nil || cond == Mal.types.False) { + // eval false slot form + if (ast.size() > 3) { + a3 = ast.nth(3); + return EVAL(a3, env); + } else { + return Mal.types.Nil; + } + } else { + // eval true slot form + a2 = ast.nth(2); + return EVAL(a2, env); + } + case "fn*": + MalList a1f = (MalList)ast.nth(1); + MalVal a2f = ast.nth(2); + Env cur_env = env; + return new MalFunction( + args => EVAL(a2f, new Env(cur_env, a1f, args)) ); + default: + el = (MalList)eval_ast(ast, env); + var f = (MalFunction)el.nth(0); + return f.apply(el.rest()); + } + } + + // print + static string PRINT(MalVal exp) { + return printer._pr_str(exp, true); + } + + // REPL + static MalVal RE(Env env, string str) { + return EVAL(READ(str), env); + } + public static Env _ref(Env env, string name, MalVal mv) { + return env.set(name, mv); + } + + static void Main(string[] args) { + string prompt = "user> "; + + var repl_env = new Mal.env.Env(null); + foreach (var entry in Mal.core.ns) { + _ref(repl_env, entry.Key, entry.Value); + } + + RE(repl_env, "(def! not (fn* (a) (if a false true)))"); + + if (args.Length > 0 && args[0] == "--raw") { + Mal.readline.mode = Mal.readline.Mode.Raw; + } + while (true) { + string line; + try { + line = Mal.readline.Readline(prompt); + if (line == null) { break; } + } catch (IOException e) { + Console.WriteLine("IOException: " + e.Message); + break; + } + try { + Console.WriteLine(PRINT(RE(repl_env, line))); + } catch (Mal.types.MalContinue) { + continue; + } catch (Mal.reader.ParseError e) { + Console.WriteLine(e.Message); + continue; + } catch (Mal.types.MalException e) { + Console.WriteLine("Error: " + e.getValue()); + continue; + } catch (Exception e) { + Console.WriteLine("Error: " + e.Message); + continue; + } + } + } + } +} diff --git a/cs/types.cs b/cs/types.cs index 8f6755f..ae9d4bf 100644 --- a/cs/types.cs +++ b/cs/types.cs @@ -4,6 +4,9 @@ using Mal; namespace Mal { public class types { + // + // Exceptiosn/Errors + // public class MalThrowable : Exception { public MalThrowable() : base() { } public MalThrowable(string msg) : base(msg) { } @@ -25,6 +28,41 @@ namespace Mal { public MalVal getValue() { return value; } } + // + // General functions + // + + public static bool _equal_Q(MalVal a, MalVal b) { + Type ota = a.GetType(), otb = b.GetType(); + if (!((ota == otb) || + (a is MalList && b is MalList))) { + return false; + } else { + if (a is MalInteger) { + return ((MalInteger)a).getValue() == + ((MalInteger)b).getValue(); + } else if (a is MalSymbol) { + return ((MalSymbol)a).getName() == + ((MalSymbol)b).getName(); + } else if (a is MalString) { + return ((MalString)a).getValue() == + ((MalString)b).getValue(); + } else if (a is MalList) { + if (((MalList)a).size() != ((MalList)b).size()) { + return false; + } + for (int i=0; i<((MalList)a).size(); i++) { + if (! _equal_Q(((MalList)a)[i], ((MalList)b)[i])) { + return false; + } + } + return true; + } else { + return a == b; + } + } + } + public abstract class MalVal { // Default is just to call regular toString() @@ -63,29 +101,29 @@ namespace Mal { public override string ToString(bool print_readably) { return value.ToString(); } - public MalInteger add(MalInteger other) { - return new MalInteger(value + other.getValue()); + public static MalConstant operator <(MalInteger a, MalInteger b) { + return a.getValue() < b.getValue() ? True : False; } - public MalInteger subtract(MalInteger other) { - return new MalInteger(value - other.getValue()); + public static MalConstant operator <=(MalInteger a, MalInteger b) { + return a.getValue() <= b.getValue() ? True : False; } - public MalInteger multiply(MalInteger other) { - return new MalInteger(value * other.getValue()); + public static MalConstant operator >(MalInteger a, MalInteger b) { + return a.getValue() > b.getValue() ? True : False; } - public MalInteger divide(MalInteger other) { - return new MalInteger(value / other.getValue()); + public static MalConstant operator >=(MalInteger a, MalInteger b) { + return a.getValue() >= b.getValue() ? True : False; } - public MalConstant lt(MalInteger other) { - return (value < other.getValue()) ? True : False; + public static MalInteger operator +(MalInteger a, MalInteger b) { + return new MalInteger(a.getValue() + b.getValue()); } - public MalConstant lte(MalInteger other) { - return (value <= other.getValue()) ? True : False; + public static MalInteger operator -(MalInteger a, MalInteger b) { + return new MalInteger(a.getValue() - b.getValue()); } - public MalConstant gt(MalInteger other) { - return (value > other.getValue()) ? True : False; + public static MalInteger operator *(MalInteger a, MalInteger b) { + return new MalInteger(a.getValue() * b.getValue()); } - public MalConstant gte(MalInteger other) { - return (value >= other.getValue()) ? True : False; + public static MalInteger operator /(MalInteger a, MalInteger b) { + return new MalInteger(a.getValue() / b.getValue()); } } @@ -114,8 +152,9 @@ namespace Mal { } public override string ToString(bool print_readably) { if (print_readably) { - //return "\"" + printer.escapeString(value) + "\""; - return "\"" + value + "\""; + return "\"" + value.Replace("\\", "\\\\") + .Replace("\"", "\\\"") + .Replace("\n", "\\n") + "\""; } else { return value; } @@ -160,6 +199,9 @@ namespace Mal { public int size() { return value.Count; } public MalVal nth(int idx) { return value[idx]; } + public MalVal this[int idx] { + get { return value[idx]; } + } public MalList rest() { if (size() > 0) { return new MalList(value.GetRange(1, value.Count-1)); @@ -229,7 +271,7 @@ namespace Mal { public override string ToString() { return "{" + printer.join(value, " ", true) + "}"; } - public override string ToString(Boolean print_readably) { + public override string ToString(bool print_readably) { return "{" + printer.join(value, " ", print_readably) + "}"; } @@ -247,9 +289,15 @@ namespace Mal { } } - public abstract class MalFunction : MalVal { - public abstract MalVal apply(MalList args); - } + public class MalFunction : MalVal { + Func<MalList, MalVal> value = null; + public MalFunction(Func<MalList, MalVal> f) { + value = f; + } + public MalVal apply(MalList args) { + return value(args); + } + } } } |
