From 4807c1b65f0d9920cad586447a56ed31ee4556c6 Mon Sep 17 00:00:00 2001 From: Nicolas Boulenguez Date: Fri, 4 Jun 2021 01:26:31 +0200 Subject: [PATCH] Print a stack trace for uncaught exceptions in self-hosting An uncaught exception in the self-hosting implementation causes the interpreter to display the EVALed ast for each EVAL level until the exception, something similare to a stack trace. This does not cost much and may help a lot debugging the self-hosting step. On the other hand, remove try* from step0 where it serves no useful purpose. Because of indentation level, this diff is better viewed with the git -b command line option. --- impls/mal/step0_repl.mal | 5 +- impls/mal/step2_eval.mal | 29 ++++++---- impls/mal/step3_env.mal | 41 ++++++++------ impls/mal/step4_if_fn_do.mal | 61 ++++++++++++--------- impls/mal/step6_file.mal | 61 ++++++++++++--------- impls/mal/step7_quote.mal | 73 ++++++++++++++----------- impls/mal/step8_macros.mal | 85 ++++++++++++++++------------- impls/mal/step9_try.mal | 101 ++++++++++++++++++++--------------- impls/mal/stepA_mal.mal | 101 ++++++++++++++++++++--------------- 9 files changed, 323 insertions(+), 234 deletions(-) diff --git a/impls/mal/step0_repl.mal b/impls/mal/step0_repl.mal index d4a7be83..837a5fc6 100644 --- a/impls/mal/step0_repl.mal +++ b/impls/mal/step0_repl.mal @@ -18,10 +18,7 @@ (if line (do (if (not (= "" line)) - (try* - (println (rep line)) - (catch* exc - (println "Uncaught exception:" exc)))) + (println (rep line))) (repl-loop (readline "mal-user> ")))))) ;; main diff --git a/impls/mal/step2_eval.mal b/impls/mal/step2_eval.mal index 430020e7..a42c4748 100644 --- a/impls/mal/step2_eval.mal +++ b/impls/mal/step2_eval.mal @@ -1,3 +1,7 @@ +;; EVAL extends this stack trace when propagating exceptions. If the +;; exception reaches the REPL loop, the full trace is printed. +(def! trace (atom "")) + ;; read (def! READ read-string) @@ -23,15 +27,20 @@ (def! EVAL (fn* [ast env] ;; (do (prn "EVAL" ast) ) - (if (not (list? ast)) - (eval-ast ast env) + (try* + (if (not (list? ast)) + (eval-ast ast env) - ;; apply list - (if (empty? ast) - ast - (let* [el (eval-ast ast env)] - (apply (first el) (rest el))))))) + ;; apply list + (if (empty? ast) + ast + (let* [el (eval-ast ast env)] + (apply (first el) (rest el))))) + (catch* exc + (do + (swap! trace str "\n in mal EVAL: " ast) + (throw exc)))))) ;; print (def! PRINT pr-str) @@ -39,7 +48,7 @@ ;; repl (def! repl-env {"+" + "-" - - "*" * + "*" * "/" /}) (def! rep (fn* [strng] (PRINT (EVAL (READ strng) repl-env)))) @@ -52,7 +61,9 @@ (try* (println (rep line)) (catch* exc - (println "Uncaught exception:" exc)))) + (do + (println "Uncaught exception:" exc @trace) + (reset! trace ""))))) (repl-loop (readline "mal-user> ")))))) ;; main diff --git a/impls/mal/step3_env.mal b/impls/mal/step3_env.mal index fda2dbec..55747fed 100644 --- a/impls/mal/step3_env.mal +++ b/impls/mal/step3_env.mal @@ -1,5 +1,9 @@ (load-file "../mal/env.mal") +;; EVAL extends this stack trace when propagating exceptions. If the +;; exception reaches the REPL loop, the full trace is printed. +(def! trace (atom "")) + ;; read (def! READ read-string) @@ -30,25 +34,30 @@ (def! EVAL (fn* [ast env] ;; (do (prn "EVAL" ast "/" (keys @env)) ) - (if (not (list? ast)) - (eval-ast ast env) + (try* + (if (not (list? ast)) + (eval-ast ast env) - ;; apply list - (let* [a0 (first ast)] - (cond - (empty? ast) - ast + ;; apply list + (let* [a0 (first ast)] + (cond + (empty? ast) + ast - (= 'def! a0) - (env-set env (nth ast 1) (EVAL (nth ast 2) env)) + (= 'def! a0) + (env-set env (nth ast 1) (EVAL (nth ast 2) env)) - (= 'let* a0) - (LET (new-env env) (nth ast 1) (nth ast 2)) + (= 'let* a0) + (LET (new-env env) (nth ast 1) (nth ast 2)) - "else" - (let* [el (eval-ast ast env)] - (apply (first el) (rest el)))))))) + "else" + (let* [el (eval-ast ast env)] + (apply (first el) (rest el)))))) + (catch* exc + (do + (swap! trace str "\n in mal EVAL: " ast) + (throw exc)))))) ;; print (def! PRINT pr-str) @@ -71,7 +80,9 @@ (try* (println (rep line)) (catch* exc - (println "Uncaught exception:" exc)))) + (do + (println "Uncaught exception:" exc @trace) + (reset! trace ""))))) (repl-loop (readline "mal-user> ")))))) ;; main diff --git a/impls/mal/step4_if_fn_do.mal b/impls/mal/step4_if_fn_do.mal index a07e6dd7..d23d790b 100644 --- a/impls/mal/step4_if_fn_do.mal +++ b/impls/mal/step4_if_fn_do.mal @@ -1,6 +1,10 @@ (load-file "../mal/env.mal") (load-file "../mal/core.mal") +;; EVAL extends this stack trace when propagating exceptions. If the +;; exception reaches the REPL loop, the full trace is printed. +(def! trace (atom "")) + ;; read (def! READ read-string) @@ -31,38 +35,43 @@ (def! EVAL (fn* [ast env] ;; (do (prn "EVAL" ast "/" (keys @env)) ) - (if (not (list? ast)) - (eval-ast ast env) + (try* + (if (not (list? ast)) + (eval-ast ast env) - ;; apply list - (let* [a0 (first ast)] - (cond - (empty? ast) - ast + ;; apply list + (let* [a0 (first ast)] + (cond + (empty? ast) + ast - (= 'def! a0) - (env-set env (nth ast 1) (EVAL (nth ast 2) env)) + (= 'def! a0) + (env-set env (nth ast 1) (EVAL (nth ast 2) env)) - (= 'let* a0) - (LET (new-env env) (nth ast 1) (nth ast 2)) + (= 'let* a0) + (LET (new-env env) (nth ast 1) (nth ast 2)) - (= 'do a0) - (let* [el (eval-ast (rest ast) env)] - (nth el (- (count el) 1))) + (= 'do a0) + (let* [el (eval-ast (rest ast) env)] + (nth el (- (count el) 1))) - (= 'if a0) - (if (EVAL (nth ast 1) env) - (EVAL (nth ast 2) env) - (if (> (count ast) 3) - (EVAL (nth ast 3) env))) + (= 'if a0) + (if (EVAL (nth ast 1) env) + (EVAL (nth ast 2) env) + (if (> (count ast) 3) + (EVAL (nth ast 3) env))) - (= 'fn* a0) - (fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args))) + (= 'fn* a0) + (fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args))) - "else" - (let* [el (eval-ast ast env)] - (apply (first el) (rest el)))))))) + "else" + (let* [el (eval-ast ast env)] + (apply (first el) (rest el)))))) + (catch* exc + (do + (swap! trace str "\n in mal EVAL: " ast) + (throw exc)))))) ;; print (def! PRINT pr-str) @@ -86,7 +95,9 @@ (try* (println (rep line)) (catch* exc - (println "Uncaught exception:" exc)))) + (do + (println "Uncaught exception:" exc @trace) + (reset! trace ""))))) (repl-loop (readline "mal-user> ")))))) ;; main diff --git a/impls/mal/step6_file.mal b/impls/mal/step6_file.mal index bb97cb1a..9890924d 100644 --- a/impls/mal/step6_file.mal +++ b/impls/mal/step6_file.mal @@ -1,6 +1,10 @@ (load-file "../mal/env.mal") (load-file "../mal/core.mal") +;; EVAL extends this stack trace when propagating exceptions. If the +;; exception reaches the REPL loop, the full trace is printed. +(def! trace (atom "")) + ;; read (def! READ read-string) @@ -31,38 +35,43 @@ (def! EVAL (fn* [ast env] ;; (do (prn "EVAL" ast "/" (keys @env)) ) - (if (not (list? ast)) - (eval-ast ast env) + (try* + (if (not (list? ast)) + (eval-ast ast env) - ;; apply list - (let* [a0 (first ast)] - (cond - (empty? ast) - ast + ;; apply list + (let* [a0 (first ast)] + (cond + (empty? ast) + ast - (= 'def! a0) - (env-set env (nth ast 1) (EVAL (nth ast 2) env)) + (= 'def! a0) + (env-set env (nth ast 1) (EVAL (nth ast 2) env)) - (= 'let* a0) - (LET (new-env env) (nth ast 1) (nth ast 2)) + (= 'let* a0) + (LET (new-env env) (nth ast 1) (nth ast 2)) - (= 'do a0) - (let* [el (eval-ast (rest ast) env)] - (nth el (- (count el) 1))) + (= 'do a0) + (let* [el (eval-ast (rest ast) env)] + (nth el (- (count el) 1))) - (= 'if a0) - (if (EVAL (nth ast 1) env) - (EVAL (nth ast 2) env) - (if (> (count ast) 3) - (EVAL (nth ast 3) env))) + (= 'if a0) + (if (EVAL (nth ast 1) env) + (EVAL (nth ast 2) env) + (if (> (count ast) 3) + (EVAL (nth ast 3) env))) - (= 'fn* a0) - (fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args))) + (= 'fn* a0) + (fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args))) - "else" - (let* [el (eval-ast ast env)] - (apply (first el) (rest el)))))))) + "else" + (let* [el (eval-ast ast env)] + (apply (first el) (rest el)))))) + (catch* exc + (do + (swap! trace str "\n in mal EVAL: " ast) + (throw exc)))))) ;; print (def! PRINT pr-str) @@ -89,7 +98,9 @@ (try* (println (rep line)) (catch* exc - (println "Uncaught exception:" exc)))) + (do + (println "Uncaught exception:" exc @trace) + (reset! trace ""))))) (repl-loop (readline "mal-user> ")))))) ;; main diff --git a/impls/mal/step7_quote.mal b/impls/mal/step7_quote.mal index c0f0546e..7739c85d 100644 --- a/impls/mal/step7_quote.mal +++ b/impls/mal/step7_quote.mal @@ -1,6 +1,10 @@ (load-file "../mal/env.mal") (load-file "../mal/core.mal") +;; EVAL extends this stack trace when propagating exceptions. If the +;; exception reaches the REPL loop, the full trace is printed. +(def! trace (atom "")) + ;; read (def! READ read-string) @@ -49,47 +53,52 @@ (def! EVAL (fn* [ast env] ;; (do (prn "EVAL" ast "/" (keys @env)) ) - (if (not (list? ast)) - (eval-ast ast env) + (try* + (if (not (list? ast)) + (eval-ast ast env) - ;; apply list - (let* [a0 (first ast)] - (cond - (empty? ast) - ast + ;; apply list + (let* [a0 (first ast)] + (cond + (empty? ast) + ast - (= 'def! a0) - (env-set env (nth ast 1) (EVAL (nth ast 2) env)) + (= 'def! a0) + (env-set env (nth ast 1) (EVAL (nth ast 2) env)) - (= 'let* a0) - (LET (new-env env) (nth ast 1) (nth ast 2)) + (= 'let* a0) + (LET (new-env env) (nth ast 1) (nth ast 2)) - (= 'quote a0) - (nth ast 1) + (= 'quote a0) + (nth ast 1) - (= 'quasiquoteexpand a0) - (QUASIQUOTE (nth ast 1)) + (= 'quasiquoteexpand a0) + (QUASIQUOTE (nth ast 1)) - (= 'quasiquote a0) - (EVAL (QUASIQUOTE (nth ast 1)) env) + (= 'quasiquote a0) + (EVAL (QUASIQUOTE (nth ast 1)) env) - (= 'do a0) - (let* [el (eval-ast (rest ast) env)] - (nth el (- (count el) 1))) + (= 'do a0) + (let* [el (eval-ast (rest ast) env)] + (nth el (- (count el) 1))) - (= 'if a0) - (if (EVAL (nth ast 1) env) - (EVAL (nth ast 2) env) - (if (> (count ast) 3) - (EVAL (nth ast 3) env))) + (= 'if a0) + (if (EVAL (nth ast 1) env) + (EVAL (nth ast 2) env) + (if (> (count ast) 3) + (EVAL (nth ast 3) env))) - (= 'fn* a0) - (fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args))) + (= 'fn* a0) + (fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args))) - "else" - (let* [el (eval-ast ast env)] - (apply (first el) (rest el)))))))) + "else" + (let* [el (eval-ast ast env)] + (apply (first el) (rest el)))))) + (catch* exc + (do + (swap! trace str "\n in mal EVAL: " ast) + (throw exc)))))) ;; print (def! PRINT pr-str) @@ -116,7 +125,9 @@ (try* (println (rep line)) (catch* exc - (println "Uncaught exception:" exc)))) + (do + (println "Uncaught exception:" exc @trace) + (reset! trace ""))))) (repl-loop (readline "mal-user> ")))))) ;; main diff --git a/impls/mal/step8_macros.mal b/impls/mal/step8_macros.mal index 7d5e1806..53f06a47 100644 --- a/impls/mal/step8_macros.mal +++ b/impls/mal/step8_macros.mal @@ -1,6 +1,10 @@ (load-file "../mal/env.mal") (load-file "../mal/core.mal") +;; EVAL extends this stack trace when propagating exceptions. If the +;; exception reaches the REPL loop, the full trace is printed. +(def! trace (atom "")) + ;; read (def! READ read-string) @@ -57,55 +61,60 @@ (def! EVAL (fn* [ast env] ;; (do (prn "EVAL" ast "/" (keys @env)) ) - (let* [ast (MACROEXPAND ast env)] - (if (not (list? ast)) - (eval-ast ast env) + (try* + (let* [ast (MACROEXPAND ast env)] + (if (not (list? ast)) + (eval-ast ast env) - ;; apply list - (let* [a0 (first ast)] - (cond - (empty? ast) - ast + ;; apply list + (let* [a0 (first ast)] + (cond + (empty? ast) + ast - (= 'def! a0) - (env-set env (nth ast 1) (EVAL (nth ast 2) env)) + (= 'def! a0) + (env-set env (nth ast 1) (EVAL (nth ast 2) env)) - (= 'let* a0) - (LET (new-env env) (nth ast 1) (nth ast 2)) + (= 'let* a0) + (LET (new-env env) (nth ast 1) (nth ast 2)) - (= 'quote a0) - (nth ast 1) + (= 'quote a0) + (nth ast 1) - (= 'quasiquoteexpand a0) - (QUASIQUOTE (nth ast 1)) + (= 'quasiquoteexpand a0) + (QUASIQUOTE (nth ast 1)) - (= 'quasiquote a0) - (EVAL (QUASIQUOTE (nth ast 1)) env) + (= 'quasiquote a0) + (EVAL (QUASIQUOTE (nth ast 1)) env) - (= 'defmacro! a0) - (env-set env (nth ast 1) (hash-map :__MAL_MACRO__ - (EVAL (nth ast 2) env))) + (= 'defmacro! a0) + (env-set env (nth ast 1) (hash-map :__MAL_MACRO__ + (EVAL (nth ast 2) env))) - (= 'macroexpand a0) - (MACROEXPAND (nth ast 1) env) + (= 'macroexpand a0) + (MACROEXPAND (nth ast 1) env) - (= 'do a0) - (let* [el (eval-ast (rest ast) env)] - (nth el (- (count el) 1))) + (= 'do a0) + (let* [el (eval-ast (rest ast) env)] + (nth el (- (count el) 1))) - (= 'if a0) - (if (EVAL (nth ast 1) env) - (EVAL (nth ast 2) env) - (if (> (count ast) 3) - (EVAL (nth ast 3) env))) + (= 'if a0) + (if (EVAL (nth ast 1) env) + (EVAL (nth ast 2) env) + (if (> (count ast) 3) + (EVAL (nth ast 3) env))) - (= 'fn* a0) - (fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args))) + (= 'fn* a0) + (fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args))) - "else" - (let* [el (eval-ast ast env)] - (apply (first el) (rest el))))))))) + "else" + (let* [el (eval-ast ast env)] + (apply (first el) (rest el))))))) + (catch* exc + (do + (swap! trace str "\n in mal EVAL: " ast) + (throw exc)))))) ;; print (def! PRINT pr-str) @@ -133,7 +142,9 @@ (try* (println (rep line)) (catch* exc - (println "Uncaught exception:" exc)))) + (do + (println "Uncaught exception:" exc @trace) + (reset! trace ""))))) (repl-loop (readline "mal-user> ")))))) ;; main diff --git a/impls/mal/step9_try.mal b/impls/mal/step9_try.mal index 3ca405bd..bf90c65a 100644 --- a/impls/mal/step9_try.mal +++ b/impls/mal/step9_try.mal @@ -1,6 +1,10 @@ (load-file "../mal/env.mal") (load-file "../mal/core.mal") +;; EVAL extends this stack trace when propagating exceptions. If the +;; exception reaches the REPL loop, the full trace is printed. +(def! trace (atom "")) + ;; read (def! READ read-string) @@ -57,64 +61,71 @@ (def! EVAL (fn* [ast env] ;; (do (prn "EVAL" ast "/" (keys @env)) ) - (let* [ast (MACROEXPAND ast env)] - (if (not (list? ast)) - (eval-ast ast env) + (try* + (let* [ast (MACROEXPAND ast env)] + (if (not (list? ast)) + (eval-ast ast env) - ;; apply list - (let* [a0 (first ast)] - (cond - (empty? ast) - ast + ;; apply list + (let* [a0 (first ast)] + (cond + (empty? ast) + ast - (= 'def! a0) - (env-set env (nth ast 1) (EVAL (nth ast 2) env)) + (= 'def! a0) + (env-set env (nth ast 1) (EVAL (nth ast 2) env)) - (= 'let* a0) - (LET (new-env env) (nth ast 1) (nth ast 2)) + (= 'let* a0) + (LET (new-env env) (nth ast 1) (nth ast 2)) - (= 'quote a0) - (nth ast 1) + (= 'quote a0) + (nth ast 1) - (= 'quasiquoteexpand a0) - (QUASIQUOTE (nth ast 1)) + (= 'quasiquoteexpand a0) + (QUASIQUOTE (nth ast 1)) - (= 'quasiquote a0) - (EVAL (QUASIQUOTE (nth ast 1)) env) + (= 'quasiquote a0) + (EVAL (QUASIQUOTE (nth ast 1)) env) - (= 'defmacro! a0) - (env-set env (nth ast 1) (hash-map :__MAL_MACRO__ - (EVAL (nth ast 2) env))) + (= 'defmacro! a0) + (env-set env (nth ast 1) (hash-map :__MAL_MACRO__ + (EVAL (nth ast 2) env))) - (= 'macroexpand a0) - (MACROEXPAND (nth ast 1) env) + (= 'macroexpand a0) + (MACROEXPAND (nth ast 1) env) - (= 'try* a0) - (if (< (count ast) 3) - (EVAL (nth ast 1) env) - (try* + (= 'try* a0) + (if (< (count ast) 3) (EVAL (nth ast 1) env) - (catch* exc - (let* [a2 (nth ast 2)] - (EVAL (nth a2 2) (new-env env [(nth a2 1)] [exc])))))) + (try* + (EVAL (nth ast 1) env) + (catch* exc + (do + (reset! trace "") + (let* [a2 (nth ast 2)] + (EVAL (nth a2 2) (new-env env [(nth a2 1)] [exc]))))))) - (= 'do a0) - (let* [el (eval-ast (rest ast) env)] - (nth el (- (count el) 1))) + (= 'do a0) + (let* [el (eval-ast (rest ast) env)] + (nth el (- (count el) 1))) - (= 'if a0) - (if (EVAL (nth ast 1) env) - (EVAL (nth ast 2) env) - (if (> (count ast) 3) - (EVAL (nth ast 3) env))) + (= 'if a0) + (if (EVAL (nth ast 1) env) + (EVAL (nth ast 2) env) + (if (> (count ast) 3) + (EVAL (nth ast 3) env))) - (= 'fn* a0) - (fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args))) + (= 'fn* a0) + (fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args))) - "else" - (let* [el (eval-ast ast env)] - (apply (first el) (rest el))))))))) + "else" + (let* [el (eval-ast ast env)] + (apply (first el) (rest el))))))) + (catch* exc + (do + (swap! trace str "\n in mal EVAL: " ast) + (throw exc)))))) ;; print (def! PRINT pr-str) @@ -142,7 +153,9 @@ (try* (println (rep line)) (catch* exc - (println "Uncaught exception:" exc)))) + (do + (println "Uncaught exception:" exc @trace) + (reset! trace ""))))) (repl-loop (readline "mal-user> ")))))) ;; main diff --git a/impls/mal/stepA_mal.mal b/impls/mal/stepA_mal.mal index 57443922..c584f381 100644 --- a/impls/mal/stepA_mal.mal +++ b/impls/mal/stepA_mal.mal @@ -1,6 +1,10 @@ (load-file "../mal/env.mal") (load-file "../mal/core.mal") +;; EVAL extends this stack trace when propagating exceptions. If the +;; exception reaches the REPL loop, the full trace is printed. +(def! trace (atom "")) + ;; read (def! READ read-string) @@ -57,64 +61,71 @@ (def! EVAL (fn* [ast env] ;; (do (prn "EVAL" ast "/" (keys @env)) ) - (let* [ast (MACROEXPAND ast env)] - (if (not (list? ast)) - (eval-ast ast env) + (try* + (let* [ast (MACROEXPAND ast env)] + (if (not (list? ast)) + (eval-ast ast env) - ;; apply list - (let* [a0 (first ast)] - (cond - (empty? ast) - ast + ;; apply list + (let* [a0 (first ast)] + (cond + (empty? ast) + ast - (= 'def! a0) - (env-set env (nth ast 1) (EVAL (nth ast 2) env)) + (= 'def! a0) + (env-set env (nth ast 1) (EVAL (nth ast 2) env)) - (= 'let* a0) - (LET (new-env env) (nth ast 1) (nth ast 2)) + (= 'let* a0) + (LET (new-env env) (nth ast 1) (nth ast 2)) - (= 'quote a0) - (nth ast 1) + (= 'quote a0) + (nth ast 1) - (= 'quasiquoteexpand a0) - (QUASIQUOTE (nth ast 1)) + (= 'quasiquoteexpand a0) + (QUASIQUOTE (nth ast 1)) - (= 'quasiquote a0) - (EVAL (QUASIQUOTE (nth ast 1)) env) + (= 'quasiquote a0) + (EVAL (QUASIQUOTE (nth ast 1)) env) - (= 'defmacro! a0) - (env-set env (nth ast 1) (hash-map :__MAL_MACRO__ - (EVAL (nth ast 2) env))) + (= 'defmacro! a0) + (env-set env (nth ast 1) (hash-map :__MAL_MACRO__ + (EVAL (nth ast 2) env))) - (= 'macroexpand a0) - (MACROEXPAND (nth ast 1) env) + (= 'macroexpand a0) + (MACROEXPAND (nth ast 1) env) - (= 'try* a0) - (if (< (count ast) 3) - (EVAL (nth ast 1) env) - (try* + (= 'try* a0) + (if (< (count ast) 3) (EVAL (nth ast 1) env) - (catch* exc - (let* [a2 (nth ast 2)] - (EVAL (nth a2 2) (new-env env [(nth a2 1)] [exc])))))) + (try* + (EVAL (nth ast 1) env) + (catch* exc + (do + (reset! trace "") + (let* [a2 (nth ast 2)] + (EVAL (nth a2 2) (new-env env [(nth a2 1)] [exc]))))))) - (= 'do a0) - (let* [el (eval-ast (rest ast) env)] - (nth el (- (count el) 1))) + (= 'do a0) + (let* [el (eval-ast (rest ast) env)] + (nth el (- (count el) 1))) - (= 'if a0) - (if (EVAL (nth ast 1) env) - (EVAL (nth ast 2) env) - (if (> (count ast) 3) - (EVAL (nth ast 3) env))) + (= 'if a0) + (if (EVAL (nth ast 1) env) + (EVAL (nth ast 2) env) + (if (> (count ast) 3) + (EVAL (nth ast 3) env))) - (= 'fn* a0) - (fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args))) + (= 'fn* a0) + (fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args))) - "else" - (let* [el (eval-ast ast env)] - (apply (first el) (rest el))))))))) + "else" + (let* [el (eval-ast ast env)] + (apply (first el) (rest el))))))) + (catch* exc + (do + (swap! trace str "\n in mal EVAL: " ast) + (throw exc)))))) ;; print (def! PRINT pr-str) @@ -143,7 +154,9 @@ (try* (println (rep line)) (catch* exc - (println "Uncaught exception:" exc)))) + (do + (println "Uncaught exception:" exc @trace) + (reset! trace ""))))) (repl-loop (readline "mal-user> ")))))) ;; main