Skip to content

Commit

Permalink
mal impl: report more errors in step files
Browse files Browse the repository at this point in the history
  • Loading branch information
asarhaddon authored and kanaka committed Aug 7, 2024
1 parent 2304fea commit 3f6a40f
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 130 deletions.
16 changes: 13 additions & 3 deletions impls/mal/env.mal
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,21 @@
;; Private helper for new-env.
(def! bind-env (fn* [env b e]
(if (empty? b)
env
(if (empty? e)
env
(throw "too many arguments in function call"))
(let* [b0 (first b)]
(if (= '& b0)
(assoc env (str (nth b 1)) e)
(bind-env (assoc env (str b0) (first e)) (rest b) (rest e)))))))
(if (= 2 (count b))
(if (symbol? (nth b 1))
(assoc env (str (nth b 1)) e)
(throw "formal parameters must be symbols"))
(throw "misplaced '&' construct"))
(if (empty? e)
(throw "too few arguments in function call")
(if (symbol? b0)
(bind-env (assoc env (str b0) (first e)) (rest b) (rest e))
(throw "formal parameters must be symbols"))))))))

(def! new-env (fn* [& args]
(if (<= (count args) 1)
Expand Down
4 changes: 3 additions & 1 deletion impls/mal/step2_eval.mal
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
(let* [a0 (first ast)
f (EVAL a0 env)
args (rest ast)]
(apply f (map (fn* [exp] (EVAL exp env)) args))))
(if (fn? f)
(apply f (map (fn* [exp] (EVAL exp env)) args))
(throw "can only apply functions"))))

"else"
ast)
Expand Down
28 changes: 18 additions & 10 deletions impls/mal/step3_env.mal
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
(def! LET (fn* [env binds form]
(if (empty? binds)
(EVAL form env)
(do
(env-set env (first binds) (EVAL (nth binds 1) env))
(LET env (rest (rest binds)) form)))))
(if (if (< 1 (count binds)) (symbol? (first binds)))
(do
(env-set env (first binds) (EVAL (nth binds 1) env))
(LET env (rest (rest binds)) form))
(throw "invalid binds")))))

(def! EVAL (fn* [ast env]
(do
Expand All @@ -38,18 +40,24 @@
(let* [a0 (first ast)]
(cond
(= 'def! a0)
(let* [val (EVAL (nth ast 2) env)]
(if (if (= 3 (count ast)) (symbol? (nth ast 1)))
(let* [val (EVAL (nth ast 2) env)]
(do
(env-set env (nth ast 1) val)
val))
(throw "bad arguments"))

(= 'let* a0)
(LET (new-env env) (nth ast 1) (nth ast 2))
(if (if (= 3 (count ast)) (sequential? (nth ast 1)))
(LET (new-env env) (nth ast 1) (nth ast 2))
(throw "bad arguments"))

"else"
(let* [f (EVAL a0 env)
args (rest ast)]
(apply f (map (fn* [exp] (EVAL exp env)) args))))))
(if (fn? f)
(apply f (map (fn* [exp] (EVAL exp env)) args))
(throw "can only apply functions"))))))

"else"
ast)
Expand All @@ -67,10 +75,10 @@
(def! rep (fn* [strng]
(PRINT (EVAL (READ strng) repl-env))))

