From cbc41f10fb3e0e776767d2266b22068172b0f69a Mon Sep 17 00:00:00 2001 From: Eduardo Julian Date: Mon, 1 Mar 2021 01:49:30 -0400 Subject: Done with Ruby. --- compilers.md | 26 +- lux-ruby/source/program.lux | 196 ++++++++---- stdlib/source/lux.lux | 2 + stdlib/source/lux/control/concurrency/atom.lux | 9 +- stdlib/source/lux/control/thread.lux | 3 +- stdlib/source/lux/data/collection/array.lux | 15 +- stdlib/source/lux/data/text/encoding.lux | 37 ++- stdlib/source/lux/data/text/format.lux | 9 +- stdlib/source/lux/debug.lux | 43 ++- stdlib/source/lux/host.rb.lux | 334 +++++++++++++++++++++ stdlib/source/lux/math.lux | 40 ++- stdlib/source/lux/target/ruby.lux | 47 ++- .../language/lux/phase/extension/analysis/lua.lux | 7 +- .../language/lux/phase/extension/analysis/ruby.lux | 164 ++++++++++ .../lux/phase/extension/generation/ruby.lux | 4 +- .../lux/phase/extension/generation/ruby/common.lux | 85 ++++-- .../lux/phase/extension/generation/ruby/host.lux | 135 +++++++++ .../language/lux/phase/generation/python.lux | 4 +- .../language/lux/phase/generation/python/case.lux | 50 ++- .../lux/phase/generation/python/runtime.lux | 45 +-- .../language/lux/phase/generation/ruby.lux | 59 +++- .../language/lux/phase/generation/ruby/case.lux | 169 +++++++---- .../lux/phase/generation/ruby/function.lux | 19 +- .../language/lux/phase/generation/ruby/loop.lux | 99 +++--- .../language/lux/phase/generation/ruby/runtime.lux | 109 +++++-- stdlib/source/lux/world/file.lux | 211 +++++++++++++ stdlib/source/lux/world/program.lux | 34 ++- stdlib/source/test/lux.lux | 3 +- stdlib/source/test/lux/extension.lux | 6 +- stdlib/source/test/lux/host.rb.lux | 24 ++ 30 files changed, 1637 insertions(+), 351 deletions(-) create mode 100644 stdlib/source/lux/host.rb.lux create mode 100644 stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/ruby/host.lux create mode 100644 stdlib/source/test/lux/host.rb.lux diff --git a/compilers.md b/compilers.md index 0bea1a06c..3e70d6137 100644 --- a/compilers.md +++ b/compilers.md @@ -198,25 +198,25 @@ cd ~/lux/stdlib/ \ --- -# PHP compiler +# Ruby compiler ## Test ``` -cd ~/lux/lux-php/ && lein lux auto test -cd ~/lux/lux-php/ && lein clean && lein lux auto test +cd ~/lux/lux-ruby/ && lein lux auto test +cd ~/lux/lux-ruby/ && lein clean && lein lux auto test ``` ## Build ``` ## Develop -cd ~/lux/lux-php/ \ +cd ~/lux/lux-ruby/ \ && lein clean \ && lein lux auto build ## Build JVM-based compiler -cd ~/lux/lux-php/ \ +cd ~/lux/lux-ruby/ \ && lein clean \ && lein lux build \ && mv target/program.jar jvm_based_compiler.jar @@ -228,30 +228,32 @@ cd ~/lux/lux-php/ \ ## Compile Lux's Standard Library's tests using a JVM-based compiler. cd ~/lux/stdlib/ \ && lein clean \ -&& time java -jar ~/lux/lux-php/jvm_based_compiler.jar build --source ~/lux/stdlib/source --target ~/lux/stdlib/target --module test/lux +&& time java -jar ~/lux/lux-ruby/target/program.jar build --source ~/lux/stdlib/source --target ~/lux/stdlib/target --module test/lux + +RUBY_THREAD_VM_STACK_SIZE=15700000 ruby ~/lux/stdlib/target/program.rb ``` --- -# Ruby compiler +# PHP compiler ## Test ``` -cd ~/lux/lux-ruby/ && lein lux auto test -cd ~/lux/lux-ruby/ && lein clean && lein lux auto test +cd ~/lux/lux-php/ && lein lux auto test +cd ~/lux/lux-php/ && lein clean && lein lux auto test ``` ## Build ``` ## Develop -cd ~/lux/lux-ruby/ \ +cd ~/lux/lux-php/ \ && lein clean \ && lein lux auto build ## Build JVM-based compiler -cd ~/lux/lux-ruby/ \ +cd ~/lux/lux-php/ \ && lein clean \ && lein lux build \ && mv target/program.jar jvm_based_compiler.jar @@ -263,7 +265,7 @@ cd ~/lux/lux-ruby/ \ ## Compile Lux's Standard Library's tests using a JVM-based compiler. cd ~/lux/stdlib/ \ && lein clean \ -&& time java -jar ~/lux/lux-ruby/jvm_based_compiler.jar build --source ~/lux/stdlib/source --target ~/lux/stdlib/target --module test/lux +&& time java -jar ~/lux/lux-php/jvm_based_compiler.jar build --source ~/lux/stdlib/source --target ~/lux/stdlib/target --module test/lux ``` --- diff --git a/lux-ruby/source/program.lux b/lux-ruby/source/program.lux index 044e97923..64a34c003 100644 --- a/lux-ruby/source/program.lux +++ b/lux-ruby/source/program.lux @@ -29,6 +29,7 @@ [math [number ["n" nat] + ["i" int] ["." i64]]] ["." world #_ ["." file] @@ -90,6 +91,10 @@ (#static newInternalFromJavaExternal [org/jruby/Ruby java/lang/String] org/jruby/RubyString) (asJavaString [] java/lang/String)]) +(import: org/jruby/RubySymbol + ["#::." + (asJavaString [] java/lang/String)]) + (import: org/jruby/runtime/builtin/IRubyObject) (import: org/jruby/Ruby @@ -110,6 +115,11 @@ (import: org/jruby/runtime/ThreadContext) +(import: org/jruby/RubyRange + ["#::." + (first [org/jruby/runtime/ThreadContext] org/jruby/runtime/builtin/IRubyObject) + (size [org/jruby/runtime/ThreadContext] org/jruby/runtime/builtin/IRubyObject)]) + (template [] [(host.interface: (getValue [] java/lang/Object)) @@ -311,6 +321,18 @@ (exception.report ["Index" (%.nat index)])) +(exception: (invalid_index {index java/lang/Object}) + (exception.report + ["Class" (|> index + java/lang/Object::getClass + java/lang/Object::toString)] + ["Index" (|> index + java/lang/Object::toString)])) + +(import: java/util/Arrays + ["#::." + (#static [t] copyOfRange [[t] int int] [t])]) + (def: (lux_wrapper_access lux_structure value) (-> (-> (Array java/lang/Object) org/jruby/runtime/builtin/IRubyObject) (-> (Array java/lang/Object) org/jruby/internal/runtime/methods/DynamicMethod)) @@ -327,48 +349,61 @@ {block org/jruby/runtime/Block}) org/jruby/runtime/builtin/IRubyObject (let [member (host.array_read 0 args)] - (case (host.check org/jruby/RubyFixnum member) - (#.Some member) - (case (array.read (org/jruby/RubyFixnum::getLongValue member) value) - (#.Some value) - (wrapped_lux_value lux_structure value) - - #.None - (error! (exception.construct ..invalid_tuple_access [(org/jruby/RubyFixnum::getLongValue member)]))) - - #.None - (case (host.check org/jruby/RubyString member) - (#.Some member) - (case (:coerce Text (org/jruby/RubyString::asJavaString member)) - (^ (static runtime.variant_tag_field)) - (|> value - (array.read 0) - maybe.assume - (:coerce java/lang/Integer) - java/lang/Integer::longValue - (org/jruby/RubyFixnum::new ..initial_ruby_runtime)) - - (^ (static runtime.variant_flag_field)) - (case (array.read 1 value) - #.None - ..ruby_nil - - (#.Some flag) - ..lux_unit) - - (^ (static runtime.variant_value_field)) - (case (array.read 2 value) + (<| (case (host.check org/jruby/RubyFixnum member) + (#.Some member) + (case (array.read (org/jruby/RubyFixnum::getLongValue member) value) (#.Some value) (wrapped_lux_value lux_structure value) #.None - (error! (exception.construct ..nil_has_no_lux_representation []))) + (error! (exception.construct ..invalid_tuple_access [(org/jruby/RubyFixnum::getLongValue member)]))) + + #.None) + (case (host.check org/jruby/RubyString member) + (#.Some member) + (case (:coerce Text (org/jruby/RubyString::asJavaString member)) + (^ (static runtime.variant_tag_field)) + (|> value + (array.read 0) + maybe.assume + (:coerce java/lang/Integer) + java/lang/Integer::longValue + (org/jruby/RubyFixnum::new ..initial_ruby_runtime)) + + (^ (static runtime.variant_flag_field)) + (case (array.read 1 value) + #.None + ..ruby_nil + + (#.Some flag) + ..lux_unit) + + (^ (static runtime.variant_value_field)) + (case (array.read 2 value) + (#.Some value) + (wrapped_lux_value lux_structure value) - field - (error! (exception.construct ..invalid_variant_access [field]))) - - #.None - (error! (format "lux_wrapper_access INVALID INDEX")))))))) + #.None + (error! (exception.construct ..nil_has_no_lux_representation []))) + + field + (error! (exception.construct ..invalid_variant_access [field]))) + + #.None) + (case (host.check org/jruby/RubyRange member) + (#.Some member) + (case [(|> member (org/jruby/RubyRange::first thread_context) (host.check org/jruby/RubyFixnum)) + (|> member (org/jruby/RubyRange::size thread_context) (host.check org/jruby/RubyFixnum))] + [(#.Some first) (#.Some size)] + (let [first (org/jruby/RubyFixnum::getLongValue first) + size (org/jruby/RubyFixnum::getLongValue size)] + (lux_structure (java/util/Arrays::copyOfRange value first (i.+ first size)))) + + _ + (error! (exception.construct ..invalid_index (:coerce java/lang/Object member)))) + + #.None) + (error! (exception.construct ..invalid_index (:coerce java/lang/Object member)))))))) (def: (lux_wrapper_equality value) (-> (Array java/lang/Object) org/jruby/internal/runtime/methods/DynamicMethod) @@ -410,6 +445,63 @@ array.size (org/jruby/RubyFixnum::new ..initial_ruby_runtime))))) +(def: (lux_wrapper_to_s value) + (-> (Array java/lang/Object) org/jruby/internal/runtime/methods/DynamicMethod) + (host.object [] org/jruby/internal/runtime/methods/DynamicMethod [] + [{java/lang/String "to_s"}] + + (org/jruby/internal/runtime/methods/DynamicMethod + [] (call self + {thread_context org/jruby/runtime/ThreadContext} + {self org/jruby/runtime/builtin/IRubyObject} + {module org/jruby/RubyModule} + {method java/lang/String} + {args [org/jruby/runtime/builtin/IRubyObject]} + {block org/jruby/runtime/Block}) + org/jruby/runtime/builtin/IRubyObject + (|> value + debug.inspect + (org/jruby/RubyString::newInternalFromJavaExternal ..initial_ruby_runtime))))) + +(exception: (invalid_operation {method Text}) + (exception.report + ["Method" (%.text method)])) + +(def: (lux_wrapper_respond_to? value) + (-> (Array java/lang/Object) org/jruby/internal/runtime/methods/DynamicMethod) + (host.object [] org/jruby/internal/runtime/methods/DynamicMethod [] + [{java/lang/String "respond_to?"}] + + (org/jruby/internal/runtime/methods/DynamicMethod + [] (call self + {thread_context org/jruby/runtime/ThreadContext} + {self org/jruby/runtime/builtin/IRubyObject} + {module org/jruby/RubyModule} + {method java/lang/String} + {args [org/jruby/runtime/builtin/IRubyObject]} + {block org/jruby/runtime/Block}) + org/jruby/runtime/builtin/IRubyObject + (case (|> args + (host.array_read 0) + (host.check org/jruby/RubySymbol)) + (#.Some method) + (|> (case (|> method + org/jruby/RubySymbol::asJavaString + (:coerce Text)) + (^or "==" "equal?" + "to_s" "inspect" + "[]" "length" "respond_to?" + ## "to_hash" + ) + true + + _ + false) + (org/jruby/RubyBoolean::newBoolean ..initial_ruby_runtime)) + + #.None + (error! (exception.construct ..invalid_operation ["respond_to?"])))))) + (exception: (unknown_method {method Text}) (exception.report ["Method" (%.text method)])) @@ -428,12 +520,18 @@ "[]" (org/jruby/runtime/callsite/CacheEntry::new (..lux_wrapper_access lux_structure value) 0) - "==" + (^or "==" "equal?") (org/jruby/runtime/callsite/CacheEntry::new (..lux_wrapper_equality value) 1) "length" (org/jruby/runtime/callsite/CacheEntry::new (..lux_wrapper_length value) 2) + (^or "to_s" "inspect") + (org/jruby/runtime/callsite/CacheEntry::new (..lux_wrapper_to_s value) 3) + + "respond_to?" + (org/jruby/runtime/callsite/CacheEntry::new (..lux_wrapper_respond_to? value) 4) + _ (error! (exception.construct ..unknown_method [(:coerce Text method)])))))] (org/jruby/java/proxies/JavaProxy::new ..initial_ruby_runtime meta_class (:coerce java/lang/Object value)))) @@ -519,7 +617,7 @@ (run! (_.global (reference.artifact context)))))))))) (def: platform - (IO (Platform _.LVar _.Expression _.Statement)) + (IO (Platform Register _.Expression _.Statement)) (do io.monad [host ..host] (wrap {#platform.&file_system (file.async file.default) @@ -530,9 +628,9 @@ (def: (program context program) (Program _.Expression _.Statement) - (_.statement (_.apply/* (list (runtime.lux//program_args _.command_line_arguments) - _.nil) - program))) + (_.statement (_.apply_lambda/* (list (runtime.lux//program_args _.command_line_arguments) + _.nil) + program))) (def: extender Extender @@ -564,14 +662,6 @@ (-> Any (Promise Any)) (promise.future (\ world/program.default exit +0))) -(def: (scope body!) - (-> _.Statement _.Statement) - (let [@program (_.local "lux_program")] - ($_ _.then - (_.function @program (list) body!) - (_.statement (_.apply/* (list) @program)) - ))) - (program: [{service /cli.service}] (let [extension ".rb"] (exec (do promise.monad @@ -585,15 +675,13 @@ generation.bundle extension/bundle.empty ..program - [_.LVar - _.Expression - _.Statement] + [Register _.Expression _.Statement] ..extender service [(packager.package (: _.Statement (_.manual "")) _.code _.then - ..scope) + (|>>)) (format (/cli.target service) (\ file.default separator) "program" diff --git a/stdlib/source/lux.lux b/stdlib/source/lux.lux index c18603b4b..1bb7efa07 100644 --- a/stdlib/source/lux.lux +++ b/stdlib/source/lux.lux @@ -5281,6 +5281,8 @@ _ (\ meta_monad return token) + ## TODO: Figure out why this doesn't work: + ## (\ meta_monad wrap token) )) (macro: #export (static tokens) diff --git a/stdlib/source/lux/control/concurrency/atom.lux b/stdlib/source/lux/control/concurrency/atom.lux index 3b57678fc..350554437 100644 --- a/stdlib/source/lux/control/concurrency/atom.lux +++ b/stdlib/source/lux/control/concurrency/atom.lux @@ -25,15 +25,18 @@ (with_expansions [ (for {@.js "js array new" @.python "python array new" - @.lua "lua array new"} + @.lua "lua array new" + @.ruby "ruby array new"} (as_is)) (for {@.js "js array write" @.python "python array write" - @.lua "lua array write"} + @.lua "lua array write" + @.ruby "ruby array write"} (as_is)) (for {@.js "js array read" @.python "python array read" - @.lua "lua array read"} + @.lua "lua array read" + @.ruby "ruby array read"} (as_is))] (abstract: #export (Atom a) (with_expansions [ (java/util/concurrent/atomic/AtomicReference a)] diff --git a/stdlib/source/lux/control/thread.lux b/stdlib/source/lux/control/thread.lux index 8e707e6d2..6be40ef63 100644 --- a/stdlib/source/lux/control/thread.lux +++ b/stdlib/source/lux/control/thread.lux @@ -44,7 +44,8 @@ @.js ("js array read" 0 (:representation box)) @.python ("python array read" 0 (:representation box)) - @.lua ("lua array read" 0 (:representation box))}))) + @.lua ("lua array read" 0 (:representation box)) + @.ruby ("ruby 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 0bc661941..b9162e53a 100644 --- a/stdlib/source/lux/data/collection/array.lux +++ b/stdlib/source/lux/data/collection/array.lux @@ -47,7 +47,8 @@ @.js ("js array new" size) @.python ("python array new" size) - @.lua ("lua array new" size)})) + @.lua ("lua array new" size) + @.ruby ("ruby array new" size)})) (def: #export (size array) (All [a] (-> (Array a) Nat)) @@ -65,7 +66,8 @@ @.js ("js array length" array) @.python ("python array length" array) - @.lua ("lua array length" array)})) + @.lua ("lua array length" array) + @.ruby ("ruby array length" array)})) (template: (!read ) (let [output ( index array)] @@ -93,7 +95,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?")}) + @.lua (!read "lua array read" "lua object nil?") + @.ruby (!read "ruby array read" "ruby object nil?")}) #.None)) (def: #export (write! index value array) @@ -110,7 +113,8 @@ @.js ("js array write" index value array) @.python ("python array write" index value array) - @.lua ("lua array write" index value array)})) + @.lua ("lua array write" index value array) + @.ruby ("ruby array write" index value array)})) (def: #export (delete! index array) (All [a] @@ -124,7 +128,8 @@ @.js ("js array delete" index array) @.python ("python array delete" index array) - @.lua ("lua array delete" index array)}) + @.lua ("lua array delete" index array) + @.ruby ("ruby array delete" index array)}) array)) ) diff --git a/stdlib/source/lux/data/text/encoding.lux b/stdlib/source/lux/data/text/encoding.lux index 55afc77ed..88bbea138 100644 --- a/stdlib/source/lux/data/text/encoding.lux +++ b/stdlib/source/lux/data/text/encoding.lux @@ -192,7 +192,16 @@ (host.import: TextDecoder (new [host.String]) - (decode [Uint8Array] host.String)))} + (decode [Uint8Array] host.String))) + + @.ruby + (as_is (host.import: String #as RubyString + (encode [Text] RubyString) + (force_encoding [Text] Text) + (bytes [] Binary)) + + (host.import: Array #as RubyArray + (pack [Text] RubyString)))} (as_is))) (def: (utf8\encode value) @@ -224,10 +233,16 @@ ) @.python - (:coerce Binary ("python apply" (:assume ("python constant" "bytearray")) value "utf-8"))} + (:coerce Binary ("python apply" (:assume ("python constant" "bytearray")) value "utf-8")) - ## Default - ("lua utf8 encode" value))) + @.lua + ("lua utf8 encode" value) + + @.ruby + (|> value + (:coerce RubyString) + (RubyString::encode ["UTF-8"]) + (RubyString::bytes []))})) (def: (utf8\decode value) (-> Binary (Try Text)) @@ -252,10 +267,18 @@ #try.Success)) @.python - (host.try (:coerce Text ("python object do" "decode" (:assume value) "utf-8")))} + (host.try (:coerce Text ("python object do" "decode" (:assume value) "utf-8"))) + + @.lua + (#try.Success ("lua utf8 decode" value)) - ## Default - (#try.Success ("lua utf8 decode" value))))) + @.ruby + (|> value + (:coerce RubyArray) + (RubyArray::pack ["C*"]) + (:coerce RubyString) + (RubyString::force_encoding ["UTF-8"]) + #try.Success)}))) (structure: #export utf8 (Codec Binary Text) diff --git a/stdlib/source/lux/data/text/format.lux b/stdlib/source/lux/data/text/format.lux index 2232e0b6d..c67ce2030 100644 --- a/stdlib/source/lux/data/text/format.lux +++ b/stdlib/source/lux/data/text/format.lux @@ -16,7 +16,7 @@ ["." json]] [collection ["." list ("#\." monad)]]] - [time + ["." time ["." instant] ["." duration] ["." date]] @@ -62,16 +62,21 @@ [rev Rev (\ rev.decimal encode)] [frac Frac (\ frac.decimal encode)] [ratio ratio.Ratio (\ ratio.codec encode)] + [text Text text.format] + [name Name (\ name.codec encode)] + [location Location location.format] [code Code code.format] [type Type type.format] + [xml xml.XML (\ xml.codec encode)] [json json.JSON (\ json.codec encode)] + [instant instant.Instant (\ instant.codec encode)] [duration duration.Duration (\ duration.codec encode)] [date date.Date (\ date.codec encode)] - [location Location location.format] + [time time.Time (\ time.codec encode)] ) (template [ ,] diff --git a/stdlib/source/lux/debug.lux b/stdlib/source/lux/debug.lux index 8006c83dd..47d62fd34 100644 --- a/stdlib/source/lux/debug.lux +++ b/stdlib/source/lux/debug.lux @@ -79,7 +79,13 @@ (import: (tostring [.Any] host.String)) (import: math - (#static type [.Any] #? host.String)))})) + (#static type [.Any] #? host.String))) + + @.ruby + (as_is (import: Class) + + (import: Object + (type [] Class)))})) (def: Inspector (-> Any Text)) @@ -230,6 +236,41 @@ _ (..tostring value)) + + @.ruby + (template.with [(class_of ) + (Object::type (:coerce ..Object ))] + (let [value_class (Object::type (:coerce ..Object value))] + (`` (cond (~~ (template [ ] + [(is? (class_of ) value_class) + (|> value (:coerce ) )] + + [#0 Bit %.bit] + [#1 Bit %.bit] + [+123 Int %.int] + [+123.456 Frac %.frac] + ["+123.456" Text %.text] + [("ruby object nil") Any (new> "nil" [])] + )) + + (is? (class_of #.None) value_class) + (let [variant_tag ("ruby object get" "_lux_tag" value) + variant_flag ("ruby object get" "_lux_flag" value) + variant_value ("ruby object get" "_lux_value" value)] + (if (not (or ("ruby object nil?" variant_tag) + ("ruby object nil?" variant_flag) + ("ruby object nil?" variant_value))) + (|> (format (|> variant_tag (:coerce .Int) %.int) + " " (%.bit (not ("ruby object nil?" variant_flag))) + " " (inspect variant_value)) + (text.enclose ["(" ")"])) + (inspect_tuple inspect value))) + + (is? (class_of [[] []]) value_class) + (inspect_tuple inspect value) + + ## else + (:coerce Text ("ruby object do" "to_s" value)))))) }))) (exception: #export (cannot_represent_value {type Type}) diff --git a/stdlib/source/lux/host.rb.lux b/stdlib/source/lux/host.rb.lux new file mode 100644 index 000000000..63f14e8a3 --- /dev/null +++ b/stdlib/source/lux/host.rb.lux @@ -0,0 +1,334 @@ +(.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 [] + [(with_expansions [ (template.identifier [ "'"])] + (abstract: #export Any) + (type: #export + (..Object )))] + + [Nil] + [Function] + ) + +(template [ ] + [(type: #export + )] + + [Boolean Bit] + [Integer Int] + [Float Frac] + [String Text] + ) + +(type: Nilable + [Bit Code]) + +(def: nilable + (Parser Nilable) + (let [token (' #?)] + (<| (<>.and (<>.parses? (.this! token))) + (<>.after (<>.not (.this! token))) + .any))) + +(type: Alias + Text) + +(def: alias + (Parser Alias) + (<>.after (.this! (' #as)) .local_identifier)) + +(type: Field + [Bit Text (Maybe Alias) Nilable]) + +(def: static! + (Parser Any) + (.this! (' #static))) + +(def: field + (Parser Field) + (.form ($_ <>.and + (<>.parses? ..static!) + .local_identifier + (<>.maybe ..alias) + ..nilable))) + +(def: constant + (Parser Field) + (.form ($_ <>.and + (<>\wrap true) + .local_identifier + (<>.maybe ..alias) + ..nilable))) + +(type: Common_Method + {#name Text + #alias (Maybe Alias) + #inputs (List Nilable) + #io? Bit + #try? Bit + #output Nilable}) + +(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 + .local_identifier + (<>.maybe ..alias) + (.tuple (<>.some ..nilable)) + (<>.parses? (.this! (' #io))) + (<>.parses? (.this! (' #try))) + ..nilable)) + +(def: static_method + (<>.after ..static! ..common_method)) + +(def: method + (Parser Method) + (.form (<>.or ..static_method + ..common_method))) + +(type: Member + (#Field Field) + (#Method Method)) + +(def: member + (Parser Member) + ($_ <>.or + ..field + ..method + )) + +(def: input_variables + (-> (List Nilable) (List [Bit Code])) + (|>> list.enumeration + (list\map (function (_ [idx [nilable? type]]) + [nilable? (|> idx %.nat code.local_identifier)])))) + +(def: (nilable_type [nilable? type]) + (-> Nilable Code) + (if nilable? + (` (.Maybe (~ type))) + type)) + +(def: (with_nil g!temp [nilable? input]) + (-> Code [Bit Code] Code) + (if nilable? + (` (case (~ input) + (#.Some (~ g!temp)) + (~ g!temp) + + #.Nil + ("ruby object nil"))) + input)) + +(def: (without_nil g!temp [nilable? outputT] output) + (-> Code Nilable Code Code) + (if nilable? + (` (let [(~ g!temp) (~ output)] + (if ("ruby object nil?" (~ g!temp)) + #.None + (#.Some (~ g!temp))))) + (` (let [(~ g!temp) (~ output)] + (if (not ("ruby object nil?" (~ g!temp))) + (~ g!temp) + (.error! "Nil is an invalid value!")))))) + +(type: Import + (#Class Text (Maybe Alias) (List Member)) + (#Function Static_Method) + (#Constant Field)) + +(def: import + (Parser [(Maybe Text) Import]) + ($_ <>.and + (<>.maybe .text) + ($_ <>.or + ($_ <>.and + .local_identifier + (<>.maybe ..alias) + (<>.some member)) + (.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 Nilable) Bit Bit Nilable Code) + (let [g!inputs (input_variables inputsT)] + (` (def: ((~ g!method) + [(~+ (list\map product.right g!inputs))]) + (-> [(~+ (list\map nilable_type inputsT))] + (~ (|> (nilable_type outputT) + (try_type try?) + (io_type io?)))) + (:assume + (~ (<| (with_io io?) + (with_try try?) + (without_nil g!temp outputT) + (` ("ruby apply" + (:coerce ..Function (~ source)) + (~+ (list\map (with_nil g!temp) g!inputs))))))))))) + +(syntax: #export (import: {[?module 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)) + module_import (: (List Code) + (case ?module + (#.Some module) + (list (` ("ruby import" (~ (code.text module))))) + + #.None + (list))) + class_import (` ("ruby 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 (~ (nilable_type fieldT)) + (.exec + (~+ module_import) + ("ruby constant" (~ (code.text (format class "::" field))))))))))) + (` (def: ((~ (qualify field)) + (~ g!object)) + (-> (~ g!type) + (~ (nilable_type fieldT))) + (:assume + (~ (without_nil g!temp fieldT (` ("ruby 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 + (` ("ruby object get" (~ (code.text method)) + (:coerce (..Object .Any) + (.exec + (~+ module_import) + ("ruby 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 nilable_type inputsT))] + (~ g!type) + (~ (|> (nilable_type outputT) + (try_type try?) + (io_type io?)))) + (:assume + (~ (<| (with_io io?) + (with_try try?) + (without_nil g!temp outputT) + (` ("ruby object do" + (~ (code.text method)) + (~ g!object) + (~+ (list\map (with_nil g!temp) g!inputs))))))))))))) + members))))) + + (#Function [name alias inputsT io? try? outputT]) + (let [imported (` (.exec + (~+ (case ?module + (#.Some module) + (list (` ("ruby import" (~ (code.text module))))) + + #.None + (list))) + ("ruby 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 (` (.exec + (~+ (case ?module + (#.Some module) + (list (` ("ruby import" (~ (code.text module))))) + + #.None + (list))) + ("ruby constant" (~ (code.text name)))))] + (wrap (list (` ((~! syntax:) ((~ (code.local_identifier (maybe.default name alias)))) + (\ (~! meta.monad) (~' wrap) + (list (` (.:coerce (~ (nilable_type fieldT)) (~ imported)))))))))) + ))) diff --git a/stdlib/source/lux/math.lux b/stdlib/source/lux/math.lux index 1c4247ad2..7193b417f 100644 --- a/stdlib/source/lux/math.lux +++ b/stdlib/source/lux/math.lux @@ -175,7 +175,45 @@ (def: #export root/3 (-> Frac Frac) - (..pow ("lux f64 /" +3.0 +1.0))))}) + (..pow ("lux f64 /" +3.0 +1.0)))) + + @.ruby + (as_is (template [ ] + [(def: #export + (-> Frac Frac) + (|>> ("ruby apply" ("ruby constant" )) + (:coerce Frac)))] + + [cos "Math.cos"] + [sin "Math.sin"] + [tan "Math.tan"] + + [acos "Math.acos"] + [asin "Math.asin"] + [atan "Math.atan"] + + [exp "Math.exp"] + [log "Math.log"] + + [root/2 "Math.sqrt"] + [root/3 "Math.cbrt"] + ) + + (template [ ] + [(def: #export + (-> Frac Frac) + (|>> ("ruby object do" ) + (:coerce Int) + ("lux i64 f64")))] + + [ceil "ceil"] + [floor "floor"] + ) + + (def: #export (pow param subject) + (-> Frac Frac Frac) + (:coerce Frac ("ruby object do" "**" subject param)))) + }) (def: #export (round input) (-> Frac Frac) diff --git a/stdlib/source/lux/target/ruby.lux b/stdlib/source/lux/target/ruby.lux index e884d6c70..641cc8d2e 100644 --- a/stdlib/source/lux/target/ruby.lux +++ b/stdlib/source/lux/target/ruby.lux @@ -124,7 +124,8 @@ ) (template [ ] - [(def: #export (..global ))] + [(def: #export + (..global ))] ["@" latest_error] ["_" last_string_read] @@ -135,11 +136,17 @@ ["/" input_record_separator] ["\" output_record_separator] ["0" script_name] - ["*" command_line_arguments] ["$" process_id] ["?" exit_status] ) + (template [ ] + [(def: #export + (..local ))] + + ["ARGV" command_line_arguments] + ) + (def: #export nil Literal (:abstraction "nil")) @@ -172,8 +179,9 @@ (-> Literal) (|>> :abstraction))] - [%.int int Int (<|)] + [%.int int Int (<|)] [%.text string Text ..sanitize] + [(<|) symbol Text (format ":")] ) (def: #export float @@ -323,6 +331,13 @@ (..nest (:representation rescue))))) (text.join_with text.new_line))))) + (def: #export (catch expectation body!) + (-> Expression Statement Statement) + (<| :abstraction + ..block + (format "catch(" (:representation expectation) ") do" + (..nest (:representation body!))))) + (def: #export (return value) (-> Expression Statement) (:abstraction (format "return " (:representation value) ..statement_suffix))) @@ -360,8 +375,7 @@ (list\map (|>> :representation)) (text.join_with ..input_separator) (text.enclose' "|")) - " " - (:representation body!)) + (..nest (:representation body!))) (text.enclose ["{" "}"]) (format "lambda "))] (|> (case name @@ -401,9 +415,14 @@ [">>" bit_shr] ) - (def: #export (not subject) - (-> Expression Computation) - (:abstraction (format "(!" (:representation subject) ")"))) + (template [ ] + [(def: #export ( subject) + (-> Expression Computation) + (:abstraction (format "(" (:representation subject) ")")))] + + ["!" not] + ["-" negate] + ) (def: #export (comment commentary on) (All [brand] (-> Text (Code brand) (Code brand))) @@ -448,11 +467,17 @@ ))] [1 - [["print"]]] + [["print"] + ["require"]]] [2 - []] + [["print"]]] [3 - []] + [["print"]]] ) + +(def: #export throw/1 + (-> Expression Statement) + (|>> (..apply/1 (..local "throw")) + ..statement)) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/analysis/lua.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/analysis/lua.lux index 04df1bdbb..99154e105 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/analysis/lua.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/analysis/lua.lux @@ -28,8 +28,7 @@ ["." phase]]]]]]) (def: Nil - (for {@.lua - host.Nil} + (for {@.lua host.Nil} Any)) (def: Object @@ -222,7 +221,7 @@ [_ (analysis/type.infer ..Object)] (wrap (#analysis.Extension extension (list (analysis.text name))))))])) -(def: python::function +(def: lua::function Handler (custom [($_ <>.and .nat .any) @@ -247,6 +246,6 @@ (bundle.install "apply" lua::apply) (bundle.install "power" lua::power) (bundle.install "import" lua::import) - (bundle.install "function" python::function) + (bundle.install "function" lua::function) (bundle.install "script universe" (/.nullary .Bit)) ))) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/analysis/ruby.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/analysis/ruby.lux index 3b9f4ad75..8bbd32b3c 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/analysis/ruby.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/analysis/ruby.lux @@ -27,8 +27,172 @@ [/// ["." phase]]]]]]) +(def: array::new + Handler + (custom + [.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 + [.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 .any .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 .any .any .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 .any .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: Nil + (for {@.ruby host.Nil} + Any)) + +(def: Object + (for {@.ruby (type (host.Object Any))} + Any)) + +(def: Function + (for {@.ruby host.Function} + Any)) + +(def: object::get + Handler + (custom + [($_ <>.and .text .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 .text .any (<>.some .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 "nil" (/.nullary ..Nil)) + (bundle.install "nil?" (/.unary Any Bit)) + ))) + +(def: ruby::constant + Handler + (custom + [.text + (function (_ extension phase archive name) + (do phase.monad + [_ (analysis/type.infer Any)] + (wrap (#analysis.Extension extension (list (analysis.text name))))))])) + +(def: ruby::apply + Handler + (custom + [($_ <>.and .any (<>.some .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: ruby::import + Handler + (custom + [.text + (function (_ extension phase archive name) + (do phase.monad + [_ (analysis/type.infer Bit)] + (wrap (#analysis.Extension extension (list (analysis.text name))))))])) + (def: #export bundle Bundle (<| (bundle.prefix "ruby") (|> bundle.empty + (dictionary.merge bundle::array) + (dictionary.merge bundle::object) + + (bundle.install "constant" ruby::constant) + (bundle.install "apply" ruby::apply) + (bundle.install "import" ruby::import) + (bundle.install "script universe" (/.nullary .Bit)) ))) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/ruby.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/ruby.lux index 8b1b94bbb..12bcfc9b1 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/ruby.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/ruby.lux @@ -5,6 +5,7 @@ ["." dictionary]]]] ["." / #_ ["#." common] + ["#." host] [//// [generation [ruby @@ -12,4 +13,5 @@ (def: #export bundle Bundle - /common.bundle) + (dictionary.merge /common.bundle + /host.bundle)) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/ruby/common.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/ruby/common.lux index 9f04b35d2..50eddb998 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/ruby/common.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/ruby/common.lux @@ -47,34 +47,71 @@ (#try.Failure error) (/////.throw extension.invalid_syntax [extension_name %synthesis input])))) +## TODO: Get rid of this ASAP +(def: lux::syntax_char_case! + (..custom [($_ <>.and + .any + .any + (<>.some (.tuple ($_ <>.and + (.tuple (<>.many .i64)) + .any)))) + (function (_ extension_name phase archive [input else conditionals]) + (do {! /////.monad} + [inputG (phase archive input) + elseG (phase archive else) + @input (\ ! map _.local (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 (_.lambda #.None (list @input) + (list\fold (function (_ [test then] else) + (_.if test (_.return then) else)) + (_.return elseG) + conditionalsG))]] + (wrap (_.apply_lambda/* (list inputG) closure))))])) + (def: lux_procs Bundle (|> /.empty - (/.install "is" (binary (product.uncurry _.=))) + (/.install "syntax char case!" lux::syntax_char_case!) + (/.install "is" (binary (function (_ [reference subject]) + (_.do "equal?" (list reference) subject)))) (/.install "try" (unary //runtime.lux//try)))) -(def: keep_i64 - (All [input] - (-> (-> input Expression) - (-> input Expression))) - (function.compose (_.bit_and (_.manual "0xFFFFFFFFFFFFFFFF")))) +(def: (capped operation parameter subject) + (-> (-> Expression Expression Expression) + (-> Expression Expression Expression)) + (//runtime.i64//64 (operation parameter subject))) (def: i64_procs Bundle (<| (/.prefix "i64") (|> /.empty - (/.install "and" (binary (product.uncurry _.bit_and))) - (/.install "or" (binary (product.uncurry _.bit_or))) - (/.install "xor" (binary (product.uncurry _.bit_xor))) - (/.install "left-shift" (binary (..keep_i64 (product.uncurry _.bit_shl)))) - (/.install "right-shift" (binary (product.uncurry //runtime.i64//logic_right_shift))) - (/.install "=" (binary (product.uncurry _.=))) - (/.install "+" (binary (..keep_i64 (product.uncurry _.+)))) - (/.install "-" (binary (..keep_i64 (product.uncurry _.-)))) + (/.install "and" (binary (product.uncurry //runtime.i64//and))) + (/.install "or" (binary (product.uncurry //runtime.i64//or))) + (/.install "xor" (binary (product.uncurry //runtime.i64//xor))) + (/.install "left-shift" (binary (product.uncurry //runtime.i64//left_shift))) + (/.install "right-shift" (binary (product.uncurry //runtime.i64//right_shift))) + (/.install "<" (binary (product.uncurry _.<))) - (/.install "*" (binary (..keep_i64 (product.uncurry _.*)))) - (/.install "/" (binary (product.uncurry _./))) - (/.install "%" (binary (product.uncurry _.%))) + (/.install "=" (binary (product.uncurry _.=))) + (/.install "+" (binary (product.uncurry (..capped _.+)))) + (/.install "-" (binary (product.uncurry (..capped _.-)))) + (/.install "*" (binary (product.uncurry (..capped _.*)))) + (/.install "/" (binary (product.uncurry //runtime.i64//division))) + (/.install "%" (binary (function (_ [parameter subject]) + (_.do "remainder" (list parameter) subject)))) + (/.install "f64" (unary (_./ (_.float +1.0)))) (/.install "char" (unary (_.do "chr" (list (_.string "UTF-8"))))) ))) @@ -87,10 +124,11 @@ (/.install "-" (binary (product.uncurry _.-))) (/.install "*" (binary (product.uncurry _.*))) (/.install "/" (binary (product.uncurry _./))) - (/.install "%" (binary (product.uncurry _.%))) + (/.install "%" (binary (function (_ [parameter subject]) + (_.do "remainder" (list parameter) subject)))) (/.install "=" (binary (product.uncurry _.=))) (/.install "<" (binary (product.uncurry _.<))) - (/.install "int" (unary (_.do "floor" (list)))) + (/.install "i64" (unary (_.do "floor" (list)))) (/.install "encode" (unary (_.do "to_s" (list)))) (/.install "decode" (unary //runtime.f64//decode))))) @@ -100,7 +138,7 @@ (def: (text//clip [paramO extraO subjectO]) (Trinary Expression) - (//runtime.text//clip subjectO paramO extraO)) + (//runtime.text//clip paramO extraO subjectO)) (def: (text//index [startO partO textO]) (Trinary Expression) @@ -112,7 +150,7 @@ (|> /.empty (/.install "=" (binary (product.uncurry _.=))) (/.install "<" (binary (product.uncurry _.<))) - (/.install "concat" (binary (product.uncurry _.+))) + (/.install "concat" (binary (product.uncurry (function.flip _.+)))) (/.install "index" (trinary text//index)) (/.install "size" (unary (_.the "length"))) (/.install "char" (binary (product.uncurry //runtime.text//char))) @@ -121,9 +159,8 @@ (def: (io//log! messageG) (Unary Expression) - (_.or (_.apply/* (list (|> messageG (_.+ (_.string text.new_line)))) - (_.local "puts")) - //runtime.unit)) + (_.or //runtime.unit + (_.print/2 messageG (_.string text.new_line)))) (def: io//error! (Unary Expression) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/ruby/host.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/ruby/host.lux new file mode 100644 index 000000000..206034cd7 --- /dev/null +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/extension/generation/ruby/host.lux @@ -0,0 +1,135 @@ +(.module: + [lux #* + [abstract + ["." monad (#+ do)]] + [control + ["." function] + ["<>" parser + ["" synthesis (#+ Parser)]]] + [data + [collection + ["." dictionary] + ["." list]] + [text + ["%" format (#+ format)]]] + [target + ["_" ruby (#+ Var Expression)]]] + ["." // #_ + ["#." common (#+ custom)] + ["//#" /// #_ + ["/" bundle] + ["/#" // #_ + ["." extension] + [generation + [extension (#+ Nullary Unary Binary Trinary + nullary unary binary trinary)] + ["." reference] + ["//" ruby #_ + ["#." runtime (#+ Operation Phase Handler Bundle + with_vars)]]] + ["/#" // #_ + ["." generation] + ["//#" /// #_ + ["#." phase]]]]]]) + +(def: (array::new [size]) + (Unary Expression) + (_.do "new" (list size) (_.local "Array"))) + +(def: array::length + (Unary Expression) + (_.the "size")) + +(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 _.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 .text .any) + (function (_ extension phase archive [fieldS objectS]) + (do ////////phase.monad + [objectG (phase archive objectS)] + (wrap (_.the fieldS objectG))))])) + +(def: object::do + Handler + (custom + [($_ <>.and .text .any (<>.some .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 [ ] + [(def: (Nullary Expression) (function.constant )) + (def: (Unary Expression) (_.= ))] + + [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: ruby::constant + (custom + [.text + (function (_ extension phase archive name) + (\ ////////phase.monad wrap (_.local name)))])) + +(def: ruby::apply + (custom + [($_ <>.and .any (<>.some .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: ruby::import + (custom + [.text + (function (_ extension phase archive module) + (\ ////////phase.monad wrap + (_.require/1 (_.string module))))])) + +(def: #export bundle + Bundle + (<| (/.prefix "ruby") + (|> /.empty + (dictionary.merge ..array) + (dictionary.merge ..object) + + (/.install "constant" ruby::constant) + (/.install "apply" ruby::apply) + (/.install "import" ruby::import) + (/.install "script universe" (nullary (function.constant (_.bool reference.universe)))) + ))) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/python.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/python.lux index cdaabfc08..2e86ad107 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/python.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/python.lux @@ -26,8 +26,6 @@ [reference (#+) [variable (#+)]]]]]]]) -(exception: #export cannot-recur-as-an-expression) - (def: (statement expression archive synthesis) Phase! (case synthesis @@ -60,6 +58,8 @@ (//////phase\map _.return (/function.function statement expression archive abstraction)) )) +(exception: #export cannot-recur-as-an-expression) + (def: #export (expression archive synthesis) Phase (case synthesis diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/python/case.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/python/case.lux index eb6ae3e19..202e922c1 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/python/case.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/python/case.lux @@ -151,27 +151,29 @@ [right_choice (_.string "") inc] ) -(def: (alternation in_closure? g!once pre! post!) - (-> Bit SVar (Statement Any) (Statement Any) (Statement Any)) +(def: (with_looping in_closure? g!once body!) + (-> Bit SVar (Statement Any) (Statement Any)) (.if in_closure? - ($_ _.then - (_.while (_.bool true) - ($_ _.then - ..save! - pre!) - #.None) - ..restore! - post!) + (_.while (_.bool true) + body! + #.None) ($_ _.then (_.set (list g!once) (_.bool true)) (_.while g!once ($_ _.then (_.set (list g!once) (_.bool false)) - ..save! - pre!) - (#.Some _.continue)) - ..restore! - post!))) + body!) + (#.Some _.continue))))) + +(def: (alternation in_closure? g!once pre! post!) + (-> Bit SVar (Statement Any) (Statement Any) (Statement Any)) + ($_ _.then + (..with_looping in_closure? g!once + ($_ _.then + ..save! + pre!)) + ..restore! + post!)) (def: (pattern_matching' in_closure? statement expression archive) (-> Bit Phase! Phase Archive Path (Operation (Statement Any))) @@ -271,20 +273,10 @@ (do ///////phase.monad [pattern_matching! (pattern_matching' in_closure? statement expression archive pathP) g!once (..gensym "once")] - (wrap (.if in_closure? - ($_ _.then - (_.while (_.bool true) - pattern_matching! - #.None) - (_.raise (_.Exception/1 (_.string case.pattern_matching_error)))) - ($_ _.then - (_.set (list g!once) (_.bool true)) - (_.while g!once - ($_ _.then - (_.set (list g!once) (_.bool false)) - pattern_matching!) - (#.Some _.continue)) - (_.raise (_.Exception/1 (_.string case.pattern_matching_error)))))))) + (wrap ($_ _.then + (..with_looping in_closure? g!once + pattern_matching!) + (_.raise (_.Exception/1 (_.string case.pattern_matching_error))))))) (def: #export dependencies (-> Path (List SVar)) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/python/runtime.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/python/runtime.lux index 933bcf6b0..1638a64ca 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/python/runtime.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/python/runtime.lux @@ -247,8 +247,8 @@ test_recursion! (_.if is_last? ## Must recurse. ($_ _.then - (_.set (list sum) sum_value) - (_.set (list wantedTag) (_.- sum_tag wantedTag))) + (_.set (list wantedTag) (_.- sum_tag wantedTag)) + (_.set (list sum) sum_value)) no_match!)] (<| (_.while (_.bool true)) (_.cond (list [(_.= wantedTag sum_tag) @@ -272,31 +272,12 @@ @sum//get )) -(runtime: i64//+limit - (|> (_.int +1) - (_.bit_shl (_.int +63)) - (_.- (_.int +1)))) - -(runtime: i64//-limit - (_.- (|> (_.int +1) - (_.bit_shl (_.int +63))) - (_.int +0))) - -(runtime: i64//+iteration - (|> (_.int +1) - (_.bit_shl (_.int +64)))) - -(runtime: i64//-iteration - (|> ..i64//+iteration - _.negate)) - -(runtime: i64//+cap - (|> ..i64//+limit - (_.+ (_.int +1)))) - -(runtime: i64//-cap - (|> ..i64//-limit - (_.- (_.int +1)))) +(def: i64//+limit (_.manual "+0x7FFFFFFFFFFFFFFF")) +(def: i64//-limit (_.manual "-0x8000000000000000")) +(def: i64//+iteration (_.manual "+0x10000000000000000")) +(def: i64//-iteration (_.manual "-0x10000000000000000")) +(def: i64//+cap (_.manual "+0x8000000000000000")) +(def: i64//-cap (_.manual "-0x8000000000000001")) (runtime: (i64//64 input) (with_vars [temp] @@ -355,9 +336,9 @@ (_.return (_.- (|> subject (..i64//division param) (_.* param)) subject))) -(template [ ] +(template [ ] [(runtime: ( left right) - (_.return (..i64//64 ( (..as_nat left) (..as_nat right)))))] + (_.return (..i64//64 ( (..as_nat left) (..as_nat right)))))] [i64//and _.bit_and] [i64//or _.bit_or] @@ -378,12 +359,6 @@ (def: runtime//i64 (Statement Any) ($_ _.then - @i64//+limit - @i64//-limit - @i64//+iteration - @i64//-iteration - @i64//+cap - @i64//-cap @i64//64 @i64//nat_top @i64//left_shift diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby.lux index 9524441f2..f1a4e3c1c 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby.lux @@ -26,7 +26,41 @@ [reference (#+) [variable (#+)]]]]]]]) -(def: #export (generate archive synthesis) +(def: (statement expression archive synthesis) + Phase! + (case synthesis + (^template [] + [(^ ( 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! false statement expression archive case) + + (^template [ ] + [(^ ( value)) + ( 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: (expression archive synthesis) Phase (case synthesis (^template [ ] @@ -39,23 +73,32 @@ (^template [ ] [(^ ( value)) - ( generate archive value)]) + ( expression 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/abstraction /function.function] [////synthesis.function/apply /function.apply]) + (^template [ ] + [(^ ( value)) + ( 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.Reference value) (//reference.reference /reference.system archive value) (#////synthesis.Extension extension) - (///extension.apply archive generate extension))) + (///extension.apply archive expression extension))) + +(def: #export generate + Phase + ..expression) 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 428ac6279..e21957afe 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 @@ -35,6 +35,10 @@ [meta [archive (#+ Archive)]]]]]]]) +(def: #export (gensym prefix) + (-> Text (Operation LVar)) + (///////phase\map (|>> %.nat (format prefix) _.local) /////generation.next)) + (def: #export register (-> Register LVar) (|>> (///reference.local //reference.system) :assume)) @@ -54,6 +58,15 @@ (_.lambda #.None (list (..register register))) (_.apply_lambda/* (list valueO)))))) +(def: #export (let! statement expression archive [valueS register bodyS]) + (Generator! [Synthesis Register Synthesis]) + (do ///////phase.monad + [valueO (expression archive valueS) + bodyO (statement expression archive bodyS)] + (wrap ($_ _.then + (_.set (list (..register register)) valueO) + bodyO)))) + (def: #export (if expression archive [testS thenS elseS]) (Generator [Synthesis Synthesis Synthesis]) (do ///////phase.monad @@ -62,6 +75,16 @@ elseO (expression archive elseS)] (wrap (_.? testO thenO elseO)))) +(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 @@ -106,7 +129,13 @@ Statement (_.set (list @cursor) (|> @savepoint (_.do "pop" (list))))) -(def: fail! _.break) +(def: #export symbol + (_.symbol "lux_break")) + +(def: fail! + _.break + ## (_.throw/1 ..symbol) + ) (def: (multi_pop! pops) (-> Nat Statement) @@ -130,23 +159,44 @@ [right_choice (_.string "") inc] ) -(def: (alternation pre! post!) - (-> Statement Statement Statement) +(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) + body!)) + ($_ _.then + (_.set (list g!once) (_.bool true)) + (_.set (list g!continue?) (_.bool false)) + (<| (_.while (_.bool true)) + (_.if g!once + ($_ _.then + (_.set (list g!once) (_.bool false)) + body!) + ($_ _.then + (_.set (list g!continue?) (_.bool true)) + _.break))) + (_.when g!continue? + _.next))) + ) + +(def: (alternation in_closure? g!once g!continue? pre! post!) + (-> Bit LVar LVar Statement Statement Statement) ($_ _.then - (_.while (_.bool true) - ($_ _.then - ..save! - pre!)) - ($_ _.then - ..restore! - post!))) - -(def: (pattern_matching' expression archive) - (-> Phase Archive Path (Operation Statement)) + (with_looping in_closure? g!once g!continue? + ($_ _.then + ..save! + pre!)) + ..restore! + post!)) + +(def: (pattern_matching' in_closure? statement expression archive) + (-> Bit (Generator! Path)) (function (recur pathP) (.case pathP (#/////synthesis.Then bodyS) - (///////phase\map _.return (expression archive bodyS)) + (statement expression archive bodyS) #/////synthesis.Pop (///////phase\wrap ..pop!) @@ -221,58 +271,49 @@ (..multi_pop! (n.+ 2 extra_pops)) next!)))) - (^template [ ] - [(^ ( preP postP)) - (do ///////phase.monad - [pre! (recur preP) - post! (recur postP)] - (wrap ( pre! post!)))]) - ([/////synthesis.path/seq _.then] - [/////synthesis.path/alt ..alternation])))) - -(def: (pattern_matching expression archive pathP) - (-> Phase Archive Path (Operation Statement)) + (^ (/////synthesis.path/seq preP postP)) + (do ///////phase.monad + [pre! (recur preP) + post! (recur postP)] + (wrap ($_ _.then + pre! + post!))) + + (^ (/////synthesis.path/alt preP postP)) + (do ///////phase.monad + [pre! (recur preP) + post! (recur postP) + g!once (..gensym "once") + g!continue? (..gensym "continue")] + (wrap (..alternation in_closure? g!once g!continue? pre! post!))) + ))) + +(def: (pattern_matching in_closure? statement expression archive pathP) + (-> Bit (Generator! Path)) (do ///////phase.monad - [pattern_matching! (pattern_matching' expression archive pathP)] + [pattern_matching! (pattern_matching' in_closure? statement expression archive pathP) + g!once (..gensym "once") + g!continue? (..gensym "continue")] (wrap ($_ _.then - (_.while (_.bool true) - pattern_matching!) + (..with_looping in_closure? g!once g!continue? + pattern_matching!) (_.statement (_.raise (_.string case.pattern_matching_error))))))) -(def: #export dependencies - (-> Path (List LVar)) - (|>> case.storage - (get@ #case.dependencies) - set.to_list - (list\map (function (_ variable) - (.case variable - (#///////variable.Local register) - (..register register) - - (#///////variable.Foreign register) - (..capture register)))))) - -(def: #export (case expression archive [valueS pathP]) - (Generator [Synthesis Path]) +(def: #export (case! in_closure? statement expression archive [valueS pathP]) + (-> Bit (Generator! [Synthesis Path])) (do ///////phase.monad - [initG (expression archive valueS) - [[case_module case_artifact] pattern_matching!] (/////generation.with_new_context archive - (pattern_matching expression archive pathP)) - #let [## @case (_.local (///reference.artifact [case_module case_artifact])) - ## @dependencies+ (..dependencies (/////synthesis.path/seq (/////synthesis.path/then valueS) - ## pathP)) - ## directive (_.function @case @dependencies+ - ## ($_ _.then - ## (_.set (list @cursor) (_.array (list initG))) - ## (_.set (list @savepoint) (_.array (list))) - ## pattern_matching!)) - directive (_.lambda #.None (list) - ($_ _.then - (_.set (list @cursor) (_.array (list initG))) - (_.set (list @savepoint) (_.array (list))) - pattern_matching!))] - ## _ (/////generation.execute! directive) - ## _ (/////generation.save! (%.nat case_artifact) directive) - ] - ## (wrap (_.apply/* @dependencies+ @case)) - (wrap (_.apply_lambda/* (list) directive)))) + [stack_init (expression archive valueS) + pattern_matching! (pattern_matching in_closure? statement expression archive pathP)] + (wrap ($_ _.then + (_.set (list @cursor) (_.array (list stack_init))) + (_.set (list @savepoint) (_.array (list))) + pattern_matching! + )))) + +(def: #export (case statement expression archive case) + (-> Phase! (Generator [Synthesis Path])) + (|> case + (case! true statement expression archive) + (\ ///////phase.monad map + (|>> (_.lambda #.None (list)) + (_.apply_lambda/* (list)))))) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/function.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/function.lux index e2ace391d..21d74f8cd 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/function.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/function.lux @@ -62,15 +62,12 @@ (def: input (|>> inc //case.register)) -(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_module function_artifact] bodyO] (/////generation.with_new_context archive - (do ! - [function_name (\ ! map ///reference.artifact - (/////generation.context archive))] - (/////generation.with_anchor (_.local function_name) - (expression archive bodyS)))) + [[[function_module function_artifact] body!] (/////generation.with_new_context archive + (/////generation.with_anchor 1 + (statement expression archive bodyS))) closureO+ (monad.map ! (expression archive) environment) #let [function_name (///reference.artifact [function_module function_artifact]) @curried (_.local "curried") @@ -90,9 +87,9 @@ ($_ _.then (_.set (list @num_args) (_.the "length" @curried)) (_.cond (list [(|> @num_args (_.= arityO)) - ($_ _.then - initialize! - (_.return bodyO))] + (<| (_.then initialize!) + //loop.with_scope + body!)] [(|> @num_args (_.> arityO)) (let [slice (.function (_ from to) (_.array_range from to @curried)) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/loop.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/loop.lux index 4bdf1bc55..a2df0884a 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/loop.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/loop.lux @@ -4,7 +4,7 @@ ["." monad (#+ do)]] [data ["." product] - [text + ["." text ["%" format (#+ format)]] [collection ["." list ("#\." functor fold)] @@ -30,59 +30,66 @@ [reference ["#." variable (#+ Register)]]]]]]]) -(def: loop_name - (-> Nat LVar) - (|>> %.nat (format "loop") _.local)) +(def: (setup offset bindings body) + (-> Register (List Expression) Statement Statement) + (|> bindings + list.enumeration + (list\map (function (_ [register value]) + (_.set (list (//case.register (n.+ offset register))) + value))) + list.reverse + (list\fold _.then body))) -(def: #export (scope expression archive [start initsS+ bodyS]) - (Generator (Scope Synthesis)) +(def: symbol + (_.symbol "lux_continue")) + +(def: #export with_scope + (-> Statement Statement) + (_.while (_.bool true))) + +(def: #export (scope! statement expression archive [start initsS+ bodyS]) + (Generator! (Scope Synthesis)) (case initsS+ ## function/false/non-independent loop #.Nil - (expression archive bodyS) + (statement expression archive bodyS) ## true loop _ (do {! ///////phase.monad} - [@loop (\ ! map ..loop_name /////generation.next) - initsO+ (monad.map ! (expression archive) initsS+) - [[loop_module loop_artifact] bodyO] (/////generation.with_new_context archive - (do ! - [@loop (\ ! map (|>> ///reference.artifact _.local) - (/////generation.context archive))] - (/////generation.with_anchor @loop - (expression archive bodyS)))) - #let [@loop (|> [loop_module loop_artifact] ///reference.artifact _.local) - locals (|> initsS+ - list.enumeration - (list\map (|>> product.left (n.+ start) //case.register))) - actual_loop (_.statement - (_.lambda (#.Some @loop) locals - (_.return bodyO))) - [directive instantiation] (: [Statement Expression] - (case (|> (synthesis.path/then bodyS) - //case.dependencies - (set.from_list _.code_hash) - (set.difference (set.from_list _.code_hash locals)) - set.to_list) - #.Nil - [actual_loop - @loop] + [initsO+ (monad.map ! (expression archive) initsS+) + body! (/////generation.with_anchor start + (statement expression archive bodyS))] + (wrap (<| (..setup start initsO+) + ..with_scope + body!))))) - foreigns - [(_.statement - (_.lambda (#.Some @loop) foreigns - ($_ _.then - actual_loop - (_.return @loop)))) - (_.apply_lambda/* foreigns @loop)]))] - _ (/////generation.execute! directive) - _ (/////generation.save! (%.nat loop_artifact) directive)] - (wrap (_.apply_lambda/* initsO+ instantiation))))) +(def: #export (scope statement expression archive [start initsS+ bodyS]) + (-> Phase! (Generator (Scope Synthesis))) + (case initsS+ + ## function/false/non-independent loop + #.Nil + (expression archive bodyS) + + ## true loop + _ + (do {! ///////phase.monad} + [body! (scope! statement expression archive [start initsS+ bodyS])] + (wrap (|> body! + (_.lambda #.None (list)) + (_.apply_lambda/* (list))))))) -(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 - argsO+ (monad.map ! (expression archive) argsS+)] - (wrap (_.apply_lambda/* argsO+ @scope)))) + [offset /////generation.anchor + @temp (//case.gensym "lux_recur_values") + argsO+ (monad.map ! (expression archive) argsS+) + #let [re_binds (|> argsO+ + list.enumeration + (list\map (function (_ [idx _]) + (_.nth (_.int (.int idx)) @temp))))]] + (wrap ($_ _.then + (_.set (list @temp) (_.array argsO+)) + (..setup offset re_binds + _.next))))) diff --git a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/runtime.lux b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/runtime.lux index d74915164..01befb892 100644 --- a/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/runtime.lux +++ b/stdlib/source/lux/tool/compiler/language/lux/phase/generation/ruby/runtime.lux @@ -39,7 +39,7 @@ (template [ ] [(type: #export - ( LVar Expression Statement))] + ( Register Expression Statement))] [Operation /////generation.Operation] [Phase /////generation.Phase] @@ -51,12 +51,10 @@ (-> Phase Archive i (Operation Expression))) (type: #export Phase! - (-> Phase Archive Synthesis (Operation (Statement Any)))) + (-> Phase Archive Synthesis (Operation Statement))) (type: #export (Generator! i) - (-> Phase! Phase Archive i (Operation (Statement Any)))) - -(def: prefix Text "LuxRuntime") + (-> Phase! Phase Archive i (Operation Statement))) (def: #export unit (_.string /////synthesis.unit)) @@ -196,8 +194,8 @@ test_recursion! (_.if is_last? ## Must recurse. ($_ _.then - (_.set (list sum) sum_value) - (_.set (list wantedTag) (_.- sum_tag wantedTag))) + (_.set (list wantedTag) (_.- sum_tag wantedTag)) + (_.set (list sum) sum_value)) no_match!)] (<| (_.while (_.bool true)) (_.cond (list [(_.= sum_tag wantedTag) @@ -245,18 +243,76 @@ @lux//program_args )) -(runtime: (i64//logic_right_shift param subject) - (let [mask (|> (_.int +1) - (_.bit_shl (_.- param (_.int +64))) - (_.- (_.int +1)))] +(def: i64//+limit (_.manual "+0x7FFFFFFFFFFFFFFF")) +(def: i64//-limit (_.manual "-0x8000000000000000")) +(def: i64//+iteration (_.manual "+0x10000000000000000")) +(def: i64//-iteration (_.manual "-0x10000000000000000")) +(def: i64//+cap (_.manual "+0x8000000000000000")) +(def: i64//-cap (_.manual "-0x8000000000000001")) + +(runtime: (i64//64 input) + (with_vars [temp] + (`` (<| (~~ (template [ ] + [(_.if (|> input ) + ($_ _.then + (_.set (list temp) (_.% input)) + (_.return (_.? (|> temp ) + (|> temp (_.- ) (_.+ )) + temp))))] + + [(_.> ..i64//+limit) ..i64//+iteration ..i64//+cap ..i64//-limit] + [(_.< ..i64//-limit) ..i64//-iteration ..i64//-cap ..i64//+limit] + )) + (_.return input))))) + +(runtime: i64//nat_top + (|> (_.int +1) + (_.bit_shl (_.int +64)) + (_.- (_.int +1)))) + +(def: as_nat + (_.% (_.manual "0x10000000000000000"))) + +(runtime: (i64//left_shift param subject) + (_.return (|> subject + (_.bit_shl (_.% (_.int +64) param)) + ..i64//64))) + +(runtime: (i64//right_shift param subject) + ($_ _.then + (_.set (list param) (_.% (_.int +64) param)) + (_.return (_.? (_.= (_.int +0) param) + subject + (|> subject + ..as_nat + (_.bit_shr param)))))) + +(template [ ] + [(runtime: ( left right) + (_.return (..i64//64 ( (..as_nat left) (..as_nat right)))))] + + [i64//and _.bit_and] + [i64//or _.bit_or] + [i64//xor _.bit_xor] + ) + +(runtime: (i64//division parameter subject) + (let [extra (_.do "remainder" (list parameter) subject)] (_.return (|> subject - (_.bit_shr param) - (_.bit_and mask))))) + (_.- extra) + (_./ parameter))))) (def: runtime//i64 Statement ($_ _.then - @i64//logic_right_shift + @i64//64 + @i64//nat_top + @i64//left_shift + @i64//right_shift + @i64//and + @i64//or + @i64//xor + @i64//division )) (runtime: (f64//decode inputG) @@ -291,13 +347,15 @@ (_.and (|> value (_.>= (_.int +0))) (|> value (_.< top)))) -(runtime: (text//clip @text @from @to) - (_.return (|> @text (_.array_range @from @to)))) +(runtime: (text//clip offset length text) + (_.if (_.= (_.int +0) length) + (_.return (_.string "")) + (_.return (_.array_range offset (_.+ offset (_.- (_.int +1) length)) text)))) (runtime: (text//char idx text) (_.if (|> idx (within? (_.the "length" text))) - (_.return (..some (|> text (_.array_range idx idx) (_.do "ord" (list))))) - (_.return ..none))) + (_.return (|> text (_.array_range idx idx) (_.do "ord" (list)))) + (_.statement (_.raise (_.string "[Lux Error] Cannot get char from text."))))) (def: runtime//text Statement @@ -307,6 +365,17 @@ @text//char )) +(runtime: (array//write idx value array) + ($_ _.then + (_.set (list (_.nth idx array)) value) + (_.return array))) + +(def: runtime//array + Statement + ($_ _.then + @array//write + )) + (def: runtime Statement ($_ _.then @@ -315,11 +384,9 @@ runtime//i64 runtime//f64 runtime//text + runtime//array )) -(def: #export artifact - ..prefix) - (def: #export generate (Operation [Registry Output]) (do ///////phase.monad diff --git a/stdlib/source/lux/world/file.lux b/stdlib/source/lux/world/file.lux index 972019c39..0d6958d23 100644 --- a/stdlib/source/lux/world/file.lux +++ b/stdlib/source/lux/world/file.lux @@ -1139,6 +1139,217 @@ ..default_separator) )) ) + + @.ruby + (as_is (host.import: Time #as RubyTime + (#static at [Frac] RubyTime) + + (to_f [] Frac)) + + (host.import: Stat #as RubyStat + (executable? [] Bit) + (size Int) + (mtime [] RubyTime)) + + (host.import: File #as RubyFile + (#static SEPARATOR host.String) + (#static open [Path host.String] #io #try RubyFile) + (#static stat [Path] #io #try RubyStat) + (#static delete [Path] #io #try Int) + (#static file? [Path] #io #try Bit) + (#static directory? [Path] #io #try Bit) + (#static utime [RubyTime RubyTime Path] #io #try Int) + + (read [] #io #try Binary) + (write [Binary] #io #try Int) + (flush [] #io #try #? Any) + (close [] #io #try #? Any)) + + (host.import: Dir #as RubyDir + (#static open [Path] #io #try RubyDir) + + (children [] #io #try (Array Path)) + (close [] #io #try #? Any)) + + (host.import: "fileutils" FileUtils #as RubyFileUtils + (#static touch [Path] #io #try #? Any) + (#static move [Path Path] #io #try #? Any) + (#static rmdir [Path] #io #try #? Any) + (#static mkdir [Path] #io #try #? Any)) + + (def: default_separator + Text + (..RubyFile::SEPARATOR)) + + (`` (structure: (file path) + (-> Path (File IO)) + + (~~ (template [ ] + [(def: + (..can_modify + (function ( data) + (do {! (try.with io.monad)} + [file (RubyFile::open [path ]) + data (RubyFile::write [data] file) + _ (RubyFile::flush [] file) + _ (RubyFile::close [] file)] + (wrap [])))))] + + [over_write "wb"] + [append "ab"] + )) + + (def: content + (..can_query + (function (_ _) + (do {! (try.with io.monad)} + [file (RubyFile::open [path "rb"]) + data (RubyFile::read [] file) + _ (RubyFile::close [] file)] + (wrap 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 [ ] + [(def: + ( + (function (_ _) + (do {! (try.with io.monad)} + [stat (: (IO (Try RubyStat)) + (RubyFile::stat [path]))] + (wrap (`` (|> stat (: RubyStat) (~~ (template.splice )))))))))] + + [..can_query size [RubyStat::size .nat]] + [..can_query last_modified [(RubyStat::mtime []) + (RubyTime::to_f []) + (f.* +1,000.0) + f.int + duration.from_millis + instant.absolute]] + [..can_query can_execute? [(RubyStat::executable? [])]] + )) + + (def: modify + (..can_modify + (function (_ moment) + (let [moment (|> moment + instant.relative + duration.to_millis + i.frac + (f./ +1,000.0) + RubyTime::at)] + (do {! (try.with io.monad)} + [_ (RubyFile::utime [moment moment path])] + (wrap [])))))) + + (def: move + (..can_open + (function (_ destination) + (do {! (try.with io.monad)} + [_ (RubyFileUtils::move [path destination])] + (wrap (file destination)))))) + + (def: delete + (..can_delete + (function (_ _) + (do {! (try.with io.monad)} + [_ (RubyFile::delete [path])] + (wrap []))))) + )) + + (`` (structure: (directory path) + (-> Path (Directory IO)) + + (def: scope + (..can_see + (function (_ _) + path))) + + (~~ (template [ ] + [(def: + (..can_query + (function (_ _) + (do {! (try.with io.monad)} + [self (RubyDir::open [path]) + children (RubyDir::children [] self) + output (loop [input (|> children + array.to_list + (list\map (|>> (format path ..default_separator)))) + output (: (List ( IO)) + (list))] + (case input + #.Nil + (wrap output) + + (#.Cons head tail) + (do ! + [verdict ( head)] + (if verdict + (recur tail (#.Cons ( head) output)) + (recur tail output))))) + _ (RubyDir::close [] self)] + (wrap output)))))] + + [files RubyFile::file? ..file File] + [directories RubyFile::directory? directory Directory] + )) + + (def: discard + (..can_delete + (function (discard _) + (do {! (try.with io.monad)} + [_ (RubyFileUtils::rmdir [path])] + (wrap []))))) + )) + + (`` (structure: #export default + (System IO) + + (~~ (template [ ] + [(def: + (..can_open + (function (_ path) + (do {! (try.with io.monad)} + [verdict ( path)] + (\ io.monad wrap + (if verdict + (#try.Success ( path)) + (exception.throw [path])))))))] + + [file RubyFile::file? ..file ..cannot_find_file] + [directory RubyFile::directory? ..directory ..cannot_find_directory] + )) + + (def: create_file + (..can_open + (function (_ path) + (do {! (try.with io.monad)} + [_ (RubyFileUtils::touch [path])] + (wrap (..file path)))))) + + (def: create_directory + (..can_open + (function (create_directory path) + (do {! (try.with io.monad)} + [_ (RubyFileUtils::mkdir path)] + (wrap (..directory path)))))) + + (def: separator + ..default_separator) + )) + ) })) (template [ ] diff --git a/stdlib/source/lux/world/program.lux b/stdlib/source/lux/world/program.lux index 7a3d125a0..acaf36711 100644 --- a/stdlib/source/lux/world/program.lux +++ b/stdlib/source/lux/world/program.lux @@ -19,7 +19,8 @@ ["%" format (#+ format)]] [collection ["." array (#+ Array) ("#\." fold)] - ["." dictionary (#+ Dictionary)]]] + ["." dictionary (#+ Dictionary)] + ["." list ("#\." functor)]]] [math [number ["i" int]]]] @@ -203,7 +204,19 @@ (wrap default)) (#try.Failure _) - (wrap default)))))} + (wrap default))))) + @.ruby (as_is (host.import: Env #as RubyEnv + (#static keys [] (Array Text)) + (#static fetch [Text] Text)) + + (host.import: "fileutils" FileUtils #as RubyFileUtils + (#static pwd [] #io Path)) + + (host.import: Dir #as RubyDir + (#static home [] #io Path)) + + (host.import: Kernel #as RubyKernel + (#static exit [Int] #io Nothing)))} (as_is))) (structure: #export default @@ -235,7 +248,13 @@ [value (os/environ::get [variable])] (wrap (dictionary.put variable value environment)))) environment.empty - (array.to_list keys)))} + (array.to_list keys))) + @.ruby (|> (RubyEnv::keys []) + array.to_list + (list\map (function (_ variable) + [variable (RubyEnv::fetch [variable])])) + (dictionary.from_list text.hash) + io.io)} ## TODO: Replace dummy implementation. (io.io environment.empty)))) @@ -250,7 +269,8 @@ (NodeJs_OS::homedir [])) ) @.python (os/path::expanduser ["~"]) - @.lua (..run_command "~" "echo ~")} + @.lua (..run_command "~" "echo ~") + @.ruby (RubyDir::home [])} ## TODO: Replace dummy implementation. ))) @@ -273,7 +293,8 @@ on_windows (..run_command default "cd")] (if (is? default on_windows) (..run_command default "pwd") - (wrap on_windows)))} + (wrap on_windows))) + @.ruby (RubyFileUtils::pwd [])} ## TODO: Replace dummy implementation. (io.io )))) @@ -292,4 +313,5 @@ ## else (..default_exit! code)) @.python (os::_exit [code]) - @.lua (os/exit [code])})))) + @.lua (os/exit [code]) + @.ruby (RubyKernel::exit [code])})))) diff --git a/stdlib/source/test/lux.lux b/stdlib/source/test/lux.lux index 0379b8427..ef6177deb 100644 --- a/stdlib/source/test/lux.lux +++ b/stdlib/source/test/lux.lux @@ -183,7 +183,8 @@ @.jvm on_valid_host @.js on_valid_host @.python on_valid_host - @.lua on_valid_host} + @.lua on_valid_host + @.ruby on_valid_host} on_default)))))) (def: conversion_tests diff --git a/stdlib/source/test/lux/extension.lux b/stdlib/source/test/lux/extension.lux index 67abd0eca..450570c20 100644 --- a/stdlib/source/test/lux/extension.lux +++ b/stdlib/source/test/lux/extension.lux @@ -5,7 +5,8 @@ ["." jvm] ["." js] ["." python] - ["." lua]] + ["." lua] + ["." ruby]] [abstract [monad (#+ do)]] [control @@ -65,7 +66,8 @@ @.js (js.string self) @.python (python.unicode self) - @.lua (lua.string self)}))))) + @.lua (lua.string self) + @.ruby (ruby.string self)}))))) (for {@.old (as_is)} diff --git a/stdlib/source/test/lux/host.rb.lux b/stdlib/source/test/lux/host.rb.lux new file mode 100644 index 000000000..0b6cac81b --- /dev/null +++ b/stdlib/source/test/lux/host.rb.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)))) -- cgit v1.2.3