diff options
author | Eduardo Julian | 2021-03-12 05:45:44 -0400 |
---|---|---|
committer | Eduardo Julian | 2021-03-12 05:45:44 -0400 |
commit | dff34f01e838475b817803ec856661fe8940e5c0 (patch) | |
tree | d8ddb3b6fd5963fdbdda64a13f2a430242fd7b26 /stdlib/source | |
parent | 0c75fd67e3fcfbfb09d8c11b6cf396084ce40a15 (diff) |
Almost done with PHP.
Diffstat (limited to '')
27 files changed, 1365 insertions, 391 deletions
diff --git a/stdlib/source/lux/control/concurrency/atom.lux b/stdlib/source/lux/control/concurrency/atom.lux index 350554437..8a46413da 100644 --- a/stdlib/source/lux/control/concurrency/atom.lux +++ b/stdlib/source/lux/control/concurrency/atom.lux @@ -26,17 +26,21 @@ (with_expansions [<new> (for {@.js "js array new" @.python "python array new" @.lua "lua array new" - @.ruby "ruby array new"} + @.ruby "ruby array new" + @.php "php array new"} (as_is)) <write> (for {@.js "js array write" @.python "python array write" @.lua "lua array write" - @.ruby "ruby array write"} + @.ruby "ruby array write" + @.php "php array write"} (as_is)) + <read> (for {@.js "js array read" @.python "python array read" @.lua "lua array read" - @.ruby "ruby array read"} + @.ruby "ruby array read" + @.php "php array read"} (as_is))] (abstract: #export (Atom a) (with_expansions [<jvm> (java/util/concurrent/atomic/AtomicReference a)] diff --git a/stdlib/source/lux/control/thread.lux b/stdlib/source/lux/control/thread.lux index 6be40ef63..52c0062eb 100644 --- a/stdlib/source/lux/control/thread.lux +++ b/stdlib/source/lux/control/thread.lux @@ -45,7 +45,8 @@ @.js ("js array read" 0 (:representation box)) @.python ("python array read" 0 (:representation box)) @.lua ("lua array read" 0 (:representation box)) - @.ruby ("ruby array read" 0 (:representation box))}))) + @.ruby ("ruby array read" 0 (:representation box)) + @.php ("php array read" 0 (:representation box))}))) (def: #export (write value box) (All [a] (-> a (All [!] (-> (Box ! a) (Thread ! Any))))) diff --git a/stdlib/source/lux/data/collection/array.lux b/stdlib/source/lux/data/collection/array.lux index b9162e53a..73c6767e4 100644 --- a/stdlib/source/lux/data/collection/array.lux +++ b/stdlib/source/lux/data/collection/array.lux @@ -48,7 +48,8 @@ @.js ("js array new" size) @.python ("python array new" size) @.lua ("lua array new" size) - @.ruby ("ruby array new" size)})) + @.ruby ("ruby array new" size) + @.php ("php array new" size)})) (def: #export (size array) (All [a] (-> (Array a) Nat)) @@ -67,7 +68,8 @@ @.js ("js array length" array) @.python ("python array length" array) @.lua ("lua array length" array) - @.ruby ("ruby array length" array)})) + @.ruby ("ruby array length" array) + @.php ("php array length" array)})) (template: (!read <read> <null?>) (let [output (<read> index array)] @@ -96,7 +98,8 @@ @.js (!read "js array read" "js object undefined?") @.python (!read "python array read" "python object none?") @.lua (!read "lua array read" "lua object nil?") - @.ruby (!read "ruby array read" "ruby object nil?")}) + @.ruby (!read "ruby array read" "ruby object nil?") + @.php (!read "php array read" "php object null?")}) #.None)) (def: #export (write! index value array) @@ -114,7 +117,8 @@ @.js ("js array write" index value array) @.python ("python array write" index value array) @.lua ("lua array write" index value array) - @.ruby ("ruby array write" index value array)})) + @.ruby ("ruby array write" index value array) + @.php ("php array write" index value array)})) (def: #export (delete! index array) (All [a] @@ -129,7 +133,8 @@ @.js ("js array delete" index array) @.python ("python array delete" index array) @.lua ("lua array delete" index array) - @.ruby ("ruby array delete" index array)}) + @.ruby ("ruby array delete" index array) + @.php ("php array delete" index array)}) array)) ) diff --git a/stdlib/source/lux/data/text/encoding.lux b/stdlib/source/lux/data/text/encoding.lux index 88bbea138..4622c8be9 100644 --- a/stdlib/source/lux/data/text/encoding.lux +++ b/stdlib/source/lux/data/text/encoding.lux @@ -201,7 +201,11 @@ (bytes [] Binary)) (host.import: Array #as RubyArray - (pack [Text] RubyString)))} + (pack [Text] RubyString))) + + @.php + (as_is (host.import: (unpack [host.String host.String] Binary)) + (def: php_byte_array_format "C*"))} (as_is))) (def: (utf8\encode value) @@ -242,7 +246,10 @@ (|> value (:coerce RubyString) (RubyString::encode ["UTF-8"]) - (RubyString::bytes []))})) + (RubyString::bytes [])) + + @.php + (..unpack [..php_byte_array_format value])})) (def: (utf8\decode value) (-> Binary (Try Text)) @@ -278,6 +285,11 @@ (RubyArray::pack ["C*"]) (:coerce RubyString) (RubyString::force_encoding ["UTF-8"]) + #try.Success) + + @.php + (|> value + ("php pack" ..php_byte_array_format) #try.Success)}))) (structure: #export utf8 diff --git a/stdlib/source/lux/debug.lux b/stdlib/source/lux/debug.lux index 47d62fd34..29919a588 100644 --- a/stdlib/source/lux/debug.lux +++ b/stdlib/source/lux/debug.lux @@ -85,7 +85,12 @@ (as_is (import: Class) (import: Object - (type [] Class)))})) + (type [] Class))) + + @.php + (as_is (import: (gettype [.Any] host.String)) + (import: (strval [.Any] host.String))) + })) (def: Inspector (-> Any Text)) @@ -195,7 +200,7 @@ (if (or ("python object none?" variant_tag) ("python object none?" variant_value)) (..str value) - (|> (format (|> variant_tag (:coerce .Int) %.int) + (|> (format (|> variant_tag (:coerce .Nat) %.nat) " " (|> variant_flag "python object none?" not %.bit) " " (inspect variant_value)) (text.enclose ["(" ")"])))) @@ -228,7 +233,7 @@ (if (not (or ("lua object nil?" variant_tag) ("lua object nil?" variant_flag) ("lua object nil?" variant_value))) - (|> (format (|> variant_tag (:coerce .Int) %.int) + (|> (format (|> variant_tag (:coerce .Nat) %.nat) " " (%.bit (not ("lua object nil?" variant_flag))) " " (inspect variant_value)) (text.enclose ["(" ")"])) @@ -260,7 +265,7 @@ (if (not (or ("ruby object nil?" variant_tag) ("ruby object nil?" variant_flag) ("ruby object nil?" variant_value))) - (|> (format (|> variant_tag (:coerce .Int) %.int) + (|> (format (|> variant_tag (:coerce .Nat) %.nat) " " (%.bit (not ("ruby object nil?" variant_flag))) " " (inspect variant_value)) (text.enclose ["(" ")"])) @@ -271,6 +276,34 @@ ## else (:coerce Text ("ruby object do" "to_s" value)))))) + + @.php + (case (..gettype value) + (^template [<type_of> <then>] + [<type_of> + (`` (|> value (~~ (template.splice <then>))))]) + (["boolean" [(:coerce .Bit) %.bit]] + ["integer" [(:coerce .Int) %.int]] + ["double" [(:coerce .Frac) %.frac]] + ["string" [(:coerce .Text) %.text]] + ["NULL" [(new> "null" [])]] + ["array" [(inspect_tuple inspect)]]) + + "object" + (let [variant_tag ("php object get" "_lux_tag" value) + variant_flag ("php object get" "_lux_flag" value) + variant_value ("php object get" "_lux_value" value)] + (if (not (or ("php object null?" variant_tag) + ("php object null?" variant_flag) + ("php object null?" variant_value))) + (|> (format (|> variant_tag (:coerce .Nat) %.nat) + " " (%.bit (not ("php object null?" variant_flag))) + " " (inspect variant_value)) + (text.enclose ["(" ")"])) + (..strval value))) + + _ + (..strval value)) }))) (exception: #export (cannot_represent_value {type Type}) diff --git a/stdlib/source/lux/host.php.lux b/stdlib/source/lux/host.php.lux new file mode 100644 index 000000000..ac0daf9c5 --- /dev/null +++ b/stdlib/source/lux/host.php.lux @@ -0,0 +1,307 @@ +(.module: + [lux (#- Alias) + ["." meta] + ["@" target] + [abstract + [monad (#+ do)]] + [control + ["." io] + ["<>" parser ("#\." monad) + ["<.>" code (#+ Parser)]]] + [data + ["." product] + ["." maybe] + ["." text + ["%" format (#+ format)]] + [collection + ["." list ("#\." functor fold)]]] + [type + abstract] + [macro (#+ with_gensyms) + [syntax (#+ syntax:)] + ["." code] + ["." template]]]) + +(abstract: #export (Object brand) Any) + +(template [<name>] + [(with_expansions [<brand> (template.identifier [<name> "'"])] + (abstract: #export <brand> Any) + (type: #export <name> + (..Object <brand>)))] + + [Null] + [Function] + ) + +(template [<name> <type>] + [(type: #export <name> + <type>)] + + [Boolean Bit] + [Integer Int] + [Float Frac] + [String Text] + ) + +(type: Nullable + [Bit Code]) + +(def: nullable + (Parser Nullable) + (let [token (' #?)] + (<| (<>.and (<>.parses? (<code>.this! token))) + (<>.after (<>.not (<code>.this! token))) + <code>.any))) + +(type: Alias + Text) + +(def: alias + (Parser Alias) + (<>.after (<code>.this! (' #as)) <code>.local_identifier)) + +(type: Field + [Bit Text (Maybe Alias) Nullable]) + +(def: static! + (Parser Any) + (<code>.this! (' #static))) + +(def: field + (Parser Field) + (<code>.form ($_ <>.and + (<>.parses? ..static!) + <code>.local_identifier + (<>.maybe ..alias) + ..nullable))) + +(def: constant + (Parser Field) + (<code>.form ($_ <>.and + (<>\wrap true) + <code>.local_identifier + (<>.maybe ..alias) + ..nullable))) + +(type: Common_Method + {#name Text + #alias (Maybe Alias) + #inputs (List Nullable) + #io? Bit + #try? Bit + #output Nullable}) + +(type: Static_Method Common_Method) +(type: Virtual_Method Common_Method) + +(type: Method + (#Static Static_Method) + (#Virtual Virtual_Method)) + +(def: common_method + (Parser Common_Method) + ($_ <>.and + <code>.local_identifier + (<>.maybe ..alias) + (<code>.tuple (<>.some ..nullable)) + (<>.parses? (<code>.this! (' #io))) + (<>.parses? (<code>.this! (' #try))) + ..nullable)) + +(def: static_method + (<>.after ..static! ..common_method)) + +(def: method + (Parser Method) + (<code>.form (<>.or ..static_method + ..common_method))) + +(type: Member + (#Field Field) + (#Method Method)) + +(def: member + (Parser Member) + ($_ <>.or + ..field + ..method + )) + +(def: input_variables + (-> (List Nullable) (List [Bit Code])) + (|>> list.enumeration + (list\map (function (_ [idx [nullable? type]]) + [nullable? (|> idx %.nat code.local_identifier)])))) + +(def: (nullable_type [nullable? type]) + (-> Nullable Code) + (if nullable? + (` (.Maybe (~ type))) + type)) + +(def: (with_null g!temp [nullable? input]) + (-> Code [Bit Code] Code) + (if nullable? + (` (case (~ input) + (#.Some (~ g!temp)) + (~ g!temp) + + #.Null + ("php object null"))) + input)) + +(def: (without_null g!temp [nullable? outputT] output) + (-> Code Nullable Code Code) + (if nullable? + (` (let [(~ g!temp) (~ output)] + (if ("php object null?" (~ g!temp)) + #.None + (#.Some (~ g!temp))))) + (` (let [(~ g!temp) (~ output)] + (if (not ("php object null?" (~ g!temp))) + (~ g!temp) + (.error! "Null is an invalid value!")))))) + +(type: Import + (#Class Text (Maybe Alias) (List Member)) + (#Function Static_Method) + (#Constant Field)) + +(def: import + (Parser Import) + ($_ <>.or + ($_ <>.and + <code>.local_identifier + (<>.maybe ..alias) + (<>.some member)) + (<code>.form ..common_method) + ..constant + )) + +(syntax: #export (try expression) + {#.doc (doc (case (try (risky_computation input)) + (#.Right success) + (do_something success) + + (#.Left error) + (recover_from_failure error)))} + (wrap (list (` ("lux try" ((~! io.io) (~ expression))))))) + +(def: (with_io with? without) + (-> Bit Code Code) + (if with? + (` (io.io (~ without))) + without)) + +(def: (io_type io? rawT) + (-> Bit Code Code) + (if io? + (` (io.IO (~ rawT))) + rawT)) + +(def: (with_try with? without_try) + (-> Bit Code Code) + (if with? + (` (..try (~ without_try))) + without_try)) + +(def: (try_type try? rawT) + (-> Bit Code Code) + (if try? + (` (.Either .Text (~ rawT))) + rawT)) + +(def: (make_function g!method g!temp source inputsT io? try? outputT) + (-> Code Code Code (List Nullable) Bit Bit Nullable Code) + (let [g!inputs (input_variables inputsT)] + (` (def: ((~ g!method) + [(~+ (list\map product.right g!inputs))]) + (-> [(~+ (list\map nullable_type inputsT))] + (~ (|> (nullable_type outputT) + (try_type try?) + (io_type io?)))) + (:assume + (~ (<| (with_io io?) + (with_try try?) + (without_null g!temp outputT) + (` ("php apply" + (:coerce ..Function (~ source)) + (~+ (list\map (with_null g!temp) g!inputs))))))))))) + +(syntax: #export (import: {import ..import}) + (with_gensyms [g!temp] + (case import + (#Class [class alias members]) + (with_gensyms [g!object] + (let [qualify (: (-> Text Code) + (|>> (format (maybe.default class alias) "::") code.local_identifier)) + g!type (code.local_identifier (maybe.default class alias)) + class_import (` ("php constant" (~ (code.text class))))] + (wrap (list& (` (type: (~ g!type) + (..Object (primitive (~ (code.text class)))))) + (list\map (function (_ member) + (case member + (#Field [static? field alias fieldT]) + (if static? + (` ((~! syntax:) ((~ (qualify (maybe.default field alias)))) + (\ (~! meta.monad) (~' wrap) + (list (` (.:coerce (~ (nullable_type fieldT)) + ("php constant" (~ (code.text (format class "::" field)))))))))) + (` (def: ((~ (qualify field)) + (~ g!object)) + (-> (~ g!type) + (~ (nullable_type fieldT))) + (:assume + (~ (without_null g!temp fieldT (` ("php object get" (~ (code.text field)) + (:coerce (..Object .Any) (~ g!object)))))))))) + + (#Method method) + (case method + (#Static [method alias inputsT io? try? outputT]) + (..make_function (qualify (maybe.default method alias)) + g!temp + (` ("php object get" (~ (code.text method)) + (:coerce (..Object .Any) + ("php constant" (~ (code.text (format class "::" method))))))) + inputsT + io? + try? + outputT) + + (#Virtual [method alias inputsT io? try? outputT]) + (let [g!inputs (input_variables inputsT)] + (` (def: ((~ (qualify (maybe.default method alias))) + [(~+ (list\map product.right g!inputs))] + (~ g!object)) + (-> [(~+ (list\map nullable_type inputsT))] + (~ g!type) + (~ (|> (nullable_type outputT) + (try_type try?) + (io_type io?)))) + (:assume + (~ (<| (with_io io?) + (with_try try?) + (without_null g!temp outputT) + (` ("php object do" + (~ (code.text method)) + (~ g!object) + (~+ (list\map (with_null g!temp) g!inputs))))))))))))) + members))))) + + (#Function [name alias inputsT io? try? outputT]) + (let [imported (` ("php constant" (~ (code.text name))))] + (wrap (list (..make_function (code.local_identifier (maybe.default name alias)) + g!temp + imported + inputsT + io? + try? + outputT)))) + + (#Constant [_ name alias fieldT]) + (let [imported (` ("php constant" (~ (code.text name))))] + (wrap (list (` ((~! syntax:) ((~ (code.local_identifier (maybe.default name alias)))) + (\ (~! meta.monad) (~' wrap) + (list (` (.:coerce (~ (nullable_type fieldT)) (~ imported)))))))))) + ))) diff --git a/stdlib/source/lux/math.lux b/stdlib/source/lux/math.lux index 7193b417f..420e0bc83 100644 --- a/stdlib/source/lux/math.lux +++ b/stdlib/source/lux/math.lux @@ -213,6 +213,38 @@ (def: #export (pow param subject) (-> Frac Frac Frac) (:coerce Frac ("ruby object do" "**" subject param)))) + + @.php + (as_is (template [<name> <method>] + [(def: #export <name> + (-> Frac Frac) + (|>> ("php apply" ("php constant" <method>)) + (:coerce Frac)))] + + [cos "cos"] + [sin "sin"] + [tan "tan"] + + [acos "acos"] + [asin "asin"] + [atan "atan"] + + [exp "exp"] + [log "log"] + + [ceil "ceil"] + [floor "floor"] + + [root/2 "sqrt"] + ) + + (def: #export (pow param subject) + (-> Frac Frac Frac) + (:coerce Frac ("php apply" ("php constant" "pow") subject param))) + + (def: #export root/3 + (-> Frac Frac) + (..pow ("lux f64 /" +3.0 +1.0)))) }) (def: #export (round input) diff --git a/stdlib/source/lux/math/random.lux b/stdlib/source/lux/math/random.lux index 68c33e91c..39fab5a29 100644 --- a/stdlib/source/lux/math/random.lux +++ b/stdlib/source/lux/math/random.lux @@ -4,10 +4,8 @@ [hash (#+ Hash)] [functor (#+ Functor)] [apply (#+ Apply)] - ["." monad (#+ do Monad)]] + ["." monad (#+ Monad do)]] [data - ["." product] - ["." maybe] ["." text (#+ Char) ("#\." monoid) ["." unicode #_ ["#" set]]] diff --git a/stdlib/source/lux/target/php.lux b/stdlib/source/lux/target/php.lux index 1b1b91e88..b1eb0b553 100644 --- a/stdlib/source/lux/target/php.lux +++ b/stdlib/source/lux/target/php.lux @@ -97,6 +97,7 @@ [Access [Location' Computation' Expression' Code]] [Constant [Location' Computation' Expression' Code]] [Global [Location' Computation' Expression' Code]] + [Label [Code]] ) (type: #export Argument @@ -113,9 +114,23 @@ (-> Text Var) (|>> (format "$") :abstraction)) - (def: #export constant - (-> Text Constant) - (|>> :abstraction)) + (template [<name> <type>] + [(def: #export <name> + (-> Text <type>) + (|>> :abstraction))] + + [constant Constant] + [label Label] + ) + + (def: #export (set_label label) + (-> Label Statement) + (:abstraction (format (:representation label) ":"))) + + (def: #export (go_to label) + (-> Label Statement) + (:abstraction + (format "goto " (:representation label) ..statement_suffix))) (def: #export null Literal @@ -129,7 +144,11 @@ (def: #export int (-> Int Literal) - (|>> %.int :abstraction)) + (.let [to_hex (\ n.hex encode)] + (|>> .nat + to_hex + (format "0x") + :abstraction))) (def: #export float (-> Frac Literal) @@ -160,6 +179,7 @@ [text.new_line "\n"] [text.carriage_return "\r"] [text.double_quote (format "\" text.double_quote)] + ["$" "\$"] )) ))) @@ -247,7 +267,8 @@ ["phpversion"]]] [1 - [["is_null"] + [["var_dump"] + ["is_null"] ["empty"] ["count"] ["array_pop"] @@ -262,7 +283,8 @@ ["iconv_strlen"] ["strlen"]]] [2 - [["call_user_func_array"] + [["intdiv"] + ["call_user_func_array"] ["array_slice"] ["array_push"] ["pack"] @@ -270,7 +292,8 @@ ["iconv_strpos"] ["strpos"]]] [3 - [["array_slice"] + [["array_fill"] + ["array_slice"] ["array_splice"] ["iconv"] ["iconv_strpos"] ["strpos"] @@ -309,9 +332,15 @@ (|> (format "new " (:representation constructor) (arguments inputs)) :abstraction)) + (def: #export (the field object) + (-> Text Expression Computation) + (|> (format (:representation object) "->" field) + :abstraction)) + (def: #export (do method inputs object) (-> Text (List Expression) Expression Computation) - (|> (format (:representation object) "->" method (arguments inputs)) + (|> (format (:representation (..the method object)) + (..arguments inputs)) :abstraction)) (def: #export (nth idx array) @@ -340,7 +369,8 @@ [or "||"] [and "&&"] - [= "==="] + [== "=="] + [=== "==="] [< "<"] [<= "<="] [> ">"] @@ -487,6 +517,10 @@ [break "break"] [continue "continue"] ) + + (def: #export splat + (-> Expression Expression) + (|>> :representation (format "...") :abstraction)) ) (def: #export (cond clauses else!) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/analysis/php.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/analysis/php.lux index 466c8daea..70437ea89 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/analysis/php.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/analysis/php.lux @@ -27,8 +27,176 @@ [/// ["." phase]]]]]]) +(def: array::new + Handler + (custom + [<c>.any + (function (_ extension phase archive lengthC) + (do phase.monad + [lengthA (analysis/type.with_type Nat + (phase archive lengthC)) + [var_id varT] (analysis/type.with_env check.var) + _ (analysis/type.infer (type (Array varT)))] + (wrap (#analysis.Extension extension (list lengthA)))))])) + +(def: array::length + Handler + (custom + [<c>.any + (function (_ extension phase archive arrayC) + (do phase.monad + [[var_id varT] (analysis/type.with_env check.var) + arrayA (analysis/type.with_type (type (Array varT)) + (phase archive arrayC)) + _ (analysis/type.infer Nat)] + (wrap (#analysis.Extension extension (list arrayA)))))])) + +(def: array::read + Handler + (custom + [(<>.and <c>.any <c>.any) + (function (_ extension phase archive [indexC arrayC]) + (do phase.monad + [indexA (analysis/type.with_type Nat + (phase archive indexC)) + [var_id varT] (analysis/type.with_env check.var) + arrayA (analysis/type.with_type (type (Array varT)) + (phase archive arrayC)) + _ (analysis/type.infer varT)] + (wrap (#analysis.Extension extension (list indexA arrayA)))))])) + +(def: array::write + Handler + (custom + [($_ <>.and <c>.any <c>.any <c>.any) + (function (_ extension phase archive [indexC valueC arrayC]) + (do phase.monad + [indexA (analysis/type.with_type Nat + (phase archive indexC)) + [var_id varT] (analysis/type.with_env check.var) + valueA (analysis/type.with_type varT + (phase archive valueC)) + arrayA (analysis/type.with_type (type (Array varT)) + (phase archive arrayC)) + _ (analysis/type.infer (type (Array varT)))] + (wrap (#analysis.Extension extension (list indexA valueA arrayA)))))])) + +(def: array::delete + Handler + (custom + [($_ <>.and <c>.any <c>.any) + (function (_ extension phase archive [indexC arrayC]) + (do phase.monad + [indexA (analysis/type.with_type Nat + (phase archive indexC)) + [var_id varT] (analysis/type.with_env check.var) + arrayA (analysis/type.with_type (type (Array varT)) + (phase archive arrayC)) + _ (analysis/type.infer (type (Array varT)))] + (wrap (#analysis.Extension extension (list indexA arrayA)))))])) + +(def: bundle::array + Bundle + (<| (bundle.prefix "array") + (|> bundle.empty + (bundle.install "new" array::new) + (bundle.install "length" array::length) + (bundle.install "read" array::read) + (bundle.install "write" array::write) + (bundle.install "delete" array::delete) + ))) + +(def: Null + (for {@.php host.Null} + Any)) + +(def: Object + (for {@.php (type (host.Object Any))} + Any)) + +(def: Function + (for {@.php host.Function} + Any)) + +(def: object::get + Handler + (custom + [($_ <>.and <c>.text <c>.any) + (function (_ extension phase archive [fieldC objectC]) + (do phase.monad + [objectA (analysis/type.with_type ..Object + (phase archive objectC)) + _ (analysis/type.infer .Any)] + (wrap (#analysis.Extension extension (list (analysis.text fieldC) + objectA)))))])) + +(def: object::do + Handler + (custom + [($_ <>.and <c>.text <c>.any (<>.some <c>.any)) + (function (_ extension phase archive [methodC objectC inputsC]) + (do {! phase.monad} + [objectA (analysis/type.with_type ..Object + (phase archive objectC)) + inputsA (monad.map ! (|>> (phase archive) (analysis/type.with_type Any)) inputsC) + _ (analysis/type.infer .Any)] + (wrap (#analysis.Extension extension (list& (analysis.text methodC) + objectA + inputsA)))))])) + +(def: bundle::object + Bundle + (<| (bundle.prefix "object") + (|> bundle.empty + (bundle.install "get" object::get) + (bundle.install "do" object::do) + (bundle.install "null" (/.nullary ..Null)) + (bundle.install "null?" (/.unary Any Bit)) + ))) + +(def: php::constant + Handler + (custom + [<c>.text + (function (_ extension phase archive name) + (do phase.monad + [_ (analysis/type.infer Any)] + (wrap (#analysis.Extension extension (list (analysis.text name))))))])) + +(def: php::apply + Handler + (custom + [($_ <>.and <c>.any (<>.some <c>.any)) + (function (_ extension phase archive [abstractionC inputsC]) + (do {! phase.monad} + [abstractionA (analysis/type.with_type ..Function + (phase archive abstractionC)) + inputsA (monad.map ! (|>> (phase archive) (analysis/type.with_type Any)) inputsC) + _ (analysis/type.infer Any)] + (wrap (#analysis.Extension extension (list& abstractionA inputsA)))))])) + +(def: php::pack + Handler + (custom + [($_ <>.and <c>.any <c>.any) + (function (_ extension phase archive [formatC dataC]) + (do {! phase.monad} + [formatA (analysis/type.with_type Text + (phase archive formatC)) + dataA (analysis/type.with_type (type (Array (I64 Any))) + (phase archive dataC)) + _ (analysis/type.infer Text)] + (wrap (#analysis.Extension extension (list formatA dataA)))))])) + (def: #export bundle Bundle (<| (bundle.prefix "php") (|> bundle.empty + (dictionary.merge bundle::array) + (dictionary.merge bundle::object) + + (bundle.install "constant" php::constant) + (bundle.install "apply" php::apply) + (bundle.install "pack" php::pack) + (bundle.install "script universe" (/.nullary .Bit)) ))) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/php/common.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/php/common.lux index 572f1f2a8..7dbc8bacc 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/php/common.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/php/common.lux @@ -13,6 +13,7 @@ ["%" format (#+ format)]] [collection ["." dictionary] + ["." set] ["." list ("#\." functor fold)]]] [math [number @@ -26,10 +27,12 @@ [generation [extension (#+ Nullary Unary Binary Trinary nullary unary binary trinary)] + ["." reference] ["//" php #_ - ["#." runtime (#+ Operation Phase Handler Bundle Generator)]]] + ["#." runtime (#+ Operation Phase Handler Bundle Generator)] + ["#." case]]] [// - [synthesis (#+ %synthesis)] + ["." synthesis (#+ %synthesis)] ["." generation] [/// ["#" phase]]]]]) @@ -50,45 +53,55 @@ (template: (!unary function) (|>> list _.apply/* (|> (_.constant function)))) -## ## TODO: Get rid of this ASAP -## (def: lux::syntax_char_case! -## (..custom [($_ <>.and -## <s>.any -## <s>.any -## (<>.some (<s>.tuple ($_ <>.and -## (<s>.tuple (<>.many <s>.i64)) -## <s>.any)))) -## (function (_ extension_name phase archive [input else conditionals]) -## (do {! /////.monad} -## [inputG (phase archive input) -## elseG (phase archive else) -## @input (\ ! map _.var (generation.gensym "input")) -## conditionalsG (: (Operation (List [Expression Expression])) -## (monad.map ! (function (_ [chars branch]) -## (do ! -## [branchG (phase archive branch)] -## (wrap [(|> chars -## (list\map (|>> .int _.int (_.= @input))) -## (list\fold (function (_ clause total) -## (if (is? _.nil total) -## clause -## (_.or clause total))) -## _.nil)) -## branchG]))) -## conditionals)) -## #let [closure (_.closure (list @input) -## (list\fold (function (_ [test then] else) -## (_.if test (_.return then) else)) -## (_.return elseG) -## conditionalsG))]] -## (wrap (_.apply/1 closure inputG))))])) +## TODO: Get rid of this ASAP +(def: lux::syntax_char_case! + (..custom [($_ <>.and + <s>.any + <s>.any + (<>.some (<s>.tuple ($_ <>.and + (<s>.tuple (<>.many <s>.i64)) + <s>.any)))) + (function (_ extension_name phase archive [input else conditionals]) + (do {! /////.monad} + [inputG (phase archive input) + [[context_module context_artifact] elseG] (generation.with_new_context archive + (phase archive else)) + @input (\ ! map _.var (generation.gensym "input")) + conditionalsG (: (Operation (List [Expression Expression])) + (monad.map ! (function (_ [chars branch]) + (do ! + [branchG (phase archive branch)] + (wrap [(|> chars + (list\map (|>> .int _.int (_.=== @input))) + (list\fold (function (_ clause total) + (if (is? _.null total) + clause + (_.or clause total))) + _.null)) + branchG]))) + conditionals)) + #let [foreigns (|> conditionals + (list\map (|>> product.right synthesis.path/then //case.dependencies)) + (list& (//case.dependencies (synthesis.path/then else))) + list.concat + (set.from_list _.hash) + set.to_list) + @expression (_.constant (reference.artifact [context_module context_artifact])) + directive (_.define_function @expression (list& (_.parameter @input) (list\map _.reference foreigns)) + (list\fold (function (_ [test then] else) + (_.if test (_.return then) else)) + (_.return elseG) + conditionalsG))] + _ (generation.execute! directive) + _ (generation.save! (%.nat context_artifact) directive)] + (wrap (_.apply/* (list& inputG foreigns) @expression))))])) (def: lux_procs Bundle (|> /.empty - ## (/.install "syntax char case!" lux::syntax_char_case!) - (/.install "is" (binary (product.uncurry _.=))) - ## (/.install "try" (unary //runtime.lux//try)) + (/.install "syntax char case!" lux::syntax_char_case!) + (/.install "is" (binary (product.uncurry _.===))) + (/.install "try" (unary //runtime.lux//try)) )) (def: i64_procs @@ -100,12 +113,13 @@ (/.install "xor" (binary (product.uncurry _.bit_xor))) (/.install "left-shift" (binary (product.uncurry _.bit_shl))) (/.install "right-shift" (binary (product.uncurry //runtime.i64//right_shift))) - (/.install "=" (binary (product.uncurry _.=))) + (/.install "=" (binary (product.uncurry _.==))) (/.install "+" (binary (product.uncurry _.+))) (/.install "-" (binary (product.uncurry _.-))) (/.install "<" (binary (product.uncurry _.<))) (/.install "*" (binary (product.uncurry _.*))) - (/.install "/" (binary (product.uncurry _./))) + (/.install "/" (binary (function (_ [parameter subject]) + (_.intdiv/2 [subject parameter])))) (/.install "%" (binary (product.uncurry _.%))) (/.install "f64" (unary (_./ (_.float +1.0)))) (/.install "char" (unary //runtime.i64//char)) @@ -124,7 +138,7 @@ (/.install "*" (binary (product.uncurry _.*))) (/.install "/" (binary (product.uncurry _./))) (/.install "%" (binary ..f64//%)) - (/.install "=" (binary (product.uncurry _.=))) + (/.install "=" (binary (product.uncurry _.==))) (/.install "<" (binary (product.uncurry _.<))) (/.install "i64" (unary _.intval/1)) (/.install "encode" (unary _.strval/1)) @@ -142,7 +156,7 @@ Bundle (<| (/.prefix "text") (|> /.empty - (/.install "=" (binary (product.uncurry _.=))) + (/.install "=" (binary (product.uncurry _.==))) (/.install "<" (binary (product.uncurry _.<))) (/.install "concat" (binary (product.uncurry (function.flip _.concat)))) (/.install "index" (trinary ..text//index)) @@ -151,11 +165,6 @@ (/.install "clip" (trinary ..text//clip)) ))) -(def: io//log! - (Unary Expression) - (|>> _.print/1 - (_.or //runtime.unit))) - (def: io//current-time (Nullary Expression) (|>> _.time/0 @@ -165,7 +174,7 @@ Bundle (<| (/.prefix "io") (|> /.empty - (/.install "log" (unary ..io//log!)) + (/.install "log" (unary //runtime.io//log!)) (/.install "error" (unary //runtime.io//throw!)) (/.install "current-time" (nullary ..io//current-time))))) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/php/host.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/php/host.lux index fef37539e..f523f1647 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/php/host.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/php/host.lux @@ -32,168 +32,106 @@ ["//#" /// #_ ["#." phase]]]]]]) -## (def: array::new -## (Unary Expression) -## (|>> ["n"] list _.table)) - -## (def: array::length -## (Unary Expression) -## (_.the "n")) - -## (def: (array::read [indexG arrayG]) -## (Binary Expression) -## (_.nth (_.+ (_.int +1) indexG) arrayG)) - -## (def: (array::write [indexG valueG arrayG]) -## (Trinary Expression) -## (//runtime.array//write indexG valueG arrayG)) - -## (def: (array::delete [indexG arrayG]) -## (Binary Expression) -## (//runtime.array//write indexG _.nil arrayG)) - -## (def: array -## Bundle -## (<| (/.prefix "array") -## (|> /.empty -## (/.install "new" (unary array::new)) -## (/.install "length" (unary array::length)) -## (/.install "read" (binary array::read)) -## (/.install "write" (trinary array::write)) -## (/.install "delete" (binary array::delete)) -## ))) - -## (def: object::get -## Handler -## (custom -## [($_ <>.and <s>.text <s>.any) -## (function (_ extension phase archive [fieldS objectS]) -## (do ////////phase.monad -## [objectG (phase archive objectS)] -## (wrap (_.the fieldS objectG))))])) - -## (def: object::do -## Handler -## (custom -## [($_ <>.and <s>.text <s>.any (<>.some <s>.any)) -## (function (_ extension phase archive [methodS objectS inputsS]) -## (do {! ////////phase.monad} -## [objectG (phase archive objectS) -## inputsG (monad.map ! (phase archive) inputsS)] -## (wrap (_.do methodS inputsG objectG))))])) - -## (template [<!> <?> <unit>] -## [(def: <!> (Nullary Expression) (function.constant <unit>)) -## (def: <?> (Unary Expression) (_.= <unit>))] - -## [object::nil object::nil? _.nil] -## ) - -## (def: object -## Bundle -## (<| (/.prefix "object") -## (|> /.empty -## (/.install "get" object::get) -## (/.install "do" object::do) -## (/.install "nil" (nullary object::nil)) -## (/.install "nil?" (unary object::nil?)) -## ))) - -## (def: $input -## (_.var "input")) - -## (def: utf8::encode -## (custom -## [<s>.any -## (function (_ extension phase archive inputS) -## (do {! ////////phase.monad} -## [inputG (phase archive inputS)] -## (wrap (_.apply/1 (<| (_.closure (list $input)) -## (_.return (|> (_.var "string.byte") -## (_.apply/* (list $input (_.int +1) (_.length $input))) -## (_.apply/1 (_.var "table.pack"))))) -## inputG))))])) - -## (def: utf8::decode -## (custom -## [<s>.any -## (function (_ extension phase archive inputS) -## (do {! ////////phase.monad} -## [inputG (phase archive inputS)] -## (wrap (|> inputG -## (_.apply/1 (_.var "table.unpack")) -## (_.apply/1 (_.var "string.char"))))))])) - -## (def: utf8 -## Bundle -## (<| (/.prefix "utf8") -## (|> /.empty -## (/.install "encode" utf8::encode) -## (/.install "decode" utf8::decode) -## ))) - -## (def: lua::constant -## (custom -## [<s>.text -## (function (_ extension phase archive name) -## (\ ////////phase.monad wrap (_.var name)))])) - -## (def: lua::apply -## (custom -## [($_ <>.and <s>.any (<>.some <s>.any)) -## (function (_ extension phase archive [abstractionS inputsS]) -## (do {! ////////phase.monad} -## [abstractionG (phase archive abstractionS) -## inputsG (monad.map ! (phase archive) inputsS)] -## (wrap (_.apply/* inputsG abstractionG))))])) - -## (def: lua::power -## (custom -## [($_ <>.and <s>.any <s>.any) -## (function (_ extension phase archive [powerS baseS]) -## (do {! ////////phase.monad} -## [powerG (phase archive powerS) -## baseG (phase archive baseS)] -## (wrap (_.^ powerG baseG))))])) - -## (def: lua::import -## (custom -## [<s>.text -## (function (_ extension phase archive module) -## (\ ////////phase.monad wrap -## (_.require/1 (_.string module))))])) - -## (def: lua::function -## (custom -## [($_ <>.and <s>.i64 <s>.any) -## (function (_ extension phase archive [arity abstractionS]) -## (do {! ////////phase.monad} -## [abstractionG (phase archive abstractionS) -## #let [variable (: (-> Text (Operation Var)) -## (|>> generation.gensym -## (\ ! map _.var)))] -## g!inputs (monad.map ! (function (_ _) -## (variable "input")) -## (list.repeat (.nat arity) []))] -## (wrap (<| (_.closure g!inputs) -## _.statement -## (case (.nat arity) -## 0 (_.apply/1 abstractionG //runtime.unit) -## 1 (_.apply/* g!inputs abstractionG) -## _ (_.apply/1 abstractionG (_.array g!inputs)))))))])) +(def: (array::new size) + (Unary Expression) + (//runtime.tuple//make size (_.array_fill/3 [(_.int +0) size _.null]))) + +(def: array::length + (Unary Expression) + //runtime.array//length) + +(def: (array::read [indexG arrayG]) + (Binary Expression) + (_.nth indexG arrayG)) + +(def: (array::write [indexG valueG arrayG]) + (Trinary Expression) + (//runtime.array//write indexG valueG arrayG)) + +(def: (array::delete [indexG arrayG]) + (Binary Expression) + (//runtime.array//write indexG _.null arrayG)) + +(def: array + Bundle + (<| (/.prefix "array") + (|> /.empty + (/.install "new" (unary array::new)) + (/.install "length" (unary array::length)) + (/.install "read" (binary array::read)) + (/.install "write" (trinary array::write)) + (/.install "delete" (binary array::delete)) + ))) + +(def: object::get + Handler + (custom + [($_ <>.and <s>.text <s>.any) + (function (_ extension phase archive [fieldS objectS]) + (do ////////phase.monad + [objectG (phase archive objectS)] + (wrap (_.the fieldS objectG))))])) + +(def: object::do + Handler + (custom + [($_ <>.and <s>.text <s>.any (<>.some <s>.any)) + (function (_ extension phase archive [methodS objectS inputsS]) + (do {! ////////phase.monad} + [objectG (phase archive objectS) + inputsG (monad.map ! (phase archive) inputsS)] + (wrap (_.do methodS inputsG objectG))))])) + +(template [<!> <?> <unit>] + [(def: <!> (Nullary Expression) (function.constant <unit>)) + (def: <?> (Unary Expression) (_.=== <unit>))] + + [object::null object::null? _.null] + ) + +(def: object + Bundle + (<| (/.prefix "object") + (|> /.empty + (/.install "get" object::get) + (/.install "do" object::do) + (/.install "null" (nullary object::null)) + (/.install "null?" (unary object::null?)) + ))) + +(def: php::constant + (custom + [<s>.text + (function (_ extension phase archive name) + (\ ////////phase.monad wrap (_.constant name)))])) + +(def: php::apply + (custom + [($_ <>.and <s>.any (<>.some <s>.any)) + (function (_ extension phase archive [abstractionS inputsS]) + (do {! ////////phase.monad} + [abstractionG (phase archive abstractionS) + inputsG (monad.map ! (phase archive) inputsS)] + (wrap (_.apply/* inputsG abstractionG))))])) + +(def: php::pack + (custom + [($_ <>.and <s>.any <s>.any) + (function (_ extension phase archive [formatS dataS]) + (do {! ////////phase.monad} + [formatG (phase archive formatS) + dataG (phase archive dataS)] + (wrap (_.pack/2 [formatG (_.splat dataG)]))))])) (def: #export bundle Bundle (<| (/.prefix "php") (|> /.empty - ## (dictionary.merge ..array) - ## (dictionary.merge ..object) - ## (dictionary.merge ..utf8) - - ## (/.install "constant" lua::constant) - ## (/.install "apply" lua::apply) - ## (/.install "power" lua::power) - ## (/.install "import" lua::import) - ## (/.install "function" lua::function) - ## (/.install "script universe" (nullary (function.constant (_.bool reference.universe)))) + (dictionary.merge ..array) + (dictionary.merge ..object) + + (/.install "constant" php::constant) + (/.install "apply" php::apply) + (/.install "pack" php::pack) + (/.install "script universe" (nullary (function.constant (_.bool reference.universe)))) ))) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php.lux index c310de4a9..654c07bdf 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php.lux @@ -20,39 +20,83 @@ ["#." extension] ["/#" // #_ [analysis (#+)] - ["." synthesis] + ["#." synthesis] ["//#" /// #_ ["#." phase ("#\." monad)] [reference (#+) [variable (#+)]]]]]]]) -(def: #export (generate archive synthesis) +(def: (statement expression archive synthesis) + Phase! + (case synthesis + (^template [<tag>] + [(^ (<tag> value)) + (//////phase\map _.return (expression archive synthesis))]) + ([////synthesis.bit] + [////synthesis.i64] + [////synthesis.f64] + [////synthesis.text] + [////synthesis.variant] + [////synthesis.tuple] + [#////synthesis.Reference] + [////synthesis.branch/get] + [////synthesis.function/apply] + [#////synthesis.Extension]) + + (^ (////synthesis.branch/case case)) + (/case.case! statement expression archive case) + + (^template [<tag> <generator>] + [(^ (<tag> value)) + (<generator> statement expression archive value)]) + ([////synthesis.branch/let /case.let!] + [////synthesis.branch/if /case.if!] + [////synthesis.loop/scope /loop.scope!] + [////synthesis.loop/recur /loop.recur!]) + + (^ (////synthesis.function/abstraction abstraction)) + (//////phase\map _.return (/function.function statement expression archive abstraction)) + )) + +(exception: #export cannot-recur-as-an-expression) + +(def: #export (expression archive synthesis) Phase (case synthesis (^template [<tag> <generator>] [(^ (<tag> value)) (//////phase\wrap (<generator> value))]) - ([synthesis.bit /primitive.bit] - [synthesis.i64 /primitive.i64] - [synthesis.f64 /primitive.f64] - [synthesis.text /primitive.text]) + ([////synthesis.bit /primitive.bit] + [////synthesis.i64 /primitive.i64] + [////synthesis.f64 /primitive.f64] + [////synthesis.text /primitive.text]) - (#synthesis.Reference value) + (#////synthesis.Reference value) (//reference.reference /reference.system archive value) (^template [<tag> <generator>] [(^ (<tag> value)) - (<generator> generate archive value)]) - ([synthesis.variant /structure.variant] - [synthesis.tuple /structure.tuple] - [synthesis.branch/case /case.case] - [synthesis.branch/let /case.let] - [synthesis.branch/if /case.if] - [synthesis.branch/get /case.get] - [synthesis.loop/scope /loop.scope] - [synthesis.loop/recur /loop.recur] - [synthesis.function/apply /function.apply] - [synthesis.function/abstraction /function.function]) - - (#synthesis.Extension extension) - (///extension.apply archive generate extension))) + (<generator> expression archive value)]) + ([////synthesis.variant /structure.variant] + [////synthesis.tuple /structure.tuple] + [////synthesis.branch/let /case.let] + [////synthesis.branch/if /case.if] + [////synthesis.branch/get /case.get] + [////synthesis.function/apply /function.apply]) + + (^template [<tag> <generator>] + [(^ (<tag> value)) + (<generator> statement expression archive value)]) + ([////synthesis.branch/case /case.case] + [////synthesis.loop/scope /loop.scope] + [////synthesis.function/abstraction /function.function]) + + (^ (////synthesis.loop/recur _)) + (//////phase.throw ..cannot-recur-as-an-expression []) + + (#////synthesis.Extension extension) + (///extension.apply archive expression extension))) + +(def: #export generate + Phase + ..expression) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/case.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/case.lux index b04d8e766..419c0ed2f 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/case.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/case.lux @@ -41,20 +41,47 @@ (-> Register Var) (|>> (///reference.foreign //reference.system) :assume)) -(def: #export (let generate archive [valueS register bodyS]) +(def: #export (let expression archive [valueS register bodyS]) (Generator [Synthesis Register Synthesis]) (do ///////phase.monad - [valueG (generate archive valueS) - bodyG (generate archive bodyS)] + [valueG (expression archive valueS) + bodyG (expression archive bodyS)] (wrap (|> bodyG (list (_.set (..register register) valueG)) _.array/* (_.nth (_.int +1)))))) -(def: #export (get generate archive [pathP valueS]) +(def: #export (let! statement expression archive [valueS register bodyS]) + (Generator! [Synthesis Register Synthesis]) + (do ///////phase.monad + [valueO (expression archive valueS) + body! (statement expression archive bodyS)] + (wrap ($_ _.then + (_.; (_.set (..register register) valueO)) + body!)))) + +(def: #export (if expression archive [testS thenS elseS]) + (Generator [Synthesis Synthesis Synthesis]) + (do ///////phase.monad + [testG (expression archive testS) + thenG (expression archive thenS) + elseG (expression archive elseS)] + (wrap (_.? testG thenG elseG)))) + +(def: #export (if! statement expression archive [testS thenS elseS]) + (Generator! [Synthesis Synthesis Synthesis]) + (do ///////phase.monad + [test! (expression archive testS) + then! (statement expression archive thenS) + else! (statement expression archive elseS)] + (wrap (_.if test! + then! + else!)))) + +(def: #export (get expression archive [pathP valueS]) (Generator [(List Member) Synthesis]) (do ///////phase.monad - [valueG (generate archive valueS)] + [valueG (expression archive valueS)] (wrap (list\fold (function (_ side source) (.let [method (.case side (^template [<side> <accessor>] @@ -64,15 +91,7 @@ [#.Right //runtime.tuple//right]))] (method source))) valueG - pathP)))) - -(def: #export (if generate archive [testS thenS elseS]) - (Generator [Synthesis Synthesis Synthesis]) - (do ///////phase.monad - [testG (generate archive testS) - thenG (generate archive thenS) - elseG (generate archive elseS)] - (wrap (_.? testG thenG elseG)))) + (list.reverse pathP))))) (def: @savepoint (_.var "lux_pm_savepoint")) (def: @cursor (_.var "lux_pm_cursor")) @@ -139,12 +158,12 @@ ..restore! post!))) -(def: (pattern_matching' generate archive) - (-> Phase Archive Path (Operation Statement)) +(def: (pattern_matching' statement expression archive) + (Generator! Path) (function (recur pathP) (.case pathP (#/////synthesis.Then bodyS) - (\ ///////phase.monad map _.return (generate archive bodyS)) + (statement expression archive bodyS) #/////synthesis.Pop (///////phase\wrap ..pop!) @@ -175,8 +194,8 @@ [clauses (monad.map ! (function (_ [match then]) (do ! [then! (recur then)] - (wrap [(_.= (|> match <format>) - ..peek) + (wrap [(_.=== (|> match <format>) + ..peek) then!]))) (#.Cons cons))] (wrap (_.cond clauses ..fail!)))]) @@ -228,10 +247,10 @@ ([/////synthesis.path/seq _.then] [/////synthesis.path/alt ..alternation])))) -(def: (pattern_matching generate archive pathP) - (-> Phase Archive Path (Operation Statement)) +(def: (pattern_matching statement expression archive pathP) + (Generator! Path) (do ///////phase.monad - [iteration! (pattern_matching' generate archive pathP)] + [iteration! (pattern_matching' statement expression archive pathP)] (wrap ($_ _.then (_.do_while (_.bool false) iteration!) @@ -254,20 +273,25 @@ (#///////variable.Foreign register) (..capture register)))))) -(def: #export (case generate archive [valueS pathP]) - (Generator [Synthesis Path]) +(def: #export (case! statement expression archive [valueS pathP]) + (Generator! [Synthesis Path]) + (do ///////phase.monad + [stack_init (expression archive valueS) + pattern_matching! (pattern_matching statement expression archive pathP)] + (wrap ($_ _.then + (_.; (_.set @cursor (_.array/* (list stack_init)))) + (_.; (_.set @savepoint (_.array/* (list)))) + pattern_matching!)))) + +(def: #export (case statement expression archive [valueS pathP]) + (-> Phase! (Generator [Synthesis Path])) (do {! ///////phase.monad} - [initG (generate archive valueS) - [[case_module case_artifact] pattern_matching!] (/////generation.with_new_context archive - (pattern_matching generate archive pathP)) + [[[case_module case_artifact] case!] (/////generation.with_new_context archive + (case! statement expression archive [valueS pathP])) #let [@case (_.constant (///reference.artifact [case_module case_artifact])) @dependencies+ (..dependencies (/////synthesis.path/seq (/////synthesis.path/then valueS) pathP)) - directive (<| (_.define_function @case (list\map _.parameter @dependencies+)) - ($_ _.then - (_.; (_.set @cursor (_.array/* (list initG)))) - (_.; (_.set @savepoint (_.array/* (list)))) - pattern_matching!))] + directive (_.define_function @case (list\map _.parameter @dependencies+) case!)] _ (/////generation.execute! directive) _ (/////generation.save! (%.nat case_artifact) directive)] (wrap (_.apply/* @dependencies+ @case)))) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/function.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/function.lux index 66d9eb37d..c6fa5687c 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/function.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/function.lux @@ -11,7 +11,7 @@ [collection ["." list ("#\." functor fold)]]] [target - ["_" php (#+ Var Global Expression Argument Statement)]]] + ["_" php (#+ Var Global Expression Argument Label Statement)]]] ["." // #_ ["#." runtime (#+ Operation Phase Phase! Generator)] ["#." reference] @@ -42,6 +42,10 @@ (def: input (|>> inc //case.register)) +(def: (@scope function_name) + (-> Context Label) + (_.label (format (///reference.artifact function_name) "_scope"))) + (def: (with_closure inits @selfG @selfL body!) (-> (List Expression) Global Var Statement [Statement Expression]) (case inits @@ -53,28 +57,29 @@ _ (let [@inits (|> (list.enumeration inits) - (list\map (|>> product.left ..capture _.reference)))] - [(_.; (_.set @selfG (_.closure (list) @inits + (list\map (|>> product.left ..capture)))] + [(_.; (_.set @selfG (_.closure (list) (list\map _.parameter @inits) ($_ _.then - (_.; (_.set @selfL (_.closure (list& (_.reference @selfL) @inits) + (_.; (_.set @selfL (_.closure (list& (_.reference @selfL) (list\map _.reference @inits)) (list) body!))) (_.return @selfL))))) (_.apply/* inits @selfG)]))) -(def: #export (function expression archive [environment arity bodyS]) - (Generator (Abstraction Synthesis)) +(def: #export (function statement expression archive [environment arity bodyS]) + (-> Phase! (Generator (Abstraction Synthesis))) (do {! ///////phase.monad} - [[function_name bodyG] (/////generation.with_new_context archive + [[function_name body!] (/////generation.with_new_context archive (do ! - [function_name (\ ! map ///reference.artifact - (/////generation.context archive))] - (/////generation.with_anchor (_.global function_name) - (expression archive bodyS)))) + [@scope (\ ! map ..@scope + (/////generation.context archive))] + (/////generation.with_anchor [1 @scope] + (statement expression archive bodyS)))) closureG+ (monad.map ! (expression archive) environment) #let [@curried (_.var "curried") arityG (|> arity .int _.int) @num_args (_.var "num_args") + @scope (..@scope function_name) @selfG (_.global (///reference.artifact function_name)) @selfL (_.var (///reference.artifact function_name)) initialize_self! (_.; (_.set (//case.register 0) @selfL)) @@ -88,10 +93,11 @@ ($_ _.then (_.; (_.set @num_args (_.func_num_args/0 []))) (_.; (_.set @curried (_.func_get_args/0 []))) - (_.cond (list [(|> @num_args (_.= arityG)) + (_.cond (list [(|> @num_args (_.=== arityG)) ($_ _.then initialize! - (_.return bodyG))] + (_.set_label @scope) + body!)] [(|> @num_args (_.> arityG)) (let [arity_inputs (_.array_slice/3 [@curried (_.int +0) arityG]) extra_inputs (_.array_slice/2 [@curried arityG]) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/loop.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/loop.lux index cdac65275..30e325363 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/loop.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/loop.lux @@ -4,16 +4,16 @@ ["." monad (#+ do)]] [data ["." product] - [text + ["." text ["%" format (#+ format)]] [collection - ["." list ("#\." functor)] + ["." list ("#\." functor fold)] ["." set]]] [math [number ["n" nat]]] [target - ["_" php (#+ Var Expression Statement)]]] + ["_" php (#+ Var Expression Label Statement)]]] ["." // #_ [runtime (#+ Operation Phase Phase! Generator Generator!)] ["#." case] @@ -32,8 +32,41 @@ [reference [variable (#+ Register)]]]]]]]) -(def: #export (scope expression archive [start initsS+ bodyS]) - (Generator (Scope Synthesis)) +(def: @scope + (-> Nat Label) + (|>> %.nat (format "scope") _.label)) + +(def: (setup offset bindings body) + (-> Register (List Expression) Statement Statement) + (|> bindings + list.enumeration + (list\map (function (_ [register value]) + (let [variable (//case.register (n.+ offset register))] + (_.; (_.set variable value))))) + list.reverse + (list\fold _.then body))) + +(def: #export (scope! statement expression archive [start initsS+ bodyS]) + (Generator! (Scope Synthesis)) + (case initsS+ + ## function/false/non-independent loop + #.Nil + (statement expression archive bodyS) + + ## true loop + _ + (do {! ///////phase.monad} + [@scope (\ ! map ..@scope /////generation.next) + initsO+ (monad.map ! (expression archive) initsS+) + body! (/////generation.with_anchor [start @scope] + (statement expression archive bodyS))] + (wrap (..setup start initsO+ + ($_ _.then + (_.set_label @scope) + body!)))))) + +(def: #export (scope statement expression archive [start initsS+ bodyS]) + (-> Phase! (Generator (Scope Synthesis))) (case initsS+ ## function/false/non-independent loop #.Nil @@ -42,15 +75,12 @@ ## true loop _ (do {! ///////phase.monad} - [initsO+ (monad.map ! (expression archive) initsS+) - [[loop_module loop_artifact] bodyO] (/////generation.with_new_context archive - (do ! - [loop_context (/////generation.context archive)] - (/////generation.with_anchor (_.var (///reference.artifact loop_context)) - (expression archive bodyS)))) + [[[loop_module loop_artifact] scope!] (/////generation.with_new_context archive + (..scope! statement expression archive [start initsS+ bodyS])) #let [locals (|> initsS+ list.enumeration (list\map (|>> product.left (n.+ start) //case.register _.parameter))) + @loop (_.constant (///reference.artifact [loop_module loop_artifact])) [directive instantiation] (: [Statement Expression] (case (|> (synthesis.path/then bodyS) //case.dependencies @@ -58,30 +88,30 @@ (set.difference (set.from_list _.hash (list\map product.right locals))) set.to_list) #.Nil - (let [@loop (_.var (///reference.artifact [loop_module loop_artifact]))] - [(_.; (_.set @loop - (_.closure (list (_.reference @loop)) - locals - (_.return bodyO)))) - @loop]) + [(_.define_function @loop (list) scope!) + @loop] foreigns - (let [@loop (_.constant (///reference.artifact [loop_module loop_artifact]))] - [(<| (_.define_function @loop (list\map _.parameter foreigns)) - (let [@loop (_.var (///reference.artifact [loop_module loop_artifact]))] - (_.return (_.set @loop - (_.closure (list& (_.reference @loop) - (list\map _.reference foreigns)) - locals - (_.return bodyO)))))) - (_.apply/* foreigns @loop)])))] + [(<| (_.define_function @loop (list\map _.parameter foreigns)) + (_.return (_.closure (list\map _.parameter foreigns) (list) scope!))) + (_.apply/* foreigns @loop)]))] _ (/////generation.execute! directive) _ (/////generation.save! (%.nat loop_artifact) directive)] - (wrap (_.apply/* initsO+ instantiation))))) + (wrap (_.apply/* (list) instantiation))))) + +(def: @temp + (_.var "lux_recur_values")) -(def: #export (recur expression archive argsS+) - (Generator (List Synthesis)) +(def: #export (recur! statement expression archive argsS+) + (Generator! (List Synthesis)) (do {! ///////phase.monad} - [@scope /////generation.anchor + [[offset @scope] /////generation.anchor argsO+ (monad.map ! (expression archive) argsS+)] - (wrap (_.apply/* argsO+ @scope)))) + (wrap ($_ _.then + (_.; (_.set @temp (_.array/* argsO+))) + (..setup offset + (|> argsO+ + list.enumeration + (list\map (function (_ [idx _]) + (_.nth (_.int (.int idx)) @temp)))) + (_.go_to @scope)))))) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/runtime.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/runtime.lux index 7b3e55481..5e1c36112 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/runtime.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/runtime.lux @@ -22,7 +22,7 @@ [number (#+ hex) ["." i64]]] ["@" target - ["_" php (#+ Expression Location Constant Var Computation Literal Statement)]]] + ["_" php (#+ Expression Label Constant Var Computation Literal Statement)]]] ["." /// #_ ["#." reference] ["//#" /// #_ @@ -38,7 +38,7 @@ (template [<name> <base>] [(type: #export <name> - (<base> Location Expression Statement))] + (<base> [Nat Label] Expression Statement))] [Operation /////generation.Operation] [Phase /////generation.Phase] @@ -128,6 +128,12 @@ (list (~+ (list\map (|>> (~) [false] (`)) inputsC))) (~ code)))))))))))))))) +(runtime: (io//log! message) + ($_ _.then + (_.echo message) + (_.echo (_.string text.new_line)) + (_.return ..unit))) + (runtime: (io//throw! message) ($_ _.then (_.throw (_.new (_.constant "Exception") (list message))) @@ -136,15 +142,39 @@ (def: runtime//io Statement ($_ _.then + @io//log! @io//throw! )) (def: #export tuple_size_field "_lux_size") -(def: tuple_size +(def: #export tuple_size (_.nth (_.string ..tuple_size_field))) +(def: jphp? + (_.=== (_.string "5.6.99") (_.phpversion/0 []))) + +(runtime: (array//length array) + ## TODO: Get rid of this as soon as JPHP is no longer necessary. + (_.if ..jphp? + (_.if (..tuple_size array) + (_.return (..tuple_size array)) + (_.return (_.count/1 array))) + (_.return (_.count/1 array)))) + +(runtime: (array//write idx value array) + ($_ _.then + (_.; (_.set (_.nth idx array) value)) + (_.return array))) + +(def: runtime//array + Statement + ($_ _.then + @array//length + @array//write + )) + (def: last_index (|>> ..tuple_size (_.- (_.int +1)))) @@ -167,20 +197,37 @@ ## Needs recursion <recur>))))) + ## TODO: Get rid of this as soon as JPHP is no longer necessary. + (runtime: (tuple//slice offset input) + (with_vars [size index output] + ($_ _.then + (_.; (_.set size (..array//length input))) + (_.; (_.set index (_.int +0))) + (_.; (_.set output (_.array/* (list)))) + (<| (_.while (|> index (_.+ offset) (_.< size))) + ($_ _.then + (_.; (_.set (_.nth index output) (_.nth (_.+ offset index) input))) + (_.; (_.set index (_.+ (_.int +1) index))) + )) + (_.return (..tuple//make (_.- offset size) output)) + ))) + (runtime: (tuple//right lefts tuple) (with_vars [last_index_right right_index] (<| (_.while (_.bool true)) ($_ _.then (_.; (_.set last_index_right (..last_index tuple))) (_.; (_.set right_index (_.+ (_.int +1) lefts))) - (_.cond (list [(_.= last_index_right right_index) + (_.cond (list [(_.=== last_index_right right_index) (_.return (_.nth right_index tuple))] [(_.> last_index_right right_index) ## Needs recursion. <recur>]) - ($_ _.then - (_.echo (_.string (format "[tuple//right] _.array_slice/2" text.new_line))) - (_.return (_.array_slice/2 [tuple right_index])))) + (_.if ..jphp? + (_.return (..tuple//make (_.- right_index (..tuple_size tuple)) + (..tuple//slice right_index tuple))) + (_.return (..tuple//make (_.- right_index (..tuple_size tuple)) + (_.array_slice/2 [tuple right_index]))))) ))))) (def: #export variant_tag_field "_lux_tag") @@ -222,7 +269,7 @@ ## sum_flag (_.nth (_.int +1) sum) sum_value (_.nth (_.string ..variant_value_field) sum) ## sum_value (_.nth (_.int +2) sum) - is_last? (_.= ..unit sum_flag) + is_last? (_.=== ..unit sum_flag) test_recursion! (_.if is_last? ## Must recurse. ($_ _.then @@ -230,15 +277,15 @@ (_.; (_.set sum sum_value))) no_match!)] (<| (_.while (_.bool true)) - (_.cond (list [(_.= sum_tag wantedTag) - (_.if (_.= wantsLast sum_flag) + (_.cond (list [(_.=== sum_tag wantedTag) + (_.if (_.=== wantsLast sum_flag) (_.return sum_value) test_recursion!)] [(_.< wantedTag sum_tag) test_recursion!] - [(_.= ..unit wantsLast) + [(_.=== ..unit wantsLast) (_.return (sum//make (_.- wantedTag sum_tag) sum_flag sum_value))]) no_match!)))) @@ -247,6 +294,7 @@ ($_ _.then @tuple//make @tuple//left + @tuple//slice @tuple//right @sum//make @sum//get @@ -281,12 +329,13 @@ (let [mask (|> (_.int +1) (_.bit_shl (_.- param (_.int +64))) (_.- (_.int +1)))] - (_.return (|> subject - (_.bit_and mask) - (_.bit_shr param))))) - -(def: jphp? - (_.= (_.string "5.6.99") (_.phpversion/0 []))) + ($_ _.then + (_.; (_.set param (_.bit_and (_.int +63) param))) + (_.if (_.=== (_.int +0) param) + (_.return subject) + (_.return (|> subject + (_.bit_and mask) + (_.bit_shr param))))))) (runtime: (i64//char code) (_.if ..jphp? @@ -314,12 +363,12 @@ (_.if ..jphp? ($_ _.then (_.; (_.set idx (_.strpos/3 [subject param start]))) - (_.if (_.= (_.bool false) idx) + (_.if (_.=== (_.bool false) idx) (_.return ..none) (_.return (..some idx)))) ($_ _.then (_.; (_.set idx (_.iconv_strpos/3 [subject param start]))) - (_.if (_.= (_.bool false) idx) + (_.if (_.=== (_.bool false) idx) (_.return ..none) (_.return (..some idx))))))) @@ -335,15 +384,14 @@ (runtime: (text//char idx text) (_.if (|> idx (within? (text//size text))) - (let [code_point (: (-> Expression Computation) - (|>> [(_.string "UTF-8") (_.string "UTF-32LE")] - _.iconv/3 - [(_.string "V")] - _.unpack/2 - (_.nth (_.int +1))))] - (_.if ..jphp? - (_.return (code_point (_.substr/3 [text idx (_.int +1)]))) - (_.return (code_point (_.iconv_substr/3 [text idx (_.int +1)]))))) + (_.if ..jphp? + (_.return (_.ord/1 (_.substr/3 [text idx (_.int +1)]))) + (_.return (|> (_.iconv_substr/3 [text idx (_.int +1)]) + [(_.string "UTF-8") (_.string "UTF-32LE")] + _.iconv/3 + [(_.string "V")] + _.unpack/2 + (_.nth (_.int +1))))) (_.throw (_.new (_.constant "Exception") (list (_.string "[Lux Error] Cannot get char from text.")))))) (def: runtime//text @@ -359,14 +407,14 @@ (with_vars [output] ($_ _.then (_.; (_.set output (_.floatval/1 value))) - (_.if (_.= (_.float +0.0) output) + (_.if (_.=== (_.float +0.0) output) (_.if ($_ _.or - (_.= (_.string "0.0") output) - (_.= (_.string "+0.0") output) - (_.= (_.string "-0.0") output) - (_.= (_.string "0") output) - (_.= (_.string "+0") output) - (_.= (_.string "-0") output)) + (_.=== (_.string "0.0") output) + (_.=== (_.string "+0.0") output) + (_.=== (_.string "-0.0") output) + (_.=== (_.string "0") output) + (_.=== (_.string "+0") output) + (_.=== (_.string "-0") output)) (_.return (..some output)) (_.return ..none)) (_.return (..some output))) @@ -380,7 +428,7 @@ (def: check_necessary_conditions! Statement - (let [i64_support? (_.= (_.int +8) (_.constant "PHP_INT_SIZE")) + (let [i64_support? (_.=== (_.int +8) (_.constant "PHP_INT_SIZE")) i64_error (_.string (format "Cannot run program!" text.new_line "Lux/PHP programs require 64-bit PHP builds!"))] (_.when (_.not i64_support?) @@ -390,6 +438,7 @@ Statement ($_ _.then check_necessary_conditions! + runtime//array runtime//adt runtime//lux runtime//i64 diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/structure.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/structure.lux index 307417c6c..ed4fe4ae1 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/structure.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/structure.lux @@ -2,6 +2,9 @@ [lux #* [abstract ["." monad (#+ do)]] + [data + [collection + ["." list]]] [target ["_" php (#+ Expression)]]] ["." // #_ @@ -23,9 +26,13 @@ (generate archive singletonS) _ - (|> elemsS+ - (monad.map ///////phase.monad (generate archive)) - (///////phase\map _.array/*)))) + (let [size (_.int (.int (list.size elemsS+)))] + (|> elemsS+ + (monad.map ///////phase.monad (generate archive)) + ## (///////phase\map (|>> (list& (_.key_value (_.string //runtime.tuple_size_field) size)) + ## _.array/*)) + (///////phase\map (|>> _.array/* + (//runtime.tuple//make size))))))) (def: #export (variant generate archive [lefts right? valueS]) (Generator (Variant Synthesis)) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/case.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/case.lux index e21957afe..2249874b5 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/case.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/case.lux @@ -129,13 +129,7 @@ Statement (_.set (list @cursor) (|> @savepoint (_.do "pop" (list))))) -(def: #export symbol - (_.symbol "lux_break")) - -(def: fail! - _.break - ## (_.throw/1 ..symbol) - ) +(def: fail! _.break) (def: (multi_pop! pops) (-> Nat Statement) @@ -161,7 +155,6 @@ (def: (with_looping in_closure? g!once g!continue? body!) (-> Bit LVar LVar Statement Statement) - ## (_.catch ..symbol body!) (.if in_closure? ($_ _.then (_.while (_.bool true) @@ -178,8 +171,7 @@ (_.set (list g!continue?) (_.bool true)) _.break))) (_.when g!continue? - _.next))) - ) + _.next)))) (def: (alternation in_closure? g!once g!continue? pre! post!) (-> Bit LVar LVar Statement Statement Statement) diff --git a/stdlib/source/lux/type.lux b/stdlib/source/lux/type.lux index ee7140e8b..77060876f 100644 --- a/stdlib/source/lux/type.lux +++ b/stdlib/source/lux/type.lux @@ -1,5 +1,6 @@ (.module: {#.doc "Basic functionality for working with types."} [lux (#- function) + ["@" target] [abstract [equivalence (#+ Equivalence)] [monad (#+ Monad do)]] @@ -175,7 +176,8 @@ (Equivalence Type) (def: (= x y) - (or (is? x y) + (or (for {@.php false} ## TODO: Remove this once JPHP is gone. + (is? x y)) (case [x y] [(#.Primitive xname xparams) (#.Primitive yname yparams)] (and (text\= xname yname) diff --git a/stdlib/source/lux/type/check.lux b/stdlib/source/lux/type/check.lux index 8f79817c0..c308d49c0 100644 --- a/stdlib/source/lux/type/check.lux +++ b/stdlib/source/lux/type/check.lux @@ -1,5 +1,6 @@ (.module: {#.doc "Type-checking functionality."} [lux #* + ["@" target] [abstract [functor (#+ Functor)] [apply (#+ Apply)] @@ -548,7 +549,8 @@ (def: #export (check' assumptions expected actual) {#.doc "Type-check to ensure that the 'expected' type subsumes the 'actual' type."} (Checker Type) - (if (is? expected actual) + (if (for {@.php false} ## TODO: Remove this once JPHP is gone. + (is? expected actual)) (check\wrap assumptions) (with type_check_failed [expected actual] (case [expected actual] diff --git a/stdlib/source/lux/world/file.lux b/stdlib/source/lux/world/file.lux index 0d6958d23..52a56aa04 100644 --- a/stdlib/source/lux/world/file.lux +++ b/stdlib/source/lux/world/file.lux @@ -15,10 +15,11 @@ [security ["!" capability (#+ capability:)]]] [data + ["." bit ("#\." equivalence)] ["." product] ["." maybe] ["." binary (#+ Binary)] - ["." text + ["." text ("#\." equivalence) ["%" format (#+ format)]] [collection ["." array (#+ Array)] @@ -1350,6 +1351,223 @@ ..default_separator) )) ) + + @.php + (as_is (host.import: (FILE_APPEND Int)) + ## https://www.php.net/manual/en/dir.constants.php + (host.import: (DIRECTORY_SEPARATOR host.String)) + ## https://www.php.net/manual/en/function.pack.php + ## https://www.php.net/manual/en/function.unpack.php + (host.import: (unpack [host.String host.String] Binary)) + ## https://www.php.net/manual/en/ref.filesystem.php + ## https://www.php.net/manual/en/function.file-get-contents.php + (host.import: (file_get_contents [Path] #io #try host.String)) + ## https://www.php.net/manual/en/function.file-put-contents.php + (host.import: (file_put_contents [Path host.String Int] #io #try host.Integer)) + (host.import: (filemtime [Path] #io #try host.Integer)) + (host.import: (filesize [Path] #io #try host.Integer)) + (host.import: (is_executable [Path] #io #try host.Boolean)) + (host.import: (touch [Path host.Integer] #io #try host.Boolean)) + (host.import: (rename [Path Path] #io #try host.Boolean)) + (host.import: (unlink [Path] #io #try host.Boolean)) + + ## https://www.php.net/manual/en/function.rmdir.php + (host.import: (rmdir [Path] #io #try host.Boolean)) + ## https://www.php.net/manual/en/function.scandir.php + (host.import: (scandir [Path] #io #try (Array Path))) + ## https://www.php.net/manual/en/function.is-file.php + (host.import: (is_file [Path] #io #try host.Boolean)) + ## https://www.php.net/manual/en/function.is-dir.php + (host.import: (is_dir [Path] #io #try host.Boolean)) + ## https://www.php.net/manual/en/function.mkdir.php + (host.import: (mkdir [Path] #io #try host.Boolean)) + + (def: byte_array_format "C*") + (def: default_separator (..DIRECTORY_SEPARATOR)) + + (template [<name>] + [(exception: #export (<name> {file Path}) + (exception.report + ["Path" file]))] + + [cannot_write_to_file] + ) + + (`` (structure: (file path) + (-> Path (File IO)) + + (~~ (template [<name> <mode>] + [(def: <name> + (..can_modify + (function (<name> data) + (do {! (try.with io.monad)} + [outcome (..file_put_contents [path ("php pack" ..byte_array_format data) <mode>])] + (if (bit\= false (:coerce Bit outcome)) + (\ io.monad wrap (exception.throw ..cannot_write_to_file [path])) + (wrap []))))))] + + [over_write +0] + [append (..FILE_APPEND)] + )) + + (def: content + (..can_query + (function (_ _) + (do {! (try.with io.monad)} + [data (..file_get_contents [path])] + (if (bit\= false (:coerce Bit data)) + (\ io.monad wrap (exception.throw ..cannot_find_file [path])) + (wrap (..unpack [..byte_array_format data]))))))) + + (def: name + (..can_see + (function (_ _) + (|> path + (text.split_all_with ..default_separator) + list.reverse + list.head + (maybe.default path))))) + + (def: path + (..can_see + (function (_ _) + path))) + + (~~ (template [<capability> <name> <ffi> <pipeline>] + [(def: <name> + (<capability> + (function (_ _) + (do {! (try.with io.monad)} + [value (<ffi> [path])] + (if (bit\= false (:coerce Bit value)) + (\ io.monad wrap (exception.throw ..cannot_find_file [path])) + (wrap (`` (|> value (~~ (template.splice <pipeline>))))))))))] + + [..can_query size ..filesize [.nat]] + [..can_query last_modified ..filemtime [(i.* +1,000) duration.from_millis instant.absolute]] + )) + + (def: can_execute? + (..can_query + (function (_ _) + (..is_executable [path])))) + + (def: modify + (..can_modify + (function (_ moment) + (do {! (try.with io.monad)} + [verdict (..touch [path (|> moment instant.relative duration.to_millis (i./ +1,000))])] + (if (bit\= false (:coerce Bit verdict)) + (\ io.monad wrap (exception.throw ..cannot_find_file [path])) + (wrap [])))))) + + (def: move + (..can_open + (function (_ destination) + (do {! (try.with io.monad)} + [verdict (..rename [path destination])] + (if (bit\= false (:coerce Bit verdict)) + (\ io.monad wrap (exception.throw ..cannot_find_file [path])) + (wrap (file destination))))))) + + (def: delete + (..can_delete + (function (_ _) + (do {! (try.with io.monad)} + [verdict (..unlink [path])] + (if (bit\= false (:coerce Bit verdict)) + (\ io.monad wrap (exception.throw ..cannot_find_file [path])) + (wrap [])))))) + )) + + (`` (structure: (directory path) + (-> Path (Directory IO)) + + (def: scope + (..can_see + (function (_ _) + path))) + + (~~ (template [<name> <test> <constructor> <capability>] + [(def: <name> + (..can_query + (function (_ _) + (do {! (try.with io.monad)} + [children (..scandir [path])] + (loop [input (|> children + array.to_list + (list.filter (function (_ child) + (not (or (text\= "." child) + (text\= ".." child)))))) + output (: (List (<capability> IO)) + (list))] + (case input + #.Nil + (wrap output) + + (#.Cons head tail) + (do ! + [verdict (<test> head)] + (if verdict + (recur tail (#.Cons (<constructor> head) output)) + (recur tail output)))))))))] + + [files ..is_file ..file File] + [directories ..is_dir directory Directory] + )) + + (def: discard + (..can_delete + (function (_ _) + (do {! (try.with io.monad)} + [verdict (..rmdir [path])] + (if (bit\= false (:coerce Bit verdict)) + (\ io.monad wrap (exception.throw ..cannot_find_directory [path])) + (wrap [])))))) + )) + + (`` (structure: #export default + (System IO) + + (~~ (template [<name> <test> <constructor> <exception>] + [(def: <name> + (..can_open + (function (_ path) + (do {! (try.with io.monad)} + [verdict (<test> path)] + (\ io.monad wrap + (if verdict + (#try.Success (<constructor> path)) + (exception.throw <exception> [path])))))))] + + [file ..is_file ..file ..cannot_find_file] + [directory ..is_dir ..directory ..cannot_find_directory] + )) + + (def: create_file + (..can_open + (function (_ path) + (do {! (try.with io.monad)} + [verdict (..touch [path (|> instant.now io.run instant.relative duration.to_millis (i./ +1,000))])] + (\ io.monad wrap + (if verdict + (#try.Success (..file path)) + (exception.throw ..cannot_create_file [path]))))))) + + (def: create_directory + (..can_open + (function (_ path) + (do {! (try.with io.monad)} + [verdict (..mkdir path)] + (\ io.monad wrap + (if verdict + (#try.Success (..directory path)) + (exception.throw ..cannot_create_directory [path]))))))) + + (def: separator + ..default_separator) + )) + ) })) (template [<get> <signature> <create> <find> <exception>] diff --git a/stdlib/source/lux/world/program.lux b/stdlib/source/lux/world/program.lux index acaf36711..d6fe4c2e3 100644 --- a/stdlib/source/lux/world/program.lux +++ b/stdlib/source/lux/world/program.lux @@ -14,6 +14,7 @@ [parser ["." environment (#+ Environment)]]] [data + ["." bit ("#\." equivalence)] ["." maybe] ["." text ["%" format (#+ format)]] @@ -216,7 +217,19 @@ (#static home [] #io Path)) (host.import: Kernel #as RubyKernel - (#static exit [Int] #io Nothing)))} + (#static exit [Int] #io Nothing))) + + @.php + (as_is (host.import: (exit [Int] #io Nothing)) + ## https://www.php.net/manual/en/function.exit.php + (host.import: (getcwd [] #io host.String)) + ## https://www.php.net/manual/en/function.getcwd.php + (host.import: (getenv #as getenv/1 [host.String] #io host.String)) + (host.import: (getenv #as getenv/0 [] #io (Array host.String))) + ## https://www.php.net/manual/en/function.getenv.php + ## https://www.php.net/manual/en/function.array-keys.php + (host.import: (array_keys [(Array host.String)] (Array host.String))) + )} (as_is))) (structure: #export default @@ -254,7 +267,15 @@ (list\map (function (_ variable) [variable (RubyEnv::fetch [variable])])) (dictionary.from_list text.hash) - io.io)} + io.io) + @.php (do io.monad + [environment (..getenv/0 [])] + (wrap (|> environment + ..array_keys + array.to_list + (list\map (function (_ variable) + [variable ("php array read" (:coerce Nat variable) environment)])) + (dictionary.from_list text.hash))))} ## TODO: Replace dummy implementation. (io.io environment.empty)))) @@ -270,7 +291,12 @@ <default>) @.python (os/path::expanduser ["~"]) @.lua (..run_command "~" "echo ~") - @.ruby (RubyDir::home [])} + @.ruby (RubyDir::home []) + @.php (do io.monad + [output (..getenv/1 ["HOME"])] + (wrap (if (bit\= false (:coerce Bit output)) + "~" + output)))} ## TODO: Replace dummy implementation. <default>))) @@ -294,7 +320,12 @@ (if (is? default on_windows) (..run_command default "pwd") (wrap on_windows))) - @.ruby (RubyFileUtils::pwd [])} + @.ruby (RubyFileUtils::pwd []) + @.php (do io.monad + [output (..getcwd [])] + (wrap (if (bit\= false (:coerce Bit output)) + "." + output)))} ## TODO: Replace dummy implementation. (io.io <default>)))) @@ -314,4 +345,5 @@ (..default_exit! code)) @.python (os::_exit [code]) @.lua (os/exit [code]) - @.ruby (RubyKernel::exit [code])})))) + @.ruby (RubyKernel::exit [code]) + @.php (..exit [code])})))) diff --git a/stdlib/source/test/lux.lux b/stdlib/source/test/lux.lux index ef6177deb..8d9f68922 100644 --- a/stdlib/source/test/lux.lux +++ b/stdlib/source/test/lux.lux @@ -184,7 +184,8 @@ @.js on_valid_host @.python on_valid_host @.lua on_valid_host - @.ruby on_valid_host} + @.ruby on_valid_host + @.php on_valid_host} on_default)))))) (def: conversion_tests diff --git a/stdlib/source/test/lux/control/remember.lux b/stdlib/source/test/lux/control/remember.lux index bfe18fa5b..1002e3a11 100644 --- a/stdlib/source/test/lux/control/remember.lux +++ b/stdlib/source/test/lux/control/remember.lux @@ -28,7 +28,7 @@ ["." /]}) (def: deadline (Random Date) random.date) -(def: message (Random Text) (random\map %.nat random.nat)) +(def: message (Random Text) (random.ascii/lower 10)) (def: focus (Random Code) (random\map code.text (random.ascii/upper 10))) (def: (to_remember macro deadline message focus) diff --git a/stdlib/source/test/lux/extension.lux b/stdlib/source/test/lux/extension.lux index 450570c20..cdd934e3e 100644 --- a/stdlib/source/test/lux/extension.lux +++ b/stdlib/source/test/lux/extension.lux @@ -6,7 +6,8 @@ ["." js] ["." python] ["." lua] - ["." ruby]] + ["." ruby] + ["." php]] [abstract [monad (#+ do)]] [control @@ -67,7 +68,8 @@ @.js (js.string self) @.python (python.unicode self) @.lua (lua.string self) - @.ruby (ruby.string self)}))))) + @.ruby (ruby.string self) + @.php (php.string self)}))))) (for {@.old (as_is)} diff --git a/stdlib/source/test/lux/host.php.lux b/stdlib/source/test/lux/host.php.lux new file mode 100644 index 000000000..0b6cac81b --- /dev/null +++ b/stdlib/source/test/lux/host.php.lux @@ -0,0 +1,24 @@ +(.module: + [lux #* + ["_" test (#+ Test)] + [abstract + [monad (#+ do)]] + [control + ["." try]] + [data + ["." text ("#\." equivalence)]] + [math + ["." random (#+ Random)] + [number + ["." nat] + ["." frac]]]] + {1 + ["." /]}) + +(def: #export test + Test + (do {! random.monad} + [] + (<| (_.covering /._) + (_.test "TBD" + true)))) |