(env-set repl-env "+" +)
(env-set repl-env "-" -)
(env-set repl-env "*" *)
(env-set repl-env "/" /)
(env-set repl-env '+ +)
(env-set repl-env '- -)
(env-set repl-env '* *)
(env-set repl-env '/ /)

;; repl loop
(def! repl-loop (fn* [line]
Expand Down
38 changes: 26 additions & 12 deletions impls/mal/step4_if_fn_do.mal
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
(def! LET (fn* [env binds form]
(if (empty? binds)
(EVAL form env)
(do
(env-set env (first binds) (EVAL (nth binds 1) env))
(LET env (rest (rest binds)) form)))))
(if (if (< 1 (count binds)) (symbol? (first binds)))
(do
(env-set env (first binds) (EVAL (nth binds 1) env))
(LET env (rest (rest binds)) form))
(throw "invalid binds")))))

(def! EVAL (fn* [ast env]
(do
Expand All @@ -39,30 +41,42 @@
(let* [a0 (first ast)]
(cond
(= 'def! a0)
(let* [val (EVAL (nth ast 2) env)]
(if (if (= 3 (count ast)) (symbol? (nth ast 1)))
(let* [val (EVAL (nth ast 2) env)]
(do
(env-set env (nth ast 1) val)
val))
(throw "bad arguments"))

(= 'let* a0)
(LET (new-env env) (nth ast 1) (nth ast 2))
(if (if (= 3 (count ast)) (sequential? (nth ast 1)))
(LET (new-env env) (nth ast 1) (nth ast 2))
(throw "bad arguments"))

(= 'do a0)
(nth (map (fn* [exp] (EVAL exp env)) (rest ast)) (- (count ast) 2))
(if (<= 2 (count ast))
(nth (map (fn* [exp] (EVAL exp env)) (rest ast)) (- (count ast) 2))
(throw "bad argument count"))

(= 'if a0)
(if (EVAL (nth ast 1) env)
(EVAL (nth ast 2) env)
(if (> (count ast) 3)
(EVAL (nth ast 3) env)))
(if (if (<= 3 (count ast)) (<= (count ast) 4))
(if (EVAL (nth ast 1) env)
(EVAL (nth ast 2) env)
(if (= 4 (count ast))
(EVAL (nth ast 3) env)))
(throw "bad argument count"))

(= 'fn* a0)
(fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args)))
(if (if (= 3 (count ast)) (sequential? (nth ast 1)))
(fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args)))
(throw "bad arguments"))

"else"
(let* [f (EVAL a0 env)
args (rest ast)]
(apply f (map (fn* [exp] (EVAL exp env)) args))))))
(if (fn? f)
(apply f (map (fn* [exp] (EVAL exp env)) args))
(throw "can only apply functions"))))))

"else"
ast)
Expand Down
38 changes: 26 additions & 12 deletions impls/mal/step6_file.mal
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
(def! LET (fn* [env binds form]
(if (empty? binds)
(EVAL form env)
(do
(env-set env (first binds) (EVAL (nth binds 1) env))
(LET env (rest (rest binds)) form)))))
(if (if (< 1 (count binds)) (symbol? (first binds)))
(do
(env-set env (first binds) (EVAL (nth binds 1) env))
(LET env (rest (rest binds)) form))
(throw "invalid binds")))))

(def! EVAL (fn* [ast env]
(do
Expand All @@ -39,30 +41,42 @@
(let* [a0 (first ast)]
(cond
(= 'def! a0)
(let* [val (EVAL (nth ast 2) env)]
(if (if (= 3 (count ast)) (symbol? (nth ast 1)))
(let* [val (EVAL (nth ast 2) env)]
(do
(env-set env (nth ast 1) val)
val))
(throw "bad arguments"))

(= 'let* a0)
(LET (new-env env) (nth ast 1) (nth ast 2))
(if (if (= 3 (count ast)) (sequential? (nth ast 1)))
(LET (new-env env) (nth ast 1) (nth ast 2))
(throw "bad arguments"))

(= 'do a0)
(nth (map (fn* [exp] (EVAL exp env)) (rest ast)) (- (count ast) 2))
(if (<= 2 (count ast))
(nth (map (fn* [exp] (EVAL exp env)) (rest ast)) (- (count ast) 2))
(throw "bad argument count"))

(= 'if a0)
(if (EVAL (nth ast 1) env)
(EVAL (nth ast 2) env)
(if (> (count ast) 3)
(EVAL (nth ast 3) env)))
(if (if (<= 3 (count ast)) (<= (count ast) 4))
(if (EVAL (nth ast 1) env)
(EVAL (nth ast 2) env)
(if (= 4 (count ast))
(EVAL (nth ast 3) env)))
(throw "bad argument count"))

(= 'fn* a0)
(fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args)))
(if (if (= 3 (count ast)) (sequential? (nth ast 1)))
(fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args)))
(throw "bad arguments"))

"else"
(let* [f (EVAL a0 env)
args (rest ast)]
(apply f (map (fn* [exp] (EVAL exp env)) args))))))
(if (fn? f)
(apply f (map (fn* [exp] (EVAL exp env)) args))
(throw "can only apply functions"))))))

