diff --git a/impls/vala/env.vala b/impls/vala/env.vala index ffe9cfdd7b..6b341a227e 100644 --- a/impls/vala/env.vala +++ b/impls/vala/env.vala @@ -59,18 +59,11 @@ class Mal.Env : GC.Object { data[key] = f; } - public Mal.Env? find(Mal.Sym key) { + public new Mal.Val? get(Mal.Sym key) { if (key in data) - return this; + return data[key]; if (outer == null) return null; return outer.find(key); } - - public new Mal.Val get(Mal.Sym key) throws Mal.Error { - var found = find(key); - if (found == null) - throw new Error.ENV_LOOKUP_FAILED("'%s' not found", key.v); - return found.data[key]; - } } diff --git a/impls/vala/step2_eval.vala b/impls/vala/step2_eval.vala index f62e8806a2..0504eca424 100644 --- a/impls/vala/step2_eval.vala +++ b/impls/vala/step2_eval.vala @@ -88,18 +88,15 @@ class Mal.Main : GLib.Object { } } - public static Mal.Val eval_ast(Mal.Val ast, Mal.Env env) + public static Mal.Val EVAL(Mal.Val ast, Mal.Env env) throws Mal.Error { - var roota = new GC.Root(ast); (void)roota; + var ast_root = new GC.Root(ast); (void)ast_root; + GC.Core.maybe_collect(); + + # stdout.printf("EVAL: %s\n", pr_str(ast)); + if (ast is Mal.Sym) return env.get(ast as Mal.Sym); - if (ast is Mal.List) { - var result = new Mal.List.empty(); - var root = new GC.Root(result); (void)root; - foreach (var elt in (ast as Mal.List).vs) - result.vs.append(EVAL(elt, env)); - return result; - } if (ast is Mal.Vector) { var vec = ast as Mal.Vector; var result = new Mal.Vector.with_size(vec.length); @@ -116,25 +113,20 @@ class Mal.Main : GLib.Object { result.insert(key, EVAL(map[key], env)); return result; } - return ast; - } - - public static Mal.Val EVAL(Mal.Val ast, Mal.Env env) - throws Mal.Error { - var ast_root = new GC.Root(ast); (void)ast_root; - GC.Core.maybe_collect(); - if (ast is Mal.List) { unowned GLib.List list = (ast as Mal.List).vs; if (list.first() == null) return ast; - var newlist = eval_ast(ast, env) as Mal.List; + var newlist = new Mal.List.empty(); + var root = new GC.Root(newlist); (void)root; + for (var x in list) + newlist.vs.append(EVAL(x, env)); unowned GLib.List firstlink = newlist.vs.first(); var fn = firstlink.data as Mal.BuiltinFunction; newlist.vs.remove_link(firstlink); return fn.call(newlist); } else { - return eval_ast(ast, env); + return ast; } } diff --git a/impls/vala/step3_env.vala b/impls/vala/step3_env.vala index 429b5b17db..0f302ee71c 100644 --- a/impls/vala/step3_env.vala +++ b/impls/vala/step3_env.vala @@ -69,38 +69,6 @@ class Mal.Main : GLib.Object { } } - public static Mal.Val eval_ast(Mal.Val ast, Mal.Env env) - throws Mal.Error { - var roota = new GC.Root(ast); (void)roota; - var roote = new GC.Root(env); (void)roote; - if (ast is Mal.Sym) - return env.get(ast as Mal.Sym); - if (ast is Mal.List) { - var result = new Mal.List.empty(); - var root = new GC.Root(result); (void)root; - foreach (var elt in (ast as Mal.List).vs) - result.vs.append(EVAL(elt, env)); - return result; - } - if (ast is Mal.Vector) { - var vec = ast as Mal.Vector; - var result = new Mal.Vector.with_size(vec.length); - var root = new GC.Root(result); (void)root; - for (var i = 0; i < vec.length; i++) - result[i] = EVAL(vec[i], env); - return result; - } - if (ast is Mal.Hashmap) { - var result = new Mal.Hashmap(); - var root = new GC.Root(result); (void)root; - var map = (ast as Mal.Hashmap).vs; - foreach (var key in map.get_keys()) - result.insert(key, EVAL(map[key], env)); - return result; - } - return ast; - } - private static Mal.Val define_eval(Mal.Val key, Mal.Val value, Mal.Env env) throws Mal.Error { @@ -121,6 +89,32 @@ class Mal.Main : GLib.Object { var env_root = new GC.Root(env); (void)env_root; GC.Core.maybe_collect(); + var dbgeval = env.get(Mal.Sym("DEBUG-EVAL")); + if (dbgeval != null && dbgeval.truth_value()) + stdout.printf("EVAL: %s\n", pr_str(ast)); + + if (ast is Mal.Sym) + var key = ast as Mal.Sym; + var val = env.get(key); + if (val == null) + throw new Error.ENV_LOOKUP_FAILED("'%s' not found", key.v); + return val; + if (ast is Mal.Vector) { + var vec = ast as Mal.Vector; + var result = new Mal.Vector.with_size(vec.length); + var root = new GC.Root(result); (void)root; + for (var i = 0; i < vec.length; i++) + result[i] = EVAL(vec[i], env); + return result; + } + if (ast is Mal.Hashmap) { + var result = new Mal.Hashmap(); + var root = new GC.Root(result); (void)root; + var map = (ast as Mal.Hashmap).vs; + foreach (var key in map.get_keys()) + result.insert(key, EVAL(map[key], env)); + return result; + } if (ast is Mal.List) { unowned GLib.List list = (ast as Mal.List).vs; if (list.first() == null) @@ -169,7 +163,10 @@ class Mal.Main : GLib.Object { } } - var newlist = eval_ast(ast, env) as Mal.List; + var newlist = new Mal.List.empty(); + var root = new GC.Root(newlist); (void)root; + for (var x in list) + newlist.vs.append(EVAL(x, env)); unowned GLib.List firstlink = newlist.vs.first(); Mal.Val firstdata = firstlink.data; newlist.vs.remove_link(firstlink); @@ -181,7 +178,7 @@ class Mal.Main : GLib.Object { "bad value at start of list"); } } else { - return eval_ast(ast, env); + return ast; } } diff --git a/impls/vala/step4_if_fn_do.vala b/impls/vala/step4_if_fn_do.vala index 93d09c3f58..aed71775ed 100644 --- a/impls/vala/step4_if_fn_do.vala +++ b/impls/vala/step4_if_fn_do.vala @@ -24,38 +24,6 @@ class Mal.Main: GLib.Object { } } - public static Mal.Val eval_ast(Mal.Val ast, Mal.Env env) - throws Mal.Error { - var roota = new GC.Root(ast); (void)roota; - var roote = new GC.Root(env); (void)roote; - if (ast is Mal.Sym) - return env.get(ast as Mal.Sym); - if (ast is Mal.List) { - var result = new Mal.List.empty(); - var root = new GC.Root(result); (void)root; - foreach (var elt in (ast as Mal.List).vs) - result.vs.append(EVAL(elt, env)); - return result; - } - if (ast is Mal.Vector) { - var vec = ast as Mal.Vector; - var result = new Mal.Vector.with_size(vec.length); - var root = new GC.Root(result); (void)root; - for (var i = 0; i < vec.length; i++) - result[i] = EVAL(vec[i], env); - return result; - } - if (ast is Mal.Hashmap) { - var result = new Mal.Hashmap(); - var root = new GC.Root(result); (void)root; - var map = (ast as Mal.Hashmap).vs; - foreach (var key in map.get_keys()) - result.insert(key, EVAL(map[key], env)); - return result; - } - return ast; - } - private static Mal.Val define_eval(Mal.Val key, Mal.Val value, Mal.Env env) throws Mal.Error { @@ -76,6 +44,32 @@ class Mal.Main: GLib.Object { var env_root = new GC.Root(env); (void)env_root; GC.Core.maybe_collect(); + var dbgeval = env.get(Mal.Sym("DEBUG-EVAL")); + if (dbgeval != null && dbgeval.truth_value()) + stdout.printf("EVAL: %s\n", pr_str(ast)); + + if (ast is Mal.Sym) + var key = ast as Mal.Sym; + var val = env.get(key); + if (val == null) + throw new Error.ENV_LOOKUP_FAILED("'%s' not found", key.v); + return val; + if (ast is Mal.Vector) { + var vec = ast as Mal.Vector; + var result = new Mal.Vector.with_size(vec.length); + var root = new GC.Root(result); (void)root; + for (var i = 0; i < vec.length; i++) + result[i] = EVAL(vec[i], env); + return result; + } + if (ast is Mal.Hashmap) { + var result = new Mal.Hashmap(); + var root = new GC.Root(result); (void)root; + var map = (ast as Mal.Hashmap).vs; + foreach (var key in map.get_keys()) + result.insert(key, EVAL(map[key], env)); + return result; + } if (ast is Mal.List) { unowned GLib.List list = (ast as Mal.List).vs; if (list.first() == null) @@ -161,7 +155,10 @@ class Mal.Main: GLib.Object { } } - var newlist = eval_ast(ast, env) as Mal.List; + var newlist = new Mal.List.empty(); + var root = new GC.Root(newlist); (void)root; + for (var x in list) + newlist.vs.append(EVAL(x, env)); unowned GLib.List firstlink = newlist.vs.first(); Mal.Val firstdata = firstlink.data; newlist.vs.remove_link(firstlink); @@ -178,7 +175,7 @@ class Mal.Main: GLib.Object { "bad value at start of list"); } } else { - return eval_ast(ast, env); + return ast; } } diff --git a/impls/vala/step5_tco.vala b/impls/vala/step5_tco.vala index c29a31fd6d..b22125cc06 100644 --- a/impls/vala/step5_tco.vala +++ b/impls/vala/step5_tco.vala @@ -24,38 +24,6 @@ class Mal.Main : GLib.Object { } } - public static Mal.Val eval_ast(Mal.Val ast, Mal.Env env) - throws Mal.Error { - var roota = new GC.Root(ast); (void)roota; - var roote = new GC.Root(env); (void)roote; - if (ast is Mal.Sym) - return env.get(ast as Mal.Sym); - if (ast is Mal.List) { - var result = new Mal.List.empty(); - var root = new GC.Root(result); (void)root; - foreach (var elt in (ast as Mal.List).vs) - result.vs.append(EVAL(elt, env)); - return result; - } - if (ast is Mal.Vector) { - var vec = ast as Mal.Vector; - var result = new Mal.Vector.with_size(vec.length); - var root = new GC.Root(result); (void)root; - for (var i = 0; i < vec.length; i++) - result[i] = EVAL(vec[i], env); - return result; - } - if (ast is Mal.Hashmap) { - var result = new Mal.Hashmap(); - var root = new GC.Root(result); (void)root; - var map = (ast as Mal.Hashmap).vs; - foreach (var key in map.get_keys()) - result.insert(key, EVAL(map[key], env)); - return result; - } - return ast; - } - private static Mal.Val define_eval(Mal.Val key, Mal.Val value, Mal.Env env) throws Mal.Error { @@ -85,6 +53,33 @@ class Mal.Main : GLib.Object { ast_root.obj = ast; env_root.obj = env; GC.Core.maybe_collect(); + + var dbgeval = env.get(Mal.Sym("DEBUG-EVAL")); + if (dbgeval != null && dbgeval.truth_value()) + stdout.printf("EVAL: %s\n", pr_str(ast)); + + if (ast is Mal.Sym) + var key = ast as Mal.Sym; + var val = env.get(key); + if (val == null) + throw new Error.ENV_LOOKUP_FAILED("'%s' not found", key.v); + return val; + if (ast is Mal.Vector) { + var vec = ast as Mal.Vector; + var result = new Mal.Vector.with_size(vec.length); + var root = new GC.Root(result); (void)root; + for (var i = 0; i < vec.length; i++) + result[i] = EVAL(vec[i], env); + return result; + } + if (ast is Mal.Hashmap) { + var result = new Mal.Hashmap(); + var root = new GC.Root(result); (void)root; + var map = (ast as Mal.Hashmap).vs; + foreach (var key in map.get_keys()) + result.insert(key, EVAL(map[key], env)); + return result; + } if (ast is Mal.List) { unowned GLib.List list = (ast as Mal.List).vs; if (list.first() == null) @@ -172,7 +167,10 @@ class Mal.Main : GLib.Object { } } - var newlist = eval_ast(ast, env) as Mal.List; + var newlist = new Mal.List.empty(); + var root = new GC.Root(newlist); (void)root; + for (var x in list) + newlist.vs.append(EVAL(x, env)); unowned GLib.List firstlink = newlist.vs.first(); Mal.Val firstdata = firstlink.data; newlist.vs.remove_link(firstlink); @@ -189,7 +187,7 @@ class Mal.Main : GLib.Object { "bad value at start of list"); } } else { - return eval_ast(ast, env); + return ast; } } } diff --git a/impls/vala/step6_file.vala b/impls/vala/step6_file.vala index 8177d75b3f..b8c36e794e 100644 --- a/impls/vala/step6_file.vala +++ b/impls/vala/step6_file.vala @@ -38,38 +38,6 @@ class Mal.Main : GLib.Object { } } - public static Mal.Val eval_ast(Mal.Val ast, Mal.Env env) - throws Mal.Error { - var roota = new GC.Root(ast); (void)roota; - var roote = new GC.Root(env); (void)roote; - if (ast is Mal.Sym) - return env.get(ast as Mal.Sym); - if (ast is Mal.List) { - var result = new Mal.List.empty(); - var root = new GC.Root(result); (void)root; - foreach (var elt in (ast as Mal.List).vs) - result.vs.append(EVAL(elt, env)); - return result; - } - if (ast is Mal.Vector) { - var vec = ast as Mal.Vector; - var result = new Mal.Vector.with_size(vec.length); - var root = new GC.Root(result); (void)root; - for (var i = 0; i < vec.length; i++) - result[i] = EVAL(vec[i], env); - return result; - } - if (ast is Mal.Hashmap) { - var result = new Mal.Hashmap(); - var root = new GC.Root(result); (void)root; - var map = (ast as Mal.Hashmap).vs; - foreach (var key in map.get_keys()) - result.insert(key, EVAL(map[key], env)); - return result; - } - return ast; - } - private static Mal.Val define_eval(Mal.Val key, Mal.Val value, Mal.Env env) throws Mal.Error { @@ -99,6 +67,33 @@ class Mal.Main : GLib.Object { ast_root.obj = ast; env_root.obj = env; GC.Core.maybe_collect(); + + var dbgeval = env.get(Mal.Sym("DEBUG-EVAL")); + if (dbgeval != null && dbgeval.truth_value()) + stdout.printf("EVAL: %s\n", pr_str(ast)); + + if (ast is Mal.Sym) + var key = ast as Mal.Sym; + var val = env.get(key); + if (val == null) + throw new Error.ENV_LOOKUP_FAILED("'%s' not found", key.v); + return val; + if (ast is Mal.Vector) { + var vec = ast as Mal.Vector; + var result = new Mal.Vector.with_size(vec.length); + var root = new GC.Root(result); (void)root; + for (var i = 0; i < vec.length; i++) + result[i] = EVAL(vec[i], env); + return result; + } + if (ast is Mal.Hashmap) { + var result = new Mal.Hashmap(); + var root = new GC.Root(result); (void)root; + var map = (ast as Mal.Hashmap).vs; + foreach (var key in map.get_keys()) + result.insert(key, EVAL(map[key], env)); + return result; + } if (ast is Mal.List) { unowned GLib.List list = (ast as Mal.List).vs; if (list.first() == null) @@ -186,7 +181,10 @@ class Mal.Main : GLib.Object { } } - var newlist = eval_ast(ast, env) as Mal.List; + var newlist = new Mal.List.empty(); + var root = new GC.Root(newlist); (void)root; + for (var x in list) + newlist.vs.append(EVAL(x, env)); unowned GLib.List firstlink = newlist.vs.first(); Mal.Val firstdata = firstlink.data; newlist.vs.remove_link(firstlink); @@ -203,7 +201,7 @@ class Mal.Main : GLib.Object { "bad value at start of list"); } } else { - return eval_ast(ast, env); + return ast; } } } diff --git a/impls/vala/step7_quote.vala b/impls/vala/step7_quote.vala index 2347b9b185..e558ed5af2 100644 --- a/impls/vala/step7_quote.vala +++ b/impls/vala/step7_quote.vala @@ -38,38 +38,6 @@ class Mal.Main : GLib.Object { } } - public static Mal.Val eval_ast(Mal.Val ast, Mal.Env env) - throws Mal.Error { - var roota = new GC.Root(ast); (void)roota; - var roote = new GC.Root(env); (void)roote; - if (ast is Mal.Sym) - return env.get(ast as Mal.Sym); - if (ast is Mal.List) { - var result = new Mal.List.empty(); - var root = new GC.Root(result); (void)root; - foreach (var elt in (ast as Mal.List).vs) - result.vs.append(EVAL(elt, env)); - return result; - } - if (ast is Mal.Vector) { - var vec = ast as Mal.Vector; - var result = new Mal.Vector.with_size(vec.length); - var root = new GC.Root(result); (void)root; - for (var i = 0; i < vec.length; i++) - result[i] = EVAL(vec[i], env); - return result; - } - if (ast is Mal.Hashmap) { - var result = new Mal.Hashmap(); - var root = new GC.Root(result); (void)root; - var map = (ast as Mal.Hashmap).vs; - foreach (var key in map.get_keys()) - result.insert(key, EVAL(map[key], env)); - return result; - } - return ast; - } - private static Mal.Val define_eval(Mal.Val key, Mal.Val value, Mal.Env env) throws Mal.Error { @@ -163,6 +131,33 @@ class Mal.Main : GLib.Object { ast_root.obj = ast; env_root.obj = env; GC.Core.maybe_collect(); + + var dbgeval = env.get(Mal.Sym("DEBUG-EVAL")); + if (dbgeval != null && dbgeval.truth_value()) + stdout.printf("EVAL: %s\n", pr_str(ast)); + + if (ast is Mal.Sym) + var key = ast as Mal.Sym; + var val = env.get(key); + if (val == null) + throw new Error.ENV_LOOKUP_FAILED("'%s' not found", key.v); + return val; + if (ast is Mal.Vector) { + var vec = ast as Mal.Vector; + var result = new Mal.Vector.with_size(vec.length); + var root = new GC.Root(result); (void)root; + for (var i = 0; i < vec.length; i++) + result[i] = EVAL(vec[i], env); + return result; + } + if (ast is Mal.Hashmap) { + var result = new Mal.Hashmap(); + var root = new GC.Root(result); (void)root; + var map = (ast as Mal.Hashmap).vs; + foreach (var key in map.get_keys()) + result.insert(key, EVAL(map[key], env)); + return result; + } if (ast is Mal.List) { unowned GLib.List list = (ast as Mal.List).vs; if (list.first() == null) @@ -253,11 +248,6 @@ class Mal.Main : GLib.Object { throw new Mal.Error.BAD_PARAMS( "quote: expected one argument"); return list.next.data; - case "quasiquoteexpand": - if (list.length() != 2) - throw new Mal.Error.BAD_PARAMS( - "quasiquoteexpand: expected one argument"); - return quasiquote(list.next.data); case "quasiquote": if (list.length() != 2) throw new Mal.Error.BAD_PARAMS( @@ -267,7 +257,10 @@ class Mal.Main : GLib.Object { } } - var newlist = eval_ast(ast, env) as Mal.List; + var newlist = new Mal.List.empty(); + var root = new GC.Root(newlist); (void)root; + for (var x in list) + newlist.vs.append(EVAL(x, env)); unowned GLib.List firstlink = newlist.vs.first(); Mal.Val firstdata = firstlink.data; newlist.vs.remove_link(firstlink); @@ -284,7 +277,7 @@ class Mal.Main : GLib.Object { "bad value at start of list"); } } else { - return eval_ast(ast, env); + return ast; } } } diff --git a/impls/vala/step8_macros.vala b/impls/vala/step8_macros.vala index 3f6f034515..b5aa2945b8 100644 --- a/impls/vala/step8_macros.vala +++ b/impls/vala/step8_macros.vala @@ -38,38 +38,6 @@ class Mal.Main : GLib.Object { } } - public static Mal.Val eval_ast(Mal.Val ast, Mal.Env env) - throws Mal.Error { - var roota = new GC.Root(ast); (void)roota; - var roote = new GC.Root(env); (void)roote; - if (ast is Mal.Sym) - return env.get(ast as Mal.Sym); - if (ast is Mal.List) { - var result = new Mal.List.empty(); - var root = new GC.Root(result); (void)root; - foreach (var elt in (ast as Mal.List).vs) - result.vs.append(EVAL(elt, env)); - return result; - } - if (ast is Mal.Vector) { - var vec = ast as Mal.Vector; - var result = new Mal.Vector.with_size(vec.length); - var root = new GC.Root(result); (void)root; - for (var i = 0; i < vec.length; i++) - result[i] = EVAL(vec[i], env); - return result; - } - if (ast is Mal.Hashmap) { - var result = new Mal.Hashmap(); - var root = new GC.Root(result); (void)root; - var map = (ast as Mal.Hashmap).vs; - foreach (var key in map.get_keys()) - result.insert(key, EVAL(map[key], env)); - return result; - } - return ast; - } - private static Mal.Val define_eval(Mal.Val key, Mal.Val value, Mal.Env env) throws Mal.Error { @@ -148,33 +116,6 @@ class Mal.Main : GLib.Object { } } - public static bool is_macro_call(Mal.Val v, Mal.Env env) { - var list = v as Mal.List; - if (list == null || list.vs == null || !(list.vs.data is Mal.Sym)) - return false; - try { - var fn = env.get(list.vs.data as Mal.Sym) as Mal.Function; - return (fn != null && fn.is_macro); - } catch (Mal.Error err) { - return false; - } - } - - public static Mal.Val macroexpand(Mal.Val ast_, Mal.Env env) - throws Mal.Error { - Mal.Val ast = ast_; - while (is_macro_call(ast, env)) { - var call = ast as Mal.List; - var macro = (env.get(call.vs.data as Mal.Sym) as Mal.Function); - var macroargs = new Mal.List(call.vs.copy()); - macroargs.vs.remove_link(macroargs.vs.first()); - var fnenv = new Mal.Env.funcall( - macro.env, macro.parameters, macroargs); - ast = Mal.Main.EVAL(macro.body, fnenv); - } - return ast; - } - public static Mal.Val EVAL(Mal.Val ast_, Mal.Env env_) throws Mal.Error { // Copy the implicitly 'unowned' function arguments into @@ -190,8 +131,33 @@ class Mal.Main : GLib.Object { ast_root.obj = ast; env_root.obj = env; GC.Core.maybe_collect(); - ast = macroexpand(ast, env); - ast_root.obj = ast; + + var dbgeval = env.get(Mal.Sym("DEBUG-EVAL")); + if (dbgeval != null && dbgeval.truth_value()) + stdout.printf("EVAL: %s\n", pr_str(ast)); + + if (ast is Mal.Sym) + var key = ast as Mal.Sym; + var val = env.get(key); + if (val == null) + throw new Error.ENV_LOOKUP_FAILED("'%s' not found", key.v); + return val; + if (ast is Mal.Vector) { + var vec = ast as Mal.Vector; + var result = new Mal.Vector.with_size(vec.length); + var root = new GC.Root(result); (void)root; + for (var i = 0; i < vec.length; i++) + result[i] = EVAL(vec[i], env); + return result; + } + if (ast is Mal.Hashmap) { + var result = new Mal.Hashmap(); + var root = new GC.Root(result); (void)root; + var map = (ast as Mal.Hashmap).vs; + foreach (var key in map.get_keys()) + result.insert(key, EVAL(map[key], env)); + return result; + } if (ast is Mal.List) { unowned GLib.List list = (ast as Mal.List).vs; if (list.first() == null) @@ -286,34 +252,34 @@ class Mal.Main : GLib.Object { throw new Mal.Error.BAD_PARAMS( "quote: expected one argument"); return list.next.data; - case "quasiquoteexpand": - if (list.length() != 2) - throw new Mal.Error.BAD_PARAMS( - "quasiquoteexpand: expected one argument"); - return quasiquote(list.next.data); case "quasiquote": if (list.length() != 2) throw new Mal.Error.BAD_PARAMS( "quasiquote: expected one argument"); ast = quasiquote(list.next.data); continue; // tail-call optimisation - case "macroexpand": - if (list.length() != 2) - throw new Mal.Error.BAD_PARAMS( - "macroexpand: expected one argument"); - return macroexpand(list.next.data, env); } } - var newlist = eval_ast(ast, env) as Mal.List; - unowned GLib.List firstlink = newlist.vs.first(); - Mal.Val firstdata = firstlink.data; - newlist.vs.remove_link(firstlink); - + Mal.Val firstdata = EVAL(list.first().data, env); + var args = new Mal.List.empty(); + var root = new GC.Root(args); (void)root; + foreach (var iter = list.iter().step(); iter.nonempty(); iter.step()) + args.vs.append(EVAL(iter.deref(), env)); if (firstdata is Mal.BuiltinFunction) { + for (var x in args) + x = EVAL(x, env); return (firstdata as Mal.BuiltinFunction).call(newlist); } else if (firstdata is Mal.Function) { var fn = firstdata as Mal.Function; + if (fn.is_macro) { + var fenv = new Mal.Env.funcall(fn.env, fn.parameters, + args); + ast = EVAL(fn.body, fenv); + continue; + } + for (var x in args) + x = EVAL(x, env); env = new Mal.Env.funcall(fn.env, fn.parameters, newlist); ast = fn.body; continue; // tail-call optimisation @@ -322,7 +288,7 @@ class Mal.Main : GLib.Object { "bad value at start of list"); } } else { - return eval_ast(ast, env); + return ast; } } } diff --git a/impls/vala/step9_try.vala b/impls/vala/step9_try.vala index fc1e94d0b8..7ee366874b 100644 --- a/impls/vala/step9_try.vala +++ b/impls/vala/step9_try.vala @@ -39,38 +39,6 @@ class Mal.Main : GLib.Object { } } - public static Mal.Val eval_ast(Mal.Val ast, Mal.Env env) - throws Mal.Error { - var roota = new GC.Root(ast); (void)roota; - var roote = new GC.Root(env); (void)roote; - if (ast is Mal.Sym) - return env.get(ast as Mal.Sym); - if (ast is Mal.List) { - var result = new Mal.List.empty(); - var root = new GC.Root(result); (void)root; - foreach (var elt in (ast as Mal.List).vs) - result.vs.append(EVAL(elt, env)); - return result; - } - if (ast is Mal.Vector) { - var vec = ast as Mal.Vector; - var result = new Mal.Vector.with_size(vec.length); - var root = new GC.Root(result); (void)root; - for (var i = 0; i < vec.length; i++) - result[i] = EVAL(vec[i], env); - return result; - } - if (ast is Mal.Hashmap) { - var result = new Mal.Hashmap(); - var root = new GC.Root(result); (void)root; - var map = (ast as Mal.Hashmap).vs; - foreach (var key in map.get_keys()) - result.insert(key, EVAL(map[key], env)); - return result; - } - return ast; - } - private static Mal.Val define_eval(Mal.Val key, Mal.Val value, Mal.Env env) throws Mal.Error { @@ -149,35 +117,6 @@ class Mal.Main : GLib.Object { } } - public static bool is_macro_call(Mal.Val v, Mal.Env env) - throws Mal.Error { - var list = v as Mal.List; - if (list == null || list.vs == null || !(list.vs.data is Mal.Sym)) - return false; - try { - var fn = env.get(list.vs.data as Mal.Sym) as Mal.Function; - return (fn != null && fn.is_macro); - } catch (Mal.Error.ENV_LOOKUP_FAILED err) { - return false; - } - } - - public static Mal.Val macroexpand(Mal.Val ast_, Mal.Env env) - throws Mal.Error { - // Copy the parameter into an owned variable (see comment in EVAL). - Mal.Val ast = ast_; - while (is_macro_call(ast, env)) { - var call = ast as Mal.List; - var macro = (env.get(call.vs.data as Mal.Sym) as Mal.Function); - var macroargs = new Mal.List(call.vs.copy()); - macroargs.vs.remove_link(macroargs.vs.first()); - var fnenv = new Mal.Env.funcall( - macro.env, macro.parameters, macroargs); - ast = Mal.Main.EVAL(macro.body, fnenv); - } - return ast; - } - public static Mal.Val EVAL(Mal.Val ast_, Mal.Env env_) throws Mal.Error { // Copy the implicitly 'unowned' function arguments into @@ -193,8 +132,33 @@ class Mal.Main : GLib.Object { ast_root.obj = ast; env_root.obj = env; GC.Core.maybe_collect(); - ast = macroexpand(ast, env); - ast_root.obj = ast; + + var dbgeval = env.get(Mal.Sym("DEBUG-EVAL")); + if (dbgeval != null && dbgeval.truth_value()) + stdout.printf("EVAL: %s\n", pr_str(ast)); + + if (ast is Mal.Sym) + var key = ast as Mal.Sym; + var val = env.get(key); + if (val == null) + throw new Error.ENV_LOOKUP_FAILED("'%s' not found", key.v); + return val; + if (ast is Mal.Vector) { + var vec = ast as Mal.Vector; + var result = new Mal.Vector.with_size(vec.length); + var root = new GC.Root(result); (void)root; + for (var i = 0; i < vec.length; i++) + result[i] = EVAL(vec[i], env); + return result; + } + if (ast is Mal.Hashmap) { + var result = new Mal.Hashmap(); + var root = new GC.Root(result); (void)root; + var map = (ast as Mal.Hashmap).vs; + foreach (var key in map.get_keys()) + result.insert(key, EVAL(map[key], env)); + return result; + } if (ast is Mal.List) { unowned GLib.List list = (ast as Mal.List).vs; if (list.first() == null) @@ -289,22 +253,12 @@ class Mal.Main : GLib.Object { throw new Mal.Error.BAD_PARAMS( "quote: expected one argument"); return list.next.data; - case "quasiquoteexpand": - if (list.length() != 2) - throw new Mal.Error.BAD_PARAMS( - "quasiquoteexpand: expected one argument"); - return quasiquote(list.next.data); case "quasiquote": if (list.length() != 2) throw new Mal.Error.BAD_PARAMS( "quasiquote: expected one argument"); ast = quasiquote(list.next.data); continue; // tail-call optimisation - case "macroexpand": - if (list.length() != 2) - throw new Mal.Error.BAD_PARAMS( - "macroexpand: expected one argument"); - return macroexpand(list.next.data, env); case "try*": if (list.length() != 2 && list.length() != 3) throw new Mal.Error.BAD_PARAMS( @@ -341,15 +295,25 @@ class Mal.Main : GLib.Object { } } - var newlist = eval_ast(ast, env) as Mal.List; - unowned GLib.List firstlink = newlist.vs.first(); - Mal.Val firstdata = firstlink.data; - newlist.vs.remove_link(firstlink); - + Mal.Val firstdata = EVAL(list.first().data, env); + var args = new Mal.List.empty(); + var root = new GC.Root(args); (void)root; + foreach (var iter = list.iter().step(); iter.nonempty(); iter.step()) + args.vs.append(EVAL(iter.deref(), env)); if (firstdata is Mal.BuiltinFunction) { + for (var x in args) + x = EVAL(x, env); return (firstdata as Mal.BuiltinFunction).call(newlist); } else if (firstdata is Mal.Function) { var fn = firstdata as Mal.Function; + if (fn.is_macro) { + var fenv = new Mal.Env.funcall(fn.env, fn.parameters, + args); + ast = EVAL(fn.body, fenv); + continue; + } + for (var x in args) + x = EVAL(x, env); env = new Mal.Env.funcall(fn.env, fn.parameters, newlist); ast = fn.body; continue; // tail-call optimisation @@ -358,7 +322,7 @@ class Mal.Main : GLib.Object { "bad value at start of list"); } } else { - return eval_ast(ast, env); + return ast; } } } diff --git a/impls/vala/stepA_mal.vala b/impls/vala/stepA_mal.vala index 0b0c4ed286..510437bcbf 100644 --- a/impls/vala/stepA_mal.vala +++ b/impls/vala/stepA_mal.vala @@ -39,38 +39,6 @@ class Mal.Main : GLib.Object { } } - public static Mal.Val eval_ast(Mal.Val ast, Mal.Env env) - throws Mal.Error { - var roota = new GC.Root(ast); (void)roota; - var roote = new GC.Root(env); (void)roote; - if (ast is Mal.Sym) - return env.get(ast as Mal.Sym); - if (ast is Mal.List) { - var result = new Mal.List.empty(); - var root = new GC.Root(result); (void)root; - foreach (var elt in (ast as Mal.List).vs) - result.vs.append(EVAL(elt, env)); - return result; - } - if (ast is Mal.Vector) { - var vec = ast as Mal.Vector; - var result = new Mal.Vector.with_size(vec.length); - var root = new GC.Root(result); (void)root; - for (var i = 0; i < vec.length; i++) - result[i] = EVAL(vec[i], env); - return result; - } - if (ast is Mal.Hashmap) { - var result = new Mal.Hashmap(); - var root = new GC.Root(result); (void)root; - var map = (ast as Mal.Hashmap).vs; - foreach (var key in map.get_keys()) - result.insert(key, EVAL(map[key], env)); - return result; - } - return ast; - } - private static Mal.Val define_eval(Mal.Val key, Mal.Val value, Mal.Env env) throws Mal.Error { @@ -149,35 +117,6 @@ class Mal.Main : GLib.Object { } } - public static bool is_macro_call(Mal.Val v, Mal.Env env) - throws Mal.Error { - var list = v as Mal.List; - if (list == null || list.vs == null || !(list.vs.data is Mal.Sym)) - return false; - try { - var fn = env.get(list.vs.data as Mal.Sym) as Mal.Function; - return (fn != null && fn.is_macro); - } catch (Mal.Error.ENV_LOOKUP_FAILED err) { - return false; - } - } - - public static Mal.Val macroexpand(Mal.Val ast_, Mal.Env env) - throws Mal.Error { - // Copy the parameter into an owned variable (see comment in EVAL). - Mal.Val ast = ast_; - while (is_macro_call(ast, env)) { - var call = ast as Mal.List; - var macro = (env.get(call.vs.data as Mal.Sym) as Mal.Function); - var macroargs = new Mal.List(call.vs.copy()); - macroargs.vs.remove_link(macroargs.vs.first()); - var fnenv = new Mal.Env.funcall( - macro.env, macro.parameters, macroargs); - ast = Mal.Main.EVAL(macro.body, fnenv); - } - return ast; - } - public static Mal.Val EVAL(Mal.Val ast_, Mal.Env env_) throws Mal.Error { // Copy the implicitly 'unowned' function arguments into @@ -193,8 +132,33 @@ class Mal.Main : GLib.Object { ast_root.obj = ast; env_root.obj = env; GC.Core.maybe_collect(); - ast = macroexpand(ast, env); - ast_root.obj = ast; + + var dbgeval = env.get(Mal.Sym("DEBUG-EVAL")); + if (dbgeval != null && dbgeval.truth_value()) + stdout.printf("EVAL: %s\n", pr_str(ast)); + + if (ast is Mal.Sym) + var key = ast as Mal.Sym; + var val = env.get(key); + if (val == null) + throw new Error.ENV_LOOKUP_FAILED("'%s' not found", key.v); + return val; + if (ast is Mal.Vector) { + var vec = ast as Mal.Vector; + var result = new Mal.Vector.with_size(vec.length); + var root = new GC.Root(result); (void)root; + for (var i = 0; i < vec.length; i++) + result[i] = EVAL(vec[i], env); + return result; + } + if (ast is Mal.Hashmap) { + var result = new Mal.Hashmap(); + var root = new GC.Root(result); (void)root; + var map = (ast as Mal.Hashmap).vs; + foreach (var key in map.get_keys()) + result.insert(key, EVAL(map[key], env)); + return result; + } if (ast is Mal.List) { unowned GLib.List list = (ast as Mal.List).vs; if (list.first() == null) @@ -289,22 +253,12 @@ class Mal.Main : GLib.Object { throw new Mal.Error.BAD_PARAMS( "quote: expected one argument"); return list.next.data; - case "quasiquoteexpand": - if (list.length() != 2) - throw new Mal.Error.BAD_PARAMS( - "quasiquoteexpand: expected one argument"); - return quasiquote(list.next.data); case "quasiquote": if (list.length() != 2) throw new Mal.Error.BAD_PARAMS( "quasiquote: expected one argument"); ast = quasiquote(list.next.data); continue; // tail-call optimisation - case "macroexpand": - if (list.length() != 2) - throw new Mal.Error.BAD_PARAMS( - "macroexpand: expected one argument"); - return macroexpand(list.next.data, env); case "try*": if (list.length() != 2 && list.length() != 3) throw new Mal.Error.BAD_PARAMS( @@ -341,15 +295,25 @@ class Mal.Main : GLib.Object { } } - var newlist = eval_ast(ast, env) as Mal.List; - unowned GLib.List firstlink = newlist.vs.first(); - Mal.Val firstdata = firstlink.data; - newlist.vs.remove_link(firstlink); - + Mal.Val firstdata = EVAL(list.first().data, env); + var args = new Mal.List.empty(); + var root = new GC.Root(args); (void)root; + foreach (var iter = list.iter().step(); iter.nonempty(); iter.step()) + args.vs.append(EVAL(iter.deref(), env)); if (firstdata is Mal.BuiltinFunction) { + for (var x in args) + x = EVAL(x, env); return (firstdata as Mal.BuiltinFunction).call(newlist); } else if (firstdata is Mal.Function) { var fn = firstdata as Mal.Function; + if (fn.is_macro) { + var fenv = new Mal.Env.funcall(fn.env, fn.parameters, + args); + ast = EVAL(fn.body, fenv); + continue; + } + for (var x in args) + x = EVAL(x, env); env = new Mal.Env.funcall(fn.env, fn.parameters, newlist); ast = fn.body; continue; // tail-call optimisation @@ -358,7 +322,7 @@ class Mal.Main : GLib.Object { "bad value at start of list"); } } else { - return eval_ast(ast, env); + return ast; } } }