(;module: lux (lux (control monad) (data [text "T/" Eq] text/format [maybe #+ Monad "Maybe/" Monad] [product] ["R" result] (coll [list "L/" Fold Monoid])) [macro]) (luxc ["&" base])) (type: Locals (Bindings Text [Type Nat])) (type: Captured (Bindings Text [Type Ref])) (do-template [ ] [(def: ( name scope) (-> Text Scope Bool) (|> scope (get@ [ #;mappings]) (&;pl-contains? name))) (def: ( name scope) (-> Text Scope (Maybe [Type Ref])) (|> scope (get@ [ #;mappings]) (&;pl-get name) (Maybe/map (function [[type value]] [type ( value)]))))] [#;locals is-local? get-local #;Local] [#;captured is-captured? get-captured id] ) (def: (is-ref? name scope) (-> Text Scope Bool) (or (is-local? name scope) (is-captured? name scope))) (def: (get-ref name scope) (-> Text Scope (Maybe [Type Ref])) (case (get-local name scope) (#;Some type) (#;Some type) _ (get-captured name scope))) (def: #export (find name) (-> Text (Lux (Maybe [Type Ref]))) (function [compiler] (let [[inner outer] (|> compiler (get@ #;scopes) (list;split-with (|>. (is-ref? name) not)))] (case outer #;Nil (#;Right [compiler #;None]) (#;Cons top-outer _) (let [[ref-type init-ref] (default (undefined) (get-ref name top-outer)) [ref inner'] (L/fold (: (-> Scope [Ref (List Scope)] [Ref (List Scope)]) (function [scope [ref inner]] [(#;Captured (get@ [#;captured #;counter] scope)) (#;Cons (update@ #;captured (: (-> Captured Captured) (|>. (update@ #;counter n.inc) (update@ #;mappings (&;pl-put name [ref-type ref])))) scope) inner)])) [init-ref #;Nil] (list;reverse inner)) scopes (L/append inner' outer)] (#;Right [(set@ #;scopes scopes compiler) (#;Some [ref-type ref])])) )))) (def: #export (with-local [name type] action) (All [a] (-> [Text Type] (Lux a) (Lux a))) (function [compiler] (case (get@ #;scopes compiler) (#;Cons head tail) (let [old-mappings (get@ [#;locals #;mappings] head) new-var-id (get@ [#;locals #;counter] head) new-head (update@ #;locals (: (-> Locals Locals) (|>. (update@ #;counter n.inc) (update@ #;mappings (&;pl-put name [type new-var-id])))) head)] (case (macro;run' (set@ #;scopes (#;Cons new-head tail) compiler) action) (#R;Success [compiler' output]) (case (get@ #;scopes compiler') (#;Cons head' tail') (let [scopes' (#;Cons (set@ #;locals (get@ #;locals head) head') tail')] (#R;Success [(set@ #;scopes scopes' compiler') output])) _ (error! "Invalid scope alteration.")) (#R;Error error) (#R;Error error))) _ (#R;Error "Cannot create local binding without a scope.")) )) (do-template [ ] [(def: (Bindings Text [Type ]) {#;counter +0 #;mappings (list)})] [init-locals Nat] [init-captured Ref] ) (def: (scope parent-name child-name) (-> (List Text) Text Scope) {#;name (list& child-name parent-name) #;inner +0 #;locals init-locals #;captured init-captured}) (def: #export (with-scope name action) (All [a] (-> Text (Lux a) (Lux a))) (function [compiler] (let [parent-name (case (get@ #;scopes compiler) #;Nil (list) (#;Cons top _) (get@ #;name top))] (case (action (update@ #;scopes (|>. (#;Cons (scope parent-name name))) compiler)) (#R;Error error) (#R;Error error) (#R;Success [compiler' output]) (#R;Success [(update@ #;scopes (|>. list;tail (default (list))) compiler') output]) )) )) (def: #export next-local (Lux Nat) (function [compiler] (case (get@ #;scopes compiler) #;Nil (#R;Error "Cannot get next reference when there is no scope.") (#;Cons top _) (#R;Success [compiler (get@ [#;locals #;counter] top)]))))