(.using [library [lux {"-" symbol} [abstract ["[0]" monad {"+" do}]] [data ["[0]" text ("[1]#[0]" monoid)] [collection ["[0]" list ("[1]#[0]" monoid monad)]]] [macro ["[0]" code]] [math [number ["[0]" nat] ["[0]" int]]]]] ["[0]" // "_" ["[1]" meta ["[0]" location] ["[0]" symbol ("[1]#[0]" codec)]]]) (def: .public (single_expansion syntax) (-> Code (Meta (List Code))) (case syntax [_ {.#Form {.#Item [[_ {.#Symbol name}] args]}}] (do //.monad [?macro (//.macro name)] (case ?macro {.#Some macro} ((:as Macro' macro) args) {.#None} (# //.monad in (list syntax)))) _ (# //.monad in (list syntax)))) (def: .public (expansion syntax) (-> Code (Meta (List Code))) (case syntax [_ {.#Form {.#Item [[_ {.#Symbol name}] args]}}] (do //.monad [?macro (//.macro name)] (case ?macro {.#Some macro} (do [! //.monad] [top_level_expansion ((:as Macro' macro) args)] (|> top_level_expansion (monad.each //.monad expansion) (# ! each list#conjoint))) {.#None} (# //.monad in (list syntax)))) _ (# //.monad in (list syntax)))) (def: .public (full_expansion syntax) (-> Code (Meta (List Code))) (case syntax [_ {.#Form {.#Item [[_ {.#Symbol name}] args]}}] (do //.monad [?macro (//.macro name)] (case ?macro {.#Some macro} (do //.monad [expansion ((:as Macro' macro) args) expansion' (monad.each //.monad full_expansion expansion)] (in (list#conjoint expansion'))) {.#None} (do //.monad [parts' (monad.each //.monad full_expansion (list& (code.symbol name) args))] (in (list (code.form (list#conjoint parts'))))))) [_ {.#Form {.#Item [harg targs]}}] (do //.monad [harg+ (full_expansion harg) targs+ (monad.each //.monad full_expansion targs)] (in (list (code.form (list#composite harg+ (list#conjoint (: (List (List Code)) targs+))))))) [_ {.#Variant members}] (do //.monad [members' (monad.each //.monad full_expansion members)] (in (list (code.variant (list#conjoint members'))))) [_ {.#Tuple members}] (do //.monad [members' (monad.each //.monad full_expansion members)] (in (list (code.tuple (list#conjoint members'))))) _ (# //.monad in (list syntax)))) (def: .public (symbol prefix) (-> Text (Meta Code)) (do //.monad [id //.seed] (in (|> id (# nat.decimal encoded) ($_ text#composite "__gensym__" prefix) [""] code.symbol)))) (def: (local_symbol ast) (-> Code (Meta Text)) (case ast [_ {.#Symbol [_ name]}] (# //.monad in name) _ (//.failure (text#composite "Code is not a local symbol: " (code.format ast))))) (def: .public wrong_syntax_error (-> Symbol Text) (|>> symbol#encoded (text.prefix (text#composite "Wrong syntax for " text.\'')) (text.suffix (text#composite text.\'' ".")))) (macro: .public (with_symbols tokens) (case tokens (^ (list [_ {.#Tuple symbols}] body)) (do [! //.monad] [symbol_names (monad.each ! ..local_symbol symbols) .let [symbol_defs (list#conjoint (list#each (: (-> Text (List Code)) (function (_ name) (list (code.symbol ["" name]) (` (..symbol (~ (code.text name))))))) symbol_names))]] (in (list (` ((~! do) (~! //.monad) [(~+ symbol_defs)] (~ body)))))) _ (//.failure (..wrong_syntax_error (.symbol ..with_symbols))))) (def: .public (one_expansion token) (-> Code (Meta Code)) (do //.monad [token+ (..expansion token)] (case token+ (^ (list token')) (in token') _ (//.failure "Macro expanded to more than 1 element.")))) (template [ ] [(macro: .public ( tokens) (let [[module _] (.symbol .._) [_ short] (.symbol ) macro_name [module short]] (case (: (Maybe [Bit Code]) (case tokens (^ (list [_ {.#Text "omit"}] token)) {.#Some [#1 token]} (^ (list token)) {.#Some [#0 token]} _ {.#None})) {.#Some [omit? token]} (do //.monad [location //.location output ( token) .let [_ ("lux io log" ($_ text#composite (symbol#encoded macro_name) " " (location.format location))) _ (list#each (|>> code.format "lux io log") output) _ ("lux io log" "")]] (in (if omit? (list) output))) {.#None} (//.failure (..wrong_syntax_error macro_name)))))] [log_single_expansion! ..single_expansion] [log_expansion! ..expansion] [log_full_expansion! ..full_expansion] )