(.module: [library [lux (#- let local) ["." meta] [abstract ["." monad (#+ do)]] [control ["." try (#+ Try)] ["." exception (#+ exception:)] ["<>" parser ("#\." functor) ["<.>" code (#+ Parser)]]] [data ["." bit ("#\." codec)] ["." text] [collection ["." list ("#\." monad)] ["." dictionary (#+ Dictionary)]]] [math [number ["." nat ("#\." decimal)] ["." int ("#\." decimal)] ["." rev ("#\." decimal)] ["." frac ("#\." decimal)]]]]] ["." // [syntax (#+ syntax:)] ["." code] ["." local]]) (syntax: .public (spliced [parts (.tuple (<>.some .any))]) (in parts)) (syntax: .public (amount [parts (.tuple (<>.some .any))]) (in (list (code.nat (list.size parts))))) (syntax: .public (with_locals [locals (.tuple (<>.some .local_identifier)) body .any]) (do {! meta.monad} [g!locals (|> locals (list\map //.identifier) (monad.all !))] (in (list (` (.with_expansions [(~+ (|> (list.zipped/2 locals g!locals) (list\map (function (_ [name identifier]) (list (code.local_identifier name) (as_is identifier)))) list\join))] (~ body))))))) (def: (name_side module_side? parser) (-> Bit (Parser Name) (Parser Text)) (do <>.monad [[module short] parser] (in (if module_side? (case module "" short _ module) short)))) (def: (snippet module_side?) (-> Bit (Parser Text)) (.let [full_identifier (..name_side module_side? .identifier) full_tag (..name_side module_side? .tag)] ($_ <>.either .text (if module_side? full_identifier (<>.either .local_identifier full_identifier)) (if module_side? full_tag (<>.either .local_tag full_tag)) (<>\map bit\encoded .bit) (<>\map nat\encoded .nat) (<>\map int\encoded .int) (<>\map rev\encoded .rev) (<>\map frac\encoded .frac) ))) (def: (part module_side?) (-> Bit (Parser (List Text))) (.tuple (<>.many (..snippet module_side?)))) (syntax: .public (text [simple (..part false)]) (in (list (|> simple (text.interposed "") code.text)))) (template [ ] [(syntax: .public ( [name (<>.or (<>.and (..part true) (..part false)) (..part false))]) (case name (#.Left [simple complex]) (in (list ( [(text.interposed "" simple) (text.interposed "" complex)]))) (#.Right simple) (in (list (|> simple (text.interposed "") )))))] [identifier code.local_identifier code.identifier] [tag code.local_tag code.tag] ) (type: Environment (Dictionary Text Code)) (def: (applied env template) (-> Environment Code Code) (case template [_ (#.Identifier "" name)] (case (dictionary.value name env) (#.Some substitute) substitute #.None template) (^template [] [[meta ( elems)] [meta ( (list\map (applied env) elems))]]) ([#.Tuple] [#.Form]) [meta (#.Record members)] [meta (#.Record (list\map (: (-> [Code Code] [Code Code]) (function (_ [key value]) [(applied env key) (applied env value)])) members))] _ template)) (type: Local {#name Text #parameters (List Text) #template (List Code)}) (exception: .public (irregular_arguments {expected Nat} {actual Nat}) (exception.report ["Expected" (\ nat.decimal encoded expected)] ["Actual" (\ nat.decimal encoded actual)])) (def: (macro (^slots [#parameters #template])) (-> Local Macro) ("lux macro" (function (_ inputs compiler) (.let [parameters_amount (list.size parameters) inputs_amount (list.size inputs)] (if (nat.= parameters_amount inputs_amount) (.let [environment (: Environment (|> (list.zipped/2 parameters inputs) (dictionary.of_list text.hash)))] (#.Right [compiler (list\map (..applied environment) template)])) (exception.except ..irregular_arguments [parameters_amount inputs_amount])))))) (def: local (Parser Local) (do <>.monad [[name parameters] (.form (<>.and .local_identifier (<>.many .local_identifier))) template (.tuple (<>.some .any))] (in {#name name #parameters parameters #template template}))) (syntax: .public (let [locals (.tuple (<>.some ..local)) body .any]) (do meta.monad [here_name meta.current_module_name expression? (: (Meta Bit) (function (_ lux) (#try.Success [lux (case (value@ #.expected lux) #.None false (#.Some _) true)]))) g!pop (local.push (list\map (function (_ local) [[here_name (value@ #name local)] (..macro local)]) locals))] (if expression? (//.with_identifiers [g!body] (in (list (` (.let [(~ g!body) (~ body)] (exec (~ g!pop) (~ g!body))))))) (in (list body g!pop)))))