diff options
| author | Joel Martin <github@martintribe.org> | 2014-04-23 21:59:50 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-04-23 21:59:50 -0500 |
| commit | 6301e0b6374cecc5599665be14d6ddc6a31ce1e8 (patch) | |
| tree | dbf1dc2ff6c682fd87c72a7907e7f6e59c8d4c03 | |
| parent | 89bd4de1e2704c1bc562788b2c5e4fc08b71a538 (diff) | |
| download | mal-6301e0b6374cecc5599665be14d6ddc6a31ce1e8.tar.gz mal-6301e0b6374cecc5599665be14d6ddc6a31ce1e8.zip | |
All: TCO let* and quasiquote.
70 files changed, 326 insertions, 158 deletions
@@ -64,7 +64,7 @@ ruby_RUNSTEP = ruby ../$(2) $(3) # Extra options to pass to runtest.py cs_TEST_OPTS = --redirect -mal_TEST_OPTS = --start-timeout 30 --test-timeout 120 +mal_TEST_OPTS = --start-timeout 60 --test-timeout 120 # Derived lists @@ -3,7 +3,7 @@ ## Description Mal is an interpreter for a subset of the Clojure programming -language. Mal is implemented from scratch in 12 different languages: +language. Mal is implemented from scratch in 13 different languages: * Bash shell * C @@ -13,6 +13,7 @@ language. Mal is implemented from scratch in 12 different languages: * Javascript * GNU Make * mal itself +* Perl * PHP * Postscript * Python diff --git a/bash/step5_tco.sh b/bash/step5_tco.sh index b57c1f7..ea5b72d 100755 --- a/bash/step5_tco.sh +++ b/bash/step5_tco.sh @@ -71,8 +71,10 @@ EVAL () { ENV_SET "${let_env}" "${ANON["${let_pairs[${idx}]}"]}" "${r}" idx=$(( idx + 2)) done - EVAL "${a2}" "${let_env}" - return ;; + ast="${a2}" + env="${let_env}" + # Continue loop + ;; do) _count "${ast}" _slice "${ast}" 1 $(( ${r} - 2 )) EVAL_AST "${r}" "${env}" diff --git a/bash/step6_file.sh b/bash/step6_file.sh index 5f26335..168698a 100755 --- a/bash/step6_file.sh +++ b/bash/step6_file.sh @@ -71,8 +71,10 @@ EVAL () { ENV_SET "${let_env}" "${ANON["${let_pairs[${idx}]}"]}" "${r}" idx=$(( idx + 2)) done - EVAL "${a2}" "${let_env}" - return ;; + ast="${a2}" + env="${let_env}" + # Continue loop + ;; do) _count "${ast}" _slice "${ast}" 1 $(( ${r} - 2 )) EVAL_AST "${r}" "${env}" diff --git a/bash/step7_quote.sh b/bash/step7_quote.sh index f1a91ca..8319f64 100755 --- a/bash/step7_quote.sh +++ b/bash/step7_quote.sh @@ -109,15 +109,18 @@ EVAL () { ENV_SET "${let_env}" "${ANON["${let_pairs[${idx}]}"]}" "${r}" idx=$(( idx + 2)) done - EVAL "${a2}" "${let_env}" - return ;; + ast="${a2}" + env="${let_env}" + # Continue loop + ;; quote) r="${a1}" return ;; quasiquote) QUASIQUOTE "${a1}" - EVAL "${r}" "${env}" - return ;; + ast="${r}" + # Continue loop + ;; do) _count "${ast}" _slice "${ast}" 1 $(( ${r} - 2 )) EVAL_AST "${r}" "${env}" diff --git a/bash/step8_macros.sh b/bash/step8_macros.sh index 7826bf2..b21c25f 100755 --- a/bash/step8_macros.sh +++ b/bash/step8_macros.sh @@ -136,15 +136,18 @@ EVAL () { ENV_SET "${let_env}" "${ANON["${let_pairs[${idx}]}"]}" "${r}" idx=$(( idx + 2)) done - EVAL "${a2}" "${let_env}" - return ;; + ast="${a2}" + env="${let_env}" + # Continue loop + ;; quote) r="${a1}" return ;; quasiquote) QUASIQUOTE "${a1}" - EVAL "${r}" "${env}" - return ;; + ast="${r}" + # Continue loop + ;; defmacro!) local k="${ANON["${a1}"]}" EVAL "${a2}" "${env}" diff --git a/bash/step9_interop.sh b/bash/step9_interop.sh index 04d3413..5e4828f 100755 --- a/bash/step9_interop.sh +++ b/bash/step9_interop.sh @@ -136,15 +136,18 @@ EVAL () { ENV_SET "${let_env}" "${ANON["${let_pairs[${idx}]}"]}" "${r}" idx=$(( idx + 2)) done - EVAL "${a2}" "${let_env}" - return ;; + ast="${a2}" + env="${let_env}" + # Continue loop + ;; quote) r="${a1}" return ;; quasiquote) QUASIQUOTE "${a1}" - EVAL "${r}" "${env}" - return ;; + ast="${r}" + # Continue loop + ;; defmacro!) local k="${ANON["${a1}"]}" EVAL "${a2}" "${env}" diff --git a/bash/stepA_more.sh b/bash/stepA_more.sh index 88f2d4f..7f582c3 100755 --- a/bash/stepA_more.sh +++ b/bash/stepA_more.sh @@ -136,15 +136,18 @@ EVAL () { ENV_SET "${let_env}" "${ANON["${let_pairs[${idx}]}"]}" "${r}" idx=$(( idx + 2)) done - EVAL "${a2}" "${let_env}" - return ;; + ast="${a2}" + env="${let_env}" + # Continue loop + ;; quote) r="${a1}" return ;; quasiquote) QUASIQUOTE "${a1}" - EVAL "${r}" "${env}" - return ;; + ast="${r}" + # Continue loop + ;; defmacro!) local k="${ANON["${a1}"]}" EVAL "${a2}" "${env}" diff --git a/c/step5_tco.c b/c/step5_tco.c index 3a46bd2..edca21b 100644 --- a/c/step5_tco.c +++ b/c/step5_tco.c @@ -101,7 +101,9 @@ MalVal *EVAL(MalVal *ast, Env *env) { assert_type(key, MAL_SYMBOL, "let* bind to non-symbol"); env_set(let_env, key->val.string, EVAL(val, let_env)); } - return EVAL(a2, let_env); + ast = a2; + env = let_env; + // Continue loop } else if ((a0->type & MAL_SYMBOL) && strcmp("do", a0->val.string) == 0) { //g_print("eval apply do\n"); diff --git a/c/step6_file.c b/c/step6_file.c index d73acfe..9ff62a9 100644 --- a/c/step6_file.c +++ b/c/step6_file.c @@ -101,7 +101,9 @@ MalVal *EVAL(MalVal *ast, Env *env) { assert_type(key, MAL_SYMBOL, "let* bind to non-symbol"); env_set(let_env, key->val.string, EVAL(val, let_env)); } - return EVAL(a2, let_env); + ast = a2; + env = let_env; + // Continue loop } else if ((a0->type & MAL_SYMBOL) && strcmp("do", a0->val.string) == 0) { //g_print("eval apply do\n"); diff --git a/c/step7_quote.c b/c/step7_quote.c index b66bde6..d0d1d3d 100644 --- a/c/step7_quote.c +++ b/c/step7_quote.c @@ -128,7 +128,9 @@ MalVal *EVAL(MalVal *ast, Env *env) { assert_type(key, MAL_SYMBOL, "let* bind to non-symbol"); env_set(let_env, key->val.string, EVAL(val, let_env)); } - return EVAL(a2, let_env); + ast = a2; + env = let_env; + // Continue loop } else if ((a0->type & MAL_SYMBOL) && strcmp("quote", a0->val.string) == 0) { //g_print("eval apply quote\n"); @@ -137,7 +139,8 @@ MalVal *EVAL(MalVal *ast, Env *env) { strcmp("quasiquote", a0->val.string) == 0) { //g_print("eval apply quasiquote\n"); MalVal *a1 = _nth(ast, 1); - return EVAL(quasiquote(a1), env); + ast = quasiquote(a1); + // Continue loop } else if ((a0->type & MAL_SYMBOL) && strcmp("do", a0->val.string) == 0) { //g_print("eval apply do\n"); diff --git a/c/step8_macros.c b/c/step8_macros.c index e7aebf2..3558caf 100644 --- a/c/step8_macros.c +++ b/c/step8_macros.c @@ -152,7 +152,9 @@ MalVal *EVAL(MalVal *ast, Env *env) { assert_type(key, MAL_SYMBOL, "let* bind to non-symbol"); env_set(let_env, key->val.string, EVAL(val, let_env)); } - return EVAL(a2, let_env); + ast = a2; + env = let_env; + // Continue loop } else if ((a0->type & MAL_SYMBOL) && strcmp("quote", a0->val.string) == 0) { //g_print("eval apply quote\n"); @@ -161,7 +163,8 @@ MalVal *EVAL(MalVal *ast, Env *env) { strcmp("quasiquote", a0->val.string) == 0) { //g_print("eval apply quasiquote\n"); MalVal *a1 = _nth(ast, 1); - return EVAL(quasiquote(a1), env); + ast = quasiquote(a1); + // Continue loop } else if ((a0->type & MAL_SYMBOL) && strcmp("defmacro!", a0->val.string) == 0) { //g_print("eval apply defmacro!\n"); diff --git a/c/step9_interop.c b/c/step9_interop.c index f248c55..6ba594e 100644 --- a/c/step9_interop.c +++ b/c/step9_interop.c @@ -153,7 +153,9 @@ MalVal *EVAL(MalVal *ast, Env *env) { assert_type(key, MAL_SYMBOL, "let* bind to non-symbol"); env_set(let_env, key->val.string, EVAL(val, let_env)); } - return EVAL(a2, let_env); + ast = a2; + env = let_env; + // Continue loop } else if ((a0->type & MAL_SYMBOL) && strcmp("quote", a0->val.string) == 0) { //g_print("eval apply quote\n"); @@ -162,7 +164,8 @@ MalVal *EVAL(MalVal *ast, Env *env) { strcmp("quasiquote", a0->val.string) == 0) { //g_print("eval apply quasiquote\n"); MalVal *a1 = _nth(ast, 1); - return EVAL(quasiquote(a1), env); + ast = quasiquote(a1); + // Continue loop } else if ((a0->type & MAL_SYMBOL) && strcmp("defmacro!", a0->val.string) == 0) { //g_print("eval apply defmacro!\n"); diff --git a/c/stepA_more.c b/c/stepA_more.c index de49568..b4b7431 100644 --- a/c/stepA_more.c +++ b/c/stepA_more.c @@ -153,7 +153,9 @@ MalVal *EVAL(MalVal *ast, Env *env) { assert_type(key, MAL_SYMBOL, "let* bind to non-symbol"); env_set(let_env, key->val.string, EVAL(val, let_env)); } - return EVAL(a2, let_env); + ast = a2; + env = let_env; + // Continue loop } else if ((a0->type & MAL_SYMBOL) && strcmp("quote", a0->val.string) == 0) { //g_print("eval apply quote\n"); @@ -162,7 +164,8 @@ MalVal *EVAL(MalVal *ast, Env *env) { strcmp("quasiquote", a0->val.string) == 0) { //g_print("eval apply quasiquote\n"); MalVal *a1 = _nth(ast, 1); - return EVAL(quasiquote(a1), env); + ast = quasiquote(a1); + // Continue loop } else if ((a0->type & MAL_SYMBOL) && strcmp("defmacro!", a0->val.string) == 0) { //g_print("eval apply defmacro!\n"); diff --git a/clojure/src/step5_tco.clj b/clojure/src/step5_tco.clj index da47669..ed19b8e 100644 --- a/clojure/src/step5_tco.clj +++ b/clojure/src/step5_tco.clj @@ -43,7 +43,7 @@ (let [let-env (env/env env)] (doseq [[b e] (partition 2 a1)] (env/env-set let-env b (EVAL e let-env))) - (EVAL a2 let-env)) + (recur a2 let-env)) 'do (do (eval-ast (->> ast (drop-last) (drop 1)) env) diff --git a/clojure/src/step6_file.clj b/clojure/src/step6_file.clj index 5d080b9..2d5e05d 100644 --- a/clojure/src/step6_file.clj +++ b/clojure/src/step6_file.clj @@ -43,7 +43,7 @@ (let [let-env (env/env env)] (doseq [[b e] (partition 2 a1)] (env/env-set let-env b (EVAL e let-env))) - (EVAL a2 let-env)) + (recur a2 let-env)) 'do (do (eval-ast (->> ast (drop-last) (drop 1)) env) diff --git a/clojure/src/step7_quote.clj b/clojure/src/step7_quote.clj index ffcca24..633a81c 100644 --- a/clojure/src/step7_quote.clj +++ b/clojure/src/step7_quote.clj @@ -60,13 +60,13 @@ (let [let-env (env/env env)] (doseq [[b e] (partition 2 a1)] (env/env-set let-env b (EVAL e let-env))) - (EVAL a2 let-env)) + (recur a2 let-env)) 'quote a1 'quasiquote - (EVAL (quasiquote a1) env) + (recur (quasiquote a1) env) 'do (do (eval-ast (->> ast (drop-last) (drop 1)) env) diff --git a/clojure/src/step8_macros.clj b/clojure/src/step8_macros.clj index 6f51415..b8b55dc 100644 --- a/clojure/src/step8_macros.clj +++ b/clojure/src/step8_macros.clj @@ -78,13 +78,13 @@ (let [let-env (env/env env)] (doseq [[b e] (partition 2 a1)] (env/env-set let-env b (EVAL e let-env))) - (EVAL a2 let-env)) + (recur a2 let-env)) 'quote a1 'quasiquote - (EVAL (quasiquote a1) env) + (recur (quasiquote a1) env) 'defmacro! (let [func (with-meta (EVAL a2 env) diff --git a/clojure/src/step9_interop.clj b/clojure/src/step9_interop.clj index 677599c..c4d67e5 100644 --- a/clojure/src/step9_interop.clj +++ b/clojure/src/step9_interop.clj @@ -78,13 +78,13 @@ (let [let-env (env/env env)] (doseq [[b e] (partition 2 a1)] (env/env-set let-env b (EVAL e let-env))) - (EVAL a2 let-env)) + (recur a2 let-env)) 'quote a1 'quasiquote - (EVAL (quasiquote a1) env) + (recur (quasiquote a1) env) 'defmacro! (let [func (with-meta (EVAL a2 env) diff --git a/clojure/src/stepA_more.clj b/clojure/src/stepA_more.clj index e233089..fc7451f 100644 --- a/clojure/src/stepA_more.clj +++ b/clojure/src/stepA_more.clj @@ -78,13 +78,13 @@ (let [let-env (env/env env)] (doseq [[b e] (partition 2 a1)] (env/env-set let-env b (EVAL e let-env))) - (EVAL a2 let-env)) + (recur a2 let-env)) 'quote a1 'quasiquote - (EVAL (quasiquote a1) env) + (recur (quasiquote a1) env) 'defmacro! (let [func (with-meta (EVAL a2 env) diff --git a/cs/step5_tco.cs b/cs/step5_tco.cs index 95df860..e243153 100644 --- a/cs/step5_tco.cs +++ b/cs/step5_tco.cs @@ -81,7 +81,9 @@ namespace Mal { val = ((MalList)a1)[i+1]; let_env.set(key.getName(), EVAL(val, let_env)); } - return EVAL(a2, let_env); + orig_ast = a2; + env = let_env; + break; case "do": eval_ast(ast.slice(1, ast.size()-1), env); orig_ast = ast[ast.size()-1]; diff --git a/cs/step6_file.cs b/cs/step6_file.cs index db1a7b2..7e3bf7e 100644 --- a/cs/step6_file.cs +++ b/cs/step6_file.cs @@ -82,7 +82,9 @@ namespace Mal { val = ((MalList)a1)[i+1]; let_env.set(key.getName(), EVAL(val, let_env)); } - return EVAL(a2, let_env); + orig_ast = a2; + env = let_env; + break; case "do": eval_ast(ast.slice(1, ast.size()-1), env); orig_ast = ast[ast.size()-1]; diff --git a/cs/step7_quote.cs b/cs/step7_quote.cs index d803ac2..537c20c 100644 --- a/cs/step7_quote.cs +++ b/cs/step7_quote.cs @@ -109,11 +109,14 @@ namespace Mal { val = ((MalList)a1)[i+1]; let_env.set(key.getName(), EVAL(val, let_env)); } - return EVAL(a2, let_env); + orig_ast = a2; + env = let_env; + break; case "quote": return ast[1]; case "quasiquote": - return EVAL(quasiquote(ast[1]), env); + orig_ast = quasiquote(ast[1]); + break; case "do": eval_ast(ast.slice(1, ast.size()-1), env); orig_ast = ast[ast.size()-1]; diff --git a/cs/step8_macros.cs b/cs/step8_macros.cs index af98fe9..b06b1fb 100644 --- a/cs/step8_macros.cs +++ b/cs/step8_macros.cs @@ -136,11 +136,14 @@ namespace Mal { val = ((MalList)a1)[i+1]; let_env.set(key.getName(), EVAL(val, let_env)); } - return EVAL(a2, let_env); + orig_ast = a2; + env = let_env; + break; case "quote": return ast[1]; case "quasiquote": - return EVAL(quasiquote(ast[1]), env); + orig_ast = quasiquote(ast[1]); + break; case "defmacro!": a1 = ast[1]; a2 = ast[2]; diff --git a/cs/stepA_more.cs b/cs/stepA_more.cs index 4fa8387..486c344 100644 --- a/cs/stepA_more.cs +++ b/cs/stepA_more.cs @@ -136,11 +136,14 @@ namespace Mal { val = ((MalList)a1)[i+1]; let_env.set(key.getName(), EVAL(val, let_env)); } - return EVAL(a2, let_env); + orig_ast = a2; + env = let_env; + break; case "quote": return ast[1]; case "quasiquote": - return EVAL(quasiquote(ast[1]), env); + orig_ast = quasiquote(ast[1]); + break; case "defmacro!": a1 = ast[1]; a2 = ast[2]; @@ -5,7 +5,6 @@ All: - hash-map with space in key string (make) - keyword type - gensym reader inside quasiquote - - quasiquote be TCO'd ? - per impl tests for step5_tco, step9_interop (if possible) - regular expression matching in runtest @@ -14,15 +13,15 @@ All: - Break out impl eval into step0.5 - Fix quasiquoting of vectors - - TCO for let* - --------------------------------------------- Bash: - explore using ${!prefix*} syntax (more like make impl) + - GC C: - come up with better way to do 20 vararg code + - GC C#: - step9_interop @@ -44,7 +43,6 @@ Mal: - step9_interop Perl: - - object exceptions: http://perldoc.perl.org/functions/die.html PHP: @@ -95,7 +93,7 @@ Future Implementations: * Ruby * C - Objective-C - - Perl + * Perl * Shell (Bash 4) - Tier 2 diff --git a/java/src/main/java/mal/step5_tco.java b/java/src/main/java/mal/step5_tco.java index dd1dc89..aa3f7a7 100644 --- a/java/src/main/java/mal/step5_tco.java +++ b/java/src/main/java/mal/step5_tco.java @@ -80,7 +80,9 @@ public class step5_tco { val = ((MalList)a1).nth(i+1); let_env.set(key.getName(), EVAL(val, let_env)); } - return EVAL(a2, let_env); + orig_ast = a2; + env = let_env; + break; case "do": eval_ast(ast.slice(1, ast.size()-1), env); orig_ast = ast.nth(ast.size()-1); diff --git a/java/src/main/java/mal/step6_file.java b/java/src/main/java/mal/step6_file.java index 4bf0f0e..d3f4914 100644 --- a/java/src/main/java/mal/step6_file.java +++ b/java/src/main/java/mal/step6_file.java @@ -80,7 +80,9 @@ public class step6_file { val = ((MalList)a1).nth(i+1); let_env.set(key.getName(), EVAL(val, let_env)); } - return EVAL(a2, let_env); + orig_ast = a2; + env = let_env; + break; case "do": eval_ast(ast.slice(1, ast.size()-1), env); orig_ast = ast.nth(ast.size()-1); diff --git a/java/src/main/java/mal/step7_quote.java b/java/src/main/java/mal/step7_quote.java index da0781b..639f8b9 100644 --- a/java/src/main/java/mal/step7_quote.java +++ b/java/src/main/java/mal/step7_quote.java @@ -107,11 +107,14 @@ public class step7_quote { val = ((MalList)a1).nth(i+1); let_env.set(key.getName(), EVAL(val, let_env)); } - return EVAL(a2, let_env); + orig_ast = a2; + env = let_env; + break; case "quote": return ast.nth(1); case "quasiquote": - return EVAL(quasiquote(ast.nth(1)), env); + orig_ast = quasiquote(ast.nth(1)); + break; case "do": eval_ast(ast.slice(1, ast.size()-1), env); orig_ast = ast.nth(ast.size()-1); diff --git a/java/src/main/java/mal/step8_macros.java b/java/src/main/java/mal/step8_macros.java index c4cb1de..fb3ffdc 100644 --- a/java/src/main/java/mal/step8_macros.java +++ b/java/src/main/java/mal/step8_macros.java @@ -135,11 +135,14 @@ public class step8_macros { val = ((MalList)a1).nth(i+1); let_env.set(key.getName(), EVAL(val, let_env)); } - return EVAL(a2, let_env); + orig_ast = a2; + env = let_env; + break; case "quote": return ast.nth(1); case "quasiquote": - return EVAL(quasiquote(ast.nth(1)), env); + orig_ast = quasiquote(ast.nth(1)); + break; case "defmacro!": a1 = ast.nth(1); a2 = ast.nth(2); diff --git a/java/src/main/java/mal/stepA_more.java b/java/src/main/java/mal/stepA_more.java index 20dee3f..75ec301 100644 --- a/java/src/main/java/mal/stepA_more.java +++ b/java/src/main/java/mal/stepA_more.java @@ -137,11 +137,14 @@ public class stepA_more { val = ((MalList)a1).nth(i+1); let_env.set(key.getName(), EVAL(val, let_env)); } - return EVAL(a2, let_env); + orig_ast = a2; + env = let_env; + break; case "quote": return ast.nth(1); case "quasiquote": - return EVAL(quasiquote(ast.nth(1)), env); + orig_ast = quasiquote(ast.nth(1)); + break; case "defmacro!": a1 = ast.nth(1); a2 = ast.nth(2); @@ -193,9 +193,9 @@ var ns = {'type': types._obj_type, 'rest': rest, 'empty?': empty_Q, 'count': count, - 'conj': conj, 'apply': apply, 'map': map, + 'conj': conj, 'with-meta': with_meta, 'meta': meta, diff --git a/js/step5_tco.js b/js/step5_tco.js index 9335aa8..7640327 100644 --- a/js/step5_tco.js +++ b/js/step5_tco.js @@ -52,7 +52,9 @@ function _EVAL(ast, env) { for (var i=0; i < a1.length; i+=2) { let_env.set(a1[i].value, EVAL(a1[i+1], let_env)); } - return EVAL(a2, let_env); + ast = a2; + env = let_env; + break; case "do": eval_ast(ast.slice(1, -1), env); ast = ast[ast.length-1]; diff --git a/js/step6_file.js b/js/step6_file.js index 85de49e..0dfe71e 100644 --- a/js/step6_file.js +++ b/js/step6_file.js @@ -52,7 +52,9 @@ function _EVAL(ast, env) { for (var i=0; i < a1.length; i+=2) { let_env.set(a1[i].value, EVAL(a1[i+1], let_env)); } - return EVAL(a2, let_env); + ast = a2; + env = let_env; + break; case "do": eval_ast(ast.slice(1, -1), env); ast = ast[ast.length-1]; diff --git a/js/step7_quote.js b/js/step7_quote.js index 8676d07..067d68e 100644 --- a/js/step7_quote.js +++ b/js/step7_quote.js @@ -72,11 +72,14 @@ function _EVAL(ast, env) { for (var i=0; i < a1.length; i+=2) { let_env.set(a1[i].value, EVAL(a1[i+1], let_env)); } - return EVAL(a2, let_env); + ast = a2; + env = let_env; + break; case "quote": return a1; case "quasiquote": - return EVAL(quasiquote(a1), env); + ast = quasiquote(a1); + break; case "do": eval_ast(ast.slice(1, -1), env); ast = ast[ast.length-1]; diff --git a/js/step8_macros.js b/js/step8_macros.js index dca7beb..2ddb56c 100644 --- a/js/step8_macros.js +++ b/js/step8_macros.js @@ -90,11 +90,14 @@ function _EVAL(ast, env) { for (var i=0; i < a1.length; i+=2) { let_env.set(a1[i].value, EVAL(a1[i+1], let_env)); } - return EVAL(a2, let_env); + ast = a2; + env = let_env; + break; case "quote": return a1; case "quasiquote": - return EVAL(quasiquote(a1), env); + ast = quasiquote(a1); + break; case 'defmacro!': var func = EVAL(a2, env); func._ismacro_ = true; diff --git a/js/step9_interop.js b/js/step9_interop.js index e95b4ca..3988da1 100644 --- a/js/step9_interop.js +++ b/js/step9_interop.js @@ -90,11 +90,14 @@ function _EVAL(ast, env) { for (var i=0; i < a1.length; i+=2) { let_env.set(a1[i].value, EVAL(a1[i+1], let_env)); } - return EVAL(a2, let_env); + ast = a2; + env = let_env; + break; case "quote": return a1; case "quasiquote": - return EVAL(quasiquote(a1), env); + ast = quasiquote(a1); + break; case 'defmacro!': var func = EVAL(a2, env); func._ismacro_ = true; diff --git a/js/stepA_more.js b/js/stepA_more.js index 58840eb..6058da1 100644 --- a/js/stepA_more.js +++ b/js/stepA_more.js @@ -90,11 +90,14 @@ function _EVAL(ast, env) { for (var i=0; i < a1.length; i+=2) { let_env.set(a1[i].value, EVAL(a1[i+1], let_env)); } - return EVAL(a2, let_env); + ast = a2; + env = let_env; + break; case "quote": return a1; case "quasiquote": - return EVAL(quasiquote(a1), env); + ast = quasiquote(a1); + break; case 'defmacro!': var func = EVAL(a2, env); func._ismacro_ = true; diff --git a/js/types.js b/js/types.js index 889e154..d288231 100644 --- a/js/types.js +++ b/js/types.js @@ -107,6 +107,7 @@ function _function(Eval, Env, ast, env, params) { fn.__meta__ = null; fn.__ast__ = ast; fn.__gen_env__ = function(args) { return new Env(env, params, args); }; + fn._ismacro_ = false; return fn; } function _function_Q(obj) { return typeof obj == "function"; } @@ -131,7 +132,7 @@ function _vector() { v.__isvector__ = true; return v; } -function _vector_Q(obj) { return Array.isArray(obj) && obj.__isvector__; } +function _vector_Q(obj) { return Array.isArray(obj) && !!obj.__isvector__; } diff --git a/perl/step5_tco.pl b/perl/step5_tco.pl index b041110..44de718 100644 --- a/perl/step5_tco.pl +++ b/perl/step5_tco.pl @@ -68,10 +68,12 @@ sub EVAL { } $ast = $a2; $env = $let_env; + # Continue loop (TCO) } when (/^do$/) { eval_ast($ast->slice(1, $#{$ast->{val}}-1), $env); $ast = $ast->nth($#{$ast->{val}}); + # Continue loop (TCO) } when (/^if$/) { my $cond = EVAL($a1, $env); @@ -80,6 +82,7 @@ sub EVAL { } else { $ast = $a2; } + # Continue loop (TCO) } when (/^fn\*$/) { return Function->new(\&EVAL, $a2, $env, $a1); @@ -90,6 +93,7 @@ sub EVAL { if ((ref $f) =~ /^Function/) { $ast = $f->{ast}; $env = $f->gen_env($el->rest()); + # Continue loop (TCO) } else { return &{ $f }($el->rest()); } diff --git a/perl/step6_file.pl b/perl/step6_file.pl index a5f7791..9fcac1d 100644 --- a/perl/step6_file.pl +++ b/perl/step6_file.pl @@ -68,10 +68,12 @@ sub EVAL { } $ast = $a2; $env = $let_env; + # Continue loop (TCO) } when (/^do$/) { eval_ast($ast->slice(1, $#{$ast->{val}}-1), $env); $ast = $ast->nth($#{$ast->{val}}); + # Continue loop (TCO) } when (/^if$/) { my $cond = EVAL($a1, $env); @@ -80,6 +82,7 @@ sub EVAL { } else { $ast = $a2; } + # Continue loop (TCO) } when (/^fn\*$/) { return Function->new(\&EVAL, $a2, $env, $a1); @@ -90,6 +93,7 @@ sub EVAL { if ((ref $f) =~ /^Function/) { $ast = $f->{ast}; $env = $f->gen_env($el->rest()); + # Continue loop (TCO) } else { return &{ $f }($el->rest()); } diff --git a/perl/step7_quote.pl b/perl/step7_quote.pl index 9654cc8..19c0599 100644 --- a/perl/step7_quote.pl +++ b/perl/step7_quote.pl @@ -91,16 +91,19 @@ sub EVAL { } $ast = $a2; $env = $let_env; + # Continue loop (TCO) } when (/^quote$/) { return $a1; } when (/^quasiquote$/) { - return EVAL(quasiquote($a1), $env); + $ast = quasiquote($a1); + # Continue loop (TCO) } when (/^do$/) { eval_ast($ast->slice(1, $#{$ast->{val}}-1), $env); $ast = $ast->nth($#{$ast->{val}}); + # Continue loop (TCO) } when (/^if$/) { my $cond = EVAL($a1, $env); @@ -109,6 +112,7 @@ sub EVAL { } else { $ast = $a2; } + # Continue loop (TCO) } when (/^fn\*$/) { return Function->new(\&EVAL, $a2, $env, $a1); @@ -119,6 +123,7 @@ sub EVAL { if ((ref $f) =~ /^Function/) { $ast = $f->{ast}; $env = $f->gen_env($el->rest()); + # Continue loop (TCO) } else { return &{ $f }($el->rest()); } diff --git a/perl/step8_macros.pl b/perl/step8_macros.pl index 22f078f..47004a2 100644 --- a/perl/step8_macros.pl +++ b/perl/step8_macros.pl @@ -117,12 +117,14 @@ sub EVAL { } $ast = $a2; $env = $let_env; + # Continue loop (TCO) } when (/^quote$/) { return $a1; } when (/^quasiquote$/) { - return EVAL(quasiquote($a1), $env); + $ast = quasiquote($a1); + # Continue loop (TCO) } when (/^defmacro!$/) { my $func = EVAL($a2, $env); @@ -135,6 +137,7 @@ sub EVAL { when (/^do$/) { eval_ast($ast->slice(1, $#{$ast->{val}}-1), $env); $ast = $ast->nth($#{$ast->{val}}); + # Continue loop (TCO) } when (/^if$/) { my $cond = EVAL($a1, $env); @@ -143,6 +146,7 @@ sub EVAL { } else { $ast = $a2; } + # Continue loop (TCO) } when (/^fn\*$/) { return Function->new(\&EVAL, $a2, $env, $a1); @@ -153,6 +157,7 @@ sub EVAL { if ((ref $f) =~ /^Function/) { $ast = $f->{ast}; $env = $f->gen_env($el->rest()); + # Continue loop (TCO) } else { return &{ $f }($el->rest()); } diff --git a/perl/step9_interop.pl b/perl/step9_interop.pl index 2c20e89..45dd4af 100644 --- a/perl/step9_interop.pl +++ b/perl/step9_interop.pl @@ -118,12 +118,14 @@ sub EVAL { } $ast = $a2; $env = $let_env; + # Continue loop (TCO) } when (/^quote$/) { return $a1; } when (/^quasiquote$/) { - return EVAL(quasiquote($a1), $env); + $ast = quasiquote($a1); + # Continue loop (TCO) } when (/^defmacro!$/) { my $func = EVAL($a2, $env); @@ -139,6 +141,7 @@ sub EVAL { when (/^do$/) { eval_ast($ast->slice(1, $#{$ast->{val}}-1), $env); $ast = $ast->nth($#{$ast->{val}}); + # Continue loop (TCO) } when (/^if$/) { my $cond = EVAL($a1, $env); @@ -147,6 +150,7 @@ sub EVAL { } else { $ast = $a2; } + # Continue loop (TCO) } when (/^fn\*$/) { return Function->new(\&EVAL, $a2, $env, $a1); @@ -157,6 +161,7 @@ sub EVAL { if ((ref $f) =~ /^Function/) { $ast = $f->{ast}; $env = $f->gen_env($el->rest()); + # Continue loop (TCO) } else { return &{ $f }($el->rest()); } diff --git a/perl/stepA_more.pl b/perl/stepA_more.pl index 8520480..eca2b6e 100644 --- a/perl/stepA_more.pl +++ b/perl/stepA_more.pl @@ -118,12 +118,14 @@ sub EVAL { } $ast = $a2; $env = $let_env; + # Continue loop (TCO) } when (/^quote$/) { return $a1; } when (/^quasiquote$/) { - return EVAL(quasiquote($a1), $env); + $ast = quasiquote($a1); + # Continue loop (TCO) } when (/^defmacro!$/) { my $func = EVAL($a2, $env); @@ -166,6 +168,7 @@ sub EVAL { when (/^do$/) { eval_ast($ast->slice(1, $#{$ast->{val}}-1), $env); $ast = $ast->nth($#{$ast->{val}}); + # Continue loop (TCO) } when (/^if$/) { my $cond = EVAL($a1, $env); @@ -174,6 +177,7 @@ sub EVAL { } else { $ast = $a2; } + # Continue loop (TCO) } when (/^fn\*$/) { return Function->new(\&EVAL, $a2, $env, $a1); @@ -184,6 +188,7 @@ sub EVAL { if ((ref $f) =~ /^Function/) { $ast = $f->{ast}; $env = $f->gen_env($el->rest()); + # Continue loop (TCO) } else { return &{ $f }($el->rest()); } diff --git a/php/step5_tco.php b/php/step5_tco.php index 5ae29a7..88557b5 100644 --- a/php/step5_tco.php +++ b/php/step5_tco.php @@ -56,11 +56,13 @@ function MAL_EVAL($ast, $env) { for ($i=0; $i < count($a1); $i+=2) { $let_env->set($a1[$i]->value, MAL_EVAL($a1[$i+1], $let_env)); } - return MAL_EVAL($ast[2], $let_env); + $ast = $ast[2]; + $env = $let_env; + break; // Continue loop (TCO) case "do": eval_ast($ast->slice(1, -1), $env); $ast = $ast[count($ast)-1]; - break; + break; // Continue loop (TCO) case "if": $cond = MAL_EVAL($ast[1], $env); if ($cond === NULL || $cond === false) { @@ -69,7 +71,7 @@ function MAL_EVAL($ast, $env) { } else { $ast = $ast[2]; } - break; + break; // Continue loop (TCO) case "fn*": return _function('MAL_EVAL', 'native', $ast[2], $env, $ast[1]); @@ -80,6 +82,7 @@ function MAL_EVAL($ast, $env) { if ($f->type === 'native') { $ast = $f->ast; $env = $f->gen_env($args); + // Continue loop (TCO) } else { return $f->apply($args); } diff --git a/php/step6_file.php b/php/step6_file.php index b7cdcc3..1e83c28 100644 --- a/php/step6_file.php +++ b/php/step6_file.php @@ -56,11 +56,13 @@ function MAL_EVAL($ast, $env) { for ($i=0; $i < count($a1); $i+=2) { $let_env->set($a1[$i]->value, MAL_EVAL($a1[$i+1], $let_env)); } - return MAL_EVAL($ast[2], $let_env); + $ast = $ast[2]; + $env = $let_env; + break; // Continue loop (TCO) case "do": eval_ast($ast->slice(1, -1), $env); $ast = $ast[count($ast)-1]; - break; + break; // Continue loop (TCO) case "if": $cond = MAL_EVAL($ast[1], $env); if ($cond === NULL || $cond === false) { @@ -69,7 +71,7 @@ function MAL_EVAL($ast, $env) { } else { $ast = $ast[2]; } - break; + break; // Continue loop (TCO) case "fn*": return _function('MAL_EVAL', 'native', $ast[2], $env, $ast[1]); @@ -80,6 +82,7 @@ function MAL_EVAL($ast, $env) { if ($f->type === 'native') { $ast = $f->ast; $env = $f->gen_env($args); + // Continue loop (TCO) } else { return $f->apply($args); } diff --git a/php/step7_quote.php b/php/step7_quote.php index fd1c922..07d3d2a 100644 --- a/php/step7_quote.php +++ b/php/step7_quote.php @@ -75,15 +75,18 @@ function MAL_EVAL($ast, $env) { for ($i=0; $i < count($a1); $i+=2) { $let_env->set($a1[$i]->value, MAL_EVAL($a1[$i+1], $let_env)); } - return MAL_EVAL($ast[2], $let_env); + $ast = $ast[2]; + $env = $let_env; + break; // Continue loop (TCO) case "quote": return $ast[1]; case "quasiquote": - return MAL_EVAL(quasiquote($ast[1]), $env); + $ast = quasiquote($ast[1]); + break; // Continue loop (TCO) case "do": eval_ast($ast->slice(1, -1), $env); $ast = $ast[count($ast)-1]; - break; + break; // Continue loop (TCO) case "if": $cond = MAL_EVAL($ast[1], $env); if ($cond === NULL || $cond === false) { @@ -92,7 +95,7 @@ function MAL_EVAL($ast, $env) { } else { $ast = $ast[2]; } - break; + break; // Continue loop (TCO) case "fn*": return _function('MAL_EVAL', 'native', $ast[2], $env, $ast[1]); @@ -103,6 +106,7 @@ function MAL_EVAL($ast, $env) { if ($f->type === 'native') { $ast = $f->ast; $env = $f->gen_env($args); + // Continue loop (TCO) } else { return $f->apply($args); } diff --git a/php/step8_macros.php b/php/step8_macros.php index b33111d..aacf33e 100644 --- a/php/step8_macros.php +++ b/php/step8_macros.php @@ -94,11 +94,14 @@ function MAL_EVAL($ast, $env) { for ($i=0; $i < count($a1); $i+=2) { $let_env->set($a1[$i]->value, MAL_EVAL($a1[$i+1], $let_env)); } - return MAL_EVAL($ast[2], $let_env); + $ast = $ast[2]; + $env = $let_env; + break; // Continue loop (TCO) case "quote": return $ast[1]; case "quasiquote": - return MAL_EVAL(quasiquote($ast[1]), $env); + $ast = quasiquote($ast[1]); + break; // Continue loop (TCO) case "defmacro!": $func = MAL_EVAL($ast[2], $env); $func->ismacro = true; @@ -108,7 +111,7 @@ function MAL_EVAL($ast, $env) { case "do": eval_ast($ast->slice(1, -1), $env); $ast = $ast[count($ast)-1]; - break; + break; // Continue loop (TCO) case "if": $cond = MAL_EVAL($ast[1], $env); if ($cond === NULL || $cond === false) { @@ -117,7 +120,7 @@ function MAL_EVAL($ast, $env) { } else { $ast = $ast[2]; } - break; + break; // Continue loop (TCO) case "fn*": return _function('MAL_EVAL', 'native', $ast[2], $env, $ast[1]); @@ -128,6 +131,7 @@ function MAL_EVAL($ast, $env) { if ($f->type === 'native') { $ast = $f->ast; $env = $f->gen_env($args); + // Continue loop (TCO) } else { return $f->apply($args); } diff --git a/php/step9_interop.php b/php/step9_interop.php index f35244c..d4a59c7 100644 --- a/php/step9_interop.php +++ b/php/step9_interop.php @@ -94,11 +94,14 @@ function MAL_EVAL($ast, $env) { for ($i=0; $i < count($a1); $i+=2) { $let_env->set($a1[$i]->value, MAL_EVAL($a1[$i+1], $let_env)); } - return MAL_EVAL($ast[2], $let_env); + $ast = $ast[2]; + $env = $let_env; + break; // Continue loop (TCO) case "quote": return $ast[1]; case "quasiquote": - return MAL_EVAL(quasiquote($ast[1]), $env); + $ast = quasiquote($ast[1]); + break; // Continue loop (TCO) case "defmacro!": $func = MAL_EVAL($ast[2], $env); $func->ismacro = true; @@ -110,7 +113,7 @@ function MAL_EVAL($ast, $env) { case "do": eval_ast($ast->slice(1, -1), $env); $ast = $ast[count($ast)-1]; - break; + break; // Continue loop (TCO) case "if": $cond = MAL_EVAL($ast[1], $env); if ($cond === NULL || $cond === false) { @@ -119,7 +122,7 @@ function MAL_EVAL($ast, $env) { } else { $ast = $ast[2]; } - break; + break; // Continue loop (TCO) case "fn*": return _function('MAL_EVAL', 'native', $ast[2], $env, $ast[1]); @@ -130,6 +133,7 @@ function MAL_EVAL($ast, $env) { if ($f->type === 'native') { $ast = $f->ast; $env = $f->gen_env($args); + // Continue loop (TCO) } else { return $f->apply($args); } diff --git a/php/stepA_more.php b/php/stepA_more.php index 0f4c8ae..f38656f 100644 --- a/php/stepA_more.php +++ b/php/stepA_more.php @@ -94,11 +94,14 @@ function MAL_EVAL($ast, $env) { for ($i=0; $i < count($a1); $i+=2) { $let_env->set($a1[$i]->value, MAL_EVAL($a1[$i+1], $let_env)); } - return MAL_EVAL($ast[2], $let_env); + $ast = $ast[2]; + $env = $let_env; + break; // Continue loop (TCO) case "quote": return $ast[1]; case "quasiquote": - return MAL_EVAL(quasiquote($ast[1]), $env); + $ast = quasiquote($ast[1]); + break; // Continue loop (TCO) case "defmacro!": $func = MAL_EVAL($ast[2], $env); $func->ismacro = true; @@ -128,7 +131,7 @@ function MAL_EVAL($ast, $env) { case "do": eval_ast($ast->slice(1, -1), $env); $ast = $ast[count($ast)-1]; - break; + break; // Continue loop (TCO) case "if": $cond = MAL_EVAL($ast[1], $env); if ($cond === NULL || $cond === false) { @@ -137,7 +140,7 @@ function MAL_EVAL($ast, $env) { } else { $ast = $ast[2]; } - break; + break; // Continue loop (TCO) case "fn*": return _function('MAL_EVAL', 'native', $ast[2], $env, $ast[1]); @@ -148,6 +151,7 @@ function MAL_EVAL($ast, $env) { if ($f->type === 'native') { $ast = $f->ast; $env = $f->gen_env($args); + // Continue loop (TCO) } else { return $f->apply($args); } diff --git a/ps/step5_tco.ps b/ps/step5_tco.ps index c1698d6..83fd43b 100644 --- a/ps/step5_tco.ps +++ b/ps/step5_tco.ps @@ -65,7 +65,9 @@ end } def env_set pop % discard the return value } for - a2 let_env EVAL + a2 + let_env + /loop? true def % loop }{ /do a0 eq { %if do ast _count 2 gt { %if ast has more than 2 elements ast 1 ast _count 2 sub _slice env eval_ast pop diff --git a/ps/step6_file.ps b/ps/step6_file.ps index 00598be..7d1c876 100644 --- a/ps/step6_file.ps +++ b/ps/step6_file.ps @@ -65,7 +65,9 @@ end } def env_set pop % discard the return value } for - a2 let_env EVAL + a2 + let_env + /loop? true def % loop }{ /do a0 eq { %if do ast _count 2 gt { %if ast has more than 2 elements ast 1 ast _count 2 sub _slice env eval_ast pop diff --git a/ps/step7_quote.ps b/ps/step7_quote.ps index 10c8089..d7340fd 100644 --- a/ps/step7_quote.ps +++ b/ps/step7_quote.ps @@ -93,11 +93,15 @@ end } def env_set pop % discard the return value } for - a2 let_env EVAL + a2 + let_env + /loop? true def % loop }{ /quote a0 eq { %if quote ast 1 _nth }{ /quasiquote a0 eq { %if quasiquote - ast 1 _nth quasiquote env EVAL + ast 1 _nth quasiquote + env + /loop? true def % loop }{ /do a0 eq { %if do ast _count 2 gt { %if ast has more than 2 elements ast 1 ast _count 2 sub _slice env eval_ast pop diff --git a/ps/step8_macros.ps b/ps/step8_macros.ps index 74cf50f..3bf304c 100644 --- a/ps/step8_macros.ps +++ b/ps/step8_macros.ps @@ -126,11 +126,15 @@ end } def env_set pop % discard the return value } for - a2 let_env EVAL + a2 + let_env + /loop? true def % loop }{ /quote a0 eq { %if quote ast 1 _nth }{ /quasiquote a0 eq { %if quasiquote - ast 1 _nth quasiquote env EVAL + ast 1 _nth quasiquote + env + /loop? true def % loop }{ /defmacro! a0 eq { %if defmacro! /a1 ast 1 _nth def /a2 ast 2 _nth def diff --git a/ps/step9_interop.ps b/ps/step9_interop.ps index 4f324d5..de3d2af 100644 --- a/ps/step9_interop.ps +++ b/ps/step9_interop.ps @@ -126,11 +126,15 @@ end } def env_set pop % discard the return value } for - a2 let_env EVAL + a2 + let_env + /loop? true def % loop }{ /quote a0 eq { %if quote ast 1 _nth }{ /quasiquote a0 eq { %if quasiquote - ast 1 _nth quasiquote env EVAL + ast 1 _nth quasiquote + env + /loop? true def % loop }{ /defmacro! a0 eq { %if defmacro! /a1 ast 1 _nth def /a2 ast 2 _nth def diff --git a/ps/stepA_more.ps b/ps/stepA_more.ps index 744a092..76d0a86 100644 --- a/ps/stepA_more.ps +++ b/ps/stepA_more.ps @@ -126,11 +126,15 @@ end } def env_set pop % discard the return value } for - a2 let_env EVAL + a2 + let_env + /loop? true def % loop }{ /quote a0 eq { %if quote ast 1 _nth }{ /quasiquote a0 eq { %if quasiquote - ast 1 _nth quasiquote env EVAL + ast 1 _nth quasiquote + env + /loop? true def % loop }{ /defmacro! a0 eq { %if defmacro! /a1 ast 1 _nth def /a2 ast 2 _nth def diff --git a/python/step5_tco.py b/python/step5_tco.py index 72457e9..cbb92c9 100644 --- a/python/step5_tco.py +++ b/python/step5_tco.py @@ -45,7 +45,9 @@ def EVAL(ast, env): let_env = Env(env) for i in range(0, len(a1), 2): let_env.set(a1[i], EVAL(a1[i+1], let_env)) - return EVAL(a2, let_env) + ast = a2 + env = let_env + # Continue loop (TCO) elif "do" == a0: eval_ast(ast[1:-1], env) ast = ast[-1] diff --git a/python/step6_file.py b/python/step6_file.py index 764eb53..9d84d1f 100644 --- a/python/step6_file.py +++ b/python/step6_file.py @@ -45,7 +45,9 @@ def EVAL(ast, env): let_env = Env(env) for i in range(0, len(a1), 2): let_env.set(a1[i], EVAL(a1[i+1], let_env)) - return EVAL(a2, let_env) + ast = a2 + env = let_env + # Continue loop (TCO) elif "do" == a0: eval_ast(ast[1:-1], env) ast = ast[-1] diff --git a/python/step7_quote.py b/python/step7_quote.py index 1002613..de19c6d 100644 --- a/python/step7_quote.py +++ b/python/step7_quote.py @@ -63,11 +63,14 @@ def EVAL(ast, env): let_env = Env(env) for i in range(0, len(a1), 2): let_env.set(a1[i], EVAL(a1[i+1], let_env)) - return EVAL(a2, let_env) + ast = a2 + env = let_env + # Continue loop (TCO) elif "quote" == a0: return ast[1] elif "quasiquote" == a0: - return EVAL(quasiquote(ast[1]), env) + ast = quasiquote(ast[1]); + # Continue loop (TCO) elif "do" == a0: eval_ast(ast[1:-1], env) ast = ast[-1] diff --git a/python/step8_macros.py b/python/step8_macros.py index 28b68fb..80ca239 100644 --- a/python/step8_macros.py +++ b/python/step8_macros.py @@ -77,11 +77,14 @@ def EVAL(ast, env): let_env = Env(env) for i in range(0, len(a1), 2): let_env.set(a1[i], EVAL(a1[i+1], let_env)) - return EVAL(a2, let_env) + ast = a2 + env = let_env + # Continue loop (TCO) elif "quote" == a0: return ast[1] elif "quasiquote" == a0: - return EVAL(quasiquote(ast[1]), env) + ast = quasiquote(ast[1]); + # Continue loop (TCO) elif 'defmacro!' == a0: func = EVAL(ast[2], env) func._ismacro_ = True diff --git a/python/step9_interop.py b/python/step9_interop.py index 2f7c5e0..7cacf1f 100644 --- a/python/step9_interop.py +++ b/python/step9_interop.py @@ -77,11 +77,14 @@ def EVAL(ast, env): let_env = Env(env) for i in range(0, len(a1), 2): let_env.set(a1[i], EVAL(a1[i+1], let_env)) - return EVAL(a2, let_env) + ast = a2 + env = let_env + # Continue loop (TCO) elif "quote" == a0: return ast[1] elif "quasiquote" == a0: - return EVAL(quasiquote(ast[1]), env) + ast = quasiquote(ast[1]); + # Continue loop (TCO) elif 'defmacro!' == a0: func = EVAL(ast[2], env) func._ismacro_ = True diff --git a/python/stepA_more.py b/python/stepA_more.py index b9d8152..723f0ed 100644 --- a/python/stepA_more.py +++ b/python/stepA_more.py @@ -77,11 +77,14 @@ def EVAL(ast, env): let_env = Env(env) for i in range(0, len(a1), 2): let_env.set(a1[i], EVAL(a1[i+1], let_env)) - return EVAL(a2, let_env) + ast = a2 + env = let_env + # Continue loop (TCO) elif "quote" == a0: return ast[1] elif "quasiquote" == a0: - return EVAL(quasiquote(ast[1]), env) + ast = quasiquote(ast[1]); + # Continue loop (TCO) elif 'defmacro!' == a0: func = EVAL(ast[2], env) func._ismacro_ = True diff --git a/ruby/step5_tco.rb b/ruby/step5_tco.rb index 6be04ae..38bb204 100644 --- a/ruby/step5_tco.rb +++ b/ruby/step5_tco.rb @@ -48,17 +48,18 @@ def EVAL(ast, env) a1.each_slice(2) do |a,e| let_env.set(a, EVAL(e, let_env)) end - return EVAL(a2, let_env) + env = let_env + ast = a2 # Continue loop (TCO) when :do eval_ast(ast[1..-2], env) - ast = ast.last + ast = ast.last # Continue loop (TCO) when :if cond = EVAL(a1, env) if not cond return nil if a3 == nil - ast = a3 + ast = a3 # Continue loop (TCO) else - ast = a2 + ast = a2 # Continue loop (TCO) end when :"fn*" return Function.new(a2, env, a1) {|*args| @@ -69,7 +70,7 @@ def EVAL(ast, env) f = el[0] if f.class == Function ast = f.ast - env = f.gen_env(el.drop(1)) + env = f.gen_env(el.drop(1)) # Continue loop (TCO) else return f[*el.drop(1)] end diff --git a/ruby/step6_file.rb b/ruby/step6_file.rb index 191febe..0c99cee 100644 --- a/ruby/step6_file.rb +++ b/ruby/step6_file.rb @@ -48,17 +48,18 @@ def EVAL(ast, env) a1.each_slice(2) do |a,e| let_env.set(a, EVAL(e, let_env)) end - return EVAL(a2, let_env) + env = let_env + ast = a2 # Continue loop (TCO) when :do eval_ast(ast[1..-2], env) - ast = ast.last + ast = ast.last # Continue loop (TCO) when :if cond = EVAL(a1, env) if not cond return nil if a3 == nil - ast = a3 + ast = a3 # Continue loop (TCO) else - ast = a2 + ast = a2 # Continue loop (TCO) end when :"fn*" return Function.new(a2, env, a1) {|*args| @@ -69,7 +70,7 @@ def EVAL(ast, env) f = el[0] if f.class == Function ast = f.ast - env = f.gen_env(el.drop(1)) + env = f.gen_env(el.drop(1)) # Continue loop (TCO) else return f[*el.drop(1)] end diff --git a/ruby/step7_quote.rb b/ruby/step7_quote.rb index 18b7db3..48385f1 100644 --- a/ruby/step7_quote.rb +++ b/ruby/step7_quote.rb @@ -64,21 +64,22 @@ def EVAL(ast, env) a1.each_slice(2) do |a,e| let_env.set(a, EVAL(e, let_env)) end - return EVAL(a2, let_env) + env = let_env + ast = a2 # Continue loop (TCO) when :quote return a1 when :quasiquote - return EVAL(quasiquote(a1), env) + ast = quasiquote(a1); # Continue loop (TCO) when :do eval_ast(ast[1..-2], env) - ast = ast.last + ast = ast.last # Continue loop (TCO) when :if cond = EVAL(a1, env) if not cond return nil if a3 == nil - ast = a3 + ast = a3 # Continue loop (TCO) else - ast = a2 + ast = a2 # Continue loop (TCO) end when :"fn*" return Function.new(a2, env, a1) {|*args| @@ -89,7 +90,7 @@ def EVAL(ast, env) f = el[0] if f.class == Function ast = f.ast - env = f.gen_env(el.drop(1)) + env = f.gen_env(el.drop(1)) # Continue loop (TCO) else return f[*el.drop(1)] end diff --git a/ruby/step8_macros.rb b/ruby/step8_macros.rb index 3c99cce..58adaea 100644 --- a/ruby/step8_macros.rb +++ b/ruby/step8_macros.rb @@ -83,11 +83,12 @@ def EVAL(ast, env) a1.each_slice(2) do |a,e| let_env.set(a, EVAL(e, let_env)) end - return EVAL(a2, let_env) + env = let_env + ast = a2 # Continue loop (TCO) when :quote return a1 when :quasiquote - return EVAL(quasiquote(a1), env) + ast = quasiquote(a1); # Continue loop (TCO) when :defmacro! func = EVAL(a2, env) func.is_macro = true @@ -96,14 +97,14 @@ def EVAL(ast, env) return macroexpand(a1, env) when :do eval_ast(ast[1..-2], env) - ast = ast.last + ast = ast.last # Continue loop (TCO) when :if cond = EVAL(a1, env) if not cond return nil if a3 == nil - ast = a3 + ast = a3 # Continue loop (TCO) else - ast = a2 + ast = a2 # Continue loop (TCO) end when :"fn*" return Function.new(a2, env, a1) {|*args| @@ -114,7 +115,7 @@ def EVAL(ast, env) f = el[0] if f.class == Function ast = f.ast - env = f.gen_env(el.drop(1)) + env = f.gen_env(el.drop(1)) # Continue loop (TCO) else return f[*el.drop(1)] end diff --git a/ruby/step9_interop.rb b/ruby/step9_interop.rb index 507114e..6d2cbe2 100644 --- a/ruby/step9_interop.rb +++ b/ruby/step9_interop.rb @@ -83,11 +83,12 @@ def EVAL(ast, env) a1.each_slice(2) do |a,e| let_env.set(a, EVAL(e, let_env)) end - return EVAL(a2, let_env) + env = let_env + ast = a2 # Continue loop (TCO) when :quote return a1 when :quasiquote - return EVAL(quasiquote(a1), env) + ast = quasiquote(a1); # Continue loop (TCO) when :defmacro! func = EVAL(a2, env) func.is_macro = true @@ -98,14 +99,14 @@ def EVAL(ast, env) return eval(a1) when :do eval_ast(ast[1..-2], env) - ast = ast.last + ast = ast.last # Continue loop (TCO) when :if cond = EVAL(a1, env) if not cond return nil if a3 == nil - ast = a3 + ast = a3 # Continue loop (TCO) else - ast = a2 + ast = a2 # Continue loop (TCO) end when :"fn*" return Function.new(a2, env, a1) {|*args| @@ -116,7 +117,7 @@ def EVAL(ast, env) f = el[0] if f.class == Function ast = f.ast - env = f.gen_env(el.drop(1)) + env = f.gen_env(el.drop(1)) # Continue loop (TCO) else return f[*el.drop(1)] end diff --git a/ruby/stepA_more.rb b/ruby/stepA_more.rb index 101dee3..6123293 100644 --- a/ruby/stepA_more.rb +++ b/ruby/stepA_more.rb @@ -83,11 +83,12 @@ def EVAL(ast, env) a1.each_slice(2) do |a,e| let_env.set(a, EVAL(e, let_env)) end - return EVAL(a2, let_env) + env = let_env + ast = a2 # Continue loop (TCO) when :quote return a1 when :quasiquote - return EVAL(quasiquote(a1), env) + ast = quasiquote(a1); # Continue loop (TCO) when :defmacro! func = EVAL(a2, env) func.is_macro = true @@ -113,14 +114,14 @@ def EVAL(ast, env) end when :do eval_ast(ast[1..-2], env) - ast = ast.last + ast = ast.last # Continue loop (TCO) when :if cond = EVAL(a1, env) if not cond return nil if a3 == nil - ast = a3 + ast = a3 # Continue loop (TCO) else - ast = a2 + ast = a2 # Continue loop (TCO) end when :"fn*" return Function.new(a2, env, a1) {|*args| @@ -131,7 +132,7 @@ def EVAL(ast, env) f = el[0] if f.class == Function ast = f.ast - env = f.gen_env(el.drop(1)) + env = f.gen_env(el.drop(1)) # Continue loop (TCO) else return f[*el.drop(1)] end diff --git a/tests/stepA_more.mal b/tests/stepA_more.mal index 0378c58..7b7dac5 100644 --- a/tests/stepA_more.mal +++ b/tests/stepA_more.mal @@ -6,8 +6,9 @@ ;=>nil ;;;TODO: fix so long lines don't trigger ANSI escape codes ;;;(try* -(throw {"data" "foo"}) (catch* exc (do (prn "exc is:" exc) 7))) ;;;; -"exc is:" {"data" "foo"} ;;;;=>7 +;;;(try* (throw {"data" "foo"}) (catch* exc (do (prn "exc is:" exc) 7))) ;;;; +;;;; "exc is:" {"data" "foo"} ;;;;=>7 +;;;;=>7 (try* (throw {"data" "foo"}) (catch* exc (do (prn "err:" exc) 7))) ; "err:" {"data" "foo"} @@ -69,8 +70,9 @@ (read-string "7 ;; comment") ;=>7 +;;; Differing output, but make sure no fatal error (read-string ";; comment") -;=>nil + (eval (read-string "(+ 4 5)")) ;=>9 |
