From 2b5351eb4624ce3c3ada994caaaea77c9d397eb8 Mon Sep 17 00:00:00 2001 From: Eduardo Julian Date: Tue, 15 Oct 2019 00:50:03 -0400 Subject: Compiler extensions have been tested to work. --- lux-mode/lux-mode.el | 24 ++-- .../luxc/lang/translation/jvm/extension/common.lux | 2 +- new-luxc/source/program.lux | 43 ++++++- stdlib/source/lux/control/exception.lux | 23 ++-- stdlib/source/lux/control/parser/analysis.lux | 140 +++++++++++++++++++++ stdlib/source/lux/control/parser/code.lux | 6 +- stdlib/source/lux/control/parser/synthesis.lux | 39 +++++- stdlib/source/lux/extension.lux | 87 +++++++++++++ stdlib/source/lux/tool/compiler/analysis.lux | 7 +- stdlib/source/lux/tool/compiler/default/init.lux | 9 +- .../source/lux/tool/compiler/default/platform.lux | 8 +- .../lux/tool/compiler/phase/analysis/primitive.lux | 14 +-- .../source/lux/tool/compiler/phase/extension.lux | 9 +- .../compiler/phase/extension/directive/lux.lux | 61 +++++---- stdlib/source/lux/tool/compiler/synthesis.lux | 12 +- stdlib/source/program/compositor.lux | 8 +- stdlib/source/test/lux.lux | 9 +- stdlib/source/test/lux/extension.lux | 46 +++++++ 18 files changed, 454 insertions(+), 93 deletions(-) create mode 100644 stdlib/source/lux/control/parser/analysis.lux create mode 100644 stdlib/source/lux/extension.lux create mode 100644 stdlib/source/test/lux/extension.lux diff --git a/lux-mode/lux-mode.el b/lux-mode/lux-mode.el index 7f67ac1f0..26b31f03c 100644 --- a/lux-mode/lux-mode.el +++ b/lux-mode/lux-mode.el @@ -255,7 +255,7 @@ Called by `imenu--generic-function'." (type//capability (altRE "capability:")) ;; Data (data//record (altRE "get@" "set@" "update@")) - (data//signature (altRE "signature:" "structure:" "open:" "structure" "::")) + (data//signature (altRE "open:" "structure" "::")) (data//implicit (altRE "implicit:" "implicit" ":::")) (data//collection (altRE "list" "list&" "row" "tree")) ;; Code @@ -268,7 +268,14 @@ Called by `imenu--generic-function'." (alternative-format (altRE "char" "bin" "oct" "hex")) (documentation (altRE "doc" "comment")) (function-application (altRE "|>" "|>>" "<|" "<<|" "_\\$" "\\$_")) - (remember (altRE "remember" "to-do" "fix-me"))) + (remember (altRE "remember" "to-do" "fix-me")) + (definition (altRE "\\.module:" + "def:" "type:" "program:" + "signature:" "structure:" + "macro:" "syntax:" + "exception:" + "word:" + "analysis:" "synthesis:" "generation:" "directive:"))) (let ((control (altRE control//flow control//pattern-matching control//logic @@ -294,22 +301,19 @@ Called by `imenu--generic-function'." type data code - ;; ;;;;;;;;;;;;;;;;;;;;;; + ;;;;;;;;;;;;;;;;;;;;;;;; actor jvm-host alternative-format documentation function-application remember - ;; ;;;;;;;;;;;;;;;;;;;;;; - "\\.module:" - "def:" "type:" "program:" - "macro:" "syntax:" + definition + ;;;;;;;;;;;;;;;;;;;;;;;; "with-expansions" - "exception:" - "word:" "function" "undefined" "name-of" "static" - "for" "io" + "for" + "io" "infix" "format" "regex") diff --git a/new-luxc/source/luxc/lang/translation/jvm/extension/common.lux b/new-luxc/source/luxc/lang/translation/jvm/extension/common.lux index a46813232..c3b806dd7 100644 --- a/new-luxc/source/luxc/lang/translation/jvm/extension/common.lux +++ b/new-luxc/source/luxc/lang/translation/jvm/extension/common.lux @@ -42,7 +42,7 @@ (-> Text Phase s (Operation Inst))] Handler)) (function (_ extension-name phase input) - (case (.run input parser) + (case (.run parser input) (#try.Success input') (handler extension-name phase input') diff --git a/new-luxc/source/program.lux b/new-luxc/source/program.lux index 91b42c981..f975d2a87 100644 --- a/new-luxc/source/program.lux +++ b/new-luxc/source/program.lux @@ -24,7 +24,7 @@ [compiler [phase ["." macro (#+ Expander)] - [extension + [extension (#+ Phase Bundle Operation Handler Extender) ["." analysis #_ ["#" jvm]]]] [default @@ -60,19 +60,27 @@ (java/lang/Class java/lang/Object) (host.class-for java/lang/Object)) -(def: _apply-args +(def: _apply2-args (Array (java/lang/Class java/lang/Object)) (|> (host.array (java/lang/Class java/lang/Object) 2) (host.array-write 0 _object-class) (host.array-write 1 _object-class))) +(def: _apply4-args + (Array (java/lang/Class java/lang/Object)) + (|> (host.array (java/lang/Class java/lang/Object) 4) + (host.array-write 0 _object-class) + (host.array-write 1 _object-class) + (host.array-write 2 _object-class) + (host.array-write 3 _object-class))) + (def: #export (expander macro inputs lux) Expander (do try.monad [apply-method (|> macro (:coerce java/lang/Object) (java/lang/Object::getClass) - (java/lang/Class::getMethod "apply" _apply-args))] + (java/lang/Class::getMethod "apply" _apply2-args))] (:coerce (Try (Try [Lux (List Code)])) (java/lang/reflect/Method::invoke (:coerce java/lang/Object macro) @@ -158,6 +166,34 @@ run-ioI $i.RETURN))))])) +(def: extender + Extender + ## TODO: Stop relying on coercions ASAP. + (<| (:coerce Extender) + (function (@self handler)) + (:coerce Handler) + (function (@self name phase)) + (:coerce Phase) + (function (@self parameters)) + (:coerce Operation) + (function (@self state)) + (:coerce Try) + try.assume + (:coerce Try) + (do try.monad + [method (|> handler + (:coerce java/lang/Object) + (java/lang/Object::getClass) + (java/lang/Class::getMethod "apply" _apply4-args))] + (java/lang/reflect/Method::invoke + (:coerce java/lang/Object handler) + (|> (host.array java/lang/Object 4) + (host.array-write 0 (:coerce java/lang/Object name)) + (host.array-write 1 (:coerce java/lang/Object phase)) + (host.array-write 2 (:coerce java/lang/Object parameters)) + (host.array-write 3 (:coerce java/lang/Object state))) + method)))) + (program: [{service /cli.service}] (let [(^slots [#/cli.target #/cli.module]) (case service (#/cli.Compilation configuration) configuration @@ -171,5 +207,6 @@ translation.bundle directive.bundle ..program + ..extender service [(packager.package ..program-class) jar-path]))) diff --git a/stdlib/source/lux/control/exception.lux b/stdlib/source/lux/control/exception.lux index 21bdc1040..118b9ed1a 100644 --- a/stdlib/source/lux/control/exception.lux +++ b/stdlib/source/lux/control/exception.lux @@ -15,11 +15,10 @@ ["." list ("#@." functor fold)]]] ["." macro ["." code] - [syntax (#+ syntax:)] - [syntax - ["cs" common - ["csr" reader] - ["csw" writer]]]]] + [syntax (#+ syntax:) + ["sc" common + ["scr" reader] + ["scw" writer]]]]] [// ["//" try (#+ Try)]]) @@ -83,10 +82,10 @@ (#//.Success []) (..throw exception message))) -(syntax: #export (exception: {export csr.export} - {t-vars (p.default (list) csr.type-variables)} +(syntax: #export (exception: {export scr.export} + {t-vars (p.default (list) scr.type-variables)} {[name inputs] (p.either (p.and s.local-identifier (wrap (list))) - (s.form (p.and s.local-identifier (p.some csr.typed-input))))} + (s.form (p.and s.local-identifier (p.some scr.typed-input))))} {body (p.maybe s.any)}) {#.doc (doc "Define a new exception type." "It moslty just serves as a way to tag error messages for later catching." @@ -102,13 +101,13 @@ [current-module macro.current-module-name #let [descriptor ($_ text@compose "{" current-module "." name "}" text.new-line) g!self (code.local-identifier name)]] - (wrap (list (` (def: (~+ (csw.export export)) + (wrap (list (` (def: (~+ (scw.export export)) (~ g!self) - (All [(~+ (csw.type-variables t-vars))] - (..Exception [(~+ (list@map (get@ #cs.input-type) inputs))])) + (All [(~+ (scw.type-variables t-vars))] + (..Exception [(~+ (list@map (get@ #sc.input-type) inputs))])) (let [(~ g!descriptor) (~ (code.text descriptor))] {#..label (~ g!descriptor) - #..constructor (function ((~ g!self) [(~+ (list@map (get@ #cs.input-binding) inputs))]) + #..constructor (function ((~ g!self) [(~+ (list@map (get@ #sc.input-binding) inputs))]) ((~! text@compose) (~ g!descriptor) (~ (maybe.default (' "") body))))}))))) ))) diff --git a/stdlib/source/lux/control/parser/analysis.lux b/stdlib/source/lux/control/parser/analysis.lux new file mode 100644 index 000000000..0cef19fd9 --- /dev/null +++ b/stdlib/source/lux/control/parser/analysis.lux @@ -0,0 +1,140 @@ +(.module: + [lux (#- nat int rev) + [abstract + [monad (#+ do)]] + [control + ["." try (#+ Try)] + ["." exception (#+ exception:)]] + [data + ["." bit] + ["." name] + [number + ["." i64] + ["." nat] + ["." int] + ["." rev] + ["." frac]] + ["." text + ["%" format (#+ format)]] + [collection + ["." list ("#@." functor)]]] + [tool + [compiler + [reference (#+)] + [arity (#+ Arity)] + ["/" analysis (#+ Variant Tuple Environment Analysis)]]]] + ["." //]) + +(def: (remaining-inputs asts) + (-> (List Analysis) Text) + (format text.new-line "Remaining input: " + (|> asts + (list@map /.%analysis) + (list.interpose " ") + (text.join-with "")))) + +## TODO: Use "type:" ASAP. +(def: Input Type (type (List Analysis))) + +(exception: #export (cannot-parse {input ..Input}) + (exception.report + ["Input" (exception.enumerate /.%analysis input)])) + +(exception: #export (unconsumed-input {input ..Input}) + (exception.report + ["Input" (exception.enumerate /.%analysis input)])) + +(exception: #export (wrong-arity {expected Arity} {actual Arity}) + (exception.report + ["Expected" (%.nat expected)] + ["Actual" (%.nat actual)])) + +(exception: #export empty-input) + +(type: #export Parser + (//.Parser ..Input)) + +(def: #export (run parser input) + (All [a] (-> (Parser a) ..Input (Try a))) + (case (parser input) + (#try.Failure error) + (#try.Failure error) + + (#try.Success [#.Nil value]) + (#try.Success value) + + (#try.Success [unconsumed _]) + (exception.throw ..unconsumed-input unconsumed))) + +(def: #export any + (Parser Analysis) + (function (_ input) + (case input + #.Nil + (exception.throw ..empty-input []) + + (#.Cons [head tail]) + (#try.Success [tail head])))) + +(def: #export end! + {#.doc "Ensures there are no more inputs."} + (Parser Any) + (function (_ tokens) + (case tokens + #.Nil (#try.Success [tokens []]) + _ (#try.Failure (format "Expected list of tokens to be empty!" + (remaining-inputs tokens)))))) + +(def: #export end? + {#.doc "Checks whether there are no more inputs."} + (Parser Bit) + (function (_ tokens) + (#try.Success [tokens (case tokens + #.Nil true + _ false)]))) + +(template [ ] + [(def: #export + (Parser ) + (function (_ input) + (case input + (^ (list& ( x) input')) + (#try.Success [input' x]) + + _ + (exception.throw ..cannot-parse input)))) + + (def: #export ( expected) + (-> (Parser Any)) + (function (_ input) + (case input + (^ (list& ( actual) input')) + (if (:: = expected actual) + (#try.Success [input' []]) + (exception.throw ..cannot-parse input)) + + _ + (exception.throw ..cannot-parse input))))] + + [bit bit! /.bit Bit bit.equivalence] + [nat nat! /.nat Nat nat.equivalence] + [int int! /.int Int int.equivalence] + [rev rev! /.rev Rev rev.equivalence] + [frac frac! /.frac Frac frac.equivalence] + [text text! /.text Text text.equivalence] + [local local! /.variable/local Nat nat.equivalence] + [foreign foreign! /.variable/foreign Nat nat.equivalence] + [constant constant! /.constant Name name.equivalence] + ) + +(def: #export (tuple parser) + (All [a] (-> (Parser a) (Parser a))) + (function (_ input) + (case input + (^ (list& (/.tuple head) tail)) + (do try.monad + [output (..run parser head)] + (#try.Success [tail output])) + + _ + (exception.throw ..cannot-parse input)))) diff --git a/stdlib/source/lux/control/parser/code.lux b/stdlib/source/lux/control/parser/code.lux index 5ea2247d6..30344aaa0 100644 --- a/stdlib/source/lux/control/parser/code.lux +++ b/stdlib/source/lux/control/parser/code.lux @@ -152,9 +152,9 @@ {#.doc "Checks whether there are no more inputs."} (Parser Bit) (function (_ tokens) - (case tokens - #.Nil (#try.Success [tokens #1]) - _ (#try.Success [tokens #0])))) + (#try.Success [tokens (case tokens + #.Nil true + _ false)]))) (def: #export (run syntax inputs) (All [a] (-> (Parser a) (List Code) (Try a))) diff --git a/stdlib/source/lux/control/parser/synthesis.lux b/stdlib/source/lux/control/parser/synthesis.lux index 8fdeb4911..0c52b878c 100644 --- a/stdlib/source/lux/control/parser/synthesis.lux +++ b/stdlib/source/lux/control/parser/synthesis.lux @@ -13,14 +13,26 @@ ["n" nat] ["." frac]] ["." text - ["%" format (#+ format)]]] + ["%" format (#+ format)]] + [collection + ["." list ("#@." functor)]]] [tool [compiler + [reference (#+)] [arity (#+ Arity)] [analysis (#+ Variant Tuple Environment)] ["/" synthesis (#+ Synthesis Abstraction)]]]] ["." //]) +(def: (remaining-inputs asts) + (-> (List Synthesis) Text) + (format text.new-line "Remaining input: " + (|> asts + (list@map /.%synthesis) + (list.interpose " ") + (text.join-with "")))) + +## TODO: Use "type:" ASAP. (def: Input Type (type (List Synthesis))) (exception: #export (cannot-parse {input ..Input}) @@ -41,8 +53,8 @@ (type: #export Parser (//.Parser ..Input)) -(def: #export (run input parser) - (All [a] (-> ..Input (Parser a) (Try a))) +(def: #export (run parser input) + (All [a] (-> (Parser a) ..Input (Try a))) (case (parser input) (#try.Failure error) (#try.Failure error) @@ -63,6 +75,23 @@ (#.Cons [head tail]) (#try.Success [tail head])))) +(def: #export end! + {#.doc "Ensures there are no more inputs."} + (Parser Any) + (.function (_ tokens) + (case tokens + #.Nil (#try.Success [tokens []]) + _ (#try.Failure (format "Expected list of tokens to be empty!" + (remaining-inputs tokens)))))) + +(def: #export end? + {#.doc "Checks whether there are no more inputs."} + (Parser Bit) + (.function (_ tokens) + (#try.Success [tokens (case tokens + #.Nil true + _ false)]))) + (template [ ] [(def: #export (Parser ) @@ -101,7 +130,7 @@ (case input (^ (list& (/.tuple head) tail)) (do try.monad - [output (..run head parser)] + [output (..run parser head)] (#try.Success [tail output])) _ @@ -114,7 +143,7 @@ (^ (list& (/.function/abstraction [environment actual body]) tail)) (if (n.= expected actual) (do try.monad - [output (..run (list body) parser)] + [output (..run parser (list body))] (#try.Success [tail [environment output]])) (exception.throw ..wrong-arity [expected actual])) diff --git a/stdlib/source/lux/extension.lux b/stdlib/source/lux/extension.lux new file mode 100644 index 000000000..f5bce33a7 --- /dev/null +++ b/stdlib/source/lux/extension.lux @@ -0,0 +1,87 @@ +(.module: + [lux #* + [abstract + ["." monad]] + [control + ["<>" parser ("#@." monad) + ["" code (#+ Parser)] + ["" analysis] + ["" synthesis]]] + [data + ["." product] + [collection + ["." list ("#@." functor)]]] + [macro (#+ with-gensyms) + ["." code] + [syntax (#+ syntax:)]] + [tool + [compiler + ["." phase]]]]) + +(type: Input + {#variable Text + #parser Code}) + +(def: (simple default) + (-> Code (Parser Input)) + ($_ <>.and + .local-identifier + (<>@wrap default))) + +(def: complex + (Parser Input) + (.record ($_ <>.and + .local-identifier + .any))) + +(def: (input default) + (-> Code (Parser Input)) + (<>.either (..simple default) + ..complex)) + +(type: Declaration + {#name Code + #label Text + #phase Text + #inputs (List Input)}) + +(def: (declaration default) + (-> Code (Parser Declaration)) + (.form ($_ <>.and + .any + .local-identifier + .local-identifier + (<>.some (..input default))))) + +(template [ ] + [(syntax: #export ( + {[name extension phase inputs] (..declaration (` ))} + body) + (let [g!parser (case (list@map product.right inputs) + #.Nil + (` ) + + parsers + (` (.$_ (~+ parsers)))) + g!name (code.local-identifier extension) + g!phase (code.local-identifier phase)] + (with-gensyms [g!handler g!inputs g!error] + (wrap (list (` ( (~ name) + (.function ((~ g!handler) (~ g!name) (~ g!phase) (~ g!inputs)) + (.case ((~! ) (~ g!parser) (~ g!inputs)) + (#.Right [(~+ (list@map (|>> product.left + code.local-identifier) + inputs))]) + ((~! monad.do) (~! phase.monad) + [] + (~ body)) + + (#.Left (~ g!error)) + ((~! phase.fail) (~ g!error))) + ))))))))] + + [.any .end! .and .run "lux def analysis" analysis:] + [.any .end! .and .run "lux def synthesis" synthesis:] + [.any .end! .and .run "lux def generation" generation:] + [.any .end! .and .run "lux def directive" directive:] + ) diff --git a/stdlib/source/lux/tool/compiler/analysis.lux b/stdlib/source/lux/tool/compiler/analysis.lux index e59397ed9..5d9d899ab 100644 --- a/stdlib/source/lux/tool/compiler/analysis.lux +++ b/stdlib/source/lux/tool/compiler/analysis.lux @@ -129,8 +129,11 @@ content))] - [variable #reference.Variable] - [constant #reference.Constant] + [variable #reference.Variable] + [constant #reference.Constant] + + [variable/local reference.local] + [variable/foreign reference.foreign] ) (template [ ] diff --git a/stdlib/source/lux/tool/compiler/default/init.lux b/stdlib/source/lux/tool/compiler/default/init.lux index 40549f8d0..c053445f2 100644 --- a/stdlib/source/lux/tool/compiler/default/init.lux +++ b/stdlib/source/lux/tool/compiler/default/init.lux @@ -29,11 +29,11 @@ [".P" synthesis] ["." generation] [".P" directive] - ["." extension + ["." extension (#+ Extender) [".E" analysis] [".E" synthesis] [directive - [".S" lux]]]] + [".D" lux]]]] [meta [archive ["." signature] @@ -47,7 +47,7 @@ #.version //.version #.mode #.Build}) -(def: #export (state target expander host-analysis host generate generation-bundle host-directive-bundle program) +(def: #export (state target expander host-analysis host generate generation-bundle host-directive-bundle program extender) (All [anchor expression directive] (-> Text Expander @@ -57,13 +57,14 @@ (generation.Bundle anchor expression directive) (///directive.Bundle anchor expression directive) (-> expression directive) + Extender (///directive.State+ anchor expression directive))) (let [synthesis-state [synthesisE.bundle ///synthesis.init] generation-state [generation-bundle (generation.state host)] eval (//evaluation.evaluator expander synthesis-state generation-state generate) analysis-state [(analysisE.bundle eval host-analysis) (///analysis.state (..info target) host)]] - [(dictionary.merge (luxS.bundle expander host-analysis program) + [(dictionary.merge (luxD.bundle expander host-analysis program extender) host-directive-bundle) {#///directive.analysis {#///directive.state analysis-state #///directive.phase (analysisP.phase expander)} diff --git a/stdlib/source/lux/tool/compiler/default/platform.lux b/stdlib/source/lux/tool/compiler/default/platform.lux index 04937092a..b37e74c2b 100644 --- a/stdlib/source/lux/tool/compiler/default/platform.lux +++ b/stdlib/source/lux/tool/compiler/default/platform.lux @@ -23,7 +23,7 @@ ["#." phase [macro (#+ Expander)] ## TODO: Get rid of this import ASAP - [extension (#+)] + [extension (#+ Extender)] ["." generation (#+ Buffer)] [analysis ["." module]]] @@ -57,7 +57,7 @@ (as-is (///directive.State+ anchor expression directive)) (as-is (generation.Bundle anchor expression directive))] - (def: #export (initialize target expander host-analysis platform generation-bundle host-directive-bundle program) + (def: #export (initialize target expander host-analysis platform generation-bundle host-directive-bundle program extender) (All (-> Text Expander @@ -66,6 +66,7 @@ (///directive.Bundle anchor expression directive) (-> expression directive) + Extender (! (Try )))) (|> (do ///phase.monad [_ (:share [anchor expression directive] @@ -95,7 +96,8 @@ (get@ #phase platform) generation-bundle host-directive-bundle - program)) + program + extender)) (:: try.functor map product.left) (:: (get@ #&monad platform) wrap)) diff --git a/stdlib/source/lux/tool/compiler/phase/analysis/primitive.lux b/stdlib/source/lux/tool/compiler/phase/analysis/primitive.lux index 766dc6616..392ae4d8e 100644 --- a/stdlib/source/lux/tool/compiler/phase/analysis/primitive.lux +++ b/stdlib/source/lux/tool/compiler/phase/analysis/primitive.lux @@ -15,16 +15,16 @@ [_ (//type.infer )] (wrap (#/.Primitive ( value)))))] - [bit Bit #/.Bit] - [nat Nat #/.Nat] - [int Int #/.Int] - [rev Rev #/.Rev] - [frac Frac #/.Frac] - [text Text #/.Text] + [bit .Bit #/.Bit] + [nat .Nat #/.Nat] + [int .Int #/.Int] + [rev .Rev #/.Rev] + [frac .Frac #/.Frac] + [text .Text #/.Text] ) (def: #export unit (Operation Analysis) (do ///.monad - [_ (//type.infer Any)] + [_ (//type.infer .Any)] (wrap (#/.Primitive #/.Unit)))) diff --git a/stdlib/source/lux/tool/compiler/phase/extension.lux b/stdlib/source/lux/tool/compiler/phase/extension.lux index a0564cedd..7ba769476 100644 --- a/stdlib/source/lux/tool/compiler/phase/extension.lux +++ b/stdlib/source/lux/tool/compiler/phase/extension.lux @@ -61,13 +61,16 @@ (list.sort text@<) (exception.enumerate %.text))])) -(def: #export (install name handler) +(type: #export (Extender s i o) + (-> Any (Handler s i o))) + +(def: #export (install extender name handler) (All [s i o] - (-> Text (Handler s i o) (Operation s i o Any))) + (-> (Extender s i o) Text (Handler s i o) (Operation s i o Any))) (function (_ [bundle state]) (case (dictionary.get name bundle) #.None - (#try.Success [[(dictionary.put name handler bundle) state] + (#try.Success [[(dictionary.put name (extender handler) bundle) state] []]) _ diff --git a/stdlib/source/lux/tool/compiler/phase/extension/directive/lux.lux b/stdlib/source/lux/tool/compiler/phase/extension/directive/lux.lux index 9344169f2..5f62d4d50 100644 --- a/stdlib/source/lux/tool/compiler/phase/extension/directive/lux.lux +++ b/stdlib/source/lux/tool/compiler/phase/extension/directive/lux.lux @@ -19,7 +19,7 @@ ["." code]] ["." type (#+ :share :by-example) ("#@." equivalence) ["." check]]] - ["." /// + ["." /// (#+ Extender) ["#." bundle] ["#." analysis] ["#/" // @@ -243,35 +243,38 @@ (define-alias alias def-name)))] (wrap /////directive.no-requirements)))])) -(template [ ] - [(def: +(template [ ] + [(def: ( extender) (All [anchor expression directive] - (Handler anchor expression directive)) + (-> Extender + (Handler anchor expression directive))) (function (handler extension-name phase inputsC+) (case inputsC+ - (^ (list [_ (#.Text name)] valueC)) + (^ (list nameC valueC)) (do ////.monad - [[_ handlerT handlerV] (evaluate! (:by-example [anchor expression directive] - {(Handler anchor expression directive) - handler} - ) - valueC) + [[_ _ name] (evaluate! Text nameC) + [_ _ handlerV] (evaluate! (:by-example [anchor expression directive] + {(Handler anchor expression directive) + handler} + ) + valueC) _ (<| - (///.install name) + (///.install extender (:coerce Text name)) (:share [anchor expression directive] {(Handler anchor expression directive) handler} { - (:assume handlerV)}))] + (:assume handlerV)})) + #let [_ (log! (format " " (%.text (:coerce Text name))))]] (wrap /////directive.no-requirements)) _ (////.throw ///.invalid-syntax [extension-name %.code inputsC+]))))] - [def::analysis /////analysis.Handler /////directive.lift-analysis] - [def::synthesis /////synthesis.Handler /////directive.lift-synthesis] - [def::generation (////generation.Handler anchor expression directive) /////directive.lift-generation] - [def::directive (/////directive.Handler anchor expression directive) (<|)] + ["Analysis" def::analysis /////analysis.Handler /////directive.lift-analysis] + ["Synthesis" def::synthesis /////synthesis.Handler /////directive.lift-synthesis] + ["Generation" def::generation (////generation.Handler anchor expression directive) /////directive.lift-generation] + ["Directive" def::directive (/////directive.Handler anchor expression directive) (<|)] ) ## TODO; Both "prepare-program" and "define-program" exist only @@ -321,25 +324,33 @@ _ (////.throw ///.invalid-syntax [extension-name %.code inputsC+])))) -(def: (bundle::def expander host-analysis program) +(def: (bundle::def expander host-analysis program extender) (All [anchor expression directive] - (-> Expander /////analysis.Bundle (-> expression directive) (Bundle anchor expression directive))) + (-> Expander + /////analysis.Bundle + (-> expression directive) + Extender + (Bundle anchor expression directive))) (<| (///bundle.prefix "def") (|> ///bundle.empty (dictionary.put "module" def::module) (dictionary.put "alias" def::alias) (dictionary.put "type tagged" (def::type-tagged expander host-analysis)) - (dictionary.put "analysis" def::analysis) - (dictionary.put "synthesis" def::synthesis) - (dictionary.put "generation" def::generation) - (dictionary.put "directive" def::directive) + (dictionary.put "analysis" (def::analysis extender)) + (dictionary.put "synthesis" (def::synthesis extender)) + (dictionary.put "generation" (def::generation extender)) + (dictionary.put "directive" (def::directive extender)) (dictionary.put "program" (def::program program)) ))) -(def: #export (bundle expander host-analysis program) +(def: #export (bundle expander host-analysis program extender) (All [anchor expression directive] - (-> Expander /////analysis.Bundle (-> expression directive) (Bundle anchor expression directive))) + (-> Expander + /////analysis.Bundle + (-> expression directive) + Extender + (Bundle anchor expression directive))) (<| (///bundle.prefix "lux") (|> ///bundle.empty (dictionary.put "def" (lux::def expander host-analysis)) - (dictionary.merge (..bundle::def expander host-analysis program))))) + (dictionary.merge (..bundle::def expander host-analysis program extender))))) diff --git a/stdlib/source/lux/tool/compiler/synthesis.lux b/stdlib/source/lux/tool/compiler/synthesis.lux index e44432bcb..3d1f7c6e3 100644 --- a/stdlib/source/lux/tool/compiler/synthesis.lux +++ b/stdlib/source/lux/tool/compiler/synthesis.lux @@ -228,20 +228,12 @@ content))] + [variable //reference.variable] + [constant //reference.constant] [variable/local //reference.local] [variable/foreign //reference.foreign] ) -(template [ ] - [(template: #export ( content) - (.<| #..Reference - - content))] - - [variable //reference.variable] - [constant //reference.constant] - ) - (template [ ] [(template: #export ( content) (.<| #..Control diff --git a/stdlib/source/program/compositor.lux b/stdlib/source/program/compositor.lux index b9b2995ad..31f018081 100644 --- a/stdlib/source/program/compositor.lux +++ b/stdlib/source/program/compositor.lux @@ -30,6 +30,7 @@ ["." directive] ["." phase [macro (#+ Expander)] + [extension (#+ Extender)] ["." generation]] [default ["." platform (#+ Platform)] @@ -79,7 +80,9 @@ (#try.Failure error) (:: io.monad wrap (#try.Failure error))))) -(def: #export (compiler target partial-host-extension expander host-analysis platform generation-bundle host-directive-bundle program service +(def: #export (compiler target partial-host-extension + expander host-analysis platform generation-bundle host-directive-bundle program extender + service packager,package) (All [anchor expression directive] (-> Text @@ -90,6 +93,7 @@ (generation.Bundle anchor expression directive) (directive.Bundle anchor expression directive) (-> expression directive) + Extender Service [(-> (generation.Output directive) Binary) Path] (IO Any))) @@ -104,7 +108,7 @@ {(Platform IO anchor expression directive) platform} {(IO (Try (directive.State+ anchor expression directive))) - (platform.initialize target expander host-analysis platform generation-bundle host-directive-bundle program)}) + (platform.initialize target expander host-analysis platform generation-bundle host-directive-bundle program extender)}) [archive state] (:share [anchor expression directive] {(Platform IO anchor expression directive) platform} diff --git a/stdlib/source/test/lux.lux b/stdlib/source/test/lux.lux index d9fbc7b1d..4be2dcf27 100644 --- a/stdlib/source/test/lux.lux +++ b/stdlib/source/test/lux.lux @@ -136,6 +136,7 @@ ["#." type] ["#." world] ["#." host] + ["#." extension] ["#." target #_ ["#/." jvm]]] )) @@ -368,9 +369,11 @@ /tool.test /type.test /world.test)) - /host.test - ($_ _.and - /target/jvm.test) + (!bundle ($_ _.and + /host.test + /extension.test + ($_ _.and + /target/jvm.test))) ))) (program: args diff --git a/stdlib/source/test/lux/extension.lux b/stdlib/source/test/lux/extension.lux new file mode 100644 index 000000000..f73ad63a1 --- /dev/null +++ b/stdlib/source/test/lux/extension.lux @@ -0,0 +1,46 @@ +(.module: + [lux #* + [abstract + [monad (#+ do)]] + [control + ["<>" parser + ["" code] + ["" analysis]]] + [data + ["." text ("#@." equivalence) + ["%" format (#+ format)]]] + [tool + [compiler + ["." analysis] + ["." synthesis] + ["." directive] + [phase + [analysis + ["." type]]]]] + ["_" test (#+ Test)]] + {1 + ["." / (#+ analysis: synthesis: directive:)]}) + +(def: my-extension "example YOLO") + +(analysis: (..my-extension self phase {parameters (<>.some .any)}) + (do @ + [_ (type.infer .Text)] + (wrap (#analysis.Extension self (list))))) + +(synthesis: (..my-extension self phase {parameters (<>.some .any)}) + (wrap (synthesis.text self))) + +(directive: (..my-extension self phase {parameters (<>.some .any)}) + (do @ + [#let [_ (log! (format "directive: " (%.text self)))]] + (wrap directive.no-requirements))) + +("example YOLO") + +(def: #export test + Test + (<| (_.context (%.name (name-of /._))) + (_.test "Can define and user analysis & synthesis extensions." + (text@= ("example YOLO") + "example YOLO")))) -- cgit v1.2.3