"else"
ast)
Expand Down
54 changes: 38 additions & 16 deletions impls/mal/step7_quote.mal
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@

(def! qq-loop (fn* [elt acc]
(if (if (list? elt) (= (first elt) 'splice-unquote)) ; 2nd 'if' means 'and'
(list 'concat (nth elt 1) acc)
(if (= 2 (count elt))
(list 'concat (nth elt 1) acc)
(throw "splice-unquote expects 1 argument"))
(list 'cons (QUASIQUOTE elt) acc))))
(def! qq-foldr (fn* [xs]
(if (empty? xs)
Expand All @@ -25,15 +27,19 @@
(map? ast) (list 'quote ast)
(symbol? ast) (list 'quote ast)
(not (list? ast)) ast
(= (first ast) 'unquote) (nth ast 1)
(= (first ast) 'unquote) (if (= 2 (count ast))
(nth ast 1)
(throw "unquote expects 1 argument"))
"else" (qq-foldr ast))))

(def! LET (fn* [env binds form]
(if (empty? binds)
(EVAL form env)
(do
(env-set env (first binds) (EVAL (nth binds 1) env))
(LET env (rest (rest binds)) form)))))
(if (if (< 1 (count binds)) (symbol? (first binds)))
(do
(env-set env (first binds) (EVAL (nth binds 1) env))
(LET env (rest (rest binds)) form))
(throw "invalid binds")))))

(def! EVAL (fn* [ast env]
(do
Expand All @@ -57,36 +63,52 @@
(let* [a0 (first ast)]
(cond
(= 'def! a0)
(let* [val (EVAL (nth ast 2) env)]
(if (if (= 3 (count ast)) (symbol? (nth ast 1)))
(let* [val (EVAL (nth ast 2) env)]
(do
(env-set env (nth ast 1) val)
val))
(throw "bad arguments"))

(= 'let* a0)
(LET (new-env env) (nth ast 1) (nth ast 2))
(if (if (= 3 (count ast)) (sequential? (nth ast 1)))
(LET (new-env env) (nth ast 1) (nth ast 2))
(throw "bad arguments"))

(= 'quote a0)
(nth ast 1)
(if (= 2 (count ast))
(nth ast 1)
(throw "bad argument count"))

(= 'quasiquote a0)
(EVAL (QUASIQUOTE (nth ast 1)) env)
(if (= 2 (count ast))
(EVAL (QUASIQUOTE (nth ast 1)) env)
(throw "bad argument count"))

(= 'do a0)
(nth (map (fn* [exp] (EVAL exp env)) (rest ast)) (- (count ast) 2))
(if (<= 2 (count ast))
(nth (map (fn* [exp] (EVAL exp env)) (rest ast)) (- (count ast) 2))
(throw "bad argument count"))

(= 'if a0)
(if (EVAL (nth ast 1) env)
(EVAL (nth ast 2) env)
(if (> (count ast) 3)
(EVAL (nth ast 3) env)))
(if (if (<= 3 (count ast)) (<= (count ast) 4))
(if (EVAL (nth ast 1) env)
(EVAL (nth ast 2) env)
(if (= 4 (count ast))
(EVAL (nth ast 3) env)))
(throw "bad argument count"))

(= 'fn* a0)
(fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args)))
(if (if (= 3 (count ast)) (sequential? (nth ast 1)))
(fn* [& args] (EVAL (nth ast 2) (new-env env (nth ast 1) args)))
(throw "bad arguments"))

"else"
(let* [f (EVAL a0 env)
args (rest ast)]
(apply f (map (fn* [exp] (EVAL exp env)) args))))))
(if (fn? f)
(apply f (map (fn* [exp] (EVAL exp env)) args))
(throw "can only apply functions"))))))

"else"
ast)
Expand Down
Loading

0 comments on commit 3f6a40f

Please sign in to comment.