From cf3ffce3165dcbf741a5f2d6daa1146ad50fd95c Mon Sep 17 00:00:00 2001 From: Eduardo Julian Date: Fri, 8 Jul 2022 13:02:38 -0400 Subject: Extensible macro vocabulary for "lux/macro/pattern.`". --- .../meta/compiler/language/lux/phase/analysis.lux | 14 +- stdlib/source/library/lux/meta/macro/class.lux | 55 ----- stdlib/source/library/lux/meta/macro/pattern.lux | 240 ++++++++++++--------- .../source/library/lux/meta/macro/vocabulary.lux | 53 +++++ stdlib/source/test/lux/meta/macro.lux | 2 +- 5 files changed, 200 insertions(+), 164 deletions(-) delete mode 100644 stdlib/source/library/lux/meta/macro/class.lux create mode 100644 stdlib/source/library/lux/meta/macro/vocabulary.lux diff --git a/stdlib/source/library/lux/meta/compiler/language/lux/phase/analysis.lux b/stdlib/source/library/lux/meta/compiler/language/lux/phase/analysis.lux index 72885ce92..e9ef84319 100644 --- a/stdlib/source/library/lux/meta/compiler/language/lux/phase/analysis.lux +++ b/stdlib/source/library/lux/meta/compiler/language/lux/phase/analysis.lux @@ -111,25 +111,25 @@ [.#Int /simple.int] [.#Rev /simple.rev]) - (^.` [(,* elems)]) + (^.` [(^.,* elems)]) (/complex.record analysis archive elems) - (^.` {(, [_ {.#Symbol tag}]) (,* values)}) + (^.` {(^., [_ {.#Symbol tag}]) (^.,* values)}) (..variant_analysis analysis archive tag values) - (^.` ({(,* branches)} (, input))) + (^.` ({(^.,* branches)} (^., input))) (..case_analysis analysis archive input branches code) - (^.` ([(, [_ {.#Symbol ["" function_name]}]) (, [_ {.#Symbol ["" arg_name]}])] (, body))) + (^.` ([(^., [_ {.#Symbol ["" function_name]}]) (^., [_ {.#Symbol ["" arg_name]}])] (^., body))) (/function.function analysis function_name arg_name archive body) - (^.` ((, [_ {.#Text extension_name}]) (,* extension_args))) + (^.` ((^., [_ {.#Text extension_name}]) (^.,* extension_args))) (//extension.apply archive analysis [extension_name extension_args]) - (^.` ((, functionC) (,* argsC+))) + (^.` ((^., functionC) (^.,* argsC+))) (..apply_analysis expander analysis archive functionC argsC+) - (^.` {(, [_ {.#Nat lefts}]) (, [_ {.#Bit right?}]) (,* values)}) + (^.` {(^., [_ {.#Nat lefts}]) (^., [_ {.#Bit right?}]) (^.,* values)}) (..sum_analysis analysis archive lefts right? values) _ diff --git a/stdlib/source/library/lux/meta/macro/class.lux b/stdlib/source/library/lux/meta/macro/class.lux deleted file mode 100644 index 1c529d7cc..000000000 --- a/stdlib/source/library/lux/meta/macro/class.lux +++ /dev/null @@ -1,55 +0,0 @@ -... [Not everything is an expression](https://codewords.recurse.com/issues/two/not-everything-is-an-expression) - -(.require - [library - [lux (.except local) - [abstract - [monad (.only do)]] - [control - ["?" parser (.use "[1]#[0]" functor)] - ["[0]" exception (.only exception)]]]] - ["[0]" // (.only) - [syntax (.only syntax) - ["[0]" export]] - ["/[1]" // (.only) - ["[0]" code (.only) - ["?[1]" \\parser (.only Parser)]] - ["[0]" type (.only) - [primitive (.except)]]]]) - -(exception .public (invalid_type [expected Type - actual Type]) - (exception.report - (list ["Expected" (type.format expected)] - ["Actual" (type.format actual)]))) - -(def local - (Parser Code) - (?#each code.local ?code.local)) - -(def .public custom - (syntax (_ [[public|private ] - (export.parser (all ?.and - ..local - ..local - ..local - ..local))]) - (//.with_symbols [g!_ g!type g!value] - (in (list (` (primitive (, public|private) (, ) - Macro)) - - (` (def (, public|private) (, ) - (-> Macro (, )) - (|>> abstraction))) - - (` (def (, public|private) (, ) - (-> (, ) Macro) - (|>> representation))) - - (` (def (, public|private) ((, ) (, g!_)) - (-> Symbol (Meta (, ))) - ((,! do) (,! ///.monad) - [[(, g!_) (, g!type) (, g!value)] ((,! ///.export) (, g!_))] - (if (at (,! type.equivalence) (,' =) (, ) (, g!type)) - ((,' in) (as (, ) (, g!value))) - ((,! ///.failure) ((,! exception.except) ..invalid_type [(, ) (, g!type)]))))))))))) diff --git a/stdlib/source/library/lux/meta/macro/pattern.lux b/stdlib/source/library/lux/meta/macro/pattern.lux index 7e3b30d9d..4c78c8c36 100644 --- a/stdlib/source/library/lux/meta/macro/pattern.lux +++ b/stdlib/source/library/lux/meta/macro/pattern.lux @@ -1,17 +1,28 @@ (.require [library - [lux (.except or let with_template |> `)]]) - -(def list#partial - (`` ("lux in-module" (,, (static .prelude)) .list#partial))) + [lux (.except or let with_template |> + ` , ,* + UnQuote unquote unquote_macro + Spliced_UnQuote spliced_unquote spliced_unquote_macro) + [abstract + ["[0]" monad (.only do)]] + [control + ["[0]" maybe] + ["[0]" try]] + [data + [collection + ["[0]" list (.use "[1]#[0]" monoid monad)]]]]] + ["[0]" // (.only) + [vocabulary (.only vocabulary)] + ["/[1]" // (.use "[1]#[0]" monad)]]) (def locally (macro (_ tokens lux) (.let [[prelude _] (symbol ._)] (case tokens (list [@ {.#Symbol ["" name]}]) - {.#Right [lux (list (.` ("lux in-module" (, [@ {.#Text prelude}]) - (, [@ {.#Symbol [prelude name]}]))))]} + {.#Right [lux (list (.` ("lux in-module" (., [@ {.#Text prelude}]) + (., [@ {.#Symbol [prelude name]}]))))]} _ {.#Left ""})))) @@ -19,22 +30,8 @@ (.with_template [] [(def (..locally ))] - [list#size] - [list#composite] - [list#each] - [list#conjoint] - [every?] - - [maybe#monad] - [function#composite] - [failure] - [meta#in] - - [do] - [monad#each] - [Replacement_Environment] [realized_template] [replacement_environment] @@ -42,7 +39,6 @@ [symbol_short] [tuple_list] - [meta#monad] [text$] [generated_symbol] [type_definition] @@ -52,7 +48,6 @@ [module_alias] [symbol$] [tuple$] - [monad#mix] [zipped_2] [multi_level_case^] @@ -63,47 +58,48 @@ [wrong_syntax_error] [local$] - [list#reversed] [untemplated_list] [bit$] [nat$] [int$] [rev$] [frac$] + + [one_expansion] ) (def .public or (pattern (macro (_ tokens) (case tokens - (list#partial [_ {.#Form patterns}] body branches) + (list.partial [_ {.#Form patterns}] body branches) (case patterns {.#End} - (failure (..wrong_syntax_error (symbol ..or))) + (///.failure (..wrong_syntax_error (symbol ..or))) _ (.let [pairs (.|> patterns (list#each (function (_ pattern) (list pattern body))) list#conjoint)] - (meta#in (list#composite pairs branches)))) + (///#in (list#composite pairs branches)))) _ - (failure (..wrong_syntax_error (symbol ..or))))))) + (///.failure (..wrong_syntax_error (symbol ..or))))))) (def .public with_template (pattern (macro (_ tokens) (case tokens - (list#partial [_ {.#Form (list [_ {.#Tuple bindings}] + (list.partial [_ {.#Form (list [_ {.#Tuple bindings}] [_ {.#Tuple templates}])}] [_ {.#Form data}] branches) (case (is (Maybe (List Code)) - (do maybe#monad - [bindings' (monad#each maybe#monad symbol_short bindings) - data' (monad#each maybe#monad tuple_list data)] - (.let [num_bindings (list#size bindings')] - (if (every? (|>> ("lux i64 =" num_bindings)) - (list#each list#size data')) + (do maybe.monad + [bindings' (monad.each maybe.monad symbol_short bindings) + data' (monad.each maybe.monad tuple_list data)] + (.let [num_bindings (list.size bindings')] + (if (list.every? (|>> ("lux i64 =" num_bindings)) + (list#each list.size data')) (.let [apply (is (-> Replacement_Environment (List Code)) (function (_ env) (list#each (realized_template env) templates)))] (.|> data' @@ -112,20 +108,20 @@ in)) {.#None})))) {.#Some output} - (meta#in (list#composite output branches)) + (///#in (list#composite output branches)) {.#None} - (failure (..wrong_syntax_error (symbol ..with_template)))) + (///.failure (..wrong_syntax_error (symbol ..with_template)))) _ - (failure (..wrong_syntax_error (symbol ..with_template))))))) + (///.failure (..wrong_syntax_error (symbol ..with_template))))))) (def .public multi (pattern (macro (_ tokens) (case tokens - (list#partial [_meta {.#Form levels}] body next_branches) - (do meta#monad + (list.partial [_meta {.#Form levels}] body next_branches) + (do ///.monad [mlc (multi_level_case^ levels) .let [initial_bind? (case mlc [[_ {.#Symbol _}] _] @@ -136,53 +132,53 @@ expected ..expected_type g!temp (..generated_symbol "temp")] (in (list g!temp - (.` ({{.#Some (, g!temp)} - (, g!temp) + (.` ({{.#Some (., g!temp)} + (., g!temp) {.#None} - (.case (, g!temp) - (,* next_branches))} - ("lux type check" {.#Apply (, (type_code expected)) Maybe} - (.case (, g!temp) - (,* (multi_level_case$ g!temp [mlc body])) - - (,* (if initial_bind? - (list) - (list g!temp (.` {.#None}))))))))))) + (.case (., g!temp) + (.,* next_branches))} + ("lux type check" {.#Apply (., (type_code expected)) Maybe} + (.case (., g!temp) + (.,* (multi_level_case$ g!temp [mlc body])) + + (.,* (if initial_bind? + (list) + (list g!temp (.` {.#None}))))))))))) _ - (failure (..wrong_syntax_error (symbol ..multi))))))) + (///.failure (..wrong_syntax_error (symbol ..multi))))))) (def .public let (pattern (macro (_ tokens) (case tokens - (list#partial [_meta {.#Form (list [_ {.#Symbol ["" name]}] pattern)}] body branches) + (list.partial [_meta {.#Form (list [_ {.#Symbol ["" name]}] pattern)}] body branches) (.let [g!whole (local$ name)] - (meta#in (list#partial g!whole - (.` (case (, g!whole) (, pattern) (, body))) - branches))) + (///#in (list.partial g!whole + (.` (case (., g!whole) (., pattern) (., body))) + branches))) _ - (failure (..wrong_syntax_error (symbol ..let))))))) + (///.failure (..wrong_syntax_error (symbol ..let))))))) (def .public |> (pattern (macro (_ tokens) (case tokens - (list#partial [_meta {.#Form (list [_ {.#Symbol ["" name]}] [_ {.#Tuple steps}])}] body branches) + (list.partial [_meta {.#Form (list [_ {.#Symbol ["" name]}] [_ {.#Tuple steps}])}] body branches) (.let [g!name (local$ name)] - (meta#in (list#partial g!name - (.` (.let [(, g!name) (.|> (, g!name) (,* steps))] - (, body))) - branches))) + (///#in (list.partial g!name + (.` (.let [(., g!name) (.|> (., g!name) (.,* steps))] + (., body))) + branches))) _ - (failure (..wrong_syntax_error (symbol ..|>))))))) + (///.failure (..wrong_syntax_error (symbol ..|>))))))) (def (name$ [module name]) (-> Symbol Code) - (.` [(, (text$ module)) (, (text$ name))])) + (.` [(., (text$ module)) (., (text$ name))])) (def (untemplated_partial_list last inits) (-> Code (List Code) Code) @@ -191,37 +187,62 @@ last {.#Item [init inits']} - (.` {.#Item (, init) (, (untemplated_partial_list last inits'))}))) - -(.with_template [ ] - [(def ( g!meta untemplated_pattern elems) - (-> Code (-> Code (Meta Code)) - (-> (List Code) (Meta Code))) - (case (list#reversed elems) - {.#Item [_ {.#Form {.#Item [[_ {.#Symbol ["" ",*"]}] {.#Item [spliced {.#End}]}]}}] - inits} - (do meta#monad - [=inits (monad#each meta#monad untemplated_pattern (list#reversed inits))] - (in (.` [(, g!meta) { (, (untemplated_partial_list spliced =inits))}]))) + (.` {.#Item (., init) (., (untemplated_partial_list last inits'))}))) + +(vocabulary + [.public Spliced_UnQuote] + [.public spliced_unquote] + [.public spliced_unquote_macro] + [.private named_spliced_unquote]) + +(def (untemplated_composite g!meta untemplated_pattern elems) + (-> Code Code (-> Code (Meta Code)) + (-> (List Code) (Meta Code))) + (with_expansions [ (do ///.monad + [=elems (monad.each ///.monad untemplated_pattern elems)] + (in (.` [(., g!meta) {(., ) (., (untemplated_list =elems))}])))] + (case (list.reversed elems) + {.#Item [_ {.#Form {.#Item [_ {.#Symbol global}] parameters}}] + inits} + (do ///.monad + [micro (///.try (..named_spliced_unquote global))] + (case micro + {try.#Success micro} + (do ///.monad + [output (..one_expansion ((//.function micro) parameters)) + =inits (monad.each ///.monad untemplated_pattern (list.reversed inits))] + (in (.` [(., g!meta) {(., ) (., (untemplated_partial_list output =inits))}]))) + + {try.#Failure error} + )) + + _ + ))) + +(def .public ,* + (..spliced_unquote + (macro (_ tokens) + ({{.#Item it {.#End}} + (at ///.monad in (list it)) _ - (do meta#monad - [=elems (monad#each meta#monad untemplated_pattern elems)] - (in (.` [(, g!meta) { (, (untemplated_list =elems))}])))))] + (///.failure (..wrong_syntax_error (symbol ..,*)))} + tokens)))) - [.#Form untemplated_form] - [.#Variant untemplated_variant] - [.#Tuple untemplated_tuple] - ) +(vocabulary + [.public UnQuote] + [.public unquote] + [.public unquote_macro] + [.private named_unquote]) (def (untemplated_pattern pattern) (-> Code (Meta Code)) - (do meta#monad + (do ///.monad [g!meta (..generated_symbol "g!meta")] (case pattern (..with_template [ ] [[_ { value}] - (in (.` [(, g!meta) { (, ( value))}]))]) + (in (.` [(., g!meta) { (., ( value))}]))]) ([.#Bit bit$] [.#Nat nat$] [.#Int int$] @@ -230,33 +251,50 @@ [.#Text text$] [.#Symbol name$]) - [_ {.#Form {.#Item [[_ {.#Symbol ["" ","]}] {.#Item [unquoted {.#End}]}]}}] - (in unquoted) - - [_ {.#Form {.#Item [[_ {.#Symbol ["" ",*"]}] {.#Item [spliced {.#End}]}]}}] - (failure "Cannot use (,*) inside of `code` unless it is the last element in a form or a tuple.") - - (..with_template [ ] - [[_ { elems}] - ( g!meta untemplated_pattern elems)]) - ([.#Form ..untemplated_form] - [.#Variant ..untemplated_variant] - [.#Tuple ..untemplated_tuple]) + [@composite {.#Form {.#Item [@global {.#Symbol global}] parameters}}] + (do ///.monad + [micro (///.try (..named_unquote global))] + (case micro + {try.#Success micro} + (do ///.monad + [[_ output] (..one_expansion ((//.function micro) parameters))] + (in [@composite output])) + + {try.#Failure error} + (untemplated_composite (.` .#Form) g!meta untemplated_pattern (list.partial [@global {.#Symbol global}] parameters)))) + + (..with_template [] + [[_ { it}] + (untemplated_composite (.` ) g!meta untemplated_pattern it)]) + ([.#Form] + [.#Variant] + [.#Tuple]) ))) (def .public ` (pattern (macro (_ tokens) (case tokens - (list#partial [_meta {.#Form (list template)}] body branches) - (do meta#monad + (list.partial [_meta {.#Form (list template)}] body branches) + (do ///.monad [pattern (untemplated_pattern template)] - (in (list#partial pattern body branches))) + (in (list.partial pattern body branches))) (list template) - (do meta#monad + (do ///.monad [pattern (untemplated_pattern template)] (in (list pattern))) _ - (failure (..wrong_syntax_error (symbol ..`))))))) + (///.failure (..wrong_syntax_error (symbol ..`))))))) + +(def .public , + UnQuote + (..unquote + (macro (_ tokens) + ({{.#Item it {.#End}} + (at ///.monad in (list it)) + + _ + (///.failure (..wrong_syntax_error (symbol ..,)))} + tokens)))) diff --git a/stdlib/source/library/lux/meta/macro/vocabulary.lux b/stdlib/source/library/lux/meta/macro/vocabulary.lux new file mode 100644 index 000000000..73b91c35a --- /dev/null +++ b/stdlib/source/library/lux/meta/macro/vocabulary.lux @@ -0,0 +1,53 @@ +... [Not everything is an expression](https://codewords.recurse.com/issues/two/not-everything-is-an-expression) + +(.require + [library + [lux (.except local) + [abstract + [monad (.only do)]] + [control + ["?" parser (.use "[1]#[0]" functor)] + ["[0]" exception (.only exception)]]]] + ["[0]" // (.only) + [syntax (.only syntax) + ["[0]" export]] + ["/[1]" // (.only) + ["[0]" code (.only) + ["?[1]" \\parser (.only Parser)]] + ["[0]" type (.only) + [primitive (.except)]]]]) + +(exception .public (invalid_type [expected Type + actual Type]) + (exception.report + (list ["Expected" (type.format expected)] + ["Actual" (type.format actual)]))) + +(def local + (Parser [Code Code]) + (?code.tuple (export.parser (?#each code.local ?code.local)))) + +(def .public vocabulary + (syntax (_ [[public|private@type type] ..local + [public|private@micro micro] ..local + [public|private@macro macro] ..local + [public|private@by_name by_name] ..local]) + (//.with_symbols [g!_ g!type g!value] + (in (list (` ((,! primitive) (, public|private@type) (, type) + Macro + + (def (, public|private@micro) (, micro) + (-> Macro (, type)) + (|>> ((,! abstraction)))) + + (def (, public|private@macro) (, macro) + (-> (, type) Macro) + (|>> ((,! representation)))))) + + (` (def (, public|private@by_name) ((, by_name) (, g!_)) + (-> Symbol (Meta Macro)) + ((,! do) (,! ///.monad) + [[(, g!_) (, g!type) (, g!value)] ((,! ///.export) (, g!_))] + (if (at (,! type.equivalence) (,' =) (, type) (, g!type)) + ((,' in) ((, macro) (as (, type) (, g!value)))) + ((,! ///.failure) ((,! exception.error) ..invalid_type [(, type) (, g!type)]))))))))))) diff --git a/stdlib/source/test/lux/meta/macro.lux b/stdlib/source/test/lux/meta/macro.lux index d128a74be..e2705e961 100644 --- a/stdlib/source/test/lux/meta/macro.lux +++ b/stdlib/source/test/lux/meta/macro.lux @@ -178,7 +178,7 @@ (/.times (..iterated ))] (let [expected_remaining (n.- )] (case (` ) - (^.` (..iterated (, [_ {.#Nat actual_remaining}]) (, [_ {.#Nat actual}]))) + (^.` (..iterated (^., [_ {.#Nat actual_remaining}]) (^., [_ {.#Nat actual}]))) (and (n.= expected_remaining actual_remaining) (n.= actual)) -- cgit v1.2.3