aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-04-06 22:38:26 -0500
committerJoel Martin <github@martintribe.org>2014-04-06 22:38:26 -0500
commitb56c49a12dad20c55fbf07775b536c9d656af313 (patch)
tree11989cec7ac0bc5ce4cc3b1ea46c9948847cc044
parent53beaa0a6ddd9d8a5fb531f97c44a9c7129d1de7 (diff)
downloadmal-b56c49a12dad20c55fbf07775b536c9d656af313.tar.gz
mal-b56c49a12dad20c55fbf07775b536c9d656af313.zip
C#: add step2_eval.
-rw-r--r--.gitignore1
-rw-r--r--cs/Makefile2
-rw-r--r--cs/step2_eval.cs146
-rw-r--r--cs/types.cs23
4 files changed, 170 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 76ce4fd..19ba294 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,7 @@ c/step9_interop
c/stepA_more
cs/*.exe
cs/*.dll
+cs/*.mdb
clojure/target
clojure/.lein-repl-history
java/target/
diff --git a/cs/Makefile b/cs/Makefile
index 0028096..7a56e5d 100644
--- a/cs/Makefile
+++ b/cs/Makefile
@@ -3,7 +3,7 @@
TESTS =
SOURCES = readline.cs types.cs reader.cs printer.cs \
- step0_repl.cs step1_read_print.cs
+ step0_repl.cs step1_read_print.cs step2_eval.cs
OTHER_SOURCES = getline.cs
#####################
diff --git a/cs/step2_eval.cs b/cs/step2_eval.cs
new file mode 100644
index 0000000..fa01901
--- /dev/null
+++ b/cs/step2_eval.cs
@@ -0,0 +1,146 @@
+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;
+
+namespace Mal {
+ class step1_repl {
+ // read
+ static MalVal READ(string str) {
+ return reader.read_str(str);
+ }
+
+ // eval
+ static MalVal eval_ast(MalVal ast, Dictionary<string, MalVal> env) {
+ if (ast is MalSymbol) {
+ MalSymbol sym = (MalSymbol)ast;
+ return (MalVal)env[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, Dictionary<string, MalVal> env) {
+ MalVal a0;
+ //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) + "'");
+ }
+ MalVal args = eval_ast(ast.rest(), env);
+ MalSymbol fsym = (MalSymbol)a0;
+ var f = (MalFunction)env[fsym.getName()];
+ if (f == null) {
+ throw new Mal.types.MalError("'" + fsym.getName() + "' not found");
+ }
+ return f.apply((MalList)args);
+
+ }
+
+ // print
+ static string PRINT(MalVal exp) {
+ return printer._pr_str(exp, true);
+ }
+
+ // REPL
+ static MalVal RE(Dictionary<string, MalVal> env, string str) {
+ 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 void Main(string[] args) {
+ string prompt = "user> ";
+
+ var repl_env = new Dictionary<string, MalVal> {
+ { "+", new plus() },
+ { "-", new minus() },
+ { "*", new multiply() },
+ { "/", new 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.types.MalError e) {
+ Console.WriteLine("Error: " + e.Message);
+ continue;
+ } catch (Mal.reader.ParseError e) {
+ Console.WriteLine(e.Message);
+ continue;
+ } catch (Exception e) {
+ Console.WriteLine("Error: " + e.Message);
+ continue;
+ }
+ }
+ }
+ }
+}
diff --git a/cs/types.cs b/cs/types.cs
index 1f2e797..7cbbd53 100644
--- a/cs/types.cs
+++ b/cs/types.cs
@@ -16,7 +16,10 @@ namespace Mal {
public abstract class MalVal {
// Default is just to call regular toString()
- public abstract string ToString(bool print_readably);
+ public virtual string ToString(bool print_readably) {
+ return "<unknown>";
+ }
+ public virtual bool list_Q() { return false; }
}
public class MalConstant : MalVal {
@@ -127,6 +130,7 @@ namespace Mal {
}
public List<MalVal> getValue() { return value; }
+ public override bool list_Q() { return true; }
public override string ToString() {
return start + printer.join(value, " ", true) + end;
@@ -141,6 +145,16 @@ namespace Mal {
}
return this;
}
+
+ public int size() { return value.Count; }
+ public MalVal nth(int idx) { return value[idx]; }
+ public MalVal rest() {
+ if (size() > 0) {
+ return new MalList(value.GetRange(1, value.Count-1));
+ } else {
+ return new MalList();
+ }
+ }
}
public class MalVector : MalList {
@@ -164,6 +178,7 @@ namespace Mal {
return (MalVector)this.MemberwiseClone();
}
+ public override bool list_Q() { return false; }
}
public class MalHashMap : MalVal {
@@ -185,6 +200,8 @@ namespace Mal {
return (MalHashMap)this.MemberwiseClone();
}
+ public Dictionary<string, MalVal> getValue() { return value; }
+
public override string ToString() {
return "{" + printer.join(value, " ", true) + "}";
}
@@ -206,5 +223,9 @@ namespace Mal {
}
}
+ public abstract class MalFunction : MalVal {
+ public abstract MalVal apply(MalList args);
+ }
+
}
}