make progress; WIP: interpreting pattern matching
This commit is contained in:
parent
3a8a236f01
commit
399f1fd4c7
|
@ -0,0 +1,18 @@
|
||||||
|
# A base library for Ludus
|
||||||
|
# Only loaded in the prelude
|
||||||
|
|
||||||
|
(defn- stringify [value]
|
||||||
|
(def typed? (when (table? value) (:^type value))
|
||||||
|
(def type (if typed? typed? (type value))
|
||||||
|
(case type
|
||||||
|
:nil ""
|
||||||
|
:number (string value)
|
||||||
|
:
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(def show {
|
||||||
|
:name "show"
|
||||||
|
:fn ()
|
||||||
|
})
|
||||||
|
|
|
@ -1,6 +1,107 @@
|
||||||
# A tree walk interpreter for ludus
|
# A tree walk interpreter for ludus
|
||||||
|
|
||||||
(var interpret nil)
|
(var interpret nil)
|
||||||
|
(var stringify nil)
|
||||||
|
(var match-pattern nil)
|
||||||
|
|
||||||
|
(defn- resolve-name [name ctx]
|
||||||
|
(print "resolving " name " in:")
|
||||||
|
(pp ctx)
|
||||||
|
(when (not ctx) (break :^not-found))
|
||||||
|
(if (has-key? ctx name)
|
||||||
|
(ctx name)
|
||||||
|
(resolve-name name (ctx :^parent))))
|
||||||
|
|
||||||
|
(defn- match-word [word value ctx]
|
||||||
|
(def name (word :data))
|
||||||
|
{:success true :ctx (set (ctx name) value)})
|
||||||
|
|
||||||
|
(defn- match-pattern [pattern value &opt ctx]
|
||||||
|
(default ctx @{})
|
||||||
|
(def data (pattern :data))
|
||||||
|
(case (pattern :type)
|
||||||
|
# always match
|
||||||
|
:placeholder {:success true :ctx ctx}
|
||||||
|
:ignored {:success true :ctx ctx}
|
||||||
|
:word (match-word value ctx)
|
||||||
|
|
||||||
|
# match on equality
|
||||||
|
:nil {:success (nil? value) :ctx ctx}
|
||||||
|
:bool {:success (= data value) :ctx ctx}
|
||||||
|
:number {:success (= data value) :ctx ctx}
|
||||||
|
:string {:success (= data value) :ctx ctx}
|
||||||
|
:keyword {:success (= data value) :ctx ctx}
|
||||||
|
|
||||||
|
# TODO: tuples, lists, dicts
|
||||||
|
# TODO: string-patterns
|
||||||
|
# TODO: typed
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(defn- lett [ast ctx]
|
||||||
|
(def [patt expr] (ast :data))
|
||||||
|
(def value (interpret expr ctx))
|
||||||
|
(def match? (match-pattern expr value))
|
||||||
|
(if match?
|
||||||
|
(do
|
||||||
|
|
||||||
|
)
|
||||||
|
(error {:node ast :msg (string "could not match " (stringify value) " with " )})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(defn- script [ast ctx]
|
||||||
|
(def lines (ast :data))
|
||||||
|
(var result nil)
|
||||||
|
(each line lines
|
||||||
|
(set result (interpret line ctx)))
|
||||||
|
result)
|
||||||
|
|
||||||
|
(defn- block [ast parent]
|
||||||
|
(def lines (ast :data))
|
||||||
|
(var result nil)
|
||||||
|
(def ctx @{:^parent parent})
|
||||||
|
(each line lines
|
||||||
|
(set result (interpret line ctx)))
|
||||||
|
result)
|
||||||
|
|
||||||
|
|
||||||
|
(defn- dict-str [dict]
|
||||||
|
(string/join
|
||||||
|
(map
|
||||||
|
(fn [[k v]] (string (stringify k) " " (stringify v)))
|
||||||
|
dict)
|
||||||
|
", "))
|
||||||
|
|
||||||
|
(defn- stringify* [value]
|
||||||
|
(def typed? (when (table? value) (:^type value)))
|
||||||
|
(def type (if typed? typed? (type value)))
|
||||||
|
(case type
|
||||||
|
:nil ""
|
||||||
|
:number (string value)
|
||||||
|
:bool (string value)
|
||||||
|
:keyword (string ":" value)
|
||||||
|
:string value
|
||||||
|
:tuple
|
||||||
|
(string/join (map stringify value) ", ")
|
||||||
|
:array
|
||||||
|
(string/join (map stringify value) ", ")
|
||||||
|
:table (dict-str value)
|
||||||
|
:set
|
||||||
|
(string/join (map stringify (keys value)) ", ")
|
||||||
|
:ref (stringify (value :^value))
|
||||||
|
# XXX: pkg, fn,
|
||||||
|
))
|
||||||
|
|
||||||
|
(set stringify stringify*)
|
||||||
|
|
||||||
|
(defn- interpolated [ast ctx]
|
||||||
|
(def terms (ast :data))
|
||||||
|
(def interpolations
|
||||||
|
(map (fn [x]
|
||||||
|
(if (string? x) x (stringify (interpret x ctx))))
|
||||||
|
terms))
|
||||||
|
(string/join interpolations))
|
||||||
|
|
||||||
(defn- iff [ast ctx]
|
(defn- iff [ast ctx]
|
||||||
(def [condition then else] (ast :data))
|
(def [condition then else] (ast :data))
|
||||||
|
@ -8,25 +109,109 @@
|
||||||
(interpret then ctx)
|
(interpret then ctx)
|
||||||
(interpret else ctx)))
|
(interpret else ctx)))
|
||||||
|
|
||||||
(defn- script [ast ctx]
|
(defn- whenn [ast ctx]
|
||||||
(print "interpreting script")
|
(def clauses (ast :data))
|
||||||
(def lines (ast :data))
|
(var result :^nothing)
|
||||||
(var result nil)
|
(each clause clauses
|
||||||
(each line lines
|
(def [lhs rhs] clause)
|
||||||
(print "interpreting script line")
|
(when (interpret lhs ctx)
|
||||||
(set result (interpret line ctx)))
|
(set result (interpret rhs ctx))
|
||||||
|
(break)))
|
||||||
|
(when (= result :^nothing)
|
||||||
|
(error {:node ast :msg "no match in when"}))
|
||||||
result)
|
result)
|
||||||
|
|
||||||
|
(defn- word [ast ctx]
|
||||||
|
(def name (ast :data))
|
||||||
|
(resolve-name name ctx))
|
||||||
|
|
||||||
|
(defn- tup [ast ctx]
|
||||||
|
(def members (ast :data))
|
||||||
|
(def the-tup @[])
|
||||||
|
(each member members
|
||||||
|
(array/push the-tup (interpret member ctx)))
|
||||||
|
(tuple ;the-tup))
|
||||||
|
|
||||||
|
(defn- sett [ast ctx]
|
||||||
|
(def members (ast :data))
|
||||||
|
(def the-set @{:^type :set})
|
||||||
|
(each member members
|
||||||
|
(def value (interpret member ctx))
|
||||||
|
(set (the-set member) true))
|
||||||
|
the-set)
|
||||||
|
|
||||||
|
(defn- list [ast ctx]
|
||||||
|
(def members (ast :data))
|
||||||
|
(def the-list @[])
|
||||||
|
(each member members
|
||||||
|
(if (= :splat (member :type))
|
||||||
|
(do
|
||||||
|
(def splatted (interpret (member :data) ctx))
|
||||||
|
(when (not= :array (type splatted))
|
||||||
|
(error {:node member :msg "cannot splat non-list into list"}))
|
||||||
|
(array/concat the-list splatted))
|
||||||
|
(array/push the-list (interpret member ctx))))
|
||||||
|
the-list)
|
||||||
|
|
||||||
|
(defn- dict [ast ctx]
|
||||||
|
(def members (ast :data))
|
||||||
|
(def the-dict @{})
|
||||||
|
(each member members
|
||||||
|
(if (= :splat (member :type))
|
||||||
|
(do
|
||||||
|
(def splatted (interpret (member :data) ctx))
|
||||||
|
(when (or
|
||||||
|
(not= :table (type splatted))
|
||||||
|
(:^type splatted))
|
||||||
|
(error {:node member :msg "cannot splat non-dict into dict"}))
|
||||||
|
(merge-into the-dict splatted))
|
||||||
|
(do
|
||||||
|
(def [key-ast value-ast] (member :data))
|
||||||
|
(def key (interpret key-ast ctx))
|
||||||
|
(def value (interpret value-ast ctx))
|
||||||
|
(set (the-dict key) value))))
|
||||||
|
the-dict)
|
||||||
|
|
||||||
|
(defn- ref [ast ctx]
|
||||||
|
(def {:data value-ast :name name} ast)
|
||||||
|
(def value (interpret value-ast ctx))
|
||||||
|
(set (ctx name) @{:^type :ref :^value value :^name name})
|
||||||
|
value)
|
||||||
|
|
||||||
|
(defn- repeatt [ast ctx]
|
||||||
|
(def [times-ast body] (ast :data))
|
||||||
|
(def times (interpret times-ast ctx))
|
||||||
|
(when (not (number? times))
|
||||||
|
(error {:node times-ast :msg (string "repeat needs a `number` of times; you gave me a " (type times))}))
|
||||||
|
(repeat times (interpret body ctx)))
|
||||||
|
|
||||||
|
(defn- panic [ast ctx]
|
||||||
|
(def info (interpret (ast :data) ctx))
|
||||||
|
(error {:node ast :msg info}))
|
||||||
|
|
||||||
(defn- interpret* [ast ctx]
|
(defn- interpret* [ast ctx]
|
||||||
(print "interpreting ast node " (ast :type))
|
(print "interpreting node " (ast :type))
|
||||||
(case (ast :type)
|
(case (ast :type)
|
||||||
:nil nil
|
:nil nil
|
||||||
:number (ast :data)
|
:number (ast :data)
|
||||||
:bool (ast :data)
|
:bool (ast :data)
|
||||||
:string (ast :data)
|
:string (ast :data)
|
||||||
|
:interpolated (interpolated ast ctx)
|
||||||
:keyword (ast :data)
|
:keyword (ast :data)
|
||||||
:if (iff ast ctx)
|
:if (iff ast ctx)
|
||||||
:script (script ast ctx)))
|
:block (block ast ctx)
|
||||||
|
:word (word ast ctx)
|
||||||
|
:tuple (tup ast ctx)
|
||||||
|
:list (list ast ctx)
|
||||||
|
:set (sett ast ctx)
|
||||||
|
:dict (dict ast ctx)
|
||||||
|
:when (whenn ast ctx)
|
||||||
|
:ref (ref ast ctx)
|
||||||
|
:script (script ast ctx)
|
||||||
|
:panic (panic ast ctx)
|
||||||
|
|
||||||
|
:let (lett ast ctx)
|
||||||
|
))
|
||||||
|
|
||||||
(set interpret interpret*)
|
(set interpret interpret*)
|
||||||
|
|
||||||
|
@ -42,13 +227,14 @@
|
||||||
(def scanned (s/scan source))
|
(def scanned (s/scan source))
|
||||||
(def parsed (p/parse scanned))
|
(def parsed (p/parse scanned))
|
||||||
(def validated (v/valid parsed))
|
(def validated (v/valid parsed))
|
||||||
(pp parsed)
|
|
||||||
(interpret (parsed :ast) @{}))
|
(interpret (parsed :ast) @{}))
|
||||||
|
|
||||||
|
|
||||||
(do
|
(do
|
||||||
(set source `
|
(set source `
|
||||||
if false then :bar else :baz
|
when {
|
||||||
|
3 -> :foo
|
||||||
|
true -> :bar
|
||||||
|
}
|
||||||
`)
|
`)
|
||||||
(run)
|
(run)
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
Tracking here, before I start writing this code, the kinds of validation we're hoping to accomplish:
|
Tracking here, before I start writing this code, the kinds of validation we're hoping to accomplish:
|
||||||
|
|
||||||
|
* [ ] validate `with` forms
|
||||||
* [ ] first-level property access with pkg, e.g. `Foo :bar`--bar must be on Foo
|
* [ ] first-level property access with pkg, e.g. `Foo :bar`--bar must be on Foo
|
||||||
- [ ] accept pkg-kws
|
- [ ] accept pkg-kws
|
||||||
* [x] `loop` form arity checking
|
* [x] `loop` form arity checking
|
||||||
|
|
Loading…
Reference in New Issue
Block a user