aboutsummaryrefslogtreecommitdiff
path: root/cs
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-04-07 00:17:13 -0500
committerJoel Martin <github@martintribe.org>2014-04-07 00:17:13 -0500
commitafdf531eba459a7a7b6505b037dbe48a363c2c79 (patch)
treeb899e21b373ac8338756140eaf7afcb399d46bb9 /cs
parentb18969c0b8d47d67d4b73b5b20742a0bc3179e72 (diff)
downloadmal-afdf531eba459a7a7b6505b037dbe48a363c2c79.tar.gz
mal-afdf531eba459a7a7b6505b037dbe48a363c2c79.zip
CS: add step4_if_fn_do
Diffstat (limited to 'cs')
-rw-r--r--cs/Makefile5
-rw-r--r--cs/core.cs83
-rw-r--r--cs/printer.cs9
-rw-r--r--cs/reader.cs9
-rw-r--r--cs/step1_read_print.cs2
-rw-r--r--cs/step2_eval.cs43
-rw-r--r--cs/step3_env.cs23
-rw-r--r--cs/step4_if_fn_do.cs166
-rw-r--r--cs/types.cs92
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))
diff --git a/cs/core.cs b/cs/core.cs
index fad4cce..ae8fe1b 100644
--- a/cs/core.cs
+++ b/cs/core.cs
@@ -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);
+ }
+ }
}
}