aboutsummaryrefslogtreecommitdiff
path: root/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib')
-rw-r--r--stdlib/source/lux/control/concurrency/atom.lux10
-rw-r--r--stdlib/source/lux/control/thread.lux3
-rw-r--r--stdlib/source/lux/data/collection/array.lux15
-rw-r--r--stdlib/source/lux/data/text/encoding.lux16
-rw-r--r--stdlib/source/lux/debug.lux41
-rw-r--r--stdlib/source/lux/host.php.lux307
-rw-r--r--stdlib/source/lux/math.lux32
-rw-r--r--stdlib/source/lux/math/random.lux4
-rw-r--r--stdlib/source/lux/target/php.lux52
-rw-r--r--stdlib/source/lux/tool/compiler/language/lux/phase/extension/analysis/php.lux168
-rw-r--r--stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/php/common.lux103
-rw-r--r--stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/php/host.lux256
-rw-r--r--stdlib/source/lux/tool/compiler/language/lux/phase/generation/php.lux86
-rw-r--r--stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/case.lux88
-rw-r--r--stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/function.lux32
-rw-r--r--stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/loop.lux92
-rw-r--r--stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/runtime.lux121
-rw-r--r--stdlib/source/lux/tool/compiler/language/lux/phase/generation/php/structure.lux13
-rw-r--r--stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/case.lux12
-rw-r--r--stdlib/source/lux/type.lux4
-rw-r--r--stdlib/source/lux/type/check.lux4
-rw-r--r--stdlib/source/lux/world/file.lux220
-rw-r--r--stdlib/source/lux/world/program.lux42
-rw-r--r--stdlib/source/test/lux.lux3
-rw-r--r--stdlib/source/test/lux/control/remember.lux2
-rw-r--r--stdlib/source/test/lux/extension.lux6
-rw-r--r--stdlib/source/test/lux/host.php.lux24
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))))