From b18969c0b8d47d67d4b73b5b20742a0bc3179e72 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Sun, 6 Apr 2014 23:58:14 -0500 Subject: CS: add step3_env Also, make Makefile more closely match the C Makefile. --- cs/Makefile | 12 +++-- cs/core.cs | 33 +++++++++++++ cs/env.cs | 55 ++++++++++++++++++++++ cs/step2_eval.cs | 16 +++---- cs/step3_env.cs | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ cs/types.cs | 26 ++++++++++- 6 files changed, 266 insertions(+), 16 deletions(-) create mode 100644 cs/core.cs create mode 100644 cs/env.cs create mode 100644 cs/step3_env.cs diff --git a/cs/Makefile b/cs/Makefile index 7a56e5d..bf8a8ef 100644 --- a/cs/Makefile +++ b/cs/Makefile @@ -2,20 +2,22 @@ TESTS = -SOURCES = readline.cs types.cs reader.cs printer.cs \ - step0_repl.cs step1_read_print.cs step2_eval.cs +SOURCES = readline.cs types.cs reader.cs printer.cs env.cs core.cs \ + step3_env.cs + OTHER_SOURCES = getline.cs ##################### -FLAGS = -debug+ +SRCS = step0_repl.cs step1_read_print.cs step2_eval.cs step3_env.cs -OBJS = LIB_SRCS = $(filter-out step%,$(OTHER_SOURCES) $(SOURCES)) +FLAGS = -debug+ + ##################### -all: mal.exe $(patsubst %.cs,%.exe,$(filter step%,$(SOURCES))) +all: mal.exe $(patsubst %.cs,%.exe,$(SRCS)) mal.exe: $(patsubst %.cs,%.exe,$(word $(words $(SOURCES)),$(SOURCES))) cp $< $@ diff --git a/cs/core.cs b/cs/core.cs new file mode 100644 index 0000000..fad4cce --- /dev/null +++ b/cs/core.cs @@ -0,0 +1,33 @@ +using MalVal = Mal.types.MalVal; +using MalInteger = Mal.types.MalInteger; +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))); + } + } + } +} diff --git a/cs/env.cs b/cs/env.cs new file mode 100644 index 0000000..cb5318f --- /dev/null +++ b/cs/env.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using Mal; +using MalVal = Mal.types.MalVal; +using MalSymbol = Mal.types.MalSymbol; +using MalList = Mal.types.MalList; + +namespace Mal { + public class env { + public class Env { + Env outer = null; + Dictionary data = new Dictionary(); + + public Env(Env outer) { + this.outer = outer; + } + public Env(Env outer, MalList binds, MalList exprs) { + this.outer = outer; + for (int i=0; i(); + 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, res; + //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); + if (!(a0 is MalSymbol)) { + throw new Mal.types.MalError("attempt to apply on non-symbol '" + + Mal.printer._pr_str(a0,true) + "'"); + } + + switch (((MalSymbol)a0).getName()) { + 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); + default: + var 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); + _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() ); + + 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 7cbbd53..8f6755f 100644 --- a/cs/types.cs +++ b/cs/types.cs @@ -13,6 +13,18 @@ namespace Mal { } public class MalContinue : MalThrowable { } + // Thrown by throw function + public class MalException : MalThrowable { + MalVal value; + public MalException(MalVal value) { + this.value = value; + } + public MalException(string value) { + this.value = new MalString(value); + } + public MalVal getValue() { return value; } + } + public abstract class MalVal { // Default is just to call regular toString() @@ -148,13 +160,20 @@ namespace Mal { public int size() { return value.Count; } public MalVal nth(int idx) { return value[idx]; } - public MalVal rest() { + public MalList rest() { if (size() > 0) { return new MalList(value.GetRange(1, value.Count-1)); } else { return new MalList(); } } + public virtual MalList slice(int start) { + return new MalList(value.GetRange(start, value.Count-start)); + } + public virtual MalList slice(int start, int end) { + return new MalList(value.GetRange(start, end-start)); + } + } public class MalVector : MalList { @@ -179,6 +198,11 @@ namespace Mal { } public override bool list_Q() { return false; } + + public override MalList slice(int start, int end) { + var val = this.getValue(); + return new MalVector(val.GetRange(start, val.Count-start)); + } } public class MalHashMap : MalVal { -- cgit v1.2.3