stash work: bugfixes, better errors, etc.

This commit is contained in:
Scott Richmond 2024-06-05 17:47:41 -04:00
parent 20cb689d12
commit 35a4b8e1c6
5 changed files with 124 additions and 51 deletions

View File

@ -89,12 +89,14 @@
:string (get-in x [:token :lexeme]) :string (get-in x [:token :lexeme])
(error (string "cannot show pattern of unknown type " (x :type))))) (error (string "cannot show pattern of unknown type " (x :type)))))
(defn pretty-patterns [fnn]
(def {:body clauses} fnn)
(string/join (map (fn [x] (-> x first show-patt)) clauses) " "))
(defn doc! [fnn] (defn doc! [fnn]
(def {:name name :doc doc :body clauses} fnn) (def {:name name :doc doc :body clauses} fnn)
(print "doccing " name)
(def patterns (map (fn [x] (-> x first show-patt)) clauses))
(print name) (print name)
(print (string/join patterns " ")) (print (pretty-patterns fnn))
(print doc)) (print doc))
(defn- conj!-set [sett value] (defn- conj!-set [sett value]
@ -239,5 +241,7 @@
(def base (let [b @{}] (def base (let [b @{}]
(each [k v] (pairs ctx) (each [k v] (pairs ctx)
(set (b (keyword k)) v)) (set (b (keyword k)) v))
(table/to-struct b))) b))
(set (base :^type) :dict)

View File

@ -1,10 +1,11 @@
(import spork/json :as j) (import spork/json :as j)
(try (os/cd "janet") ([_] nil))
(import /base :as b) (import /base :as b)
(defn- get-line [source line] (defn- get-line [source line]
((string/split "\n" source) (dec line))) ((string/split "\n" source) (dec line)))
(defn scan-error [e out] (set (out :errors) e) (j/encode out)) (defn scan-error [e] (pp e) e)
(defn parse-error [e] (defn parse-error [e]
(def msg (e :msg)) (def msg (e :msg))
@ -13,7 +14,8 @@
(def source-line (get-line source line-num)) (def source-line (get-line source line-num))
(print "Parsing error: " msg) (print "Parsing error: " msg)
(print "On line " line-num ":") (print "On line " line-num ":")
(print source-line)) (print source-line)
e)
(defn validation-error [e] (defn validation-error [e]
@ -26,9 +28,41 @@
(do (do
(print "Validation error: " msg " " (get-in e [:node :data])) (print "Validation error: " msg " " (get-in e [:node :data]))
(print "on line " line-num) (print "on line " line-num)
(print source-line) (print source-line))
) (do
) (print "Validation error: " msg)
(print "on line " line-num)
(print source-line)))
e)
(defn- fn-no-match [e]
(print "Ludus panicked! no match")
(def line-num (get-in e [:node :token :line]))
(def source (get-in e [:node :token :source]))
(def source-line (get-line source line-num))
(print "on line " line-num)
(def called (e :called))
(print "calling " (b/show called))
(def value (e :value))
(print "with " (b/show value))
(print "expecting to match one of")
(print (b/pretty-patterns called))
) )
(defn runtime-error [e out] (set (out :errors) e) (j/encode out)) (defn- generic-panic [e]
(def msg (e :msg))
(def line-num (get-in e [:node :token :line]))
(def source (get-in e [:node :token :source]))
(def source-line (get-line source line-num))
(print "Ludus panicked! " msg)
(print "on line " line-num)
(print source-line)
)
(defn runtime-error [e]
(pp e)
(def msg (e :msg))
(case msg
"no match: function call" (fn-no-match e)
(generic-panic e)
e)

View File

@ -1,7 +1,7 @@
# A tree walk interpreter for ludus # A tree walk interpreter for ludus
# for repl imports # for repl imports
# (try (os/cd "janet") ([_] nil)) (try (os/cd "janet") ([_] nil))
(import ./base :as b) (import ./base :as b)
@ -36,11 +36,11 @@
(break {:success false :miss [pattern value]})) (break {:success false :miss [pattern value]}))
(def val-len (length value)) (def val-len (length value))
(var members (pattern :data)) (var members (pattern :data))
(def patt-len (length members))
(when (empty? members) (when (empty? members)
(break (if (empty? value) (break (if (empty? value)
{:success true :ctx ctx} {:success true :ctx ctx}
{:success false :miss [pattern value]}))) {:success false :miss [pattern value]})))
(def patt-len (length members))
(var splat nil) (var splat nil)
(def splat? (= :splat ((last members) :type))) (def splat? (= :splat ((last members) :type)))
(when splat? (when splat?
@ -78,6 +78,10 @@
(break {:success false :miss [pattern value]})) (break {:success false :miss [pattern value]}))
(def val-len (length value)) (def val-len (length value))
(var members (pattern :data)) (var members (pattern :data))
(when (empty? members)
(break (if (empty? value)
{:success true :ctx ctx}
{:success false :miss [pattern value]})))
(def patt-len (length members)) (def patt-len (length members))
(var splat nil) (var splat nil)
(def splat? (= :splat ((last members) :type))) (def splat? (= :splat ((last members) :type)))
@ -201,6 +205,8 @@
(set match-pattern match-pattern*) (set match-pattern match-pattern*)
(defn- lett [ast ctx] (defn- lett [ast ctx]
# (print "lett!")
# (pp ast)
(def [patt expr] (ast :data)) (def [patt expr] (ast :data))
(def value (interpret expr ctx)) (def value (interpret expr ctx))
(def match? (match-pattern patt value)) (def match? (match-pattern patt value))
@ -208,7 +214,7 @@
(do (do
(merge-into ctx (match? :ctx)) (merge-into ctx (match? :ctx))
value) value)
(error {:node ast :value value :msg "no match"}))) (error {:node ast :value value :msg "no match: let binding"})))
(defn- matchh [ast ctx] (defn- matchh [ast ctx]
(def [to-match clauses] (ast :data)) (def [to-match clauses] (ast :data))
@ -217,7 +223,7 @@
(when (ast :match) (break ((ast :match) 0 value ctx))) (when (ast :match) (break ((ast :match) 0 value ctx)))
(defn match-fn [i value ctx] (defn match-fn [i value ctx]
(when (= len i) (when (= len i)
(error {:node ast :value value :msg "no match"})) (error {:node ast :value value :msg "no match: match form"}))
(def clause (clauses i)) (def clause (clauses i))
(def [patt guard expr] clause) (def [patt guard expr] clause)
(def match? (match-pattern patt value @{:^parent ctx})) (def match? (match-pattern patt value @{:^parent ctx}))
@ -271,11 +277,14 @@
(set result (interpret rhs ctx)) (set result (interpret rhs ctx))
(break))) (break)))
(when (= result :^nothing) (when (= result :^nothing)
(error {:node ast :msg "no match in when"})) (error {:node ast :msg "no match: when form"}))
result) result)
(defn- word [ast ctx] (defn- word [ast ctx]
(resolve-name (ast :data) ctx)) (def resolved (resolve-name (ast :data) ctx))
(if (= :^not-found resolved)
(error {:node ast :msg "unbound name"})
resolved))
(defn- tup [ast ctx] (defn- tup [ast ctx]
(def members (ast :data)) (def members (ast :data))
@ -389,18 +398,20 @@
# (pp args) # (pp args)
(def pos (find-index is_placeholder args)) (def pos (find-index is_placeholder args))
(def name (string (the-fn :name) " *partial*")) (def name (string (the-fn :name) " *partial*"))
(defn partial-fn [missing] (defn partial-fn [root-ast missing]
# (print "calling function with arg " (b/show missing)) # (print "calling function with arg " (b/show missing))
# (pp partial-args) # (pp partial-args)
(def full-args (array/slice args)) (def full-args (array/slice args))
(set (full-args pos) missing) (set (full-args pos) missing)
# (print "all args: " (b/show full-args)) # (print "all args: " (b/show full-args))
(call-fn the-fn [;full-args])) (call-fn root-ast the-fn [;full-args]))
{:^type :applied :name name :body partial-fn}) {:^type :applied :name name :body partial-fn})
(defn- call-fn* [the-fn args] (defn- call-fn* [root-ast the-fn args]
# (print "on line " (get-in root-ast [:token :line]))
# (print "calling " (b/show the-fn)) # (print "calling " (b/show the-fn))
# (print "with args " (b/show args)) # (print "with args " (b/show args))
# (pp args)
(when (or (when (or
(= :function (type the-fn)) (= :function (type the-fn))
(= :cfunction (type the-fn))) (= :cfunction (type the-fn)))
@ -408,12 +419,14 @@
(break (the-fn ;args))) (break (the-fn ;args)))
(def clauses (the-fn :body)) (def clauses (the-fn :body))
(when (= :nothing clauses) (when (= :nothing clauses)
(error {:node the-fn :value args :msg "cannot call function before it is defined"})) (error {:node root-ast :called the-fn :value args :msg "cannot call function before it is defined"}))
(when (= :function (type clauses))
(break (clauses root-ast ;args)))
(def len (length clauses)) (def len (length clauses))
(when (the-fn :match) (break ((the-fn :match) 0 args))) (when (the-fn :match) (break ((the-fn :match) 0 args)))
(defn match-fn [i args] (defn match-fn [i args]
(when (= len i) (when (= len i)
(error {:node the-fn :value args :msg "no match"})) (error {:node root-ast :called the-fn :value args :msg "no match: function call"}))
(def clause (clauses i)) (def clause (clauses i))
(def [patt guard expr] clause) (def [patt guard expr] clause)
(def match? (def match?
@ -433,19 +446,19 @@
(set call-fn call-fn*) (set call-fn call-fn*)
(defn- call-partial [the-fn arg] ((the-fn :body) ;arg)) (defn- call-partial [root-ast the-fn arg] ((the-fn :body) root-ast ;arg))
(defn- apply-synth-term [prev curr] (defn- apply-synth-term [root-ast prev curr]
# (print "applying " (b/show prev)) # (print "applying " (b/show prev))
# (print "to" (b/show curr)) # (print "to" (b/show curr))
(def types [(b/ludus/type prev) (b/ludus/type curr)]) (def types [(b/ludus/type prev) (b/ludus/type curr)])
# (print "typle:") # (print "typle:")
# (pp types) # (pp types)
(match types (match types
[:fn :tuple] (call-fn prev curr) [:fn :tuple] (call-fn root-ast prev curr)
[:fn :partial] (partial prev curr) [:fn :partial] (partial prev curr)
[:function :tuple] (call-fn prev curr) [:function :tuple] (call-fn root-ast prev curr)
[:applied :tuple] (call-partial prev curr) [:applied :tuple] (call-partial root-ast prev curr)
[:keyword :args] (get (first curr) prev :^nil) [:keyword :args] (get (first curr) prev :^nil)
[:dict :keyword] (get prev curr :^nil) [:dict :keyword] (get prev curr :^nil)
[:nil :keyword] :^nil [:nil :keyword] :^nil
@ -465,9 +478,9 @@
(for i 1 (-> terms length dec) (for i 1 (-> terms length dec)
(def curr (interpret (terms i) ctx)) (def curr (interpret (terms i) ctx))
# (print "term " i ": " curr) # (print "term " i ": " curr)
(set prev (apply-synth-term prev curr))) (set prev (apply-synth-term first-term prev curr)))
# (print "done with inner terms, applying last term") # (print "done with inner terms, applying last term")
(apply-synth-term prev (interpret last-term ctx))) (apply-synth-term first-term prev (interpret last-term ctx)))
(defn- doo [ast ctx] (defn- doo [ast ctx]
(def terms (ast :data)) (def terms (ast :data))
@ -475,9 +488,9 @@
(def last-term (last terms)) (def last-term (last terms))
(for i 1 (-> terms length dec) (for i 1 (-> terms length dec)
(def curr (interpret (terms i) ctx)) (def curr (interpret (terms i) ctx))
(set prev (call-fn curr [prev]))) (set prev (call-fn (first terms) curr [prev])))
(def last-fn (interpret last-term ctx)) (def last-fn (interpret last-term ctx))
(call-fn last-fn [prev])) (call-fn (first terms) last-fn [prev]))
(defn- pkg [ast ctx] (defn- pkg [ast ctx]
(def members (ast :data)) (def members (ast :data))
@ -504,7 +517,7 @@
# (print "calling inner loop fn") # (print "calling inner loop fn")
# (print "for the " i "th time") # (print "for the " i "th time")
(when (= len i) (when (= len i)
(error {:node ast :value args :msg "no match"})) (error {:node ast :value args :msg "no match: loop"}))
(def clause (clauses i)) (def clause (clauses i))
(def [patt guard expr] clause) (def [patt guard expr] clause)
(def match? (def match?

View File

@ -19,13 +19,28 @@ This new scene will have to return a JSON POJSO:
{:console "..." :result "..." :draw [...] :errors [...]} {:console "..." :result "..." :draw [...] :errors [...]}
) )
(def prelude-ctx @{:^parent {"base" b/base}})
# (comment
# (do
(def prelude-ctx @{:^parent {"base" b/base}})
(def prelude-src (slurp "prelude.ld")) (def prelude-src (slurp "prelude.ld"))
(def prelude-scanned (s/scan prelude-src)) (def prelude-scanned (s/scan prelude-src))
(def prelude-parsed (p/parse prelude-scanned)) (def prelude-parsed (p/parse prelude-scanned))
(def parse-errors (prelude-parsed :errors)) (def parse-errors (prelude-parsed :errors))
(when (any? parse-errors) (each err parse-errors (e/parse-error err))) (when (any? parse-errors) (each err parse-errors (e/parse-error err)))
(def prelude-validated (v/valid prelude-parsed @{"base" b/base})) (def prelude-validated (v/valid prelude-parsed prelude-ctx))
(each err (prelude-validated :errors) (e/validation-error err)) (def validation-errors (prelude-validated :errors))
(when (any? validation-errors) (each err validation-errors (e/validation-error err)))
(def prelude-pkg (try
(i/interpret (prelude-parsed :ast) prelude-ctx)
([e] e)))
(keys prelude-pkg)
(prelude-pkg :msg)
(e/runtime-error prelude-pkg)
# )
(defn run [source] (defn run [source]
(def errors @[]) (def errors @[])
@ -35,17 +50,22 @@ This new scene will have to return a JSON POJSO:
(def out @{:errors errors :draw draw :result result :console console}) (def out @{:errors errors :draw draw :result result :console console})
(def scanned (s/scan source)) (def scanned (s/scan source))
(when (any? (scanned :errors)) (when (any? (scanned :errors))
(break (-> :errors scanned (e/scan-error out)))) (break (do
(each err (scanned :errors)
(e/scan-error err)))))
(def parsed (p/parse scanned)) (def parsed (p/parse scanned))
(when (any? (parsed :errors)) (when (any? (parsed :errors))
(break (-> :errors parsed (e/parse-error out)))) (break (each err (parsed :errors)
(def validated (v/valid parsed)) (e/parse-error err))))
(def validated (v/valid parsed prelude-ctx))
(when (any? (validated :errors)) (when (any? (validated :errors))
(break (-> :errors validated (e/validation-error out)))) (break (each err (validated :errors)
(e/validation-error err))))
(setdyn :out console) (setdyn :out console)
(try (try
(set result (b/show (i/interpret (parsed :ast) @{:^parent b/base}))) (set result (b/show (i/interpret (parsed :ast) prelude-ctx)))
([err] (e/runtime-error err out))) ([err] (setdyn :out stdout) (e/runtime-error err)))
(setdyn :out stdout)
(set (out :result) result) (set (out :result) result)
(j/encode out)) (j/encode out))
@ -56,9 +76,11 @@ This new scene will have to return a JSON POJSO:
(run source)) (run source))
(def source ` (def source `
let foo = fn () -> :bar let pi = base :pi
foo () pi
`) `)
b/base
(-> source run j/decode) (-> source run j/decode)

View File

@ -132,12 +132,11 @@ fn dec {
fn count { fn count {
"Returns the number of elements in a collection (including string)." "Returns the number of elements in a collection (including string)."
(xs as :list) -> dec (base :count (xs)) (xs as :list) -> base :count (xs)
(xs as :tuple) -> dec (base :count (xs)) (xs as :tuple) -> base :count (xs)
(xs as :dict) -> base :count (xs) (xs as :dict) -> base :count (xs)
(xs as :string) -> base :count (xs) (xs as :string) -> base :count (xs)
(xs as :set) -> base :count (xs) (xs as :set) -> base :count (xs)
(xs as :struct) -> dec (base :count (xs))
} }
fn empty? { fn empty? {
@ -728,7 +727,7 @@ fn coll? {
(coll as :list) -> true (coll as :list) -> true
(coll as :tuple) -> true (coll as :tuple) -> true
(coll as :set) -> true (coll as :set) -> true
(coll as :ns) -> true (coll as :pkg) -> true
(_) -> false (_) -> false
} }
@ -742,8 +741,7 @@ fn ordered? {
fn assoc? { fn assoc? {
"Returns true if a value is an associative collection: a dict, struct, or namespace." "Returns true if a value is an associative collection: a dict, struct, or namespace."
(assoc as :dict) -> true (assoc as :dict) -> true
(assoc as :struct) -> true (assoc as :pkg) -> true
(assoc as :ns) -> true
(_) -> false (_) -> false
} }
@ -763,8 +761,7 @@ fn has? {
} }
fn dict { fn dict {
"Takes an ns, and returns it as a dict. Or, takes a list or tuple of (key, value) tuples and returns it as a dict. Returns dicts unharmed." "Takes a list or tuple of (key, value) tuples and returns it as a dict. Returns dicts unharmed."
(ns_ as :ns) -> base :to_dict (ns_)
(dict as :dict) -> dict (dict as :dict) -> dict
(list as :list) -> fold (assoc, list) (list as :list) -> fold (assoc, list)
(tup as :tuple) -> do tup > list > dict (tup as :tuple) -> do tup > list > dict
@ -795,6 +792,9 @@ fn each! {
let pi = base :pi let pi = base :pi
print! (base :pi)
print! (pi)
let tau = mult (2, pi) let tau = mult (2, pi)
fn sin { fn sin {