2024-05-15 00:44:54 +00:00
|
|
|
# A tree walk interpreter for ludus
|
|
|
|
|
2024-06-06 22:47:04 +00:00
|
|
|
(import /src/base :as b)
|
2024-05-19 22:24:11 +00:00
|
|
|
|
2024-05-15 00:44:54 +00:00
|
|
|
(var interpret nil)
|
2024-05-15 04:05:25 +00:00
|
|
|
(var match-pattern nil)
|
2024-05-15 00:44:54 +00:00
|
|
|
|
2024-05-19 05:58:10 +00:00
|
|
|
(defn- todo [msg] (error (string "not yet implemented: " msg)))
|
|
|
|
|
2024-05-15 04:05:25 +00:00
|
|
|
(defn- resolve-name [name ctx]
|
2024-06-05 15:55:06 +00:00
|
|
|
# # (print "resolving " name " in:")
|
|
|
|
# # (pp ctx)
|
2024-05-15 04:05:25 +00:00
|
|
|
(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))
|
2024-06-05 15:55:06 +00:00
|
|
|
# # (print "matched " (b/show value) " to " name)
|
2024-05-15 16:33:52 +00:00
|
|
|
(set (ctx name) value)
|
|
|
|
{:success true :ctx ctx})
|
2024-05-15 04:05:25 +00:00
|
|
|
|
2024-05-15 16:33:52 +00:00
|
|
|
(defn- typed [pattern value ctx]
|
|
|
|
(def [type-ast word] (pattern :data))
|
|
|
|
(def type (type-ast :data))
|
2024-05-19 22:24:11 +00:00
|
|
|
(if (= type (b/ludus/type value))
|
2024-05-15 16:33:52 +00:00
|
|
|
(match-word word value ctx)
|
|
|
|
{:success false :miss [pattern value]}))
|
|
|
|
|
|
|
|
(defn- match-tuple [pattern value ctx]
|
|
|
|
(when (not (tuple? value))
|
|
|
|
(break {:success false :miss [pattern value]}))
|
|
|
|
(def val-len (length value))
|
|
|
|
(var members (pattern :data))
|
2024-05-19 05:58:10 +00:00
|
|
|
(when (empty? members)
|
|
|
|
(break (if (empty? value)
|
|
|
|
{:success true :ctx ctx}
|
|
|
|
{:success false :miss [pattern value]})))
|
2024-06-05 21:47:41 +00:00
|
|
|
(def patt-len (length members))
|
2024-05-15 16:33:52 +00:00
|
|
|
(var splat nil)
|
|
|
|
(def splat? (= :splat ((last members) :type)))
|
|
|
|
(when splat?
|
|
|
|
(when (< val-len patt-len)
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "mismatched splatted tuple lengths")
|
2024-05-15 16:33:52 +00:00
|
|
|
(break {:success false :miss [pattern value]}))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "splat!")
|
2024-05-15 16:33:52 +00:00
|
|
|
(set splat (last members))
|
|
|
|
(set members (slice members 0 (dec patt-len))))
|
|
|
|
(when (and (not splat?) (not= val-len patt-len))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "mismatched tuple lengths")
|
2024-05-15 16:33:52 +00:00
|
|
|
(break {:success false :miss [pattern value]}))
|
|
|
|
(var curr-mem :^nothing)
|
|
|
|
(var curr-val :^nothing)
|
|
|
|
(var success true)
|
|
|
|
(for i 0 (length members)
|
|
|
|
(set curr-mem (get members i))
|
|
|
|
(set curr-val (get value i))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "in tuple, matching " curr-val " with ")
|
|
|
|
# (pp curr-mem)
|
2024-05-15 16:33:52 +00:00
|
|
|
(def match? (match-pattern curr-mem curr-val ctx))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (pp match?)
|
2024-05-15 16:33:52 +00:00
|
|
|
(when (not (match? :success))
|
|
|
|
(set success false)
|
|
|
|
(break)))
|
|
|
|
(when (and splat? (splat :data))
|
|
|
|
(def rest (array/slice value (length members)))
|
|
|
|
(match-word (splat :data) rest ctx))
|
|
|
|
(if success
|
|
|
|
{:success true :ctx ctx}
|
|
|
|
{:success false :miss [pattern value]}))
|
|
|
|
|
2024-05-18 21:04:23 +00:00
|
|
|
(defn- match-list [pattern value ctx]
|
|
|
|
(when (not (array? value))
|
|
|
|
(break {:success false :miss [pattern value]}))
|
|
|
|
(def val-len (length value))
|
|
|
|
(var members (pattern :data))
|
2024-06-05 21:47:41 +00:00
|
|
|
(when (empty? members)
|
|
|
|
(break (if (empty? value)
|
|
|
|
{:success true :ctx ctx}
|
|
|
|
{:success false :miss [pattern value]})))
|
2024-05-18 21:04:23 +00:00
|
|
|
(def patt-len (length members))
|
|
|
|
(var splat nil)
|
|
|
|
(def splat? (= :splat ((last members) :type)))
|
|
|
|
(when splat?
|
|
|
|
(when (< val-len patt-len)
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "mismatched splatted list lengths")
|
2024-05-18 21:04:23 +00:00
|
|
|
(break {:success false :miss [pattern value]}))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "splat!")
|
2024-05-18 21:04:23 +00:00
|
|
|
(set splat (last members))
|
|
|
|
(set members (slice members 0 (dec patt-len))))
|
|
|
|
(when (and (not splat?) (not= val-len patt-len))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "mismatched list lengths")
|
2024-05-18 21:04:23 +00:00
|
|
|
(break {:success false :miss [pattern value]}))
|
|
|
|
(var curr-mem :^nothing)
|
|
|
|
(var curr-val :^nothing)
|
|
|
|
(var success true)
|
|
|
|
(for i 0 (length members)
|
|
|
|
(set curr-mem (get members i))
|
|
|
|
(set curr-val (get value i))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "in list, matching " curr-val " with ")
|
|
|
|
# (pp curr-mem)
|
2024-05-18 21:04:23 +00:00
|
|
|
(def match? (match-pattern curr-mem curr-val ctx))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (pp match?)
|
2024-05-18 21:04:23 +00:00
|
|
|
(when (not (match? :success))
|
|
|
|
(set success false)
|
|
|
|
(break)))
|
|
|
|
(when (and splat? (splat :data))
|
|
|
|
(def rest (array/slice value (length members)))
|
|
|
|
(match-word (splat :data) rest ctx))
|
|
|
|
(if success
|
|
|
|
{:success true :ctx ctx}
|
|
|
|
{:success false :miss [pattern value]}))
|
|
|
|
|
2024-05-18 21:43:21 +00:00
|
|
|
(defn- match-string [pattern value ctx]
|
|
|
|
(when (not (string? value))
|
|
|
|
(break {:success false :miss [pattern value]}))
|
|
|
|
(def {:compiled compiled :bindings bindings} pattern)
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "matching " value " with")
|
|
|
|
# (pp (pattern :grammar))
|
2024-05-18 21:43:21 +00:00
|
|
|
(def matches (peg/match compiled value))
|
|
|
|
(when (not matches)
|
|
|
|
(break {:success false :miss [pattern value]}))
|
|
|
|
(when (not= (length matches) (length bindings))
|
|
|
|
(error "oops: different number of matches and bindings"))
|
|
|
|
(for i 0 (length matches)
|
|
|
|
(set (ctx (bindings i)) (matches i)))
|
|
|
|
{:success true :ctx ctx})
|
|
|
|
|
2024-05-20 00:19:00 +00:00
|
|
|
(defn- match-dict [pattern value ctx]
|
|
|
|
(when (not (table? value))
|
|
|
|
(break {:success false :miss [pattern value]}))
|
|
|
|
(def val-size (length value))
|
|
|
|
(var members (pattern :data))
|
|
|
|
(def patt-len (length members))
|
|
|
|
(when (empty? members)
|
|
|
|
(break (if (empty? value)
|
|
|
|
{:success true :ctx ctx}
|
|
|
|
{:success false :miss [pattern value]})))
|
|
|
|
(var splat nil)
|
|
|
|
(def splat? (= :splat ((last members) :type)))
|
|
|
|
(when splat?
|
|
|
|
(when (< val-size patt-len)
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "mismatched splatted dict lengths")
|
2024-05-20 00:19:00 +00:00
|
|
|
(break {:success false :miss [pattern value]}))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "splat!")
|
2024-05-20 00:19:00 +00:00
|
|
|
(set splat (last members))
|
|
|
|
(set members (slice members 0 (dec patt-len))))
|
|
|
|
(when (and (not splat?) (not= val-size patt-len))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "mismatched dict lengths")
|
2024-05-20 00:19:00 +00:00
|
|
|
(break {:success false :miss [pattern value]}))
|
|
|
|
(var success true)
|
|
|
|
(def matched-keys @[])
|
|
|
|
(for i 0 (length members)
|
|
|
|
(def curr-pair (get members i))
|
|
|
|
(def [curr-key curr-patt] (curr-pair :data))
|
|
|
|
(def key (interpret curr-key ctx))
|
|
|
|
(def curr-val (value key))
|
|
|
|
(def match? (match-pattern curr-patt curr-val ctx))
|
|
|
|
(array/push matched-keys key)
|
|
|
|
(when (not (match? :success))
|
|
|
|
(set success false)
|
|
|
|
(break)))
|
|
|
|
(when (and splat? (splat :data) success)
|
|
|
|
(def rest (merge value))
|
|
|
|
(each key matched-keys
|
|
|
|
(set (rest key) nil))
|
|
|
|
(match-word (splat :data) rest ctx))
|
|
|
|
(if success
|
|
|
|
{:success true :ctx ctx}
|
|
|
|
{:success false :miss [pattern value]}))
|
|
|
|
|
2024-05-19 05:58:10 +00:00
|
|
|
|
2024-05-15 16:33:52 +00:00
|
|
|
(defn- match-pattern* [pattern value &opt ctx]
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "in match-pattern, matching " value " with:")
|
|
|
|
# (pp pattern)
|
2024-05-15 04:05:25 +00:00
|
|
|
(default ctx @{})
|
|
|
|
(def data (pattern :data))
|
|
|
|
(case (pattern :type)
|
|
|
|
# always match
|
|
|
|
:placeholder {:success true :ctx ctx}
|
|
|
|
:ignored {:success true :ctx ctx}
|
2024-05-15 16:33:52 +00:00
|
|
|
:word (match-word pattern value ctx)
|
2024-05-15 04:05:25 +00:00
|
|
|
|
|
|
|
# match on equality
|
2024-06-21 15:37:23 +00:00
|
|
|
:nil {:success (= :^nil value) :ctx ctx}
|
2024-05-15 04:05:25 +00:00
|
|
|
:bool {:success (= data value) :ctx ctx}
|
|
|
|
:number {:success (= data value) :ctx ctx}
|
|
|
|
:string {:success (= data value) :ctx ctx}
|
|
|
|
:keyword {:success (= data value) :ctx ctx}
|
|
|
|
|
2024-05-15 16:33:52 +00:00
|
|
|
# TODO: lists, dicts
|
|
|
|
:tuple (match-tuple pattern value ctx)
|
2024-05-18 21:04:23 +00:00
|
|
|
:list (match-list pattern value ctx)
|
2024-05-19 05:58:10 +00:00
|
|
|
:dict (match-dict pattern value ctx)
|
|
|
|
|
2024-05-18 21:43:21 +00:00
|
|
|
:interpolated (match-string pattern value ctx)
|
2024-05-18 21:04:23 +00:00
|
|
|
|
2024-05-15 16:33:52 +00:00
|
|
|
:typed (typed pattern value ctx)
|
|
|
|
))
|
|
|
|
|
|
|
|
(set match-pattern match-pattern*)
|
2024-05-15 04:05:25 +00:00
|
|
|
|
|
|
|
(defn- lett [ast ctx]
|
2024-06-05 21:47:41 +00:00
|
|
|
# (print "lett!")
|
|
|
|
# (pp ast)
|
2024-05-15 04:05:25 +00:00
|
|
|
(def [patt expr] (ast :data))
|
|
|
|
(def value (interpret expr ctx))
|
2024-05-15 16:33:52 +00:00
|
|
|
(def match? (match-pattern patt value))
|
|
|
|
(if (match? :success)
|
2024-05-15 04:05:25 +00:00
|
|
|
(do
|
2024-05-15 16:33:52 +00:00
|
|
|
(merge-into ctx (match? :ctx))
|
|
|
|
value)
|
2024-06-05 21:47:41 +00:00
|
|
|
(error {:node ast :value value :msg "no match: let binding"})))
|
2024-05-15 00:44:54 +00:00
|
|
|
|
2024-05-18 21:04:23 +00:00
|
|
|
(defn- matchh [ast ctx]
|
|
|
|
(def [to-match clauses] (ast :data))
|
|
|
|
(def value (interpret to-match ctx))
|
2024-05-19 05:58:10 +00:00
|
|
|
(def len (length clauses))
|
|
|
|
(when (ast :match) (break ((ast :match) 0 value ctx)))
|
|
|
|
(defn match-fn [i value ctx]
|
|
|
|
(when (= len i)
|
2024-06-05 21:47:41 +00:00
|
|
|
(error {:node ast :value value :msg "no match: match form"}))
|
2024-05-19 05:58:10 +00:00
|
|
|
(def clause (clauses i))
|
2024-05-18 21:04:23 +00:00
|
|
|
(def [patt guard expr] clause)
|
2024-05-19 05:58:10 +00:00
|
|
|
(def match? (match-pattern patt value @{:^parent ctx}))
|
|
|
|
(when (not (match? :success))
|
|
|
|
(break (match-fn (inc i) value ctx)))
|
|
|
|
(def body-ctx (match? :ctx))
|
|
|
|
(def guard? (if guard
|
2024-05-19 22:24:11 +00:00
|
|
|
(b/bool (interpret guard body-ctx)) true))
|
2024-05-19 05:58:10 +00:00
|
|
|
(when (not guard?)
|
|
|
|
(break (match-fn (inc i) value ctx)))
|
|
|
|
(interpret expr body-ctx))
|
|
|
|
(set (ast :match) match-fn)
|
|
|
|
(match-fn 0 value ctx))
|
2024-05-18 21:04:23 +00:00
|
|
|
|
2024-05-15 00:44:54 +00:00
|
|
|
(defn- script [ast ctx]
|
|
|
|
(def lines (ast :data))
|
2024-05-19 05:58:10 +00:00
|
|
|
(def last-line (last lines))
|
|
|
|
(for i 0 (-> lines length dec)
|
|
|
|
(interpret (lines i) ctx))
|
|
|
|
(interpret last-line ctx))
|
2024-05-15 00:44:54 +00:00
|
|
|
|
2024-05-15 04:05:25 +00:00
|
|
|
(defn- block [ast parent]
|
|
|
|
(def lines (ast :data))
|
2024-05-19 05:58:10 +00:00
|
|
|
(def last-line (last lines))
|
2024-05-15 04:05:25 +00:00
|
|
|
(def ctx @{:^parent parent})
|
2024-05-19 05:58:10 +00:00
|
|
|
(for i 0 (-> lines length dec)
|
|
|
|
(interpret (lines i) ctx))
|
|
|
|
(interpret last-line ctx))
|
2024-05-15 04:05:25 +00:00
|
|
|
|
2024-05-19 05:58:10 +00:00
|
|
|
(defn- to_string [ctx] (fn [x]
|
2024-06-07 19:04:06 +00:00
|
|
|
(if (buffer? x)
|
|
|
|
(string x)
|
|
|
|
(b/stringify (interpret x ctx)))))
|
2024-05-19 05:58:10 +00:00
|
|
|
|
2024-05-15 04:05:25 +00:00
|
|
|
(defn- interpolated [ast ctx]
|
|
|
|
(def terms (ast :data))
|
2024-05-19 05:58:10 +00:00
|
|
|
(def interpolations (map (to_string ctx) terms))
|
2024-05-15 04:05:25 +00:00
|
|
|
(string/join interpolations))
|
|
|
|
|
|
|
|
(defn- iff [ast ctx]
|
|
|
|
(def [condition then else] (ast :data))
|
2024-05-19 22:24:11 +00:00
|
|
|
(if (b/bool (interpret condition ctx))
|
2024-05-15 04:05:25 +00:00
|
|
|
(interpret then ctx)
|
|
|
|
(interpret else ctx)))
|
|
|
|
|
2024-05-19 05:58:10 +00:00
|
|
|
# TODO: use a tail call here
|
2024-05-15 04:05:25 +00:00
|
|
|
(defn- whenn [ast ctx]
|
|
|
|
(def clauses (ast :data))
|
|
|
|
(var result :^nothing)
|
|
|
|
(each clause clauses
|
|
|
|
(def [lhs rhs] clause)
|
2024-05-19 22:24:11 +00:00
|
|
|
(when (b/bool (interpret lhs ctx))
|
2024-05-15 04:05:25 +00:00
|
|
|
(set result (interpret rhs ctx))
|
|
|
|
(break)))
|
|
|
|
(when (= result :^nothing)
|
2024-06-05 21:47:41 +00:00
|
|
|
(error {:node ast :msg "no match: when form"}))
|
2024-05-15 04:05:25 +00:00
|
|
|
result)
|
|
|
|
|
|
|
|
(defn- word [ast ctx]
|
2024-06-05 21:47:41 +00:00
|
|
|
(def resolved (resolve-name (ast :data) ctx))
|
|
|
|
(if (= :^not-found resolved)
|
|
|
|
(error {:node ast :msg "unbound name"})
|
|
|
|
resolved))
|
2024-05-15 04:05:25 +00:00
|
|
|
|
|
|
|
(defn- tup [ast ctx]
|
|
|
|
(def members (ast :data))
|
|
|
|
(def the-tup @[])
|
|
|
|
(each member members
|
|
|
|
(array/push the-tup (interpret member ctx)))
|
2024-05-19 05:58:10 +00:00
|
|
|
[;the-tup])
|
|
|
|
|
|
|
|
(defn- args [ast ctx]
|
|
|
|
(def members (ast :data))
|
|
|
|
(def the-args @[])
|
|
|
|
(each member members
|
|
|
|
(array/push the-args (interpret member ctx)))
|
|
|
|
(if (ast :partial)
|
|
|
|
{:^type :partial :args the-args}
|
|
|
|
[;the-args]))
|
2024-05-15 04:05:25 +00:00
|
|
|
|
|
|
|
(defn- sett [ast ctx]
|
|
|
|
(def members (ast :data))
|
|
|
|
(def the-set @{:^type :set})
|
|
|
|
(each member members
|
|
|
|
(def value (interpret member ctx))
|
2024-06-06 19:41:33 +00:00
|
|
|
(set (the-set value) true))
|
2024-05-15 04:05:25 +00:00
|
|
|
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))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "dict key")
|
|
|
|
# (pp key-ast)
|
|
|
|
# (print "dict value")
|
|
|
|
# (pp value-ast)
|
2024-05-15 04:05:25 +00:00
|
|
|
(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))
|
2024-06-05 19:52:03 +00:00
|
|
|
(def box @{:^type :box :^value value :name name})
|
2024-06-04 20:57:32 +00:00
|
|
|
(set (ctx name) box)
|
|
|
|
box)
|
2024-05-15 04:05:25 +00:00
|
|
|
|
|
|
|
(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}))
|
|
|
|
|
2024-05-19 05:58:10 +00:00
|
|
|
# TODO: add docstrings & pattern docs to fns
|
|
|
|
# Depends on: good string representation of patterns
|
|
|
|
# For now, this should be enough to tall the thing
|
|
|
|
(defn- fnn [ast ctx]
|
2024-06-04 17:04:53 +00:00
|
|
|
(def {:name name :data clauses :doc doc} ast)
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "defining fn " name)
|
2024-06-06 00:16:29 +00:00
|
|
|
(def closure (merge ctx))
|
2024-06-04 20:06:31 +00:00
|
|
|
(def the-fn @{:name name :^type :fn :body clauses :ctx closure :doc doc})
|
|
|
|
(when (not= :^not-found (resolve-name name ctx))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "fn "name" was forward declared")
|
2024-06-04 20:06:31 +00:00
|
|
|
(def fwd (resolve-name name ctx))
|
|
|
|
(set (fwd :body) clauses)
|
|
|
|
(set (fwd :ctx) closure)
|
|
|
|
(set (fwd :doc) doc)
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "fn " name " has been defined")
|
|
|
|
# (pp fwd)
|
2024-06-04 20:06:31 +00:00
|
|
|
(break fwd))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (pp the-fn)
|
2024-06-06 00:16:29 +00:00
|
|
|
(set (closure name) the-fn)
|
2024-06-04 20:06:31 +00:00
|
|
|
(set (ctx name) the-fn)
|
|
|
|
the-fn)
|
2024-05-19 05:58:10 +00:00
|
|
|
|
2024-05-19 23:35:41 +00:00
|
|
|
(defn- is_placeholder [x] (= x :_))
|
|
|
|
|
|
|
|
(var call-fn nil)
|
|
|
|
|
2024-06-06 00:16:29 +00:00
|
|
|
(defn- partial [root-ast the-fn partial-args]
|
|
|
|
(when (the-fn :applied)
|
|
|
|
(error {:msg "cannot partially apply a partially applied function"
|
|
|
|
:node root-ast :called the-fn :args partial-args}))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "calling partially applied function")
|
2024-05-19 23:35:41 +00:00
|
|
|
(def args (partial-args :args))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (pp args)
|
2024-05-19 23:35:41 +00:00
|
|
|
(def pos (find-index is_placeholder args))
|
2024-06-04 19:52:24 +00:00
|
|
|
(def name (string (the-fn :name) " *partial*"))
|
2024-06-05 21:47:41 +00:00
|
|
|
(defn partial-fn [root-ast missing]
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "calling function with arg " (b/show missing))
|
|
|
|
# (pp partial-args)
|
2024-05-19 23:35:41 +00:00
|
|
|
(def full-args (array/slice args))
|
|
|
|
(set (full-args pos) missing)
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "all args: " (b/show full-args))
|
2024-06-05 21:47:41 +00:00
|
|
|
(call-fn root-ast the-fn [;full-args]))
|
2024-06-06 00:16:29 +00:00
|
|
|
{:^type :fn :applied true :name name :body partial-fn})
|
2024-05-19 23:35:41 +00:00
|
|
|
|
2024-06-05 21:47:41 +00:00
|
|
|
(defn- call-fn* [root-ast the-fn args]
|
|
|
|
# (print "on line " (get-in root-ast [:token :line]))
|
|
|
|
# (print "calling " (b/show the-fn))
|
|
|
|
# (print "with args " (b/show args))
|
|
|
|
# (pp args)
|
2024-05-19 22:38:44 +00:00
|
|
|
(when (or
|
|
|
|
(= :function (type the-fn))
|
|
|
|
(= :cfunction (type the-fn)))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "Janet function")
|
2024-05-19 22:38:44 +00:00
|
|
|
(break (the-fn ;args)))
|
2024-05-19 05:58:10 +00:00
|
|
|
(def clauses (the-fn :body))
|
2024-06-04 15:54:29 +00:00
|
|
|
(when (= :nothing clauses)
|
2024-06-05 21:47:41 +00:00
|
|
|
(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)))
|
2024-05-19 05:58:10 +00:00
|
|
|
(def len (length clauses))
|
2024-06-14 20:52:07 +00:00
|
|
|
(when (the-fn :match) (break ((the-fn :match) root-ast 0 args)))
|
|
|
|
(defn match-fn [root-ast i args]
|
2024-05-19 05:58:10 +00:00
|
|
|
(when (= len i)
|
2024-06-05 21:47:41 +00:00
|
|
|
(error {:node root-ast :called the-fn :value args :msg "no match: function call"}))
|
2024-05-19 05:58:10 +00:00
|
|
|
(def clause (clauses i))
|
|
|
|
(def [patt guard expr] clause)
|
|
|
|
(def match?
|
|
|
|
(match-pattern patt args @{:^parent (the-fn :ctx)}))
|
|
|
|
(when (not (match? :success))
|
2024-06-14 20:52:07 +00:00
|
|
|
(break (match-fn root-ast (inc i) args)))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "matched!")
|
2024-05-19 05:58:10 +00:00
|
|
|
(def body-ctx (match? :ctx))
|
|
|
|
(def guard? (if guard
|
2024-05-19 22:24:11 +00:00
|
|
|
(b/bool (interpret guard body-ctx)) true))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "passed guard")
|
2024-05-19 05:58:10 +00:00
|
|
|
(when (not guard?)
|
2024-06-14 20:52:07 +00:00
|
|
|
(break (match-fn root-ast (inc i) args)))
|
2024-05-19 05:58:10 +00:00
|
|
|
(interpret expr body-ctx))
|
|
|
|
(set (the-fn :match) match-fn)
|
2024-06-14 20:52:07 +00:00
|
|
|
(match-fn root-ast 0 args))
|
2024-05-19 05:58:10 +00:00
|
|
|
|
2024-05-19 23:35:41 +00:00
|
|
|
(set call-fn call-fn*)
|
|
|
|
|
2024-06-05 21:47:41 +00:00
|
|
|
(defn- call-partial [root-ast the-fn arg] ((the-fn :body) root-ast ;arg))
|
2024-06-04 19:52:24 +00:00
|
|
|
|
2024-06-05 21:47:41 +00:00
|
|
|
(defn- apply-synth-term [root-ast prev curr]
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "applying " (b/show prev))
|
|
|
|
# (print "to" (b/show curr))
|
2024-05-19 22:24:11 +00:00
|
|
|
(def types [(b/ludus/type prev) (b/ludus/type curr)])
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "typle:")
|
|
|
|
# (pp types)
|
2024-05-19 05:58:10 +00:00
|
|
|
(match types
|
2024-06-05 21:47:41 +00:00
|
|
|
[:fn :tuple] (call-fn root-ast prev curr)
|
2024-06-06 00:16:29 +00:00
|
|
|
[:fn :partial] (partial root-ast prev curr)
|
2024-06-05 21:47:41 +00:00
|
|
|
[:function :tuple] (call-fn root-ast prev curr)
|
2024-06-06 00:16:29 +00:00
|
|
|
# [:applied :tuple] (call-partial root-ast prev curr)
|
2024-05-19 05:58:10 +00:00
|
|
|
[:keyword :args] (get (first curr) prev :^nil)
|
|
|
|
[:dict :keyword] (get prev curr :^nil)
|
|
|
|
[:nil :keyword] :^nil
|
|
|
|
[:pkg :keyword] (get prev curr :^nil)
|
2024-06-20 21:49:27 +00:00
|
|
|
[:pkg :pkg-kw] (get prev curr :^nil)
|
|
|
|
(error (string "cannot call " (b/ludus/type prev) " `" (b/show prev) "`"))))
|
2024-05-19 05:58:10 +00:00
|
|
|
|
|
|
|
(defn- synthetic [ast ctx]
|
|
|
|
(def terms (ast :data))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "interpreting synthetic")
|
|
|
|
# (pp ast)
|
|
|
|
# (pp terms)
|
2024-05-19 05:58:10 +00:00
|
|
|
(def first-term (first terms))
|
|
|
|
(def last-term (last terms))
|
|
|
|
(var prev (interpret first-term ctx))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "root term: ")
|
|
|
|
# (pp prev)
|
2024-05-19 05:58:10 +00:00
|
|
|
(for i 1 (-> terms length dec)
|
|
|
|
(def curr (interpret (terms i) ctx))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "term " i ": " curr)
|
2024-06-05 21:47:41 +00:00
|
|
|
(set prev (apply-synth-term first-term prev curr)))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "done with inner terms, applying last term")
|
2024-06-05 21:47:41 +00:00
|
|
|
(apply-synth-term first-term prev (interpret last-term ctx)))
|
2024-05-19 05:58:10 +00:00
|
|
|
|
2024-05-19 22:38:44 +00:00
|
|
|
(defn- doo [ast ctx]
|
|
|
|
(def terms (ast :data))
|
|
|
|
(var prev (interpret (first terms) ctx))
|
|
|
|
(def last-term (last terms))
|
|
|
|
(for i 1 (-> terms length dec)
|
|
|
|
(def curr (interpret (terms i) ctx))
|
2024-06-05 21:47:41 +00:00
|
|
|
(set prev (call-fn (first terms) curr [prev])))
|
2024-05-19 22:38:44 +00:00
|
|
|
(def last-fn (interpret last-term ctx))
|
2024-06-05 21:47:41 +00:00
|
|
|
(call-fn (first terms) last-fn [prev]))
|
2024-05-19 05:58:10 +00:00
|
|
|
|
2024-06-04 18:50:48 +00:00
|
|
|
(defn- pkg [ast ctx]
|
|
|
|
(def members (ast :data))
|
|
|
|
(def the-pkg @{:^name (ast :name) :^type :pkg})
|
|
|
|
(each member members
|
|
|
|
(def [key-ast value-ast] (member :data))
|
|
|
|
(def key (interpret key-ast ctx))
|
|
|
|
(def value (interpret value-ast ctx))
|
|
|
|
(set (the-pkg key) value))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (pp the-pkg)
|
2024-06-04 18:50:48 +00:00
|
|
|
(def out (table/to-struct the-pkg))
|
|
|
|
(set (ctx (ast :name)) out)
|
|
|
|
out)
|
2024-05-19 20:18:52 +00:00
|
|
|
|
2024-06-04 18:25:22 +00:00
|
|
|
(defn- loopp [ast ctx]
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "looping!")
|
2024-06-04 18:25:22 +00:00
|
|
|
(def data (ast :data))
|
|
|
|
(def args (interpret (data 0) ctx))
|
2024-06-06 19:41:33 +00:00
|
|
|
# this doesn't work: context persists between different interpretations
|
|
|
|
# we want functions to work this way, but not loops (I think)
|
|
|
|
# (when (ast :match) (break ((ast :match) 0 args)))
|
2024-06-04 18:25:22 +00:00
|
|
|
(def clauses (data 1))
|
|
|
|
(def len (length clauses))
|
2024-06-06 19:41:33 +00:00
|
|
|
(var loop-ctx @{:^parent ctx})
|
2024-06-04 18:25:22 +00:00
|
|
|
(defn match-fn [i args]
|
|
|
|
(when (= len i)
|
2024-06-05 21:47:41 +00:00
|
|
|
(error {:node ast :value args :msg "no match: loop"}))
|
2024-06-04 18:25:22 +00:00
|
|
|
(def clause (clauses i))
|
|
|
|
(def [patt guard expr] clause)
|
|
|
|
(def match?
|
|
|
|
(match-pattern patt args loop-ctx))
|
|
|
|
(when (not (match? :success))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "no match")
|
2024-06-04 18:25:22 +00:00
|
|
|
(break (match-fn (inc i) args)))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "matched!")
|
2024-06-04 18:25:22 +00:00
|
|
|
(def body-ctx (match? :ctx))
|
|
|
|
(def guard? (if guard
|
|
|
|
(b/bool (interpret guard body-ctx)) true))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "passed guard")
|
2024-06-04 18:25:22 +00:00
|
|
|
(when (not guard?)
|
|
|
|
(break (match-fn (inc i) args)))
|
|
|
|
(interpret expr body-ctx))
|
|
|
|
(set (ast :match) match-fn)
|
|
|
|
(set (loop-ctx :^recur) match-fn)
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "ATTACHED MATCH-FN")
|
2024-06-04 18:25:22 +00:00
|
|
|
(match-fn 0 args))
|
2024-05-19 20:18:52 +00:00
|
|
|
|
2024-06-04 18:25:22 +00:00
|
|
|
(defn- recur [ast ctx]
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "recurring!")
|
2024-06-04 18:25:22 +00:00
|
|
|
(def passed (ast :data))
|
|
|
|
(def args (interpret passed ctx))
|
|
|
|
(def match-fn (resolve-name :^recur ctx))
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "match fn in ctx:")
|
|
|
|
# (pp (ctx :^recur))
|
|
|
|
# (pp match-fn)
|
|
|
|
# (pp ctx)
|
2024-06-04 18:25:22 +00:00
|
|
|
(match-fn 0 args))
|
2024-05-19 20:18:52 +00:00
|
|
|
|
2024-05-31 17:29:51 +00:00
|
|
|
# TODO for 0.1.0
|
2024-05-19 23:35:41 +00:00
|
|
|
(defn- testt [ast ctx] (todo "test"))
|
2024-05-19 20:18:52 +00:00
|
|
|
|
2024-05-31 17:29:51 +00:00
|
|
|
(defn- ns [ast ctx] (todo "nses"))
|
|
|
|
|
|
|
|
(defn- importt [ast ctx] (todo "imports"))
|
|
|
|
|
|
|
|
(defn- withh [ast ctx] (todo "with"))
|
|
|
|
|
|
|
|
(defn- usee [ast ctx] (todo "use"))
|
|
|
|
|
2024-05-15 00:44:54 +00:00
|
|
|
(defn- interpret* [ast ctx]
|
2024-06-05 15:55:06 +00:00
|
|
|
# (print "interpreting node " (ast :type))
|
2024-05-15 00:44:54 +00:00
|
|
|
(case (ast :type)
|
2024-05-15 16:33:52 +00:00
|
|
|
# literals
|
2024-05-18 21:04:23 +00:00
|
|
|
:nil :^nil
|
2024-05-15 00:44:54 +00:00
|
|
|
:number (ast :data)
|
|
|
|
:bool (ast :data)
|
|
|
|
:string (ast :data)
|
|
|
|
:keyword (ast :data)
|
2024-05-19 05:58:10 +00:00
|
|
|
:placeholder :_
|
2024-05-15 16:33:52 +00:00
|
|
|
|
|
|
|
# collections
|
2024-05-15 04:05:25 +00:00
|
|
|
:tuple (tup ast ctx)
|
2024-05-19 05:58:10 +00:00
|
|
|
:args (args ast ctx)
|
2024-05-15 04:05:25 +00:00
|
|
|
:list (list ast ctx)
|
|
|
|
:set (sett ast ctx)
|
|
|
|
:dict (dict ast ctx)
|
2024-05-15 16:33:52 +00:00
|
|
|
|
|
|
|
# composite forms
|
|
|
|
:if (iff ast ctx)
|
|
|
|
:block (block ast ctx)
|
2024-05-15 04:05:25 +00:00
|
|
|
:when (whenn ast ctx)
|
|
|
|
:script (script ast ctx)
|
|
|
|
:panic (panic ast ctx)
|
|
|
|
|
2024-05-19 20:18:52 +00:00
|
|
|
# looping forms
|
|
|
|
:loop (loopp ast ctx)
|
|
|
|
:recur (recur ast ctx)
|
|
|
|
:repeat (repeatt ast ctx)
|
|
|
|
|
2024-05-15 16:33:52 +00:00
|
|
|
# named/naming forms
|
|
|
|
:word (word ast ctx)
|
|
|
|
:interpolated (interpolated ast ctx)
|
|
|
|
:ref (ref ast ctx)
|
2024-05-31 17:29:51 +00:00
|
|
|
:pkg (pkg ast ctx)
|
2024-06-04 18:50:48 +00:00
|
|
|
:pkg-name (word ast ctx)
|
2024-05-15 16:33:52 +00:00
|
|
|
|
|
|
|
# patterned forms
|
2024-05-15 04:05:25 +00:00
|
|
|
:let (lett ast ctx)
|
2024-05-18 21:04:23 +00:00
|
|
|
:match (matchh ast ctx)
|
|
|
|
|
|
|
|
# functions
|
2024-05-19 05:58:10 +00:00
|
|
|
:fn (fnn ast ctx)
|
2024-05-18 21:04:23 +00:00
|
|
|
|
|
|
|
# synthetic
|
2024-05-19 05:58:10 +00:00
|
|
|
:synthetic (synthetic ast ctx)
|
|
|
|
|
|
|
|
# do
|
|
|
|
:do (doo ast ctx)
|
2024-05-15 16:33:52 +00:00
|
|
|
|
2024-05-19 20:18:52 +00:00
|
|
|
# deferred until after computer class
|
|
|
|
# :with (withh ast ctx)
|
|
|
|
# :import (importt ast ctx)
|
2024-05-31 17:29:51 +00:00
|
|
|
# :ns (ns ast ctx)
|
|
|
|
# :use (usee ast ctx)
|
|
|
|
# :test (testt ast ctx)
|
2024-05-19 20:18:52 +00:00
|
|
|
|
2024-05-15 04:05:25 +00:00
|
|
|
))
|
2024-05-15 00:44:54 +00:00
|
|
|
|
|
|
|
(set interpret interpret*)
|
|
|
|
|
2024-06-06 22:47:04 +00:00
|
|
|
# # repl
|
2024-06-07 19:04:06 +00:00
|
|
|
# (import /src/scanner :as s)
|
|
|
|
# (import /src/parser :as p)
|
|
|
|
# (import /src/validate :as v)
|
2024-06-06 22:47:04 +00:00
|
|
|
|
|
|
|
# (var source nil)
|
|
|
|
|
|
|
|
# (defn- has-errors? [{:errors errors}] (and errors (not (empty? errors))))
|
|
|
|
|
|
|
|
# (defn run []
|
|
|
|
# (def scanned (s/scan source))
|
|
|
|
# (when (has-errors? scanned) (break (scanned :errors)))
|
|
|
|
# (def parsed (p/parse scanned))
|
|
|
|
# (when (has-errors? parsed) (break (parsed :errors)))
|
|
|
|
# (def validated (v/valid parsed b/ctx))
|
|
|
|
# # (when (has-errors? validated) (break (validated :errors)))
|
|
|
|
# # (def cleaned (get-in parsed [:ast :data 1]))
|
|
|
|
# # # (pp cleaned)
|
2024-06-21 19:28:46 +00:00
|
|
|
# (interpret (parsed :ast) @{:^parent b/lett})
|
2024-06-07 19:04:06 +00:00
|
|
|
# # (try (interpret (parsed :ast) @{:^parent b/ctx})
|
|
|
|
# # ([e] (if (struct? e) (error (e :msg)) (error e))))
|
|
|
|
# )
|
2024-06-06 22:47:04 +00:00
|
|
|
|
|
|
|
# # (do
|
|
|
|
# (comment
|
|
|
|
# (set source `
|
2024-06-07 19:04:06 +00:00
|
|
|
# let foo = 42
|
|
|
|
# "{foo} bar baz"
|
2024-06-06 22:47:04 +00:00
|
|
|
# `)
|
|
|
|
# (def result (run))
|
|
|
|
# )
|
2024-05-19 05:58:10 +00:00
|
|
|
|