aboutsummaryrefslogtreecommitdiff
path: root/lux-jvm
diff options
context:
space:
mode:
authorEduardo Julian2020-05-30 15:19:28 -0400
committerEduardo Julian2020-05-30 15:19:28 -0400
commitb4d0eba7485caf0c6cf58de1193a9114fa273d8b (patch)
treef6f7fa2967bb5923347db1ed1d4c9b08e56bf8c6 /lux-jvm
parent6eaa3b57f3f1ea2ce13b942bdb4ef502fc1729bc (diff)
Split new-luxc into lux-jvm and lux-r.
Diffstat (limited to 'lux-jvm')
-rw-r--r--lux-jvm/project.clj32
-rw-r--r--lux-jvm/source/luxc/lang/directive/jvm.lux538
-rw-r--r--lux-jvm/source/luxc/lang/host/jvm.lux131
-rw-r--r--lux-jvm/source/luxc/lang/host/jvm/def.lux298
-rw-r--r--lux-jvm/source/luxc/lang/host/jvm/inst.lux464
-rw-r--r--lux-jvm/source/luxc/lang/synthesis/variable.lux98
-rw-r--r--lux-jvm/source/luxc/lang/translation/jvm.lux182
-rw-r--r--lux-jvm/source/luxc/lang/translation/jvm/case.lux239
-rw-r--r--lux-jvm/source/luxc/lang/translation/jvm/common.lux72
-rw-r--r--lux-jvm/source/luxc/lang/translation/jvm/expression.lux72
-rw-r--r--lux-jvm/source/luxc/lang/translation/jvm/extension.lux16
-rw-r--r--lux-jvm/source/luxc/lang/translation/jvm/extension/common.lux388
-rw-r--r--lux-jvm/source/luxc/lang/translation/jvm/extension/host.lux1047
-rw-r--r--lux-jvm/source/luxc/lang/translation/jvm/function.lux331
-rw-r--r--lux-jvm/source/luxc/lang/translation/jvm/loop.lux81
-rw-r--r--lux-jvm/source/luxc/lang/translation/jvm/primitive.lux30
-rw-r--r--lux-jvm/source/luxc/lang/translation/jvm/program.lux82
-rw-r--r--lux-jvm/source/luxc/lang/translation/jvm/reference.lux65
-rw-r--r--lux-jvm/source/luxc/lang/translation/jvm/runtime.lux387
-rw-r--r--lux-jvm/source/luxc/lang/translation/jvm/structure.lux79
-rw-r--r--lux-jvm/source/program.lux180
-rw-r--r--lux-jvm/source/test/program.lux18
-rw-r--r--lux-jvm/test/test/luxc/lang/analysis/host.jvm.lux549
-rw-r--r--lux-jvm/test/test/luxc/lang/synthesis/loop.lux162
-rw-r--r--lux-jvm/test/test/luxc/lang/synthesis/procedure.lux34
-rw-r--r--lux-jvm/test/test/luxc/lang/translation/js.lux160
-rw-r--r--lux-jvm/test/test/luxc/lang/translation/jvm.lux641
27 files changed, 6376 insertions, 0 deletions
diff --git a/lux-jvm/project.clj b/lux-jvm/project.clj
new file mode 100644
index 000000000..dbff84a85
--- /dev/null
+++ b/lux-jvm/project.clj
@@ -0,0 +1,32 @@
+(def version "0.6.0-SNAPSHOT")
+(def repo "https://github.com/LuxLang/lux")
+(def sonatype "https://oss.sonatype.org")
+(def sonatype-releases (str sonatype "/service/local/staging/deploy/maven2/"))
+(def sonatype-snapshots (str sonatype "/content/repositories/snapshots/"))
+
+(defproject com.github.luxlang/lux-jvm #=(identity version)
+ :description "A JVM compiler for Lux."
+ :url ~repo
+ :license {:name "Lux License v0.1"
+ :url ~(str repo "/blob/master/license.txt")}
+ :plugins [[com.github.luxlang/lein-luxc ~version]]
+ :deploy-repositories [["releases" {:url ~sonatype-releases :creds :gpg}]
+ ["snapshots" {:url ~sonatype-snapshots :creds :gpg}]]
+ :pom-addition [:developers [:developer
+ [:name "Eduardo Julian"]
+ [:url "https://github.com/eduardoejp"]]]
+ :repositories [["releases" ~sonatype-releases]
+ ["snapshots" ~sonatype-snapshots]]
+ :scm {:name "git"
+ :url ~(str repo ".git")}
+
+ :dependencies [[com.github.luxlang/luxc-jvm ~version]
+ [com.github.luxlang/stdlib ~version]
+ ;; JVM Bytecode
+ [org.ow2.asm/asm-all "5.0.3"]]
+
+ :manifest {"lux" ~version}
+ :source-paths ["source"]
+ :lux {:program "program"
+ :test "test/program"}
+ )
diff --git a/lux-jvm/source/luxc/lang/directive/jvm.lux b/lux-jvm/source/luxc/lang/directive/jvm.lux
new file mode 100644
index 000000000..27b1c8688
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/directive/jvm.lux
@@ -0,0 +1,538 @@
+(.module:
+ [lux #*
+ [host (#+ import:)]
+ [type (#+ :share)]
+ [abstract
+ ["." monad (#+ do)]]
+ [control
+ ["." try (#+ Try)]]
+ [target
+ ["/" jvm]]
+ [data
+ [identity (#+ Identity)]
+ ["." product]
+ [number
+ ["." nat]]
+ [text
+ ["%" format (#+ format)]]
+ [collection
+ ["." list ("#@." fold)]
+ ["." dictionary (#+ Dictionary)]
+ ["." row (#+ Row) ("#@." functor fold)]]]
+ [tool
+ [compiler
+ ["." phase]
+ [language
+ [lux
+ [synthesis (#+ Synthesis)]
+ ["." generation]
+ ["." directive]
+ [phase
+ ["." extension
+ ["." bundle]
+ [directive
+ ["./" lux]]]]]]]]]
+ [///
+ [host
+ ["." jvm (#+ Inst)
+ ["_" inst]]]])
+
+(import: #long org/objectweb/asm/Label
+ (new []))
+
+(def: (literal literal)
+ (-> /.Literal Inst)
+ (case literal
+ (#/.Boolean value) (_.boolean value)
+ (#/.Int value) (_.int value)
+ (#/.Long value) (_.long value)
+ (#/.Double value) (_.double value)
+ (#/.Char value) (_.char value)
+ (#/.String value) (_.string value)))
+
+(def: (constant instruction)
+ (-> /.Constant Inst)
+ (case instruction
+ (#/.BIPUSH constant) (_.BIPUSH constant)
+
+ (#/.SIPUSH constant) (_.SIPUSH constant)
+
+ #/.ICONST_M1 _.ICONST_M1
+ #/.ICONST_0 _.ICONST_0
+ #/.ICONST_1 _.ICONST_1
+ #/.ICONST_2 _.ICONST_2
+ #/.ICONST_3 _.ICONST_3
+ #/.ICONST_4 _.ICONST_4
+ #/.ICONST_5 _.ICONST_5
+
+ #/.LCONST_0 _.LCONST_0
+ #/.LCONST_1 _.LCONST_1
+
+ #/.FCONST_0 _.FCONST_0
+ #/.FCONST_1 _.FCONST_1
+ #/.FCONST_2 _.FCONST_2
+
+ #/.DCONST_0 _.DCONST_0
+ #/.DCONST_1 _.DCONST_1
+
+ #/.ACONST_NULL _.NULL
+
+ (#/.LDC literal)
+ (..literal literal)
+ ))
+
+(def: (int-arithmetic instruction)
+ (-> /.Int-Arithmetic Inst)
+ (case instruction
+ #/.IADD _.IADD
+ #/.ISUB _.ISUB
+ #/.IMUL _.IMUL
+ #/.IDIV _.IDIV
+ #/.IREM _.IREM
+ #/.INEG _.INEG))
+
+(def: (long-arithmetic instruction)
+ (-> /.Long-Arithmetic Inst)
+ (case instruction
+ #/.LADD _.LADD
+ #/.LSUB _.LSUB
+ #/.LMUL _.LMUL
+ #/.LDIV _.LDIV
+ #/.LREM _.LREM
+ #/.LNEG _.LNEG))
+
+(def: (float-arithmetic instruction)
+ (-> /.Float-Arithmetic Inst)
+ (case instruction
+ #/.FADD _.FADD
+ #/.FSUB _.FSUB
+ #/.FMUL _.FMUL
+ #/.FDIV _.FDIV
+ #/.FREM _.FREM
+ #/.FNEG _.FNEG))
+
+(def: (double-arithmetic instruction)
+ (-> /.Double-Arithmetic Inst)
+ (case instruction
+ #/.DADD _.DADD
+ #/.DSUB _.DSUB
+ #/.DMUL _.DMUL
+ #/.DDIV _.DDIV
+ #/.DREM _.DREM
+ #/.DNEG _.DNEG))
+
+(def: (arithmetic instruction)
+ (-> /.Arithmetic Inst)
+ (case instruction
+ (#/.Int-Arithmetic int-arithmetic)
+ (..int-arithmetic int-arithmetic)
+
+ (#/.Long-Arithmetic long-arithmetic)
+ (..long-arithmetic long-arithmetic)
+
+ (#/.Float-Arithmetic float-arithmetic)
+ (..float-arithmetic float-arithmetic)
+
+ (#/.Double-Arithmetic double-arithmetic)
+ (..double-arithmetic double-arithmetic)))
+
+(def: (int-bitwise instruction)
+ (-> /.Int-Bitwise Inst)
+ (case instruction
+ #/.IOR _.IOR
+ #/.IXOR _.IXOR
+ #/.IAND _.IAND
+ #/.ISHL _.ISHL
+ #/.ISHR _.ISHR
+ #/.IUSHR _.IUSHR))
+
+(def: (long-bitwise instruction)
+ (-> /.Long-Bitwise Inst)
+ (case instruction
+ #/.LOR _.LOR
+ #/.LXOR _.LXOR
+ #/.LAND _.LAND
+ #/.LSHL _.LSHL
+ #/.LSHR _.LSHR
+ #/.LUSHR _.LUSHR))
+
+(def: (bitwise instruction)
+ (-> /.Bitwise Inst)
+ (case instruction
+ (#/.Int-Bitwise int-bitwise)
+ (..int-bitwise int-bitwise)
+
+ (#/.Long-Bitwise long-bitwise)
+ (..long-bitwise long-bitwise)))
+
+(def: (conversion instruction)
+ (-> /.Conversion Inst)
+ (case instruction
+ #/.I2B _.I2B
+ #/.I2S _.I2S
+ #/.I2L _.I2L
+ #/.I2F _.I2F
+ #/.I2D _.I2D
+ #/.I2C _.I2C
+
+ #/.L2I _.L2I
+ #/.L2F _.L2F
+ #/.L2D _.L2D
+
+ #/.F2I _.F2I
+ #/.F2L _.F2L
+ #/.F2D _.F2D
+
+ #/.D2I _.D2I
+ #/.D2L _.D2L
+ #/.D2F _.D2F))
+
+(def: (array instruction)
+ (-> /.Array Inst)
+ (case instruction
+ #/.ARRAYLENGTH _.ARRAYLENGTH
+
+ (#/.NEWARRAY type) (_.NEWARRAY type)
+ (#/.ANEWARRAY type) (_.ANEWARRAY type)
+
+ #/.BALOAD _.BALOAD
+ #/.BASTORE _.BASTORE
+
+ #/.SALOAD _.SALOAD
+ #/.SASTORE _.SASTORE
+
+ #/.IALOAD _.IALOAD
+ #/.IASTORE _.IASTORE
+
+ #/.LALOAD _.LALOAD
+ #/.LASTORE _.LASTORE
+
+ #/.FALOAD _.FALOAD
+ #/.FASTORE _.FASTORE
+
+ #/.DALOAD _.DALOAD
+ #/.DASTORE _.DASTORE
+
+ #/.CALOAD _.CALOAD
+ #/.CASTORE _.CASTORE
+
+ #/.AALOAD _.AALOAD
+ #/.AASTORE _.AASTORE))
+
+(def: (object instruction)
+ (-> /.Object Inst)
+ (case instruction
+ (^template [<tag> <inst>]
+ (<tag> class field-name field-type)
+ (<inst> class field-name field-type))
+ ([#/.GETSTATIC _.GETSTATIC]
+ [#/.PUTSTATIC _.PUTSTATIC]
+ [#/.GETFIELD _.GETFIELD]
+ [#/.PUTFIELD _.PUTFIELD])
+
+ (#/.NEW type) (_.NEW type)
+
+ (#/.INSTANCEOF type) (_.INSTANCEOF type)
+ (#/.CHECKCAST type) (_.CHECKCAST type)
+
+ (^template [<tag> <inst>]
+ (<tag> class method-name method-type)
+ (<inst> class method-name method-type))
+ ([#/.INVOKEINTERFACE _.INVOKEINTERFACE]
+ [#/.INVOKESPECIAL _.INVOKESPECIAL]
+ [#/.INVOKESTATIC _.INVOKESTATIC]
+ [#/.INVOKEVIRTUAL _.INVOKEVIRTUAL])
+ ))
+
+(def: (local-int instruction)
+ (-> /.Local-Int Inst)
+ (case instruction
+ (#/.ILOAD register) (_.ILOAD register)
+ (#/.ISTORE register) (_.ISTORE register)))
+
+(def: (local-long instruction)
+ (-> /.Local-Long Inst)
+ (case instruction
+ (#/.LLOAD register) (_.LLOAD register)
+ (#/.LSTORE register) (_.LSTORE register)))
+
+(def: (local-float instruction)
+ (-> /.Local-Float Inst)
+ (case instruction
+ (#/.FLOAD register) (_.FLOAD register)
+ (#/.FSTORE register) (_.FSTORE register)))
+
+(def: (local-double instruction)
+ (-> /.Local-Double Inst)
+ (case instruction
+ (#/.DLOAD register) (_.DLOAD register)
+ (#/.DSTORE register) (_.DSTORE register)))
+
+(def: (local-object instruction)
+ (-> /.Local-Object Inst)
+ (case instruction
+ (#/.ALOAD register) (_.ALOAD register)
+ (#/.ASTORE register) (_.ASTORE register)))
+
+(def: (local instruction)
+ (-> /.Local Inst)
+ (case instruction
+ (#/.Local-Int instruction) (..local-int instruction)
+ (#/.IINC register) (_.IINC register)
+ (#/.Local-Long instruction) (..local-long instruction)
+ (#/.Local-Float instruction) (..local-float instruction)
+ (#/.Local-Double instruction) (..local-double instruction)
+ (#/.Local-Object instruction) (..local-object instruction)))
+
+(def: (stack instruction)
+ (-> /.Stack Inst)
+ (case instruction
+ #/.DUP _.DUP
+ #/.DUP_X1 _.DUP_X1
+ #/.DUP_X2 _.DUP_X2
+ #/.DUP2 _.DUP2
+ #/.DUP2_X1 _.DUP2_X1
+ #/.DUP2_X2 _.DUP2_X2
+ #/.SWAP _.SWAP
+ #/.POP _.POP
+ #/.POP2 _.POP2))
+
+(def: (comparison instruction)
+ (-> /.Comparison Inst)
+ (case instruction
+ #/.LCMP _.LCMP
+
+ #/.FCMPG _.FCMPG
+ #/.FCMPL _.FCMPL
+
+ #/.DCMPG _.DCMPG
+ #/.DCMPL _.DCMPL))
+
+(def: (branching instruction)
+ (-> (/.Branching org/objectweb/asm/Label) Inst)
+ (case instruction
+ (#/.IF_ICMPEQ label) (_.IF_ICMPEQ label)
+ (#/.IF_ICMPGE label) (_.IF_ICMPGE label)
+ (#/.IF_ICMPGT label) (_.IF_ICMPGT label)
+ (#/.IF_ICMPLE label) (_.IF_ICMPLE label)
+ (#/.IF_ICMPLT label) (_.IF_ICMPLT label)
+ (#/.IF_ICMPNE label) (_.IF_ICMPNE label)
+ (#/.IFEQ label) (_.IFEQ label)
+ (#/.IFGE label) (_.IFGE label)
+ (#/.IFGT label) (_.IFGT label)
+ (#/.IFLE label) (_.IFLE label)
+ (#/.IFLT label) (_.IFLT label)
+ (#/.IFNE label) (_.IFNE label)
+
+ (#/.TABLESWITCH min max default labels)
+ (_.TABLESWITCH min max default labels)
+
+ (#/.LOOKUPSWITCH default keys+labels)
+ (_.LOOKUPSWITCH default keys+labels)
+
+ (#/.IF_ACMPEQ label) (_.IF_ACMPEQ label)
+ (#/.IF_ACMPNE label) (_.IF_ACMPNE label)
+ (#/.IFNONNULL label) (_.IFNONNULL label)
+ (#/.IFNULL label) (_.IFNULL label)))
+
+(def: (exception instruction)
+ (-> (/.Exception org/objectweb/asm/Label) Inst)
+ (case instruction
+ (#/.Try start end handler exception) (_.try start end handler exception)
+ #/.ATHROW _.ATHROW))
+
+(def: (concurrency instruction)
+ (-> /.Concurrency Inst)
+ (case instruction
+ #/.MONITORENTER _.MONITORENTER
+ #/.MONITOREXIT _.MONITOREXIT))
+
+(def: (return instruction)
+ (-> /.Return Inst)
+ (case instruction
+ #/.RETURN _.RETURN
+ #/.IRETURN _.IRETURN
+ #/.LRETURN _.LRETURN
+ #/.FRETURN _.FRETURN
+ #/.DRETURN _.DRETURN
+ #/.ARETURN _.ARETURN))
+
+(def: (control instruction)
+ (-> (/.Control org/objectweb/asm/Label) Inst)
+ (case instruction
+ (#/.GOTO label) (_.GOTO label)
+ (#/.Branching instruction) (..branching instruction)
+ (#/.Exception instruction) (..exception instruction)
+ (#/.Concurrency instruction) (..concurrency instruction)
+ (#/.Return instruction) (..return instruction)))
+
+(def: (instruction instruction)
+ (-> (/.Instruction org/objectweb/asm/Label) Inst)
+ (case instruction
+ #/.NOP _.NOP
+ (#/.Constant instruction) (..constant instruction)
+ (#/.Arithmetic instruction) (..arithmetic instruction)
+ (#/.Bitwise instruction) (..bitwise instruction)
+ (#/.Conversion instruction) (..conversion instruction)
+ (#/.Array instruction) (..array instruction)
+ (#/.Object instruction) (..object instruction)
+ (#/.Local instruction) (..local instruction)
+ (#/.Stack instruction) (..stack instruction)
+ (#/.Comparison instruction) (..comparison instruction)
+ (#/.Control instruction) (..control instruction)))
+
+(type: Mapping
+ (Dictionary /.Label org/objectweb/asm/Label))
+
+(type: (Re-labeler context)
+ (-> [Mapping (context /.Label)]
+ [Mapping (context org/objectweb/asm/Label)]))
+
+(def: (relabel [mapping label])
+ (Re-labeler Identity)
+ (case (dictionary.get label mapping)
+ (#.Some label)
+ [mapping label]
+
+ #.None
+ (let [label' (org/objectweb/asm/Label::new)]
+ [(dictionary.put label label' mapping) label'])))
+
+(def: (relabel-branching [mapping instruction])
+ (Re-labeler /.Branching)
+ (case instruction
+ (^template [<tag>]
+ (<tag> label)
+ (let [[mapping label] (..relabel [mapping label])]
+ [mapping (<tag> label)]))
+ ([#/.IF_ICMPEQ] [#/.IF_ICMPGE] [#/.IF_ICMPGT] [#/.IF_ICMPLE] [#/.IF_ICMPLT] [#/.IF_ICMPNE]
+ [#/.IFEQ] [#/.IFNE] [#/.IFGE] [#/.IFGT] [#/.IFLE] [#/.IFLT]
+
+ [#/.IF_ACMPEQ] [#/.IF_ACMPNE] [#/.IFNONNULL] [#/.IFNULL])
+
+ (#/.TABLESWITCH min max default labels)
+ (let [[mapping default] (..relabel [mapping default])
+ [mapping labels] (list@fold (function (_ input [mapping output])
+ (let [[mapping input] (..relabel [mapping input])]
+ [mapping (list& input output)]))
+ [mapping (list)] labels)]
+ [mapping (#/.TABLESWITCH min max default (list.reverse labels))])
+
+ (#/.LOOKUPSWITCH default keys+labels)
+ (let [[mapping default] (..relabel [mapping default])
+ [mapping keys+labels] (list@fold (function (_ [expected input] [mapping output])
+ (let [[mapping input] (..relabel [mapping input])]
+ [mapping (list& [expected input] output)]))
+ [mapping (list)] keys+labels)]
+ [mapping (#/.LOOKUPSWITCH default (list.reverse keys+labels))])
+ ))
+
+(def: (relabel-exception [mapping instruction])
+ (Re-labeler /.Exception)
+ (case instruction
+ (#/.Try start end handler exception)
+ (let [[mapping start] (..relabel [mapping start])
+ [mapping end] (..relabel [mapping end])
+ [mapping handler] (..relabel [mapping handler])]
+ [mapping (#/.Try start end handler exception)])
+
+ #/.ATHROW
+ [mapping #/.ATHROW]
+ ))
+
+(def: (relabel-control [mapping instruction])
+ (Re-labeler /.Control)
+ (case instruction
+ (^template [<tag> <relabel>]
+ (<tag> instruction)
+ (let [[mapping instruction] (<relabel> [mapping instruction])]
+ [mapping (<tag> instruction)]))
+ ([#/.GOTO ..relabel]
+ [#/.Branching ..relabel-branching]
+ [#/.Exception ..relabel-exception])
+
+ (^template [<tag>]
+ (<tag> instruction)
+ [mapping (<tag> instruction)])
+ ([#/.Concurrency] [#/.Return])
+ ))
+
+(def: (relabel-instruction [mapping instruction])
+ (Re-labeler /.Instruction)
+ (case instruction
+ #/.NOP [mapping #/.NOP]
+
+ (^template [<tag>]
+ (<tag> instruction)
+ [mapping (<tag> instruction)])
+ ([#/.Constant]
+ [#/.Arithmetic]
+ [#/.Bitwise]
+ [#/.Conversion]
+ [#/.Array]
+ [#/.Object]
+ [#/.Local]
+ [#/.Stack]
+ [#/.Comparison])
+
+ (#/.Control instruction)
+ (let [[mapping instruction] (..relabel-control [mapping instruction])]
+ [mapping (#/.Control instruction)])))
+
+(def: (relabel-bytecode [mapping bytecode])
+ (Re-labeler /.Bytecode)
+ (row@fold (function (_ input [mapping output])
+ (let [[mapping input] (..relabel-instruction [mapping input])]
+ [mapping (row.add input output)]))
+ [mapping (row.row)]
+ bytecode))
+
+(def: fresh
+ Mapping
+ (dictionary.new nat.hash))
+
+(def: bytecode
+ (-> (/.Bytecode /.Label) Inst)
+ (|>> [..fresh]
+ ..relabel-bytecode
+ product.right
+ (row@map ..instruction)
+ row.to-list
+ _.fuse))
+
+(type: Pseudo-Handler
+ (-> Text (List Synthesis) (Try (/.Bytecode /.Label))))
+
+(def: (true-handler pseudo)
+ (-> Pseudo-Handler jvm.Handler)
+ (function (_ extension-name phase archive inputs)
+ (|> (pseudo extension-name inputs)
+ (:: try.monad map ..bytecode)
+ phase.lift)))
+
+(def: (def::generation extender)
+ (-> jvm.Extender
+ (directive.Handler jvm.Anchor jvm.Inst jvm.Definition))
+ (function (handler extension-name phase archive inputsC+)
+ (case inputsC+
+ (^ (list nameC valueC))
+ (do phase.monad
+ [[_ _ name] (lux/.evaluate! archive Text nameC)
+ [_ _ pseudo-handlerV] (lux/.evaluate! archive ..Pseudo-Handler valueC)
+ _ (|> pseudo-handlerV
+ (:coerce ..Pseudo-Handler)
+ ..true-handler
+ (extension.install extender (:coerce Text name))
+ directive.lift-generation)
+ _ (directive.lift-generation
+ (generation.log! (format "Generation " (%.text (:coerce Text name)))))]
+ (wrap directive.no-requirements))
+
+ _
+ (phase.throw extension.invalid-syntax [extension-name %.code inputsC+]))))
+
+(def: #export (bundle extender)
+ (-> jvm.Extender
+ (directive.Bundle jvm.Anchor jvm.Inst jvm.Definition))
+ (|> bundle.empty
+ (dictionary.put "lux def generation" (..def::generation extender))))
diff --git a/lux-jvm/source/luxc/lang/host/jvm.lux b/lux-jvm/source/luxc/lang/host/jvm.lux
new file mode 100644
index 000000000..d957bdb1d
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/host/jvm.lux
@@ -0,0 +1,131 @@
+(.module:
+ [lux (#- Definition Type)
+ [host (#+ import:)]
+ [abstract
+ monad]
+ [control
+ ["p" parser
+ ["s" code]]]
+ [data
+ [binary (#+ Binary)]
+ [collection
+ ["." list ("#/." functor)]]]
+ [macro
+ ["." code]
+ [syntax (#+ syntax:)]]
+ [target
+ [jvm
+ ["." type (#+ Type)
+ [category (#+ Class)]]]]
+ [tool
+ [compiler
+ [reference (#+ Register)]
+ [language
+ [lux
+ ["." generation]]]
+ [meta
+ [archive (#+ Archive)]]]]])
+
+(import: org/objectweb/asm/MethodVisitor)
+
+(import: org/objectweb/asm/ClassWriter)
+
+(import: #long org/objectweb/asm/Label
+ (new []))
+
+(type: #export Def
+ (-> ClassWriter ClassWriter))
+
+(type: #export Inst
+ (-> MethodVisitor MethodVisitor))
+
+(type: #export Label
+ org/objectweb/asm/Label)
+
+(type: #export Visibility
+ #Public
+ #Protected
+ #Private
+ #Default)
+
+(type: #export Version
+ #V1_1
+ #V1_2
+ #V1_3
+ #V1_4
+ #V1_5
+ #V1_6
+ #V1_7
+ #V1_8)
+
+(type: #export ByteCode Binary)
+
+(type: #export Definition [Text ByteCode])
+
+(type: #export Anchor [Label Register])
+
+(type: #export Host
+ (generation.Host Inst Definition))
+
+(template [<name> <base>]
+ [(type: #export <name>
+ (<base> ..Anchor Inst Definition))]
+
+ [State generation.State]
+ [Operation generation.Operation]
+ [Phase generation.Phase]
+ [Handler generation.Handler]
+ [Bundle generation.Bundle]
+ [Extender generation.Extender]
+ )
+
+(type: #export (Generator i)
+ (-> Phase Archive i (Operation Inst)))
+
+(syntax: (config: {type s.local-identifier}
+ {none s.local-identifier}
+ {++ s.local-identifier}
+ {options (s.tuple (p.many s.local-identifier))})
+ (let [g!type (code.local-identifier type)
+ g!none (code.local-identifier none)
+ g!tags+ (list/map code.local-tag options)
+ g!_left (code.local-identifier "_left")
+ g!_right (code.local-identifier "_right")
+ g!options+ (list/map (function (_ option)
+ (` (def: (~' #export) (~ (code.local-identifier option))
+ (~ g!type)
+ (|> (~ g!none)
+ (set@ (~ (code.local-tag option)) #1)))))
+ options)]
+ (wrap (list& (` (type: (~' #export) (~ g!type)
+ (~ (code.record (list/map (function (_ tag)
+ [tag (` .Bit)])
+ g!tags+)))))
+
+ (` (def: (~' #export) (~ g!none)
+ (~ g!type)
+ (~ (code.record (list/map (function (_ tag)
+ [tag (` #0)])
+ g!tags+)))))
+
+ (` (def: (~' #export) ((~ (code.local-identifier ++)) (~ g!_left) (~ g!_right))
+ (-> (~ g!type) (~ g!type) (~ g!type))
+ (~ (code.record (list/map (function (_ tag)
+ [tag (` (or (get@ (~ tag) (~ g!_left))
+ (get@ (~ tag) (~ g!_right))))])
+ g!tags+)))))
+
+ g!options+))))
+
+(config: Class-Config noneC ++C [finalC])
+(config: Method-Config noneM ++M [finalM staticM synchronizedM strictM])
+(config: Field-Config noneF ++F [finalF staticF transientF volatileF])
+
+(def: #export new-label
+ (-> Any Label)
+ (function (_ _)
+ (org/objectweb/asm/Label::new)))
+
+(def: #export (simple-class name)
+ (-> Text (Type Class))
+ (type.class name (list)))
diff --git a/lux-jvm/source/luxc/lang/host/jvm/def.lux b/lux-jvm/source/luxc/lang/host/jvm/def.lux
new file mode 100644
index 000000000..f274da61f
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/host/jvm/def.lux
@@ -0,0 +1,298 @@
+(.module:
+ [lux (#- Type)
+ ["." host (#+ import: do-to)]
+ [control
+ ["." function]]
+ [data
+ ["." product]
+ [number
+ ["i" int]]
+ ["." text
+ ["%" format (#+ format)]]
+ [collection
+ ["." array (#+ Array)]
+ ["." list ("#@." functor)]]]
+ [target
+ [jvm
+ [encoding
+ ["." name]]
+ ["." type (#+ Type Constraint)
+ [category (#+ Class Value Method)]
+ ["." signature]
+ ["." descriptor]]]]]
+ ["." //])
+
+(def: signature (|>> type.signature signature.signature))
+(def: descriptor (|>> type.descriptor descriptor.descriptor))
+(def: class-name (|>> type.descriptor descriptor.class-name name.read))
+
+(import: #long java/lang/Object)
+(import: #long java/lang/String)
+
+(import: org/objectweb/asm/Opcodes
+ (#static ACC_PUBLIC int)
+ (#static ACC_PROTECTED int)
+ (#static ACC_PRIVATE int)
+
+ (#static ACC_TRANSIENT int)
+ (#static ACC_VOLATILE int)
+
+ (#static ACC_ABSTRACT int)
+ (#static ACC_FINAL int)
+ (#static ACC_STATIC int)
+ (#static ACC_SYNCHRONIZED int)
+ (#static ACC_STRICT int)
+
+ (#static ACC_SUPER int)
+ (#static ACC_INTERFACE int)
+
+ (#static V1_1 int)
+ (#static V1_2 int)
+ (#static V1_3 int)
+ (#static V1_4 int)
+ (#static V1_5 int)
+ (#static V1_6 int)
+ (#static V1_7 int)
+ (#static V1_8 int)
+ )
+
+(import: org/objectweb/asm/FieldVisitor
+ (visitEnd [] void))
+
+(import: org/objectweb/asm/MethodVisitor
+ (visitCode [] void)
+ (visitMaxs [int int] void)
+ (visitEnd [] void))
+
+(import: org/objectweb/asm/ClassWriter
+ (#static COMPUTE_MAXS int)
+ (#static COMPUTE_FRAMES int)
+ (new [int])
+ (visit [int int String String String [String]] void)
+ (visitEnd [] void)
+ (visitField [int String String String Object] FieldVisitor)
+ (visitMethod [int String String String [String]] MethodVisitor)
+ (toByteArray [] [byte]))
+
+(def: (string-array values)
+ (-> (List Text) (Array Text))
+ (let [output (host.array String (list.size values))]
+ (exec (list@map (function (_ [idx value])
+ (host.array-write idx value output))
+ (list.enumerate values))
+ output)))
+
+(def: (version-flag version)
+ (-> //.Version Int)
+ (case version
+ #//.V1_1 (Opcodes::V1_1)
+ #//.V1_2 (Opcodes::V1_2)
+ #//.V1_3 (Opcodes::V1_3)
+ #//.V1_4 (Opcodes::V1_4)
+ #//.V1_5 (Opcodes::V1_5)
+ #//.V1_6 (Opcodes::V1_6)
+ #//.V1_7 (Opcodes::V1_7)
+ #//.V1_8 (Opcodes::V1_8)))
+
+(def: (visibility-flag visibility)
+ (-> //.Visibility Int)
+ (case visibility
+ #//.Public (Opcodes::ACC_PUBLIC)
+ #//.Protected (Opcodes::ACC_PROTECTED)
+ #//.Private (Opcodes::ACC_PRIVATE)
+ #//.Default +0))
+
+(def: (class-flags config)
+ (-> //.Class-Config Int)
+ ($_ i.+
+ (if (get@ #//.finalC config) (Opcodes::ACC_FINAL) +0)))
+
+(def: (method-flags config)
+ (-> //.Method-Config Int)
+ ($_ i.+
+ (if (get@ #//.staticM config) (Opcodes::ACC_STATIC) +0)
+ (if (get@ #//.finalM config) (Opcodes::ACC_FINAL) +0)
+ (if (get@ #//.synchronizedM config) (Opcodes::ACC_SYNCHRONIZED) +0)
+ (if (get@ #//.strictM config) (Opcodes::ACC_STRICT) +0)))
+
+(def: (field-flags config)
+ (-> //.Field-Config Int)
+ ($_ i.+
+ (if (get@ #//.staticF config) (Opcodes::ACC_STATIC) +0)
+ (if (get@ #//.finalF config) (Opcodes::ACC_FINAL) +0)
+ (if (get@ #//.transientF config) (Opcodes::ACC_TRANSIENT) +0)
+ (if (get@ #//.volatileF config) (Opcodes::ACC_VOLATILE) +0)))
+
+(def: param-signature
+ (-> (Type Class) Text)
+ (|>> ..signature (format ":")))
+
+(def: (formal-param [name super interfaces])
+ (-> Constraint Text)
+ (format name
+ (param-signature super)
+ (|> interfaces
+ (list@map param-signature)
+ (text.join-with ""))))
+
+(def: (constraints-signature constraints super interfaces)
+ (-> (List Constraint) (Type Class) (List (Type Class))
+ Text)
+ (let [formal-params (if (list.empty? constraints)
+ ""
+ (format "<"
+ (|> constraints
+ (list@map formal-param)
+ (text.join-with ""))
+ ">"))]
+ (format formal-params
+ (..signature super)
+ (|> interfaces
+ (list@map ..signature)
+ (text.join-with "")))))
+
+(def: class-computes
+ Int
+ ($_ i.+
+ (ClassWriter::COMPUTE_MAXS)
+ ## (ClassWriter::COMPUTE_FRAMES)
+ ))
+
+(def: binary-name (|>> name.internal name.read))
+
+(template [<name> <flag>]
+ [(def: #export (<name> version visibility config name constraints super interfaces
+ definitions)
+ (-> //.Version //.Visibility //.Class-Config Text (List Constraint) (Type Class) (List (Type Class)) //.Def
+ (host.type [byte]))
+ (let [writer (|> (do-to (ClassWriter::new class-computes)
+ (ClassWriter::visit (version-flag version)
+ ($_ i.+
+ (Opcodes::ACC_SUPER)
+ <flag>
+ (visibility-flag visibility)
+ (class-flags config))
+ (..binary-name name)
+ (constraints-signature constraints super interfaces)
+ (..class-name super)
+ (|> interfaces
+ (list@map ..class-name)
+ string-array)))
+ definitions)
+ _ (ClassWriter::visitEnd writer)]
+ (ClassWriter::toByteArray writer)))]
+
+ [class +0]
+ [abstract (Opcodes::ACC_ABSTRACT)]
+ )
+
+(def: $Object
+ (Type Class)
+ (type.class "java.lang.Object" (list)))
+
+(def: #export (interface version visibility config name constraints interfaces
+ definitions)
+ (-> //.Version //.Visibility //.Class-Config Text (List Constraint) (List (Type Class)) //.Def
+ (host.type [byte]))
+ (let [writer (|> (do-to (ClassWriter::new class-computes)
+ (ClassWriter::visit (version-flag version)
+ ($_ i.+
+ (Opcodes::ACC_SUPER)
+ (Opcodes::ACC_INTERFACE)
+ (visibility-flag visibility)
+ (class-flags config))
+ (..binary-name name)
+ (constraints-signature constraints $Object interfaces)
+ (..class-name $Object)
+ (|> interfaces
+ (list@map ..class-name)
+ string-array)))
+ definitions)
+ _ (ClassWriter::visitEnd writer)]
+ (ClassWriter::toByteArray writer)))
+
+(def: #export (method visibility config name type then)
+ (-> //.Visibility //.Method-Config Text (Type Method) //.Inst
+ //.Def)
+ (function (_ writer)
+ (let [=method (ClassWriter::visitMethod ($_ i.+
+ (visibility-flag visibility)
+ (method-flags config))
+ (..binary-name name)
+ (..descriptor type)
+ (..signature type)
+ (string-array (list))
+ writer)
+ _ (MethodVisitor::visitCode =method)
+ _ (then =method)
+ _ (MethodVisitor::visitMaxs +0 +0 =method)
+ _ (MethodVisitor::visitEnd =method)]
+ writer)))
+
+(def: #export (abstract-method visibility config name type)
+ (-> //.Visibility //.Method-Config Text (Type Method)
+ //.Def)
+ (function (_ writer)
+ (let [=method (ClassWriter::visitMethod ($_ i.+
+ (visibility-flag visibility)
+ (method-flags config)
+ (Opcodes::ACC_ABSTRACT))
+ (..binary-name name)
+ (..descriptor type)
+ (..signature type)
+ (string-array (list))
+ writer)
+ _ (MethodVisitor::visitEnd =method)]
+ writer)))
+
+(def: #export (field visibility config name type)
+ (-> //.Visibility //.Field-Config Text (Type Value) //.Def)
+ (function (_ writer)
+ (let [=field (do-to (ClassWriter::visitField ($_ i.+
+ (visibility-flag visibility)
+ (field-flags config))
+ (..binary-name name)
+ (..descriptor type)
+ (..signature type)
+ (host.null)
+ writer)
+ (FieldVisitor::visitEnd))]
+ writer)))
+
+(template [<name> <lux-type> <jvm-type> <prepare>]
+ [(def: #export (<name> visibility config name value)
+ (-> //.Visibility //.Field-Config Text <lux-type> //.Def)
+ (function (_ writer)
+ (let [=field (do-to (ClassWriter::visitField ($_ i.+
+ (visibility-flag visibility)
+ (field-flags config))
+ (..binary-name name)
+ (..descriptor <jvm-type>)
+ (..signature <jvm-type>)
+ (<prepare> value)
+ writer)
+ (FieldVisitor::visitEnd))]
+ writer)))]
+
+ [boolean-field Bit type.boolean function.identity]
+ [byte-field Int type.byte host.long-to-byte]
+ [short-field Int type.short host.long-to-short]
+ [int-field Int type.int host.long-to-int]
+ [long-field Int type.long function.identity]
+ [float-field Frac type.float host.double-to-float]
+ [double-field Frac type.double function.identity]
+ [char-field Nat type.char (|>> .int host.long-to-int host.int-to-char)]
+ [string-field Text (type.class "java.lang.String" (list)) function.identity]
+ )
+
+(def: #export (fuse defs)
+ (-> (List //.Def) //.Def)
+ (case defs
+ #.Nil
+ function.identity
+
+ (#.Cons singleton #.Nil)
+ singleton
+
+ (#.Cons head tail)
+ (function.compose (fuse tail) head)))
diff --git a/lux-jvm/source/luxc/lang/host/jvm/inst.lux b/lux-jvm/source/luxc/lang/host/jvm/inst.lux
new file mode 100644
index 000000000..b673c7d7e
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/host/jvm/inst.lux
@@ -0,0 +1,464 @@
+(.module:
+ [lux (#- Type int char)
+ ["." host (#+ import: do-to)]
+ [abstract
+ [monad (#+ do)]]
+ [control
+ ["." function]
+ ["." try]
+ ["p" parser
+ ["s" code]]]
+ [data
+ ["." product]
+ ["." maybe]
+ [number
+ ["n" nat]
+ ["i" int]]
+ [collection
+ ["." list ("#@." functor)]]]
+ [macro
+ ["." code]
+ ["." template]
+ [syntax (#+ syntax:)]]
+ [target
+ [jvm
+ [encoding
+ ["." name (#+ External)]]
+ ["." type (#+ Type) ("#@." equivalence)
+ [category (#+ Void Value Return Method Primitive Object Class Array Var Parameter)]
+ ["." box]
+ ["." descriptor]
+ ["." reflection]]]]
+ [tool
+ [compiler
+ [phase (#+ Operation)]]]]
+ ["." // (#+ Inst)])
+
+(def: class-name (|>> type.descriptor descriptor.class-name name.read))
+(def: descriptor (|>> type.descriptor descriptor.descriptor))
+(def: reflection (|>> type.reflection reflection.reflection))
+
+## [Host]
+(import: #long java/lang/Object)
+(import: #long java/lang/String)
+
+(syntax: (declare {codes (p.many s.local-identifier)})
+ (|> codes
+ (list@map (function (_ code) (` ((~' #static) (~ (code.local-identifier code)) (~' int)))))
+ wrap))
+
+(`` (import: #long org/objectweb/asm/Opcodes
+ (#static NOP int)
+
+ ## Conversion
+ (~~ (declare D2F D2I D2L
+ F2D F2I F2L
+ I2B I2C I2D I2F I2L I2S
+ L2D L2F L2I))
+
+ ## Primitive
+ (~~ (declare T_BOOLEAN T_CHAR T_FLOAT T_DOUBLE
+ T_BYTE T_SHORT T_INT T_LONG))
+
+ ## Class
+ (~~ (declare CHECKCAST NEW INSTANCEOF))
+
+ ## Stack
+ (~~ (declare DUP DUP_X1 DUP_X2
+ DUP2 DUP2_X1 DUP2_X2
+ POP POP2
+ SWAP))
+
+ ## Jump
+ (~~ (declare IF_ICMPEQ IF_ICMPGT IF_ICMPLT
+ IF_ICMPNE IF_ICMPGE IF_ICMPLE
+ IF_ACMPEQ IF_ACMPNE IFNULL IFNONNULL
+ IFEQ IFNE IFLT IFLE IFGT IFGE
+ GOTO))
+
+ (~~ (declare BIPUSH SIPUSH))
+ (~~ (declare ICONST_M1 ICONST_0 ICONST_1 ICONST_2 ICONST_3 ICONST_4 ICONST_5
+ LCONST_0 LCONST_1
+ FCONST_0 FCONST_1 FCONST_2
+ DCONST_0 DCONST_1))
+ (#static ACONST_NULL int)
+
+ ## Var
+ (~~ (declare IINC
+ ILOAD LLOAD FLOAD DLOAD ALOAD
+ ISTORE LSTORE FSTORE DSTORE ASTORE))
+
+ ## Arithmetic
+ (~~ (declare IADD ISUB IMUL IDIV IREM INEG
+ LADD LSUB LMUL LDIV LREM LNEG LCMP
+ FADD FSUB FMUL FDIV FREM FNEG FCMPG FCMPL
+ DADD DSUB DMUL DDIV DREM DNEG DCMPG DCMPL))
+
+ ## Bit-wise
+ (~~ (declare IAND IOR IXOR ISHL ISHR IUSHR
+ LAND LOR LXOR LSHL LSHR LUSHR))
+
+ ## Array
+ (~~ (declare ARRAYLENGTH NEWARRAY ANEWARRAY
+ AALOAD AASTORE
+ BALOAD BASTORE
+ SALOAD SASTORE
+ IALOAD IASTORE
+ LALOAD LASTORE
+ FALOAD FASTORE
+ DALOAD DASTORE
+ CALOAD CASTORE))
+
+ ## Member
+ (~~ (declare GETSTATIC PUTSTATIC GETFIELD PUTFIELD
+ INVOKESTATIC INVOKESPECIAL INVOKEVIRTUAL INVOKEINTERFACE))
+
+ (#static ATHROW int)
+
+ ## Concurrency
+ (~~ (declare MONITORENTER MONITOREXIT))
+
+ ## Return
+ (~~ (declare RETURN IRETURN LRETURN FRETURN DRETURN ARETURN))
+ ))
+
+(import: #long org/objectweb/asm/Label
+ (new []))
+
+(import: #long org/objectweb/asm/MethodVisitor
+ (visitCode [] void)
+ (visitMaxs [int int] void)
+ (visitEnd [] void)
+ (visitInsn [int] void)
+ (visitLdcInsn [java/lang/Object] void)
+ (visitFieldInsn [int java/lang/String java/lang/String java/lang/String] void)
+ (visitTypeInsn [int java/lang/String] void)
+ (visitVarInsn [int int] void)
+ (visitIntInsn [int int] void)
+ (visitMethodInsn [int java/lang/String java/lang/String java/lang/String boolean] void)
+ (visitLabel [org/objectweb/asm/Label] void)
+ (visitJumpInsn [int org/objectweb/asm/Label] void)
+ (visitTryCatchBlock [org/objectweb/asm/Label org/objectweb/asm/Label org/objectweb/asm/Label java/lang/String] void)
+ (visitLookupSwitchInsn [org/objectweb/asm/Label [int] [org/objectweb/asm/Label]] void)
+ (visitTableSwitchInsn [int int org/objectweb/asm/Label [org/objectweb/asm/Label]] void)
+ )
+
+## [Insts]
+(def: #export make-label
+ (All [s] (Operation s org/objectweb/asm/Label))
+ (function (_ state)
+ (#try.Success [state (org/objectweb/asm/Label::new)])))
+
+(def: #export (with-label action)
+ (All [a] (-> (-> org/objectweb/asm/Label a) a))
+ (action (org/objectweb/asm/Label::new)))
+
+(template [<name> <type> <prepare>]
+ [(def: #export (<name> value)
+ (-> <type> Inst)
+ (function (_ visitor)
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitLdcInsn (<prepare> value)))))]
+
+ [boolean Bit function.identity]
+ [int Int host.long-to-int]
+ [long Int function.identity]
+ [double Frac function.identity]
+ [char Nat (|>> .int host.long-to-int host.int-to-char)]
+ [string Text function.identity]
+ )
+
+(template: (!prefix short)
+ (`` ((~~ (template.identifier ["org/objectweb/asm/Opcodes::" short])))))
+
+(template [<constant>]
+ [(def: #export <constant>
+ Inst
+ (function (_ visitor)
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitInsn (!prefix <constant>)))))]
+
+ [ICONST_M1] [ICONST_0] [ICONST_1] [ICONST_2] [ICONST_3] [ICONST_4] [ICONST_5]
+ [LCONST_0] [LCONST_1]
+ [FCONST_0] [FCONST_1] [FCONST_2]
+ [DCONST_0] [DCONST_1]
+ )
+
+(def: #export NULL
+ Inst
+ (function (_ visitor)
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitInsn (!prefix ACONST_NULL)))))
+
+(template [<constant>]
+ [(def: #export (<constant> constant)
+ (-> Int Inst)
+ (function (_ visitor)
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitIntInsn (!prefix <constant>) constant))))]
+
+ [BIPUSH]
+ [SIPUSH]
+ )
+
+(template [<name>]
+ [(def: #export <name>
+ Inst
+ (function (_ visitor)
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitInsn (!prefix <name>)))))]
+
+ [NOP]
+
+ ## Stack
+ [DUP] [DUP_X1] [DUP_X2] [DUP2] [DUP2_X1] [DUP2_X2]
+ [POP] [POP2]
+ [SWAP]
+
+ ## Conversions
+ [D2F] [D2I] [D2L]
+ [F2D] [F2I] [F2L]
+ [I2B] [I2C] [I2D] [I2F] [I2L] [I2S]
+ [L2D] [L2F] [L2I]
+
+ ## Integer arithmetic
+ [IADD] [ISUB] [IMUL] [IDIV] [IREM] [INEG]
+
+ ## Integer bitwise
+ [IAND] [IOR] [IXOR] [ISHL] [ISHR] [IUSHR]
+
+ ## Long arithmetic
+ [LADD] [LSUB] [LMUL] [LDIV] [LREM] [LNEG]
+ [LCMP]
+
+ ## Long bitwise
+ [LAND] [LOR] [LXOR] [LSHL] [LSHR] [LUSHR]
+
+ ## Float arithmetic
+ [FADD] [FSUB] [FMUL] [FDIV] [FREM] [FNEG] [FCMPG] [FCMPL]
+
+ ## Double arithmetic
+ [DADD] [DSUB] [DMUL] [DDIV] [DREM] [DNEG]
+ [DCMPG] [DCMPL]
+
+ ## Array
+ [ARRAYLENGTH]
+ [AALOAD] [AASTORE]
+ [BALOAD] [BASTORE]
+ [SALOAD] [SASTORE]
+ [IALOAD] [IASTORE]
+ [LALOAD] [LASTORE]
+ [FALOAD] [FASTORE]
+ [DALOAD] [DASTORE]
+ [CALOAD] [CASTORE]
+
+ ## Exceptions
+ [ATHROW]
+
+ ## Concurrency
+ [MONITORENTER] [MONITOREXIT]
+
+ ## Return
+ [RETURN] [IRETURN] [LRETURN] [FRETURN] [DRETURN] [ARETURN]
+ )
+
+(type: #export Register Nat)
+
+(template [<name>]
+ [(def: #export (<name> register)
+ (-> Register Inst)
+ (function (_ visitor)
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitVarInsn (!prefix <name>) (.int register)))))]
+
+ [IINC]
+ [ILOAD] [LLOAD] [FLOAD] [DLOAD] [ALOAD]
+ [ISTORE] [LSTORE] [FSTORE] [DSTORE] [ASTORE]
+ )
+
+(template [<name> <inst>]
+ [(def: #export (<name> class field type)
+ (-> (Type Class) Text (Type Value) Inst)
+ (function (_ visitor)
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitFieldInsn (<inst>) (..class-name class) field (..descriptor type)))))]
+
+ [GETSTATIC org/objectweb/asm/Opcodes::GETSTATIC]
+ [PUTSTATIC org/objectweb/asm/Opcodes::PUTSTATIC]
+
+ [PUTFIELD org/objectweb/asm/Opcodes::PUTFIELD]
+ [GETFIELD org/objectweb/asm/Opcodes::GETFIELD]
+ )
+
+(template [<category> <instructions>+]
+ [(`` (template [<name> <inst>]
+ [(def: #export (<name> class)
+ (-> (Type <category>) Inst)
+ (function (_ visitor)
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitTypeInsn (<inst>) (..class-name class)))))]
+
+ (~~ (template.splice <instructions>+))))]
+
+ [Object
+ [[CHECKCAST org/objectweb/asm/Opcodes::CHECKCAST]
+ [ANEWARRAY org/objectweb/asm/Opcodes::ANEWARRAY]]]
+
+ [Class
+ [[NEW org/objectweb/asm/Opcodes::NEW]
+ [INSTANCEOF org/objectweb/asm/Opcodes::INSTANCEOF]]]
+ )
+
+(def: #export (NEWARRAY type)
+ (-> (Type Primitive) Inst)
+ (function (_ visitor)
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitIntInsn (org/objectweb/asm/Opcodes::NEWARRAY)
+ (`` (cond (~~ (template [<descriptor> <opcode>]
+ [(type@= <descriptor> type) (<opcode>)]
+
+ [type.boolean org/objectweb/asm/Opcodes::T_BOOLEAN]
+ [type.byte org/objectweb/asm/Opcodes::T_BYTE]
+ [type.short org/objectweb/asm/Opcodes::T_SHORT]
+ [type.int org/objectweb/asm/Opcodes::T_INT]
+ [type.long org/objectweb/asm/Opcodes::T_LONG]
+ [type.float org/objectweb/asm/Opcodes::T_FLOAT]
+ [type.double org/objectweb/asm/Opcodes::T_DOUBLE]
+ [type.char org/objectweb/asm/Opcodes::T_CHAR]))
+ ## else
+ (undefined)))))))
+
+(template [<name> <inst> <interface?>]
+ [(def: #export (<name> class method-name method)
+ (-> (Type Class) Text (Type Method) Inst)
+ (function (_ visitor)
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitMethodInsn (<inst>)
+ (..class-name class)
+ method-name
+ (|> method type.descriptor descriptor.descriptor)
+ <interface?>))))]
+
+ [INVOKESTATIC org/objectweb/asm/Opcodes::INVOKESTATIC false]
+ [INVOKEVIRTUAL org/objectweb/asm/Opcodes::INVOKEVIRTUAL false]
+ [INVOKESPECIAL org/objectweb/asm/Opcodes::INVOKESPECIAL false]
+ [INVOKEINTERFACE org/objectweb/asm/Opcodes::INVOKEINTERFACE true]
+ )
+
+(template [<name>]
+ [(def: #export (<name> @where)
+ (-> //.Label Inst)
+ (function (_ visitor)
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitJumpInsn (!prefix <name>) @where))))]
+
+ [IF_ICMPEQ] [IF_ICMPGT] [IF_ICMPLT]
+ [IF_ICMPNE] [IF_ICMPGE] [IF_ICMPLE]
+ [IF_ACMPEQ] [IF_ACMPNE] [IFNULL] [IFNONNULL]
+ [IFEQ] [IFNE] [IFLT] [IFLE] [IFGT] [IFGE]
+ [GOTO]
+ )
+
+(def: #export (LOOKUPSWITCH default keys+labels)
+ (-> //.Label (List [Int //.Label]) Inst)
+ (function (_ visitor)
+ (let [keys+labels (list.sort (function (_ left right)
+ (i.< (product.left left) (product.left right)))
+ keys+labels)
+ array-size (list.size keys+labels)
+ keys-array (host.array int array-size)
+ labels-array (host.array org/objectweb/asm/Label array-size)
+ _ (loop [idx 0]
+ (if (n.< array-size idx)
+ (let [[key label] (maybe.assume (list.nth idx keys+labels))]
+ (exec
+ (host.array-write idx (host.long-to-int key) keys-array)
+ (host.array-write idx label labels-array)
+ (recur (inc idx))))
+ []))]
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitLookupSwitchInsn default keys-array labels-array)))))
+
+(def: #export (TABLESWITCH min max default labels)
+ (-> Int Int //.Label (List //.Label) Inst)
+ (function (_ visitor)
+ (let [num-labels (list.size labels)
+ labels-array (host.array org/objectweb/asm/Label num-labels)
+ _ (loop [idx 0]
+ (if (n.< num-labels idx)
+ (exec (host.array-write idx
+ (maybe.assume (list.nth idx labels))
+ labels-array)
+ (recur (inc idx)))
+ []))]
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitTableSwitchInsn min max default labels-array)))))
+
+(def: #export (try @from @to @handler exception)
+ (-> //.Label //.Label //.Label (Type Class) Inst)
+ (function (_ visitor)
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitTryCatchBlock @from @to @handler (..class-name exception)))))
+
+(def: #export (label @label)
+ (-> //.Label Inst)
+ (function (_ visitor)
+ (do-to visitor
+ (org/objectweb/asm/MethodVisitor::visitLabel @label))))
+
+(def: #export (array elementT)
+ (-> (Type Value) Inst)
+ (case (type.primitive? elementT)
+ (#.Left elementT)
+ (ANEWARRAY elementT)
+
+ (#.Right elementT)
+ (NEWARRAY elementT)))
+
+(template [<name> <boolean> <byte> <short> <int> <long> <float> <double> <char>]
+ [(def: (<name> type)
+ (-> (Type Primitive) Text)
+ (`` (cond (~~ (template [<descriptor> <output>]
+ [(type@= <descriptor> type) <output>]
+
+ [type.boolean <boolean>]
+ [type.byte <byte>]
+ [type.short <short>]
+ [type.int <int>]
+ [type.long <long>]
+ [type.float <float>]
+ [type.double <double>]
+ [type.char <char>]))
+ ## else
+ (undefined))))]
+
+ [primitive-wrapper
+ box.boolean box.byte box.short box.int
+ box.long box.float box.double box.char]
+ [primitive-unwrap
+ "booleanValue" "byteValue" "shortValue" "intValue"
+ "longValue" "floatValue" "doubleValue" "charValue"]
+ )
+
+(def: #export (wrap type)
+ (-> (Type Primitive) Inst)
+ (let [wrapper (type.class (primitive-wrapper type) (list))]
+ (INVOKESTATIC wrapper "valueOf" (type.method [(list type) wrapper (list)]))))
+
+(def: #export (unwrap type)
+ (-> (Type Primitive) Inst)
+ (let [wrapper (type.class (primitive-wrapper type) (list))]
+ (|>> (CHECKCAST wrapper)
+ (INVOKEVIRTUAL wrapper (primitive-unwrap type) (type.method [(list) type (list)])))))
+
+(def: #export (fuse insts)
+ (-> (List Inst) Inst)
+ (case insts
+ #.Nil
+ function.identity
+
+ (#.Cons singleton #.Nil)
+ singleton
+
+ (#.Cons head tail)
+ (function.compose (fuse tail) head)))
diff --git a/lux-jvm/source/luxc/lang/synthesis/variable.lux b/lux-jvm/source/luxc/lang/synthesis/variable.lux
new file mode 100644
index 000000000..f6a45b02e
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/synthesis/variable.lux
@@ -0,0 +1,98 @@
+(.module:
+ lux
+ (lux (data [number]
+ (coll [list "list/" Fold<List> Monoid<List>]
+ ["s" set])))
+ (luxc (lang ["la" analysis]
+ ["ls" synthesis]
+ [".L" variable #+ Variable])))
+
+(def: (bound-vars path)
+ (-> ls.Path (List Variable))
+ (case path
+ (#ls.BindP register)
+ (list (.int register))
+
+ (^or (#ls.SeqP pre post) (#ls.AltP pre post))
+ (list/compose (bound-vars pre) (bound-vars post))
+
+ _
+ (list)))
+
+(def: (path-bodies path)
+ (-> ls.Path (List ls.Synthesis))
+ (case path
+ (#ls.ExecP body)
+ (list body)
+
+ (#ls.SeqP pre post)
+ (path-bodies post)
+
+ (#ls.AltP pre post)
+ (list/compose (path-bodies pre) (path-bodies post))
+
+ _
+ (list)))
+
+(def: (non-arg? arity var)
+ (-> ls.Arity Variable Bit)
+ (and (variableL.local? var)
+ (n/> arity (.nat var))))
+
+(type: Tracker (s.Set Variable))
+
+(def: init-tracker Tracker (s.new number.Hash<Int>))
+
+(def: (unused-vars current-arity bound exprS)
+ (-> ls.Arity (List Variable) ls.Synthesis (List Variable))
+ (let [tracker (loop [exprS exprS
+ tracker (list/fold s.add init-tracker bound)]
+ (case exprS
+ (#ls.Variable var)
+ (if (non-arg? current-arity var)
+ (s.remove var tracker)
+ tracker)
+
+ (#ls.Variant tag last? memberS)
+ (recur memberS tracker)
+
+ (#ls.Tuple membersS)
+ (list/fold recur tracker membersS)
+
+ (#ls.Call funcS argsS)
+ (list/fold recur (recur funcS tracker) argsS)
+
+ (^or (#ls.Recur argsS)
+ (#ls.Procedure name argsS))
+ (list/fold recur tracker argsS)
+
+ (#ls.Let offset inputS outputS)
+ (|> tracker (recur inputS) (recur outputS))
+
+ (#ls.If testS thenS elseS)
+ (|> tracker (recur testS) (recur thenS) (recur elseS))
+
+ (#ls.Loop offset initsS bodyS)
+ (recur bodyS (list/fold recur tracker initsS))
+
+ (#ls.Case inputS outputPS)
+ (let [tracker' (list/fold s.add
+ (recur inputS tracker)
+ (bound-vars outputPS))]
+ (list/fold recur tracker' (path-bodies outputPS)))
+
+ (#ls.Function arity env bodyS)
+ (list/fold s.remove tracker env)
+
+ _
+ tracker
+ ))]
+ (s.to-list tracker)))
+
+## (def: (optimize-register-use current-arity [pathS bodyS])
+## (-> ls.Arity [ls.Path ls.Synthesis] [ls.Path ls.Synthesis])
+## (let [bound (bound-vars pathS)
+## unused (unused-vars current-arity bound bodyS)
+## adjusted (adjust-vars unused bound)]
+## [(|> pathS (clean-pattern adjusted) simplify-pattern)
+## (clean-expression adjusted bodyS)]))
diff --git a/lux-jvm/source/luxc/lang/translation/jvm.lux b/lux-jvm/source/luxc/lang/translation/jvm.lux
new file mode 100644
index 000000000..141e70184
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/translation/jvm.lux
@@ -0,0 +1,182 @@
+(.module:
+ [lux (#- Module Definition)
+ ["." host (#+ import: do-to object)]
+ [abstract
+ [monad (#+ do)]]
+ [control
+ pipe
+ ["." try (#+ Try)]
+ ["." exception (#+ exception:)]
+ ["." io (#+ IO io)]
+ [concurrency
+ ["." atom (#+ Atom atom)]]]
+ [data
+ [binary (#+ Binary)]
+ ["." product]
+ ["." text ("#@." hash)
+ ["%" format (#+ format)]]
+ [collection
+ ["." array]
+ ["." dictionary (#+ Dictionary)]]]
+ [target
+ [jvm
+ ["." loader (#+ Library)]
+ ["." type
+ ["." descriptor]]]]
+ [tool
+ [compiler
+ [language
+ [lux
+ ["." generation]]]
+ ["." meta
+ [io (#+ lux-context)]
+ [archive
+ [descriptor (#+ Module)]
+ ["." artifact]]]]]]
+ [///
+ [host
+ ["." jvm (#+ Inst Definition Host State)
+ ["." def]
+ ["." inst]]]]
+ )
+
+(import: #long java/lang/reflect/Field
+ (get [#? java/lang/Object] #try #? java/lang/Object))
+
+(import: #long (java/lang/Class a)
+ (getField [java/lang/String] #try java/lang/reflect/Field))
+
+(import: #long java/lang/Object
+ (getClass [] (java/lang/Class java/lang/Object)))
+
+(import: #long java/lang/ClassLoader)
+
+(type: #export ByteCode Binary)
+
+(def: #export value-field Text "_value")
+(def: #export $Value (type.class "java.lang.Object" (list)))
+
+(exception: #export (cannot-load {class Text} {error Text})
+ (exception.report
+ ["Class" class]
+ ["Error" error]))
+
+(exception: #export (invalid-field {class Text} {field Text} {error Text})
+ (exception.report
+ ["Class" class]
+ ["Field" field]
+ ["Error" error]))
+
+(exception: #export (invalid-value {class Text})
+ (exception.report
+ ["Class" class]))
+
+(def: (class-value class-name class)
+ (-> Text (java/lang/Class java/lang/Object) (Try Any))
+ (case (java/lang/Class::getField ..value-field class)
+ (#try.Success field)
+ (case (java/lang/reflect/Field::get #.None field)
+ (#try.Success ?value)
+ (case ?value
+ (#.Some value)
+ (#try.Success value)
+
+ #.None
+ (exception.throw ..invalid-value class-name))
+
+ (#try.Failure error)
+ (exception.throw ..cannot-load [class-name error]))
+
+ (#try.Failure error)
+ (exception.throw ..invalid-field [class-name ..value-field error])))
+
+(def: class-path-separator ".")
+
+(def: #export bytecode-name
+ (-> Text Text)
+ (text.replace-all ..class-path-separator .module-separator))
+
+(def: #export (class-name [module-id artifact-id])
+ (-> generation.Context Text)
+ (format lux-context
+ ..class-path-separator (%.nat meta.version)
+ ..class-path-separator (%.nat module-id)
+ ..class-path-separator (%.nat artifact-id)))
+
+(def: (evaluate! library loader eval-class valueI)
+ (-> Library java/lang/ClassLoader Text Inst (Try [Any Definition]))
+ (let [bytecode-name (..bytecode-name eval-class)
+ bytecode (def.class #jvm.V1_6
+ #jvm.Public jvm.noneC
+ bytecode-name
+ (list) $Value
+ (list)
+ (|>> (def.field #jvm.Public ($_ jvm.++F jvm.finalF jvm.staticF)
+ ..value-field ..$Value)
+ (def.method #jvm.Public ($_ jvm.++M jvm.staticM jvm.strictM)
+ "<clinit>"
+ (type.method [(list) type.void (list)])
+ (|>> valueI
+ (inst.PUTSTATIC (type.class bytecode-name (list)) ..value-field ..$Value)
+ inst.RETURN))))]
+ (io.run (do (try.with io.monad)
+ [_ (loader.store eval-class bytecode library)
+ class (loader.load eval-class loader)
+ value (:: io.monad wrap (..class-value eval-class class))]
+ (wrap [value
+ [eval-class bytecode]])))))
+
+(def: (execute! library loader temp-label [class-name class-bytecode])
+ (-> Library java/lang/ClassLoader Text Definition (Try Any))
+ (io.run (do (try.with io.monad)
+ [existing-class? (|> (atom.read library)
+ (:: io.monad map (dictionary.contains? class-name))
+ (try.lift io.monad)
+ (: (IO (Try Bit))))
+ _ (if existing-class?
+ (wrap [])
+ (loader.store class-name class-bytecode library))]
+ (loader.load class-name loader))))
+
+(def: (define! library loader context valueI)
+ (-> Library java/lang/ClassLoader generation.Context Inst (Try [Text Any Definition]))
+ (let [class-name (..class-name context)]
+ (do try.monad
+ [[value definition] (evaluate! library loader class-name valueI)]
+ (wrap [class-name value definition]))))
+
+(def: #export host
+ (IO Host)
+ (io (let [library (loader.new-library [])
+ loader (loader.memory library)]
+ (: Host
+ (structure
+ (def: (evaluate! temp-label valueI)
+ (:: try.monad map product.left
+ (..evaluate! library loader (text.replace-all " " "$" temp-label) valueI)))
+
+ (def: execute!
+ (..execute! library loader))
+
+ (def: define!
+ (..define! library loader))
+
+ (def: (ingest context bytecode)
+ [(..class-name context) bytecode])
+
+ (def: (re-learn context [_ bytecode])
+ (io.run
+ (loader.store (..class-name context) bytecode library)))
+
+ (def: (re-load context [_ bytecode])
+ (io.run
+ (do (try.with io.monad)
+ [#let [class-name (..class-name context)]
+ _ (loader.store class-name bytecode library)
+ class (loader.load class-name loader)]
+ (:: io.monad wrap (..class-value class-name class))))))))))
+
+(def: #export $Variant (type.array ..$Value))
+(def: #export $Tuple (type.array ..$Value))
+(def: #export $Runtime (type.class (..class-name [0 0]) (list)))
+(def: #export $Function (type.class (..class-name [0 1]) (list)))
diff --git a/lux-jvm/source/luxc/lang/translation/jvm/case.lux b/lux-jvm/source/luxc/lang/translation/jvm/case.lux
new file mode 100644
index 000000000..0d8aaa91e
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/translation/jvm/case.lux
@@ -0,0 +1,239 @@
+(.module:
+ [lux (#- Type if let case)
+ [abstract
+ [monad (#+ do)]]
+ [control
+ ["." function]
+ ["ex" exception (#+ exception:)]]
+ [data
+ [number
+ ["n" nat]]]
+ [target
+ [jvm
+ ["." type (#+ Type)
+ ["." category (#+ Void Value Return Primitive Object Class Array Var Parameter Method)]
+ ["." descriptor (#+ Descriptor)]
+ ["." signature (#+ Signature)]]]]
+ [tool
+ [compiler
+ ["." phase ("operation@." monad)]
+ [meta
+ [archive (#+ Archive)]]
+ [language
+ [lux
+ ["." synthesis (#+ Path Synthesis)]]]]]]
+ [luxc
+ [lang
+ [host
+ ["$" jvm (#+ Label Inst Operation Phase Generator)
+ ["_" inst]]]]]
+ ["." //
+ ["." runtime]])
+
+(def: (pop-altI stack-depth)
+ (-> Nat Inst)
+ (.case stack-depth
+ 0 function.identity
+ 1 _.POP
+ 2 _.POP2
+ _ ## (n.> 2)
+ (|>> _.POP2
+ (pop-altI (n.- 2 stack-depth)))))
+
+(def: peekI
+ Inst
+ (|>> _.DUP
+ (_.int +0)
+ _.AALOAD))
+
+(def: pushI
+ Inst
+ (_.INVOKESTATIC //.$Runtime "pm_push" (type.method [(list runtime.$Stack //.$Value) runtime.$Stack (list)])))
+
+(def: popI
+ (|>> (_.int +1)
+ _.AALOAD
+ (_.CHECKCAST runtime.$Stack)))
+
+(def: (path' stack-depth @else @end phase archive path)
+ (-> Nat Label Label Phase Archive Path (Operation Inst))
+ (.case path
+ #synthesis.Pop
+ (operation@wrap ..popI)
+
+ (#synthesis.Bind register)
+ (operation@wrap (|>> peekI
+ (_.ASTORE register)))
+
+ (^ (synthesis.path/bit value))
+ (operation@wrap (.let [jumpI (.if value _.IFEQ _.IFNE)]
+ (|>> peekI
+ (_.unwrap type.boolean)
+ (jumpI @else))))
+
+ (^ (synthesis.path/i64 value))
+ (operation@wrap (|>> peekI
+ (_.unwrap type.long)
+ (_.long (.int value))
+ _.LCMP
+ (_.IFNE @else)))
+
+ (^ (synthesis.path/f64 value))
+ (operation@wrap (|>> peekI
+ (_.unwrap type.double)
+ (_.double value)
+ _.DCMPL
+ (_.IFNE @else)))
+
+ (^ (synthesis.path/text value))
+ (operation@wrap (|>> peekI
+ (_.string value)
+ (_.INVOKEVIRTUAL (type.class "java.lang.Object" (list))
+ "equals"
+ (type.method [(list //.$Value) type.boolean (list)]))
+ (_.IFEQ @else)))
+
+ (#synthesis.Then bodyS)
+ (do phase.monad
+ [bodyI (phase archive bodyS)]
+ (wrap (|>> (pop-altI stack-depth)
+ bodyI
+ (_.GOTO @end))))
+
+ (^template [<pattern> <flag> <prepare>]
+ (^ (<pattern> idx))
+ (operation@wrap (<| _.with-label (function (_ @success))
+ _.with-label (function (_ @fail))
+ (|>> peekI
+ (_.CHECKCAST //.$Variant)
+ (_.int (.int (<prepare> idx)))
+ <flag>
+ (_.INVOKESTATIC //.$Runtime "pm_variant" (type.method [(list //.$Variant runtime.$Tag runtime.$Flag) runtime.$Value (list)]))
+ _.DUP
+ (_.IFNULL @fail)
+ (_.GOTO @success)
+ (_.label @fail)
+ _.POP
+ (_.GOTO @else)
+ (_.label @success)
+ pushI))))
+ ([synthesis.side/left _.NULL function.identity]
+ [synthesis.side/right (_.string "") .inc])
+
+ (^ (synthesis.member/left lefts))
+ (operation@wrap (.let [accessI (.case lefts
+ 0
+ _.AALOAD
+
+ lefts
+ (_.INVOKESTATIC //.$Runtime "tuple_left" (type.method [(list //.$Tuple runtime.$Index) //.$Value (list)])))]
+ (|>> peekI
+ (_.CHECKCAST //.$Tuple)
+ (_.int (.int lefts))
+ accessI
+ pushI)))
+
+ (^ (synthesis.member/right lefts))
+ (operation@wrap (|>> peekI
+ (_.CHECKCAST //.$Tuple)
+ (_.int (.int lefts))
+ (_.INVOKESTATIC //.$Runtime "tuple_right" (type.method [(list //.$Tuple runtime.$Index) //.$Value (list)]))
+ pushI))
+
+ ## Extra optimization
+ (^ (synthesis.path/seq
+ (synthesis.member/left 0)
+ (synthesis.!bind-top register thenP)))
+ (do phase.monad
+ [then! (path' stack-depth @else @end phase archive thenP)]
+ (wrap (|>> peekI
+ (_.CHECKCAST //.$Tuple)
+ (_.int +0)
+ _.AALOAD
+ (_.ASTORE register)
+ then!)))
+
+ ## Extra optimization
+ (^template [<pm> <getter>]
+ (^ (synthesis.path/seq
+ (<pm> lefts)
+ (synthesis.!bind-top register thenP)))
+ (do phase.monad
+ [then! (path' stack-depth @else @end phase archive thenP)]
+ (wrap (|>> peekI
+ (_.CHECKCAST //.$Tuple)
+ (_.int (.int lefts))
+ (_.INVOKESTATIC //.$Runtime <getter> (type.method [(list //.$Tuple runtime.$Index) //.$Value (list)]))
+ (_.ASTORE register)
+ then!))))
+ ([synthesis.member/left "tuple_left"]
+ [synthesis.member/right "tuple_right"])
+
+ (#synthesis.Alt leftP rightP)
+ (do phase.monad
+ [@alt-else _.make-label
+ leftI (path' (inc stack-depth) @alt-else @end phase archive leftP)
+ rightI (path' stack-depth @else @end phase archive rightP)]
+ (wrap (|>> _.DUP
+ leftI
+ (_.label @alt-else)
+ _.POP
+ rightI)))
+
+ (#synthesis.Seq leftP rightP)
+ (do phase.monad
+ [leftI (path' stack-depth @else @end phase archive leftP)
+ rightI (path' stack-depth @else @end phase archive rightP)]
+ (wrap (|>> leftI
+ rightI)))
+ ))
+
+(def: (path @end phase archive path)
+ (-> Label Phase Archive Path (Operation Inst))
+ (do phase.monad
+ [@else _.make-label
+ pathI (..path' 1 @else @end phase archive path)]
+ (wrap (|>> pathI
+ (_.label @else)
+ _.POP
+ (_.INVOKESTATIC //.$Runtime "pm_fail" (type.method [(list) type.void (list)]))
+ _.NULL
+ (_.GOTO @end)))))
+
+(def: #export (if phase archive [testS thenS elseS])
+ (Generator [Synthesis Synthesis Synthesis])
+ (do phase.monad
+ [testI (phase archive testS)
+ thenI (phase archive thenS)
+ elseI (phase archive elseS)]
+ (wrap (<| _.with-label (function (_ @else))
+ _.with-label (function (_ @end))
+ (|>> testI
+ (_.unwrap type.boolean)
+ (_.IFEQ @else)
+ thenI
+ (_.GOTO @end)
+ (_.label @else)
+ elseI
+ (_.label @end))))))
+
+(def: #export (let phase archive [inputS register exprS])
+ (Generator [Synthesis Nat Synthesis])
+ (do phase.monad
+ [inputI (phase archive inputS)
+ exprI (phase archive exprS)]
+ (wrap (|>> inputI
+ (_.ASTORE register)
+ exprI))))
+
+(def: #export (case phase archive [valueS path])
+ (Generator [Synthesis Path])
+ (do phase.monad
+ [@end _.make-label
+ valueI (phase archive valueS)
+ pathI (..path @end phase archive path)]
+ (wrap (|>> _.NULL
+ valueI
+ pushI
+ pathI
+ (_.label @end)))))
diff --git a/lux-jvm/source/luxc/lang/translation/jvm/common.lux b/lux-jvm/source/luxc/lang/translation/jvm/common.lux
new file mode 100644
index 000000000..6cd7f4f2f
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/translation/jvm/common.lux
@@ -0,0 +1,72 @@
+(.module:
+ [lux #*
+ ## [abstract
+ ## [monad (#+ do)]]
+ ## [control
+ ## ["." try (#+ Try)]
+ ## ["ex" exception (#+ exception:)]
+ ## ["." io]]
+ ## [data
+ ## [binary (#+ Binary)]
+ ## ["." text ("#/." hash)
+ ## format]
+ ## [collection
+ ## ["." dictionary (#+ Dictionary)]]]
+ ## ["." macro]
+ ## [host (#+ import:)]
+ ## [tool
+ ## [compiler
+ ## [reference (#+ Register)]
+ ## ["." name]
+ ## ["." phase]]]
+ ]
+ ## [luxc
+ ## [lang
+ ## [host
+ ## ["." jvm
+ ## [type]]]]]
+ )
+
+## (def: #export (with-artifacts action)
+## (All [a] (-> (Meta a) (Meta [Artifacts a])))
+## (function (_ state)
+## (case (action (update@ #.host
+## (|>> (:coerce Host)
+## (set@ #artifacts (dictionary.new text.hash))
+## (:coerce Nothing))
+## state))
+## (#try.Success [state' output])
+## (#try.Success [(update@ #.host
+## (|>> (:coerce Host)
+## (set@ #artifacts (|> (get@ #.host state) (:coerce Host) (get@ #artifacts)))
+## (:coerce Nothing))
+## state')
+## [(|> state' (get@ #.host) (:coerce Host) (get@ #artifacts))
+## output]])
+
+## (#try.Failure error)
+## (#try.Failure error))))
+
+## (def: #export (load-definition state)
+## (-> Lux (-> Name Binary (Try Any)))
+## (function (_ (^@ def-name [def-module def-name]) def-bytecode)
+## (let [normal-name (format (name.normalize def-name) (%n (text/hash def-name)))
+## class-name (format (text.replace-all "/" "." def-module) "." normal-name)]
+## (<| (macro.run state)
+## (do macro.monad
+## [_ (..store-class class-name def-bytecode)
+## class (..load-class class-name)]
+## (case (do try.monad
+## [field (Class::getField [..value-field] class)]
+## (Field::get [#.None] field))
+## (#try.Success (#.Some def-value))
+## (wrap def-value)
+
+## (#try.Success #.None)
+## (phase.throw invalid-definition-value (%name def-name))
+
+## (#try.Failure error)
+## (phase.throw cannot-load-definition
+## (format "Definition: " (%name def-name) "\n"
+## "Error:\n"
+## error))))))))
diff --git a/lux-jvm/source/luxc/lang/translation/jvm/expression.lux b/lux-jvm/source/luxc/lang/translation/jvm/expression.lux
new file mode 100644
index 000000000..144e35f9b
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/translation/jvm/expression.lux
@@ -0,0 +1,72 @@
+(.module:
+ [lux #*
+ [tool
+ [compiler
+ [language
+ [lux
+ ["." synthesis]
+ [phase
+ ["." extension]]]]]]]
+ [luxc
+ [lang
+ [host
+ [jvm (#+ Phase)]]]]
+ [//
+ ["." common]
+ ["." primitive]
+ ["." structure]
+ ["." reference]
+ ["." case]
+ ["." loop]
+ ["." function]])
+
+(def: #export (translate archive synthesis)
+ Phase
+ (case synthesis
+ (^ (synthesis.bit value))
+ (primitive.bit value)
+
+ (^ (synthesis.i64 value))
+ (primitive.i64 value)
+
+ (^ (synthesis.f64 value))
+ (primitive.f64 value)
+
+ (^ (synthesis.text value))
+ (primitive.text value)
+
+ (^ (synthesis.variant data))
+ (structure.variant translate archive data)
+
+ (^ (synthesis.tuple members))
+ (structure.tuple translate archive members)
+
+ (^ (synthesis.variable variable))
+ (reference.variable archive variable)
+
+ (^ (synthesis.constant constant))
+ (reference.constant archive constant)
+
+ (^ (synthesis.branch/let data))
+ (case.let translate archive data)
+
+ (^ (synthesis.branch/if data))
+ (case.if translate archive data)
+
+ (^ (synthesis.branch/case data))
+ (case.case translate archive data)
+
+ (^ (synthesis.loop/recur data))
+ (loop.recur translate archive data)
+
+ (^ (synthesis.loop/scope data))
+ (loop.scope translate archive data)
+
+ (^ (synthesis.function/apply data))
+ (function.call translate archive data)
+
+ (^ (synthesis.function/abstraction data))
+ (function.function translate archive data)
+
+ (#synthesis.Extension extension)
+ (extension.apply archive translate extension)))
diff --git a/lux-jvm/source/luxc/lang/translation/jvm/extension.lux b/lux-jvm/source/luxc/lang/translation/jvm/extension.lux
new file mode 100644
index 000000000..9066dd156
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/translation/jvm/extension.lux
@@ -0,0 +1,16 @@
+(.module:
+ [lux #*
+ [data
+ [collection
+ ["." dictionary]]]]
+ [////
+ [host
+ [jvm (#+ Bundle)]]]
+ ["." / #_
+ ["#." common]
+ ["#." host]])
+
+(def: #export bundle
+ Bundle
+ (dictionary.merge /common.bundle
+ /host.bundle))
diff --git a/lux-jvm/source/luxc/lang/translation/jvm/extension/common.lux b/lux-jvm/source/luxc/lang/translation/jvm/extension/common.lux
new file mode 100644
index 000000000..383415c0a
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/translation/jvm/extension/common.lux
@@ -0,0 +1,388 @@
+(.module:
+ [lux (#- Type)
+ [abstract
+ ["." monad (#+ do)]]
+ [control
+ ["." try]
+ ["<>" parser
+ ["<s>" synthesis (#+ Parser)]]]
+ [data
+ ["." product]
+ [number
+ ["f" frac]]
+ [collection
+ ["." list ("#@." monad)]
+ ["." dictionary]]]
+ [target
+ [jvm
+ ["." type]]]
+ [tool
+ [compiler
+ ["." phase]
+ [meta
+ [archive (#+ Archive)]]
+ [language
+ [lux
+ ["." synthesis (#+ Synthesis %synthesis)]
+ [phase
+ [generation
+ [extension (#+ Nullary Unary Binary Trinary Variadic
+ nullary unary binary trinary variadic)]]
+ ["." extension
+ ["." bundle]]]]]]]
+ [host (#+ import:)]]
+ [luxc
+ [lang
+ [host
+ ["$" jvm (#+ Label Inst Def Handler Bundle Operation Phase)
+ ["_" inst]]]]]
+ ["." ///
+ ["." runtime]])
+
+(def: #export (custom [parser handler])
+ (All [s]
+ (-> [(Parser s)
+ (-> Text Phase Archive s (Operation Inst))]
+ Handler))
+ (function (_ extension-name phase archive input)
+ (case (<s>.run parser input)
+ (#try.Success input')
+ (handler extension-name phase archive input')
+
+ (#try.Failure error)
+ (phase.throw extension.invalid-syntax [extension-name %synthesis input]))))
+
+(import: java/lang/Double
+ (#static MIN_VALUE Double)
+ (#static MAX_VALUE Double))
+
+(def: $String (type.class "java.lang.String" (list)))
+(def: $CharSequence (type.class "java.lang.CharSequence" (list)))
+(def: $System (type.class "java.lang.System" (list)))
+(def: $Object (type.class "java.lang.Object" (list)))
+
+(def: lux-intI Inst (|>> _.I2L (_.wrap type.long)))
+(def: jvm-intI Inst (|>> (_.unwrap type.long) _.L2I))
+(def: check-stringI Inst (_.CHECKCAST $String))
+
+(def: (predicateI tester)
+ (-> (-> Label Inst)
+ Inst)
+ (let [$Boolean (type.class "java.lang.Boolean" (list))]
+ (<| _.with-label (function (_ @then))
+ _.with-label (function (_ @end))
+ (|>> (tester @then)
+ (_.GETSTATIC $Boolean "FALSE" $Boolean)
+ (_.GOTO @end)
+ (_.label @then)
+ (_.GETSTATIC $Boolean "TRUE" $Boolean)
+ (_.label @end)
+ ))))
+
+(def: unitI Inst (_.string synthesis.unit))
+
+## 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])
+ (<| _.with-label (function (_ @end))
+ _.with-label (function (_ @else))
+ (do {@ phase.monad}
+ [inputG (phase archive input)
+ elseG (phase archive else)
+ conditionalsG+ (: (Operation (List [(List [Int Label])
+ Inst]))
+ (monad.map @ (function (_ [chars branch])
+ (do @
+ [branchG (phase archive branch)]
+ (wrap (<| _.with-label (function (_ @branch))
+ [(list@map (function (_ char)
+ [(.int char) @branch])
+ chars)
+ (|>> (_.label @branch)
+ branchG
+ (_.GOTO @end))]))))
+ conditionals))
+ #let [table (|> conditionalsG+
+ (list@map product.left)
+ list@join)
+ conditionalsG (|> conditionalsG+
+ (list@map product.right)
+ _.fuse)]]
+ (wrap (|>> inputG (_.unwrap type.long) _.L2I
+ (_.LOOKUPSWITCH @else table)
+ conditionalsG
+ (_.label @else)
+ elseG
+ (_.label @end)
+ )))))]))
+
+(def: (lux::is [referenceI sampleI])
+ (Binary Inst)
+ (|>> referenceI
+ sampleI
+ (predicateI _.IF_ACMPEQ)))
+
+(def: (lux::try riskyI)
+ (Unary Inst)
+ (|>> riskyI
+ (_.CHECKCAST ///.$Function)
+ (_.INVOKESTATIC ///.$Runtime "try" runtime.try)))
+
+(template [<name> <op>]
+ [(def: (<name> [maskI inputI])
+ (Binary Inst)
+ (|>> inputI (_.unwrap type.long)
+ maskI (_.unwrap type.long)
+ <op> (_.wrap type.long)))]
+
+ [i64::and _.LAND]
+ [i64::or _.LOR]
+ [i64::xor _.LXOR]
+ )
+
+(template [<name> <op>]
+ [(def: (<name> [shiftI inputI])
+ (Binary Inst)
+ (|>> inputI (_.unwrap type.long)
+ shiftI jvm-intI
+ <op>
+ (_.wrap type.long)))]
+
+ [i64::left-shift _.LSHL]
+ [i64::arithmetic-right-shift _.LSHR]
+ [i64::logical-right-shift _.LUSHR]
+ )
+
+(template [<name> <const> <type>]
+ [(def: (<name> _)
+ (Nullary Inst)
+ (|>> <const> (_.wrap <type>)))]
+
+ [f64::smallest (_.double (Double::MIN_VALUE)) type.double]
+ [f64::min (_.double (f.* -1.0 (Double::MAX_VALUE))) type.double]
+ [f64::max (_.double (Double::MAX_VALUE)) type.double]
+ )
+
+(template [<name> <type> <op>]
+ [(def: (<name> [paramI subjectI])
+ (Binary Inst)
+ (|>> subjectI (_.unwrap <type>)
+ paramI (_.unwrap <type>)
+ <op>
+ (_.wrap <type>)))]
+
+ [i64::+ type.long _.LADD]
+ [i64::- type.long _.LSUB]
+ [i64::* type.long _.LMUL]
+ [i64::/ type.long _.LDIV]
+ [i64::% type.long _.LREM]
+
+ [f64::+ type.double _.DADD]
+ [f64::- type.double _.DSUB]
+ [f64::* type.double _.DMUL]
+ [f64::/ type.double _.DDIV]
+ [f64::% type.double _.DREM]
+ )
+
+(template [<eq> <lt> <type> <cmp>]
+ [(template [<name> <reference>]
+ [(def: (<name> [paramI subjectI])
+ (Binary Inst)
+ (|>> subjectI (_.unwrap <type>)
+ paramI (_.unwrap <type>)
+ <cmp>
+ (_.int <reference>)
+ (predicateI _.IF_ICMPEQ)))]
+
+ [<eq> +0]
+ [<lt> -1])]
+
+ [i64::= i64::< type.long _.LCMP]
+ [f64::= f64::< type.double _.DCMPG]
+ )
+
+(template [<name> <prepare> <transform>]
+ [(def: (<name> inputI)
+ (Unary Inst)
+ (|>> inputI <prepare> <transform>))]
+
+ [i64::f64 (_.unwrap type.long) (<| (_.wrap type.double) _.L2D)]
+ [i64::char (_.unwrap type.long)
+ ((|>> _.L2I _.I2C (_.INVOKESTATIC (type.class "java.lang.Character" (list)) "toString" (type.method [(list type.char) $String (list)]))))]
+
+ [f64::i64 (_.unwrap type.double) (<| (_.wrap type.long) _.D2L)]
+ [f64::encode (_.unwrap type.double)
+ (_.INVOKESTATIC (type.class "java.lang.Double" (list)) "toString" (type.method [(list type.double) $String (list)]))]
+ [f64::decode ..check-stringI
+ (_.INVOKESTATIC ///.$Runtime "decode_frac" (type.method [(list $String) ///.$Variant (list)]))]
+ )
+
+(def: (text::size inputI)
+ (Unary Inst)
+ (|>> inputI
+ ..check-stringI
+ (_.INVOKEVIRTUAL $String "length" (type.method [(list) type.int (list)]))
+ lux-intI))
+
+(template [<name> <pre-subject> <pre-param> <op> <post>]
+ [(def: (<name> [paramI subjectI])
+ (Binary Inst)
+ (|>> subjectI <pre-subject>
+ paramI <pre-param>
+ <op> <post>))]
+
+ [text::= (<|) (<|)
+ (_.INVOKEVIRTUAL $Object "equals" (type.method [(list $Object) type.boolean (list)]))
+ (_.wrap type.boolean)]
+ [text::< ..check-stringI ..check-stringI
+ (_.INVOKEVIRTUAL $String "compareTo" (type.method [(list $String) type.int (list)]))
+ (predicateI _.IFLT)]
+ [text::char ..check-stringI jvm-intI
+ (_.INVOKEVIRTUAL $String "charAt" (type.method [(list type.int) type.char (list)]))
+ lux-intI]
+ )
+
+(def: (text::concat [leftI rightI])
+ (Binary Inst)
+ (|>> leftI ..check-stringI
+ rightI ..check-stringI
+ (_.INVOKEVIRTUAL $String "concat" (type.method [(list $String) $String (list)]))))
+
+(def: (text::clip [startI endI subjectI])
+ (Trinary Inst)
+ (|>> subjectI ..check-stringI
+ startI jvm-intI
+ endI jvm-intI
+ (_.INVOKEVIRTUAL $String "substring" (type.method [(list type.int type.int) $String (list)]))))
+
+(def: index-method (type.method [(list $String type.int) type.int (list)]))
+(def: (text::index [startI partI textI])
+ (Trinary Inst)
+ (<| _.with-label (function (_ @not-found))
+ _.with-label (function (_ @end))
+ (|>> textI ..check-stringI
+ partI ..check-stringI
+ startI jvm-intI
+ (_.INVOKEVIRTUAL $String "indexOf" index-method)
+ _.DUP
+ (_.int -1)
+ (_.IF_ICMPEQ @not-found)
+ lux-intI
+ runtime.someI
+ (_.GOTO @end)
+ (_.label @not-found)
+ _.POP
+ runtime.noneI
+ (_.label @end))))
+
+(def: string-method (type.method [(list $String) type.void (list)]))
+(def: (io::log messageI)
+ (Unary Inst)
+ (let [$PrintStream (type.class "java.io.PrintStream" (list))]
+ (|>> (_.GETSTATIC $System "out" $PrintStream)
+ messageI
+ ..check-stringI
+ (_.INVOKEVIRTUAL $PrintStream "println" string-method)
+ unitI)))
+
+(def: (io::error messageI)
+ (Unary Inst)
+ (let [$Error (type.class "java.lang.Error" (list))]
+ (|>> (_.NEW $Error)
+ _.DUP
+ messageI
+ ..check-stringI
+ (_.INVOKESPECIAL $Error "<init>" string-method)
+ _.ATHROW)))
+
+(def: (io::exit codeI)
+ (Unary Inst)
+ (|>> codeI jvm-intI
+ (_.INVOKESTATIC $System "exit" (type.method [(list type.int) type.void (list)]))
+ _.NULL))
+
+(def: (io::current-time _)
+ (Nullary Inst)
+ (|>> (_.INVOKESTATIC $System "currentTimeMillis" (type.method [(list) type.long (list)]))
+ (_.wrap type.long)))
+
+(def: bundle::lux
+ Bundle
+ (|> (: Bundle bundle.empty)
+ (bundle.install "syntax char case!" lux::syntax-char-case!)
+ (bundle.install "is" (binary lux::is))
+ (bundle.install "try" (unary lux::try))))
+
+(def: bundle::i64
+ Bundle
+ (<| (bundle.prefix "i64")
+ (|> (: Bundle bundle.empty)
+ (bundle.install "and" (binary i64::and))
+ (bundle.install "or" (binary i64::or))
+ (bundle.install "xor" (binary i64::xor))
+ (bundle.install "left-shift" (binary i64::left-shift))
+ (bundle.install "logical-right-shift" (binary i64::logical-right-shift))
+ (bundle.install "arithmetic-right-shift" (binary i64::arithmetic-right-shift))
+ (bundle.install "=" (binary i64::=))
+ (bundle.install "<" (binary i64::<))
+ (bundle.install "+" (binary i64::+))
+ (bundle.install "-" (binary i64::-))
+ (bundle.install "*" (binary i64::*))
+ (bundle.install "/" (binary i64::/))
+ (bundle.install "%" (binary i64::%))
+ (bundle.install "f64" (unary i64::f64))
+ (bundle.install "char" (unary i64::char)))))
+
+(def: bundle::f64
+ Bundle
+ (<| (bundle.prefix "f64")
+ (|> (: Bundle bundle.empty)
+ (bundle.install "+" (binary f64::+))
+ (bundle.install "-" (binary f64::-))
+ (bundle.install "*" (binary f64::*))
+ (bundle.install "/" (binary f64::/))
+ (bundle.install "%" (binary f64::%))
+ (bundle.install "=" (binary f64::=))
+ (bundle.install "<" (binary f64::<))
+ (bundle.install "smallest" (nullary f64::smallest))
+ (bundle.install "min" (nullary f64::min))
+ (bundle.install "max" (nullary f64::max))
+ (bundle.install "i64" (unary f64::i64))
+ (bundle.install "encode" (unary f64::encode))
+ (bundle.install "decode" (unary f64::decode)))))
+
+(def: bundle::text
+ Bundle
+ (<| (bundle.prefix "text")
+ (|> (: Bundle bundle.empty)
+ (bundle.install "=" (binary text::=))
+ (bundle.install "<" (binary text::<))
+ (bundle.install "concat" (binary text::concat))
+ (bundle.install "index" (trinary text::index))
+ (bundle.install "size" (unary text::size))
+ (bundle.install "char" (binary text::char))
+ (bundle.install "clip" (trinary text::clip)))))
+
+(def: bundle::io
+ Bundle
+ (<| (bundle.prefix "io")
+ (|> (: Bundle bundle.empty)
+ (bundle.install "log" (unary io::log))
+ (bundle.install "error" (unary io::error))
+ (bundle.install "exit" (unary io::exit))
+ (bundle.install "current-time" (nullary io::current-time)))))
+
+(def: #export bundle
+ Bundle
+ (<| (bundle.prefix "lux")
+ (|> bundle::lux
+ (dictionary.merge bundle::i64)
+ (dictionary.merge bundle::f64)
+ (dictionary.merge bundle::text)
+ (dictionary.merge bundle::io))))
diff --git a/lux-jvm/source/luxc/lang/translation/jvm/extension/host.lux b/lux-jvm/source/luxc/lang/translation/jvm/extension/host.lux
new file mode 100644
index 000000000..7b90a8e4f
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/translation/jvm/extension/host.lux
@@ -0,0 +1,1047 @@
+(.module:
+ [lux (#- Type primitive int char type)
+ [host (#+ import:)]
+ [abstract
+ ["." monad (#+ do)]]
+ [control
+ ["." exception (#+ exception:)]
+ ["." function]
+ ["<>" parser ("#@." monad)
+ ["<t>" text]
+ ["<s>" synthesis (#+ Parser)]]]
+ [data
+ ["." product]
+ ["." maybe]
+ ["." text ("#@." equivalence)
+ ["%" format (#+ format)]]
+ [number
+ ["." nat]]
+ [collection
+ ["." list ("#@." monad)]
+ ["." dictionary (#+ Dictionary)]
+ ["." set]]]
+ [target
+ [jvm
+ ["." type (#+ Type Typed Argument)
+ ["." category (#+ Void Value Return Primitive Object Class Array Var Parameter Method)]
+ ["." box]
+ ["." reflection]
+ ["." signature]
+ ["." parser]]]]
+ [tool
+ [compiler
+ ["." reference (#+ Variable)]
+ ["." phase ("#@." monad)]
+ [meta
+ [archive (#+ Archive)]]
+ [language
+ [lux
+ [analysis (#+ Environment)]
+ ["." synthesis (#+ Synthesis Path %synthesis)]
+ ["." generation]
+ [phase
+ [generation
+ [extension (#+ Nullary Unary Binary
+ nullary unary binary)]]
+ [analysis
+ [".A" reference]]
+ ["." extension
+ ["." bundle]
+ [analysis
+ ["/" jvm]]]]]]]]]
+ [luxc
+ [lang
+ [host
+ ["$" jvm (#+ Label Inst Def Handler Bundle Operation Phase)
+ ["_" inst]
+ ["_." def]]]]]
+ ["." // #_
+ [common (#+ custom)]
+ ["/#" //
+ ["#." reference]
+ ["#." function]]])
+
+(template [<name> <category> <parser>]
+ [(def: #export <name>
+ (Parser (Type <category>))
+ (<t>.embed <parser> <s>.text))]
+
+ [var Var parser.var]
+ [class Class parser.class]
+ [object Object parser.object]
+ [value Value parser.value]
+ [return Return parser.return]
+ )
+
+(exception: #export (not-an-object-array {arrayJT (Type Array)})
+ (exception.report
+ ["JVM Type" (|> arrayJT type.signature signature.signature)]))
+
+(def: #export object-array
+ (Parser (Type Object))
+ (do <>.monad
+ [arrayJT (<t>.embed parser.array <s>.text)]
+ (case (parser.array? arrayJT)
+ (#.Some elementJT)
+ (case (parser.object? elementJT)
+ (#.Some elementJT)
+ (wrap elementJT)
+
+ #.None
+ (<>.fail (exception.construct ..not-an-object-array arrayJT)))
+
+ #.None
+ (undefined))))
+
+(template [<name> <inst>]
+ [(def: <name>
+ Inst
+ <inst>)]
+
+ [L2S (|>> _.L2I _.I2S)]
+ [L2B (|>> _.L2I _.I2B)]
+ [L2C (|>> _.L2I _.I2C)]
+ )
+
+(template [<conversion> <name>]
+ [(def: (<name> inputI)
+ (Unary Inst)
+ (if (is? _.NOP <conversion>)
+ inputI
+ (|>> inputI
+ <conversion>)))]
+
+ [_.D2F conversion::double-to-float]
+ [_.D2I conversion::double-to-int]
+ [_.D2L conversion::double-to-long]
+ [_.F2D conversion::float-to-double]
+ [_.F2I conversion::float-to-int]
+ [_.F2L conversion::float-to-long]
+ [_.I2B conversion::int-to-byte]
+ [_.I2C conversion::int-to-char]
+ [_.I2D conversion::int-to-double]
+ [_.I2F conversion::int-to-float]
+ [_.I2L conversion::int-to-long]
+ [_.I2S conversion::int-to-short]
+ [_.L2D conversion::long-to-double]
+ [_.L2F conversion::long-to-float]
+ [_.L2I conversion::long-to-int]
+ [..L2S conversion::long-to-short]
+ [..L2B conversion::long-to-byte]
+ [..L2C conversion::long-to-char]
+ [_.I2B conversion::char-to-byte]
+ [_.I2S conversion::char-to-short]
+ [_.NOP conversion::char-to-int]
+ [_.I2L conversion::char-to-long]
+ [_.I2L conversion::byte-to-long]
+ [_.I2L conversion::short-to-long]
+ )
+
+(def: conversion
+ Bundle
+ (<| (bundle.prefix "conversion")
+ (|> (: Bundle bundle.empty)
+ (bundle.install "double-to-float" (unary conversion::double-to-float))
+ (bundle.install "double-to-int" (unary conversion::double-to-int))
+ (bundle.install "double-to-long" (unary conversion::double-to-long))
+ (bundle.install "float-to-double" (unary conversion::float-to-double))
+ (bundle.install "float-to-int" (unary conversion::float-to-int))
+ (bundle.install "float-to-long" (unary conversion::float-to-long))
+ (bundle.install "int-to-byte" (unary conversion::int-to-byte))
+ (bundle.install "int-to-char" (unary conversion::int-to-char))
+ (bundle.install "int-to-double" (unary conversion::int-to-double))
+ (bundle.install "int-to-float" (unary conversion::int-to-float))
+ (bundle.install "int-to-long" (unary conversion::int-to-long))
+ (bundle.install "int-to-short" (unary conversion::int-to-short))
+ (bundle.install "long-to-double" (unary conversion::long-to-double))
+ (bundle.install "long-to-float" (unary conversion::long-to-float))
+ (bundle.install "long-to-int" (unary conversion::long-to-int))
+ (bundle.install "long-to-short" (unary conversion::long-to-short))
+ (bundle.install "long-to-byte" (unary conversion::long-to-byte))
+ (bundle.install "long-to-char" (unary conversion::long-to-char))
+ (bundle.install "char-to-byte" (unary conversion::char-to-byte))
+ (bundle.install "char-to-short" (unary conversion::char-to-short))
+ (bundle.install "char-to-int" (unary conversion::char-to-int))
+ (bundle.install "char-to-long" (unary conversion::char-to-long))
+ (bundle.install "byte-to-long" (unary conversion::byte-to-long))
+ (bundle.install "short-to-long" (unary conversion::short-to-long))
+ )))
+
+(template [<name> <op>]
+ [(def: (<name> [xI yI])
+ (Binary Inst)
+ (|>> xI
+ yI
+ <op>))]
+
+ [int::+ _.IADD]
+ [int::- _.ISUB]
+ [int::* _.IMUL]
+ [int::/ _.IDIV]
+ [int::% _.IREM]
+ [int::and _.IAND]
+ [int::or _.IOR]
+ [int::xor _.IXOR]
+ [int::shl _.ISHL]
+ [int::shr _.ISHR]
+ [int::ushr _.IUSHR]
+
+ [long::+ _.LADD]
+ [long::- _.LSUB]
+ [long::* _.LMUL]
+ [long::/ _.LDIV]
+ [long::% _.LREM]
+ [long::and _.LAND]
+ [long::or _.LOR]
+ [long::xor _.LXOR]
+ [long::shl _.LSHL]
+ [long::shr _.LSHR]
+ [long::ushr _.LUSHR]
+
+ [float::+ _.FADD]
+ [float::- _.FSUB]
+ [float::* _.FMUL]
+ [float::/ _.FDIV]
+ [float::% _.FREM]
+
+ [double::+ _.DADD]
+ [double::- _.DSUB]
+ [double::* _.DMUL]
+ [double::/ _.DDIV]
+ [double::% _.DREM]
+ )
+
+(def: $Boolean (type.class box.boolean (list)))
+(def: falseI (_.GETSTATIC $Boolean "FALSE" $Boolean))
+(def: trueI (_.GETSTATIC $Boolean "TRUE" $Boolean))
+
+(template [<name> <op>]
+ [(def: (<name> [xI yI])
+ (Binary Inst)
+ (<| _.with-label (function (_ @then))
+ _.with-label (function (_ @end))
+ (|>> xI
+ yI
+ (<op> @then)
+ falseI
+ (_.GOTO @end)
+ (_.label @then)
+ trueI
+ (_.label @end))))]
+
+ [int::= _.IF_ICMPEQ]
+ [int::< _.IF_ICMPLT]
+
+ [char::= _.IF_ICMPEQ]
+ [char::< _.IF_ICMPLT]
+ )
+
+(template [<name> <op> <reference>]
+ [(def: (<name> [xI yI])
+ (Binary Inst)
+ (<| _.with-label (function (_ @then))
+ _.with-label (function (_ @end))
+ (|>> xI
+ yI
+ <op>
+ (_.int <reference>)
+ (_.IF_ICMPEQ @then)
+ falseI
+ (_.GOTO @end)
+ (_.label @then)
+ trueI
+ (_.label @end))))]
+
+ [long::= _.LCMP +0]
+ [long::< _.LCMP -1]
+
+ [float::= _.FCMPG +0]
+ [float::< _.FCMPG -1]
+
+ [double::= _.DCMPG +0]
+ [double::< _.DCMPG -1]
+ )
+
+(def: int
+ Bundle
+ (<| (bundle.prefix (reflection.reflection reflection.int))
+ (|> (: Bundle bundle.empty)
+ (bundle.install "+" (binary int::+))
+ (bundle.install "-" (binary int::-))
+ (bundle.install "*" (binary int::*))
+ (bundle.install "/" (binary int::/))
+ (bundle.install "%" (binary int::%))
+ (bundle.install "=" (binary int::=))
+ (bundle.install "<" (binary int::<))
+ (bundle.install "and" (binary int::and))
+ (bundle.install "or" (binary int::or))
+ (bundle.install "xor" (binary int::xor))
+ (bundle.install "shl" (binary int::shl))
+ (bundle.install "shr" (binary int::shr))
+ (bundle.install "ushr" (binary int::ushr))
+ )))
+
+(def: long
+ Bundle
+ (<| (bundle.prefix (reflection.reflection reflection.long))
+ (|> (: Bundle bundle.empty)
+ (bundle.install "+" (binary long::+))
+ (bundle.install "-" (binary long::-))
+ (bundle.install "*" (binary long::*))
+ (bundle.install "/" (binary long::/))
+ (bundle.install "%" (binary long::%))
+ (bundle.install "=" (binary long::=))
+ (bundle.install "<" (binary long::<))
+ (bundle.install "and" (binary long::and))
+ (bundle.install "or" (binary long::or))
+ (bundle.install "xor" (binary long::xor))
+ (bundle.install "shl" (binary long::shl))
+ (bundle.install "shr" (binary long::shr))
+ (bundle.install "ushr" (binary long::ushr))
+ )))
+
+(def: float
+ Bundle
+ (<| (bundle.prefix (reflection.reflection reflection.float))
+ (|> (: Bundle bundle.empty)
+ (bundle.install "+" (binary float::+))
+ (bundle.install "-" (binary float::-))
+ (bundle.install "*" (binary float::*))
+ (bundle.install "/" (binary float::/))
+ (bundle.install "%" (binary float::%))
+ (bundle.install "=" (binary float::=))
+ (bundle.install "<" (binary float::<))
+ )))
+
+(def: double
+ Bundle
+ (<| (bundle.prefix (reflection.reflection reflection.double))
+ (|> (: Bundle bundle.empty)
+ (bundle.install "+" (binary double::+))
+ (bundle.install "-" (binary double::-))
+ (bundle.install "*" (binary double::*))
+ (bundle.install "/" (binary double::/))
+ (bundle.install "%" (binary double::%))
+ (bundle.install "=" (binary double::=))
+ (bundle.install "<" (binary double::<))
+ )))
+
+(def: char
+ Bundle
+ (<| (bundle.prefix (reflection.reflection reflection.char))
+ (|> (: Bundle bundle.empty)
+ (bundle.install "=" (binary char::=))
+ (bundle.install "<" (binary char::<))
+ )))
+
+(def: (primitive-array-length-handler jvm-primitive)
+ (-> (Type Primitive) Handler)
+ (..custom
+ [<s>.any
+ (function (_ extension-name generate archive arrayS)
+ (do phase.monad
+ [arrayI (generate archive arrayS)]
+ (wrap (|>> arrayI
+ (_.CHECKCAST (type.array jvm-primitive))
+ _.ARRAYLENGTH))))]))
+
+(def: array::length::object
+ Handler
+ (..custom
+ [($_ <>.and ..object-array <s>.any)
+ (function (_ extension-name generate archive [elementJT arrayS])
+ (do phase.monad
+ [arrayI (generate archive arrayS)]
+ (wrap (|>> arrayI
+ (_.CHECKCAST (type.array elementJT))
+ _.ARRAYLENGTH))))]))
+
+(def: (new-primitive-array-handler jvm-primitive)
+ (-> (Type Primitive) Handler)
+ (function (_ extension-name generate archive inputs)
+ (case inputs
+ (^ (list lengthS))
+ (do phase.monad
+ [lengthI (generate archive lengthS)]
+ (wrap (|>> lengthI
+ (_.array jvm-primitive))))
+
+ _
+ (phase.throw extension.invalid-syntax [extension-name %synthesis inputs]))))
+
+(def: array::new::object
+ Handler
+ (..custom
+ [($_ <>.and ..object <s>.any)
+ (function (_ extension-name generate archive [objectJT lengthS])
+ (do phase.monad
+ [lengthI (generate archive lengthS)]
+ (wrap (|>> lengthI
+ (_.ANEWARRAY objectJT)))))]))
+
+(def: (read-primitive-array-handler jvm-primitive loadI)
+ (-> (Type Primitive) Inst Handler)
+ (function (_ extension-name generate archive inputs)
+ (case inputs
+ (^ (list idxS arrayS))
+ (do phase.monad
+ [arrayI (generate archive arrayS)
+ idxI (generate archive idxS)]
+ (wrap (|>> arrayI
+ (_.CHECKCAST (type.array jvm-primitive))
+ idxI
+ loadI)))
+
+ _
+ (phase.throw extension.invalid-syntax [extension-name %synthesis inputs]))))
+
+(def: array::read::object
+ Handler
+ (..custom
+ [($_ <>.and ..object-array <s>.any <s>.any)
+ (function (_ extension-name generate archive [elementJT idxS arrayS])
+ (do phase.monad
+ [arrayI (generate archive arrayS)
+ idxI (generate archive idxS)]
+ (wrap (|>> arrayI
+ (_.CHECKCAST (type.array elementJT))
+ idxI
+ _.AALOAD))))]))
+
+(def: (write-primitive-array-handler jvm-primitive storeI)
+ (-> (Type Primitive) Inst Handler)
+ (function (_ extension-name generate archive inputs)
+ (case inputs
+ (^ (list idxS valueS arrayS))
+ (do phase.monad
+ [arrayI (generate archive arrayS)
+ idxI (generate archive idxS)
+ valueI (generate archive valueS)]
+ (wrap (|>> arrayI
+ (_.CHECKCAST (type.array jvm-primitive))
+ _.DUP
+ idxI
+ valueI
+ storeI)))
+
+ _
+ (phase.throw extension.invalid-syntax [extension-name %synthesis inputs]))))
+
+(def: array::write::object
+ Handler
+ (..custom
+ [($_ <>.and ..object-array <s>.any <s>.any <s>.any)
+ (function (_ extension-name generate archive [elementJT idxS valueS arrayS])
+ (do phase.monad
+ [arrayI (generate archive arrayS)
+ idxI (generate archive idxS)
+ valueI (generate archive valueS)]
+ (wrap (|>> arrayI
+ (_.CHECKCAST (type.array elementJT))
+ _.DUP
+ idxI
+ valueI
+ _.AASTORE))))]))
+
+(def: array
+ Bundle
+ (<| (bundle.prefix "array")
+ (|> bundle.empty
+ (dictionary.merge (<| (bundle.prefix "length")
+ (|> bundle.empty
+ (bundle.install (reflection.reflection reflection.boolean) (primitive-array-length-handler type.boolean))
+ (bundle.install (reflection.reflection reflection.byte) (primitive-array-length-handler type.byte))
+ (bundle.install (reflection.reflection reflection.short) (primitive-array-length-handler type.short))
+ (bundle.install (reflection.reflection reflection.int) (primitive-array-length-handler type.int))
+ (bundle.install (reflection.reflection reflection.long) (primitive-array-length-handler type.long))
+ (bundle.install (reflection.reflection reflection.float) (primitive-array-length-handler type.float))
+ (bundle.install (reflection.reflection reflection.double) (primitive-array-length-handler type.double))
+ (bundle.install (reflection.reflection reflection.char) (primitive-array-length-handler type.char))
+ (bundle.install "object" array::length::object))))
+ (dictionary.merge (<| (bundle.prefix "new")
+ (|> bundle.empty
+ (bundle.install (reflection.reflection reflection.boolean) (new-primitive-array-handler type.boolean))
+ (bundle.install (reflection.reflection reflection.byte) (new-primitive-array-handler type.byte))
+ (bundle.install (reflection.reflection reflection.short) (new-primitive-array-handler type.short))
+ (bundle.install (reflection.reflection reflection.int) (new-primitive-array-handler type.int))
+ (bundle.install (reflection.reflection reflection.long) (new-primitive-array-handler type.long))
+ (bundle.install (reflection.reflection reflection.float) (new-primitive-array-handler type.float))
+ (bundle.install (reflection.reflection reflection.double) (new-primitive-array-handler type.double))
+ (bundle.install (reflection.reflection reflection.char) (new-primitive-array-handler type.char))
+ (bundle.install "object" array::new::object))))
+ (dictionary.merge (<| (bundle.prefix "read")
+ (|> bundle.empty
+ (bundle.install (reflection.reflection reflection.boolean) (read-primitive-array-handler type.boolean _.BALOAD))
+ (bundle.install (reflection.reflection reflection.byte) (read-primitive-array-handler type.byte _.BALOAD))
+ (bundle.install (reflection.reflection reflection.short) (read-primitive-array-handler type.short _.SALOAD))
+ (bundle.install (reflection.reflection reflection.int) (read-primitive-array-handler type.int _.IALOAD))
+ (bundle.install (reflection.reflection reflection.long) (read-primitive-array-handler type.long _.LALOAD))
+ (bundle.install (reflection.reflection reflection.float) (read-primitive-array-handler type.float _.FALOAD))
+ (bundle.install (reflection.reflection reflection.double) (read-primitive-array-handler type.double _.DALOAD))
+ (bundle.install (reflection.reflection reflection.char) (read-primitive-array-handler type.char _.CALOAD))
+ (bundle.install "object" array::read::object))))
+ (dictionary.merge (<| (bundle.prefix "write")
+ (|> bundle.empty
+ (bundle.install (reflection.reflection reflection.boolean) (write-primitive-array-handler type.boolean _.BASTORE))
+ (bundle.install (reflection.reflection reflection.byte) (write-primitive-array-handler type.byte _.BASTORE))
+ (bundle.install (reflection.reflection reflection.short) (write-primitive-array-handler type.short _.SASTORE))
+ (bundle.install (reflection.reflection reflection.int) (write-primitive-array-handler type.int _.IASTORE))
+ (bundle.install (reflection.reflection reflection.long) (write-primitive-array-handler type.long _.LASTORE))
+ (bundle.install (reflection.reflection reflection.float) (write-primitive-array-handler type.float _.FASTORE))
+ (bundle.install (reflection.reflection reflection.double) (write-primitive-array-handler type.double _.DASTORE))
+ (bundle.install (reflection.reflection reflection.char) (write-primitive-array-handler type.char _.CASTORE))
+ (bundle.install "object" array::write::object))))
+ )))
+
+(def: (object::null _)
+ (Nullary Inst)
+ _.NULL)
+
+(def: (object::null? objectI)
+ (Unary Inst)
+ (<| _.with-label (function (_ @then))
+ _.with-label (function (_ @end))
+ (|>> objectI
+ (_.IFNULL @then)
+ falseI
+ (_.GOTO @end)
+ (_.label @then)
+ trueI
+ (_.label @end))))
+
+(def: (object::synchronized [monitorI exprI])
+ (Binary Inst)
+ (|>> monitorI
+ _.DUP
+ _.MONITORENTER
+ exprI
+ _.SWAP
+ _.MONITOREXIT))
+
+(def: (object::throw exceptionI)
+ (Unary Inst)
+ (|>> exceptionI
+ _.ATHROW))
+
+(def: $Class (type.class "java.lang.Class" (list)))
+
+(def: (object::class extension-name generate archive inputs)
+ Handler
+ (case inputs
+ (^ (list (synthesis.text class)))
+ (do phase.monad
+ []
+ (wrap (|>> (_.string class)
+ (_.INVOKESTATIC $Class "forName" (type.method [(list (type.class "java.lang.String" (list))) $Class (list)])))))
+
+ _
+ (phase.throw extension.invalid-syntax [extension-name %synthesis inputs])))
+
+(def: object::instance?
+ Handler
+ (..custom
+ [($_ <>.and <s>.text <s>.any)
+ (function (_ extension-name generate archive [class objectS])
+ (do phase.monad
+ [objectI (generate archive objectS)]
+ (wrap (|>> objectI
+ (_.INSTANCEOF (type.class class (list)))
+ (_.wrap type.boolean)))))]))
+
+(def: (object::cast extension-name generate archive inputs)
+ Handler
+ (case inputs
+ (^ (list (synthesis.text from) (synthesis.text to) valueS))
+ (do phase.monad
+ [valueI (generate archive valueS)]
+ (`` (cond (~~ (template [<object> <type>]
+ [(and (text@= (reflection.reflection (type.reflection <type>))
+ from)
+ (text@= <object>
+ to))
+ (wrap (|>> valueI (_.wrap <type>)))
+
+ (and (text@= <object>
+ from)
+ (text@= (reflection.reflection (type.reflection <type>))
+ to))
+ (wrap (|>> valueI (_.unwrap <type>)))]
+
+ [box.boolean type.boolean]
+ [box.byte type.byte]
+ [box.short type.short]
+ [box.int type.int]
+ [box.long type.long]
+ [box.float type.float]
+ [box.double type.double]
+ [box.char type.char]))
+ ## else
+ (wrap valueI))))
+
+ _
+ (phase.throw extension.invalid-syntax [extension-name %synthesis inputs])))
+
+(def: object-bundle
+ Bundle
+ (<| (bundle.prefix "object")
+ (|> (: Bundle bundle.empty)
+ (bundle.install "null" (nullary object::null))
+ (bundle.install "null?" (unary object::null?))
+ (bundle.install "synchronized" (binary object::synchronized))
+ (bundle.install "throw" (unary object::throw))
+ (bundle.install "class" object::class)
+ (bundle.install "instance?" object::instance?)
+ (bundle.install "cast" object::cast)
+ )))
+
+(def: primitives
+ (Dictionary Text (Type Primitive))
+ (|> (list [(reflection.reflection reflection.boolean) type.boolean]
+ [(reflection.reflection reflection.byte) type.byte]
+ [(reflection.reflection reflection.short) type.short]
+ [(reflection.reflection reflection.int) type.int]
+ [(reflection.reflection reflection.long) type.long]
+ [(reflection.reflection reflection.float) type.float]
+ [(reflection.reflection reflection.double) type.double]
+ [(reflection.reflection reflection.char) type.char])
+ (dictionary.from-list text.hash)))
+
+(def: get::static
+ Handler
+ (..custom
+ [($_ <>.and <s>.text <s>.text <s>.text)
+ (function (_ extension-name generate archive [class field unboxed])
+ (do phase.monad
+ []
+ (case (dictionary.get unboxed ..primitives)
+ (#.Some primitive)
+ (wrap (_.GETSTATIC (type.class class (list)) field primitive))
+
+ #.None
+ (wrap (_.GETSTATIC (type.class class (list)) field (type.class unboxed (list)))))))]))
+
+(def: put::static
+ Handler
+ (..custom
+ [($_ <>.and <s>.text <s>.text <s>.text <s>.any)
+ (function (_ extension-name generate archive [class field unboxed valueS])
+ (do phase.monad
+ [valueI (generate archive valueS)
+ #let [$class (type.class class (list))]]
+ (case (dictionary.get unboxed ..primitives)
+ (#.Some primitive)
+ (wrap (|>> valueI
+ (_.PUTSTATIC $class field primitive)
+ (_.string synthesis.unit)))
+
+ #.None
+ (wrap (|>> valueI
+ (_.CHECKCAST $class)
+ (_.PUTSTATIC $class field $class)
+ (_.string synthesis.unit))))))]))
+
+(def: get::virtual
+ Handler
+ (..custom
+ [($_ <>.and <s>.text <s>.text <s>.text <s>.any)
+ (function (_ extension-name generate archive [class field unboxed objectS])
+ (do phase.monad
+ [objectI (generate archive objectS)
+ #let [$class (type.class class (list))
+ getI (case (dictionary.get unboxed ..primitives)
+ (#.Some primitive)
+ (_.GETFIELD $class field primitive)
+
+ #.None
+ (_.GETFIELD $class field (type.class unboxed (list))))]]
+ (wrap (|>> objectI
+ (_.CHECKCAST $class)
+ getI))))]))
+
+(def: put::virtual
+ Handler
+ (..custom
+ [($_ <>.and <s>.text <s>.text <s>.text <s>.any <s>.any)
+ (function (_ extension-name generate archive [class field unboxed valueS objectS])
+ (do phase.monad
+ [valueI (generate archive valueS)
+ objectI (generate archive objectS)
+ #let [$class (type.class class (list))
+ putI (case (dictionary.get unboxed ..primitives)
+ (#.Some primitive)
+ (_.PUTFIELD $class field primitive)
+
+ #.None
+ (let [$unboxed (type.class unboxed (list))]
+ (|>> (_.CHECKCAST $unboxed)
+ (_.PUTFIELD $class field $unboxed))))]]
+ (wrap (|>> objectI
+ (_.CHECKCAST $class)
+ _.DUP
+ valueI
+ putI))))]))
+
+(type: Input (Typed Synthesis))
+
+(def: input
+ (Parser Input)
+ (<s>.tuple (<>.and ..value <s>.any)))
+
+(def: (generate-input generate archive [valueT valueS])
+ (-> Phase Archive Input
+ (Operation (Typed Inst)))
+ (do phase.monad
+ [valueI (generate archive valueS)]
+ (case (type.primitive? valueT)
+ (#.Right valueT)
+ (wrap [valueT valueI])
+
+ (#.Left valueT)
+ (wrap [valueT (|>> valueI
+ (_.CHECKCAST valueT))]))))
+
+(def: voidI (_.string synthesis.unit))
+
+(def: (prepare-output outputT)
+ (-> (Type Return) Inst)
+ (case (type.void? outputT)
+ (#.Right outputT)
+ ..voidI
+
+ (#.Left outputT)
+ function.identity))
+
+(def: invoke::static
+ Handler
+ (..custom
+ [($_ <>.and ..class <s>.text ..return (<>.some ..input))
+ (function (_ extension-name generate archive [class method outputT inputsTS])
+ (do {@ phase.monad}
+ [inputsTI (monad.map @ (generate-input generate archive) inputsTS)]
+ (wrap (|>> (_.fuse (list@map product.right inputsTI))
+ (_.INVOKESTATIC class method (type.method [(list@map product.left inputsTI) outputT (list)]))
+ (prepare-output outputT)))))]))
+
+(template [<name> <invoke>]
+ [(def: <name>
+ Handler
+ (..custom
+ [($_ <>.and ..class <s>.text ..return <s>.any (<>.some ..input))
+ (function (_ extension-name generate archive [class method outputT objectS inputsTS])
+ (do {@ phase.monad}
+ [objectI (generate archive objectS)
+ inputsTI (monad.map @ (generate-input generate archive) inputsTS)]
+ (wrap (|>> objectI
+ (_.CHECKCAST class)
+ (_.fuse (list@map product.right inputsTI))
+ (<invoke> class method
+ (type.method [(list@map product.left inputsTI)
+ outputT
+ (list)]))
+ (prepare-output outputT)))))]))]
+
+ [invoke::virtual _.INVOKEVIRTUAL]
+ [invoke::special _.INVOKESPECIAL]
+ [invoke::interface _.INVOKEINTERFACE]
+ )
+
+(def: invoke::constructor
+ Handler
+ (..custom
+ [($_ <>.and ..class (<>.some ..input))
+ (function (_ extension-name generate archive [class inputsTS])
+ (do {@ phase.monad}
+ [inputsTI (monad.map @ (generate-input generate archive) inputsTS)]
+ (wrap (|>> (_.NEW class)
+ _.DUP
+ (_.fuse (list@map product.right inputsTI))
+ (_.INVOKESPECIAL class "<init>" (type.method [(list@map product.left inputsTI) type.void (list)]))))))]))
+
+(def: member
+ Bundle
+ (<| (bundle.prefix "member")
+ (|> (: Bundle bundle.empty)
+ (dictionary.merge (<| (bundle.prefix "get")
+ (|> (: Bundle bundle.empty)
+ (bundle.install "static" get::static)
+ (bundle.install "virtual" get::virtual))))
+ (dictionary.merge (<| (bundle.prefix "put")
+ (|> (: Bundle bundle.empty)
+ (bundle.install "static" put::static)
+ (bundle.install "virtual" put::virtual))))
+ (dictionary.merge (<| (bundle.prefix "invoke")
+ (|> (: Bundle bundle.empty)
+ (bundle.install "static" invoke::static)
+ (bundle.install "virtual" invoke::virtual)
+ (bundle.install "special" invoke::special)
+ (bundle.install "interface" invoke::interface)
+ (bundle.install "constructor" invoke::constructor))))
+ )))
+
+(def: annotation-parameter
+ (Parser (/.Annotation-Parameter Synthesis))
+ (<s>.tuple (<>.and <s>.text <s>.any)))
+
+(def: annotation
+ (Parser (/.Annotation Synthesis))
+ (<s>.tuple (<>.and <s>.text (<>.some ..annotation-parameter))))
+
+(def: argument
+ (Parser Argument)
+ (<s>.tuple (<>.and <s>.text ..value)))
+
+(def: overriden-method-definition
+ (Parser [Environment (/.Overriden-Method Synthesis)])
+ (<s>.tuple (do <>.monad
+ [_ (<s>.text! /.overriden-tag)
+ ownerT ..class
+ name <s>.text
+ strict-fp? <s>.bit
+ annotations (<s>.tuple (<>.some ..annotation))
+ vars (<s>.tuple (<>.some ..var))
+ self-name <s>.text
+ arguments (<s>.tuple (<>.some ..argument))
+ returnT ..return
+ exceptionsT (<s>.tuple (<>.some ..class))
+ [environment body] (<s>.function 1
+ (<s>.tuple <s>.any))]
+ (wrap [environment
+ [ownerT name
+ strict-fp? annotations vars
+ self-name arguments returnT exceptionsT
+ body]]))))
+
+(def: (normalize-path normalize)
+ (-> (-> Synthesis Synthesis)
+ (-> Path Path))
+ (function (recur path)
+ (case path
+ (^ (synthesis.path/then bodyS))
+ (synthesis.path/then (normalize bodyS))
+
+ (^template [<tag>]
+ (^ (<tag> leftP rightP))
+ (<tag> (recur leftP) (recur rightP)))
+ ([#synthesis.Alt]
+ [#synthesis.Seq])
+
+ (^template [<tag>]
+ (^ (<tag> value))
+ path)
+ ([#synthesis.Pop]
+ [#synthesis.Test]
+ [#synthesis.Bind]
+ [#synthesis.Access]))))
+
+(def: (normalize-method-body mapping)
+ (-> (Dictionary Variable Variable) Synthesis Synthesis)
+ (function (recur body)
+ (case body
+ (^template [<tag>]
+ (^ (<tag> value))
+ body)
+ ([#synthesis.Primitive]
+ [synthesis.constant])
+
+ (^ (synthesis.variant [lefts right? sub]))
+ (synthesis.variant [lefts right? (recur sub)])
+
+ (^ (synthesis.tuple members))
+ (synthesis.tuple (list@map recur members))
+
+ (^ (synthesis.variable var))
+ (|> mapping
+ (dictionary.get var)
+ (maybe.default var)
+ synthesis.variable)
+
+ (^ (synthesis.branch/case [inputS pathS]))
+ (synthesis.branch/case [(recur inputS) (normalize-path recur pathS)])
+
+ (^ (synthesis.branch/let [inputS register outputS]))
+ (synthesis.branch/let [(recur inputS) register (recur outputS)])
+
+ (^ (synthesis.branch/if [testS thenS elseS]))
+ (synthesis.branch/if [(recur testS) (recur thenS) (recur elseS)])
+
+ (^ (synthesis.loop/scope [offset initsS+ bodyS]))
+ (synthesis.loop/scope [offset (list@map recur initsS+) (recur bodyS)])
+
+ (^ (synthesis.loop/recur updatesS+))
+ (synthesis.loop/recur (list@map recur updatesS+))
+
+ (^ (synthesis.function/abstraction [environment arity bodyS]))
+ (synthesis.function/abstraction [(|> environment (list@map (function (_ local)
+ (|> mapping
+ (dictionary.get local)
+ (maybe.default local)))))
+ arity
+ bodyS])
+
+ (^ (synthesis.function/apply [functionS inputsS+]))
+ (synthesis.function/apply [(recur functionS) (list@map recur inputsS+)])
+
+ (#synthesis.Extension [name inputsS+])
+ (#synthesis.Extension [name (list@map recur inputsS+)]))))
+
+(def: $Object (type.class "java.lang.Object" (list)))
+
+(def: (anonymous-init-method env)
+ (-> Environment (Type Method))
+ (type.method [(list.repeat (list.size env) $Object)
+ type.void
+ (list)]))
+
+(def: (with-anonymous-init class env super-class inputsTI)
+ (-> (Type Class) Environment (Type Class) (List (Typed Inst)) Def)
+ (let [store-capturedI (|> env
+ list.size
+ list.indices
+ (list@map (.function (_ register)
+ (|>> (_.ALOAD 0)
+ (_.ALOAD (inc register))
+ (_.PUTFIELD class (///reference.foreign-name register) $Object))))
+ _.fuse)]
+ (_def.method #$.Public $.noneM "<init>" (anonymous-init-method env)
+ (|>> (_.ALOAD 0)
+ ((_.fuse (list@map product.right inputsTI)))
+ (_.INVOKESPECIAL super-class "<init>" (type.method [(list@map product.left inputsTI) type.void (list)]))
+ store-capturedI
+ _.RETURN))))
+
+(def: (anonymous-instance archive class env)
+ (-> Archive (Type Class) Environment (Operation Inst))
+ (do {@ phase.monad}
+ [captureI+ (monad.map @ (///reference.variable archive) env)]
+ (wrap (|>> (_.NEW class)
+ _.DUP
+ (_.fuse captureI+)
+ (_.INVOKESPECIAL class "<init>" (anonymous-init-method env))))))
+
+(def: (returnI returnT)
+ (-> (Type Return) Inst)
+ (case (type.void? returnT)
+ (#.Right returnT)
+ _.RETURN
+
+ (#.Left returnT)
+ (case (type.primitive? returnT)
+ (#.Left returnT)
+ (|>> (_.CHECKCAST returnT)
+ _.ARETURN)
+
+ (#.Right returnT)
+ (cond (or (:: type.equivalence = type.boolean returnT)
+ (:: type.equivalence = type.byte returnT)
+ (:: type.equivalence = type.short returnT)
+ (:: type.equivalence = type.int returnT)
+ (:: type.equivalence = type.char returnT))
+ _.IRETURN
+
+ (:: type.equivalence = type.long returnT)
+ _.LRETURN
+
+ (:: type.equivalence = type.float returnT)
+ _.FRETURN
+
+ ## (:: type.equivalence = type.double returnT)
+ _.DRETURN))))
+
+(def: class::anonymous
+ Handler
+ (..custom
+ [($_ <>.and
+ ..class
+ (<s>.tuple (<>.some ..class))
+ (<s>.tuple (<>.some ..input))
+ (<s>.tuple (<>.some ..overriden-method-definition)))
+ (function (_ extension-name generate archive [super-class super-interfaces
+ inputsTS
+ overriden-methods])
+ (do {@ phase.monad}
+ [[context _] (generation.with-new-context archive (wrap []))
+ #let [[module-id artifact-id] context
+ anonymous-class-name (///.class-name context)
+ class (type.class anonymous-class-name (list))
+ total-environment (|> overriden-methods
+ ## Get all the environments.
+ (list@map product.left)
+ ## Combine them.
+ list@join
+ ## Remove duplicates.
+ (set.from-list reference.hash)
+ set.to-list)
+ global-mapping (|> total-environment
+ ## Give them names as "foreign" variables.
+ list.enumerate
+ (list@map (function (_ [id capture])
+ [capture (#reference.Foreign id)]))
+ (dictionary.from-list reference.hash))
+ normalized-methods (list@map (function (_ [environment
+ [ownerT name
+ strict-fp? annotations vars
+ self-name arguments returnT exceptionsT
+ body]])
+ (let [local-mapping (|> environment
+ list.enumerate
+ (list@map (function (_ [foreign-id capture])
+ [(#reference.Foreign foreign-id)
+ (|> global-mapping
+ (dictionary.get capture)
+ maybe.assume)]))
+ (dictionary.from-list reference.hash))]
+ [ownerT name
+ strict-fp? annotations vars
+ self-name arguments returnT exceptionsT
+ (normalize-method-body local-mapping body)]))
+ overriden-methods)]
+ inputsTI (monad.map @ (generate-input generate archive) inputsTS)
+ method-definitions (|> normalized-methods
+ (monad.map @ (function (_ [ownerT name
+ strict-fp? annotations vars
+ self-name arguments returnT exceptionsT
+ bodyS])
+ (do @
+ [bodyG (generation.with-context artifact-id
+ (generate archive bodyS))]
+ (wrap (_def.method #$.Public
+ (if strict-fp?
+ ($_ $.++M $.finalM $.strictM)
+ $.finalM)
+ name
+ (type.method [(list@map product.right arguments)
+ returnT
+ exceptionsT])
+ (|>> bodyG (returnI returnT)))))))
+ (:: @ map _def.fuse))
+ _ (generation.save! true ["" (%.nat artifact-id)]
+ [anonymous-class-name
+ (_def.class #$.V1_6 #$.Public $.finalC
+ anonymous-class-name (list)
+ super-class super-interfaces
+ (|>> (///function.with-environment total-environment)
+ (..with-anonymous-init class total-environment super-class inputsTI)
+ method-definitions))])]
+ (anonymous-instance archive class total-environment)))]))
+
+(def: bundle::class
+ Bundle
+ (<| (bundle.prefix "class")
+ (|> (: Bundle bundle.empty)
+ (bundle.install "anonymous" class::anonymous)
+ )))
+
+(def: #export bundle
+ Bundle
+ (<| (bundle.prefix "jvm")
+ (|> ..conversion
+ (dictionary.merge ..int)
+ (dictionary.merge ..long)
+ (dictionary.merge ..float)
+ (dictionary.merge ..double)
+ (dictionary.merge ..char)
+ (dictionary.merge ..array)
+ (dictionary.merge ..object-bundle)
+ (dictionary.merge ..member)
+ (dictionary.merge ..bundle::class)
+ )))
diff --git a/lux-jvm/source/luxc/lang/translation/jvm/function.lux b/lux-jvm/source/luxc/lang/translation/jvm/function.lux
new file mode 100644
index 000000000..888ad9545
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/translation/jvm/function.lux
@@ -0,0 +1,331 @@
+(.module:
+ [lux (#- Type function)
+ [abstract
+ ["." monad (#+ do)]]
+ [control
+ [pipe (#+ when> new>)]
+ ["." function]]
+ [data
+ ["." product]
+ [text
+ ["%" format (#+ format)]]
+ [number
+ ["n" nat]
+ ["i" int]]
+ [collection
+ ["." list ("#@." functor monoid)]]]
+ [target
+ [jvm
+ ["." type (#+ Type)
+ ["." category (#+ Void Value Return Primitive Object Class Array Var Parameter Method)]]]]
+ [tool
+ [compiler
+ [arity (#+ Arity)]
+ [reference (#+ Register)]
+ ["." phase]
+ [language
+ [lux
+ [analysis (#+ Environment)]
+ [synthesis (#+ Synthesis Abstraction Apply)]
+ ["." generation]]]
+ [meta
+ [archive (#+ Archive)]]]]]
+ [luxc
+ [lang
+ [host
+ ["$" jvm (#+ Label Inst Def Operation Phase Generator)
+ ["." def]
+ ["_" inst]]]]]
+ ["." //
+ ["#." runtime]
+ ["." reference]])
+
+(def: arity-field Text "arity")
+
+(def: (poly-arg? arity)
+ (-> Arity Bit)
+ (n.> 1 arity))
+
+(def: (captured-args env)
+ (-> Environment (List (Type Value)))
+ (list.repeat (list.size env) //.$Value))
+
+(def: (init-method env arity)
+ (-> Environment Arity (Type Method))
+ (if (poly-arg? arity)
+ (type.method [(list.concat (list (captured-args env)
+ (list type.int)
+ (list.repeat (dec arity) //.$Value)))
+ type.void
+ (list)])
+ (type.method [(captured-args env) type.void (list)])))
+
+(def: (implementation-method arity)
+ (type.method [(list.repeat arity //.$Value) //.$Value (list)]))
+
+(def: get-amount-of-partialsI
+ Inst
+ (|>> (_.ALOAD 0)
+ (_.GETFIELD //.$Function //runtime.partials-field type.int)))
+
+(def: (load-fieldI class field)
+ (-> (Type Class) Text Inst)
+ (|>> (_.ALOAD 0)
+ (_.GETFIELD class field //.$Value)))
+
+(def: (inputsI start amount)
+ (-> Register Nat Inst)
+ (|> (list.n/range start (n.+ start (dec amount)))
+ (list@map _.ALOAD)
+ _.fuse))
+
+(def: (applysI start amount)
+ (-> Register Nat Inst)
+ (let [max-args (n.min amount //runtime.num-apply-variants)
+ later-applysI (if (n.> //runtime.num-apply-variants amount)
+ (applysI (n.+ //runtime.num-apply-variants start) (n.- //runtime.num-apply-variants amount))
+ function.identity)]
+ (|>> (_.CHECKCAST //.$Function)
+ (inputsI start max-args)
+ (_.INVOKEVIRTUAL //.$Function //runtime.apply-method (//runtime.apply-signature max-args))
+ later-applysI)))
+
+(def: (inc-intI by)
+ (-> Nat Inst)
+ (|>> (_.int (.int by))
+ _.IADD))
+
+(def: (nullsI amount)
+ (-> Nat Inst)
+ (|> _.NULL
+ (list.repeat amount)
+ _.fuse))
+
+(def: (instance archive class arity env)
+ (-> Archive (Type Class) Arity Environment (Operation Inst))
+ (do {@ phase.monad}
+ [captureI+ (monad.map @ (reference.variable archive) env)
+ #let [argsI (if (poly-arg? arity)
+ (|> (nullsI (dec arity))
+ (list (_.int +0))
+ _.fuse)
+ function.identity)]]
+ (wrap (|>> (_.NEW class)
+ _.DUP
+ (_.fuse captureI+)
+ argsI
+ (_.INVOKESPECIAL class "<init>" (init-method env arity))))))
+
+(def: (reset-method return)
+ (-> (Type Class) (Type Method))
+ (type.method [(list) return (list)]))
+
+(def: (with-reset class arity env)
+ (-> (Type Class) Arity Environment Def)
+ (def.method #$.Public $.noneM "reset" (reset-method class)
+ (if (poly-arg? arity)
+ (let [env-size (list.size env)
+ captureI (|> (case env-size
+ 0 (list)
+ _ (list.n/range 0 (dec env-size)))
+ (list@map (.function (_ source)
+ (|>> (_.ALOAD 0)
+ (_.GETFIELD class (reference.foreign-name source) //.$Value))))
+ _.fuse)
+ argsI (|> (nullsI (dec arity))
+ (list (_.int +0))
+ _.fuse)]
+ (|>> (_.NEW class)
+ _.DUP
+ captureI
+ argsI
+ (_.INVOKESPECIAL class "<init>" (init-method env arity))
+ _.ARETURN))
+ (|>> (_.ALOAD 0)
+ _.ARETURN))))
+
+(def: (with-implementation arity @begin bodyI)
+ (-> Nat Label Inst Def)
+ (def.method #$.Public $.strictM "impl" (implementation-method arity)
+ (|>> (_.label @begin)
+ bodyI
+ _.ARETURN)))
+
+(def: function-init-method
+ (type.method [(list type.int) type.void (list)]))
+
+(def: (function-init arity env-size)
+ (-> Arity Nat Inst)
+ (if (n.= 1 arity)
+ (|>> (_.int +0)
+ (_.INVOKESPECIAL //.$Function "<init>" function-init-method))
+ (|>> (_.ILOAD (inc env-size))
+ (_.INVOKESPECIAL //.$Function "<init>" function-init-method))))
+
+(def: (with-init class env arity)
+ (-> (Type Class) Environment Arity Def)
+ (let [env-size (list.size env)
+ offset-partial (: (-> Nat Nat)
+ (|>> inc (n.+ env-size)))
+ store-capturedI (|> (case env-size
+ 0 (list)
+ _ (list.n/range 0 (dec env-size)))
+ (list@map (.function (_ register)
+ (|>> (_.ALOAD 0)
+ (_.ALOAD (inc register))
+ (_.PUTFIELD class (reference.foreign-name register) //.$Value))))
+ _.fuse)
+ store-partialI (if (poly-arg? arity)
+ (|> (list.n/range 0 (n.- 2 arity))
+ (list@map (.function (_ idx)
+ (let [register (offset-partial idx)]
+ (|>> (_.ALOAD 0)
+ (_.ALOAD (inc register))
+ (_.PUTFIELD class (reference.partial-name idx) //.$Value)))))
+ _.fuse)
+ function.identity)]
+ (def.method #$.Public $.noneM "<init>" (init-method env arity)
+ (|>> (_.ALOAD 0)
+ (function-init arity env-size)
+ store-capturedI
+ store-partialI
+ _.RETURN))))
+
+(def: (with-apply class env function-arity @begin bodyI apply-arity)
+ (-> (Type Class) Environment Arity Label Inst Arity
+ Def)
+ (let [num-partials (dec function-arity)
+ @default ($.new-label [])
+ @labels (list@map $.new-label (list.repeat num-partials []))
+ over-extent (|> (.int function-arity) (i.- (.int apply-arity)))
+ casesI (|> (list@compose @labels (list @default))
+ (list.zip2 (list.n/range 0 num-partials))
+ (list@map (.function (_ [stage @label])
+ (let [load-partialsI (if (n.> 0 stage)
+ (|> (list.n/range 0 (dec stage))
+ (list@map (|>> reference.partial-name (load-fieldI class)))
+ _.fuse)
+ function.identity)]
+ (cond (i.= over-extent (.int stage))
+ (|>> (_.label @label)
+ (_.ALOAD 0)
+ (when> [(new> (n.> 0 stage) [])]
+ [(_.INVOKEVIRTUAL class "reset" (reset-method class))])
+ load-partialsI
+ (inputsI 1 apply-arity)
+ (_.INVOKEVIRTUAL class "impl" (implementation-method function-arity))
+ _.ARETURN)
+
+ (i.> over-extent (.int stage))
+ (let [args-to-completion (|> function-arity (n.- stage))
+ args-left (|> apply-arity (n.- args-to-completion))]
+ (|>> (_.label @label)
+ (_.ALOAD 0)
+ (_.INVOKEVIRTUAL class "reset" (reset-method class))
+ load-partialsI
+ (inputsI 1 args-to-completion)
+ (_.INVOKEVIRTUAL class "impl" (implementation-method function-arity))
+ (applysI (inc args-to-completion) args-left)
+ _.ARETURN))
+
+ ## (i.< over-extent (.int stage))
+ (let [env-size (list.size env)
+ load-capturedI (|> (case env-size
+ 0 (list)
+ _ (list.n/range 0 (dec env-size)))
+ (list@map (|>> reference.foreign-name (load-fieldI class)))
+ _.fuse)]
+ (|>> (_.label @label)
+ (_.NEW class)
+ _.DUP
+ load-capturedI
+ get-amount-of-partialsI
+ (inc-intI apply-arity)
+ load-partialsI
+ (inputsI 1 apply-arity)
+ (nullsI (|> num-partials (n.- apply-arity) (n.- stage)))
+ (_.INVOKESPECIAL class "<init>" (init-method env function-arity))
+ _.ARETURN))
+ ))))
+ _.fuse)]
+ (def.method #$.Public $.noneM //runtime.apply-method (//runtime.apply-signature apply-arity)
+ (|>> get-amount-of-partialsI
+ (_.TABLESWITCH +0 (|> num-partials dec .int)
+ @default @labels)
+ casesI
+ ))))
+
+(def: #export with-environment
+ (-> Environment Def)
+ (|>> list.enumerate
+ (list@map (.function (_ [env-idx env-source])
+ (def.field #$.Private $.finalF (reference.foreign-name env-idx) //.$Value)))
+ def.fuse))
+
+(def: (with-partial arity)
+ (-> Arity Def)
+ (if (poly-arg? arity)
+ (|> (list.n/range 0 (n.- 2 arity))
+ (list@map (.function (_ idx)
+ (def.field #$.Private $.finalF (reference.partial-name idx) //.$Value)))
+ def.fuse)
+ function.identity))
+
+(def: #export (with-function archive @begin class env arity bodyI)
+ (-> Archive Label Text Environment Arity Inst
+ (Operation [Def Inst]))
+ (let [classD (type.class class (list))
+ applyD (: Def
+ (if (poly-arg? arity)
+ (|> (n.min arity //runtime.num-apply-variants)
+ (list.n/range 1)
+ (list@map (with-apply classD env arity @begin bodyI))
+ (list& (with-implementation arity @begin bodyI))
+ def.fuse)
+ (def.method #$.Public $.strictM //runtime.apply-method (//runtime.apply-signature 1)
+ (|>> (_.label @begin)
+ bodyI
+ _.ARETURN))))
+ functionD (: Def
+ (|>> (def.int-field #$.Public ($_ $.++F $.staticF $.finalF) arity-field (.int arity))
+ (with-environment env)
+ (with-partial arity)
+ (with-init classD env arity)
+ (with-reset classD arity env)
+ applyD
+ ))]
+ (do phase.monad
+ [instanceI (instance archive classD arity env)]
+ (wrap [functionD instanceI]))))
+
+(def: #export (function generate archive [env arity bodyS])
+ (Generator Abstraction)
+ (do phase.monad
+ [@begin _.make-label
+ [function-context bodyI] (generation.with-new-context archive
+ (generation.with-anchor [@begin 1]
+ (generate archive bodyS)))
+ #let [function-class (//.class-name function-context)]
+ [functionD instanceI] (with-function archive @begin function-class env arity bodyI)
+ _ (generation.save! true ["" (%.nat (product.right function-context))]
+ [function-class
+ (def.class #$.V1_6 #$.Public $.finalC
+ function-class (list)
+ //.$Function (list)
+ functionD)])]
+ (wrap instanceI)))
+
+(def: #export (call generate archive [functionS argsS])
+ (Generator Apply)
+ (do {@ phase.monad}
+ [functionI (generate archive functionS)
+ argsI (monad.map @ (generate archive) argsS)
+ #let [applyI (|> argsI
+ (list.split-all //runtime.num-apply-variants)
+ (list@map (.function (_ chunkI+)
+ (|>> (_.CHECKCAST //.$Function)
+ (_.fuse chunkI+)
+ (_.INVOKEVIRTUAL //.$Function //runtime.apply-method (//runtime.apply-signature (list.size chunkI+))))))
+ _.fuse)]]
+ (wrap (|>> functionI
+ applyI))))
diff --git a/lux-jvm/source/luxc/lang/translation/jvm/loop.lux b/lux-jvm/source/luxc/lang/translation/jvm/loop.lux
new file mode 100644
index 000000000..1f2168fed
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/translation/jvm/loop.lux
@@ -0,0 +1,81 @@
+(.module:
+ [lux #*
+ [abstract
+ ["." monad (#+ do)]]
+ [control
+ ["." function]]
+ [data
+ [number
+ ["n" nat]]
+ [collection
+ ["." list ("#/." functor monoid)]]]
+ [tool
+ [compiler
+ [reference (#+ Register)]
+ ["." phase]
+ [language
+ [lux
+ ["." synthesis (#+ Synthesis)]
+ ["." generation]]]]]]
+ [luxc
+ [lang
+ [host
+ [jvm (#+ Inst Operation Phase Generator)
+ ["_" inst]]]]]
+ ["." //])
+
+(def: (invariant? register changeS)
+ (-> Register Synthesis Bit)
+ (case changeS
+ (^ (synthesis.variable/local var))
+ (n.= register var)
+
+ _
+ false))
+
+(def: #export (recur translate archive argsS)
+ (Generator (List Synthesis))
+ (do {@ phase.monad}
+ [[@begin start] generation.anchor
+ #let [end (|> argsS list.size dec (n.+ start))
+ pairs (list.zip2 (list.n/range start end)
+ argsS)]
+ ## It may look weird that first I compile the values separately,
+ ## and then I compile the stores/allocations.
+ ## It must be done that way in order to avoid a potential bug.
+ ## Let's say that you'll recur with 2 expressions: X and Y.
+ ## If Y depends on the value of X, and you don't compile values
+ ## and stores separately, then by the time Y is evaluated, it
+ ## will refer to the new value of X, instead of the old value, as
+ ## should be the case.
+ valuesI+ (monad.map @ (function (_ [register argS])
+ (: (Operation Inst)
+ (if (invariant? register argS)
+ (wrap function.identity)
+ (translate archive argS))))
+ pairs)
+ #let [storesI+ (list/map (function (_ [register argS])
+ (: Inst
+ (if (invariant? register argS)
+ function.identity
+ (_.ASTORE register))))
+ (list.reverse pairs))]]
+ (wrap (|>> (_.fuse valuesI+)
+ (_.fuse storesI+)
+ (_.GOTO @begin)))))
+
+(def: #export (scope translate archive [start initsS+ iterationS])
+ (Generator [Nat (List Synthesis) Synthesis])
+ (do {@ phase.monad}
+ [@begin _.make-label
+ initsI+ (monad.map @ (translate archive) initsS+)
+ iterationI (generation.with-anchor [@begin start]
+ (translate archive iterationS))
+ #let [initializationI (|> (list.enumerate initsI+)
+ (list/map (function (_ [register initI])
+ (|>> initI
+ (_.ASTORE (n.+ start register)))))
+ _.fuse)]]
+ (wrap (|>> initializationI
+ (_.label @begin)
+ iterationI))))
diff --git a/lux-jvm/source/luxc/lang/translation/jvm/primitive.lux b/lux-jvm/source/luxc/lang/translation/jvm/primitive.lux
new file mode 100644
index 000000000..873c363bd
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/translation/jvm/primitive.lux
@@ -0,0 +1,30 @@
+(.module:
+ [lux (#- i64)
+ [target
+ [jvm
+ ["." type]]]
+ [tool
+ [compiler
+ [phase ("operation@." monad)]]]]
+ [luxc
+ [lang
+ [host
+ ["." jvm (#+ Inst Operation)
+ ["_" inst]]]]])
+
+(def: #export bit
+ (-> Bit (Operation Inst))
+ (let [Boolean (type.class "java.lang.Boolean" (list))]
+ (function (_ value)
+ (operation@wrap (_.GETSTATIC Boolean (if value "TRUE" "FALSE") Boolean)))))
+
+(template [<name> <type> <load> <wrap>]
+ [(def: #export (<name> value)
+ (-> <type> (Operation Inst))
+ (let [loadI (|> value <load>)]
+ (operation@wrap (|>> loadI <wrap>))))]
+
+ [i64 (I64 Any) (<| _.long .int) (_.wrap type.long)]
+ [f64 Frac _.double (_.wrap type.double)]
+ [text Text _.string (<|)]
+ )
diff --git a/lux-jvm/source/luxc/lang/translation/jvm/program.lux b/lux-jvm/source/luxc/lang/translation/jvm/program.lux
new file mode 100644
index 000000000..7ac897009
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/translation/jvm/program.lux
@@ -0,0 +1,82 @@
+(.module:
+ [lux #*
+ [target
+ [jvm
+ ["$t" type]]]]
+ [luxc
+ [lang
+ [host
+ ["_" jvm
+ ["$d" def]
+ ["$i" inst]]]
+ [translation
+ ["." jvm
+ ["." runtime]]]]])
+
+(def: #export class "LuxProgram")
+
+(def: ^Object ($t.class "java.lang.Object" (list)))
+
+(def: #export (program programI)
+ (-> _.Inst _.Definition)
+ (let [nilI runtime.noneI
+ num-inputsI (|>> ($i.ALOAD 0) $i.ARRAYLENGTH)
+ decI (|>> ($i.int +1) $i.ISUB)
+ headI (|>> $i.DUP
+ ($i.ALOAD 0)
+ $i.SWAP
+ $i.AALOAD
+ $i.SWAP
+ $i.DUP_X2
+ $i.POP)
+ pairI (|>> ($i.int +2)
+ ($i.ANEWARRAY ..^Object)
+ $i.DUP_X1
+ $i.SWAP
+ ($i.int +0)
+ $i.SWAP
+ $i.AASTORE
+ $i.DUP_X1
+ $i.SWAP
+ ($i.int +1)
+ $i.SWAP
+ $i.AASTORE)
+ consI (|>> ($i.int +1)
+ ($i.string "")
+ $i.DUP2_X1
+ $i.POP2
+ runtime.variantI)
+ prepare-input-listI (<| $i.with-label (function (_ @loop))
+ $i.with-label (function (_ @end))
+ (|>> nilI
+ num-inputsI
+ ($i.label @loop)
+ decI
+ $i.DUP
+ ($i.IFLT @end)
+ headI
+ pairI
+ consI
+ $i.SWAP
+ ($i.GOTO @loop)
+ ($i.label @end)
+ $i.POP))
+ feed-inputsI ($i.INVOKEVIRTUAL jvm.$Function runtime.apply-method (runtime.apply-signature 1))
+ run-ioI (|>> ($i.CHECKCAST jvm.$Function)
+ $i.NULL
+ ($i.INVOKEVIRTUAL jvm.$Function runtime.apply-method (runtime.apply-signature 1)))
+ main-type ($t.method [(list ($t.array ($t.class "java.lang.String" (list))))
+ $t.void
+ (list)])]
+ [..class
+ ($d.class #_.V1_6
+ #_.Public _.finalC
+ ..class
+ (list) ..^Object
+ (list)
+ (|>> ($d.method #_.Public _.staticM "main" main-type
+ (|>> programI
+ prepare-input-listI
+ feed-inputsI
+ run-ioI
+ $i.RETURN))))]))
diff --git a/lux-jvm/source/luxc/lang/translation/jvm/reference.lux b/lux-jvm/source/luxc/lang/translation/jvm/reference.lux
new file mode 100644
index 000000000..6bcf4a2e5
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/translation/jvm/reference.lux
@@ -0,0 +1,65 @@
+(.module:
+ [lux #*
+ [abstract
+ [monad (#+ do)]]
+ [data
+ [text
+ ["%" format (#+ format)]]]
+ [target
+ [jvm
+ ["." type]]]
+ [tool
+ [compiler
+ ["." reference (#+ Register Variable)]
+ ["." phase ("operation@." monad)]
+ [meta
+ [archive (#+ Archive)]]
+ [language
+ [lux
+ ["." generation]]]]]]
+ [luxc
+ [lang
+ [host
+ [jvm (#+ Inst Operation)
+ ["_" inst]]]]]
+ ["." //
+ ["#." runtime]])
+
+(template [<name> <prefix>]
+ [(def: #export <name>
+ (-> Nat Text)
+ (|>> %.nat (format <prefix>)))]
+
+ [foreign-name "f"]
+ [partial-name "p"]
+ )
+
+(def: (foreign archive variable)
+ (-> Archive Register (Operation Inst))
+ (do {@ phase.monad}
+ [class-name (:: @ map //.class-name
+ (generation.context archive))]
+ (wrap (|>> (_.ALOAD 0)
+ (_.GETFIELD (type.class class-name (list))
+ (|> variable .nat foreign-name)
+ //.$Value)))))
+
+(def: local
+ (-> Register Inst)
+ (|>> _.ALOAD))
+
+(def: #export (variable archive variable)
+ (-> Archive Variable (Operation Inst))
+ (case variable
+ (#reference.Local variable)
+ (operation@wrap (local variable))
+
+ (#reference.Foreign variable)
+ (foreign archive variable)))
+
+(def: #export (constant archive name)
+ (-> Archive Name (Operation Inst))
+ (do {@ phase.monad}
+ [class-name (:: @ map //.class-name
+ (generation.remember archive name))]
+ (wrap (_.GETSTATIC (type.class class-name (list)) //.value-field //.$Value))))
diff --git a/lux-jvm/source/luxc/lang/translation/jvm/runtime.lux b/lux-jvm/source/luxc/lang/translation/jvm/runtime.lux
new file mode 100644
index 000000000..a657a7a38
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/translation/jvm/runtime.lux
@@ -0,0 +1,387 @@
+(.module:
+ [lux (#- Type)
+ [abstract
+ [monad (#+ do)]]
+ [data
+ [binary (#+ Binary)]
+ ["." product]
+ [text
+ ["%" format (#+ format)]]
+ [collection
+ ["." list ("#@." functor)]
+ ["." row]]]
+ ["." math]
+ [target
+ [jvm
+ ["." type (#+ Type)
+ ["." category (#+ Void Value' Value Return' Return Primitive Object Class Array Var Parameter Method)]
+ ["." reflection]]]]
+ [tool
+ [compiler (#+ Output)
+ [arity (#+ Arity)]
+ ["." phase]
+ [language
+ [lux
+ ["." synthesis]
+ ["." generation]]]
+ [meta
+ [archive
+ ["." artifact (#+ Registry)]]]]]]
+ [luxc
+ [lang
+ [host
+ ["$" jvm (#+ Label Inst Def Operation)
+ ["$d" def]
+ ["_" inst]]]]]
+ ["." // (#+ ByteCode)])
+
+(def: $Text (type.class "java.lang.String" (list)))
+(def: #export $Tag type.int)
+(def: #export $Flag (type.class "java.lang.Object" (list)))
+(def: #export $Value (type.class "java.lang.Object" (list)))
+(def: #export $Index type.int)
+(def: #export $Stack (type.array $Value))
+(def: $Throwable (type.class "java.lang.Throwable" (list)))
+
+(def: nullary-init-methodT
+ (type.method [(list) type.void (list)]))
+
+(def: throw-methodT
+ (type.method [(list) type.void (list)]))
+
+(def: #export logI
+ Inst
+ (let [PrintStream (type.class "java.io.PrintStream" (list))
+ outI (_.GETSTATIC (type.class "java.lang.System" (list)) "out" PrintStream)
+ printI (function (_ method)
+ (_.INVOKEVIRTUAL PrintStream method (type.method [(list $Value) type.void (list)])))]
+ (|>> outI (_.string "LOG: ") (printI "print")
+ outI _.SWAP (printI "println"))))
+
+(def: variant-method
+ (type.method [(list $Tag $Flag $Value) //.$Variant (list)]))
+
+(def: #export variantI
+ Inst
+ (_.INVOKESTATIC //.$Runtime "variant_make" variant-method))
+
+(def: #export leftI
+ Inst
+ (|>> (_.int +0)
+ _.NULL
+ _.DUP2_X1
+ _.POP2
+ variantI))
+
+(def: #export rightI
+ Inst
+ (|>> (_.int +1)
+ (_.string "")
+ _.DUP2_X1
+ _.POP2
+ variantI))
+
+(def: #export someI Inst rightI)
+
+(def: #export noneI
+ Inst
+ (|>> (_.int +0)
+ _.NULL
+ (_.string synthesis.unit)
+ variantI))
+
+(def: (tryI unsafeI)
+ (-> Inst Inst)
+ (<| _.with-label (function (_ @from))
+ _.with-label (function (_ @to))
+ _.with-label (function (_ @handler))
+ (|>> (_.try @from @to @handler (type.class "java.lang.Exception" (list)))
+ (_.label @from)
+ unsafeI
+ someI
+ _.ARETURN
+ (_.label @to)
+ (_.label @handler)
+ noneI
+ _.ARETURN)))
+
+(def: #export partials-field Text "partials")
+(def: #export apply-method Text "apply")
+(def: #export num-apply-variants Nat 8)
+
+(def: #export (apply-signature arity)
+ (-> Arity (Type Method))
+ (type.method [(list.repeat arity $Value) $Value (list)]))
+
+(def: adt-methods
+ Def
+ (let [store-tagI (|>> _.DUP (_.int +0) (_.ILOAD 0) (_.wrap type.int) _.AASTORE)
+ store-flagI (|>> _.DUP (_.int +1) (_.ALOAD 1) _.AASTORE)
+ store-valueI (|>> _.DUP (_.int +2) (_.ALOAD 2) _.AASTORE)]
+ (|>> ($d.method #$.Public $.staticM "variant_make"
+ (type.method [(list $Tag $Flag $Value) //.$Variant (list)])
+ (|>> (_.int +3)
+ (_.ANEWARRAY $Value)
+ store-tagI
+ store-flagI
+ store-valueI
+ _.ARETURN)))))
+
+(def: frac-methods
+ Def
+ (|>> ($d.method #$.Public $.staticM "decode_frac" (type.method [(list $Text) //.$Variant (list)])
+ (tryI
+ (|>> (_.ALOAD 0)
+ (_.INVOKESTATIC (type.class "java.lang.Double" (list)) "parseDouble" (type.method [(list $Text) type.double (list)]))
+ (_.wrap type.double))))
+ ))
+
+(def: (illegal-state-exception message)
+ (-> Text Inst)
+ (let [IllegalStateException (type.class "java.lang.IllegalStateException" (list))]
+ (|>> (_.NEW IllegalStateException)
+ _.DUP
+ (_.string message)
+ (_.INVOKESPECIAL IllegalStateException "<init>" (type.method [(list $Text) type.void (list)])))))
+
+(def: pm-methods
+ Def
+ (let [tuple-sizeI (|>> (_.ALOAD 0) _.ARRAYLENGTH)
+ last-rightI (|>> tuple-sizeI (_.int +1) _.ISUB)
+ leftsI (_.ILOAD 1)
+ left-indexI leftsI
+ sub-leftsI (|>> leftsI
+ last-rightI
+ _.ISUB)
+ sub-tupleI (|>> (_.ALOAD 0) last-rightI _.AALOAD (_.CHECKCAST //.$Tuple))
+ recurI (: (-> Label Inst)
+ (function (_ @loop)
+ (|>> sub-leftsI (_.ISTORE 1)
+ sub-tupleI (_.ASTORE 0)
+ (_.GOTO @loop))))]
+ (|>> ($d.method #$.Public $.staticM "pm_fail" throw-methodT
+ (|>> (illegal-state-exception "Invalid expression for pattern-matching.")
+ _.ATHROW))
+ ($d.method #$.Public $.staticM "apply_fail" throw-methodT
+ (|>> (illegal-state-exception "Error while applying function.")
+ _.ATHROW))
+ ($d.method #$.Public $.staticM "pm_push" (type.method [(list $Stack $Value) $Stack (list)])
+ (|>> (_.int +2)
+ (_.ANEWARRAY $Value)
+ _.DUP
+ (_.int +1)
+ (_.ALOAD 0)
+ _.AASTORE
+ _.DUP
+ (_.int +0)
+ (_.ALOAD 1)
+ _.AASTORE
+ _.ARETURN))
+ ($d.method #$.Public $.staticM "pm_variant" (type.method [(list //.$Variant $Tag $Flag) $Value (list)])
+ (<| _.with-label (function (_ @loop))
+ _.with-label (function (_ @perfect-match!))
+ _.with-label (function (_ @tags-match!))
+ _.with-label (function (_ @maybe-nested))
+ _.with-label (function (_ @mismatch!))
+ (let [$variant (_.ALOAD 0)
+ $tag (_.ILOAD 1)
+ $last? (_.ALOAD 2)
+
+ variant-partI (: (-> Nat Inst)
+ (function (_ idx)
+ (|>> (_.int (.int idx)) _.AALOAD)))
+ ::tag (: Inst
+ (|>> (variant-partI 0) (_.unwrap type.int)))
+ ::last? (variant-partI 1)
+ ::value (variant-partI 2)
+
+ super-nested-tag (|>> _.SWAP ## variant::tag, tag
+ _.ISUB)
+ super-nested (|>> super-nested-tag ## super-tag
+ $variant ::last? ## super-tag, super-last
+ $variant ::value ## super-tag, super-last, super-value
+ ..variantI)
+
+ update-$tag _.ISUB
+ update-$variant (|>> $variant ::value
+ (_.CHECKCAST //.$Variant)
+ (_.ASTORE 0))
+ iterate! (: (-> Label Inst)
+ (function (_ @loop)
+ (|>> update-$variant
+ update-$tag
+ (_.GOTO @loop))))
+
+ not-found _.NULL])
+ (|>> $tag ## tag
+ (_.label @loop)
+ $variant ::tag ## tag, variant::tag
+ _.DUP2 (_.IF_ICMPEQ @tags-match!) ## tag, variant::tag
+ _.DUP2 (_.IF_ICMPGT @maybe-nested) ## tag, variant::tag
+ $last? (_.IFNULL @mismatch!) ## tag, variant::tag
+ super-nested ## super-variant
+ _.ARETURN
+ (_.label @tags-match!) ## tag, variant::tag
+ $last? ## tag, variant::tag, last?
+ $variant ::last? ## tag, variant::tag, last?, variant::last?
+ (_.IF_ACMPEQ @perfect-match!) ## tag, variant::tag
+ (_.label @maybe-nested) ## tag, variant::tag
+ $variant ::last? ## tag, variant::tag, variant::last?
+ (_.IFNULL @mismatch!) ## tag, variant::tag
+ (iterate! @loop)
+ (_.label @perfect-match!) ## tag, variant::tag
+ ## _.POP2
+ $variant ::value
+ _.ARETURN
+ (_.label @mismatch!) ## tag, variant::tag
+ ## _.POP2
+ not-found
+ _.ARETURN)))
+ ($d.method #$.Public $.staticM "tuple_left" (type.method [(list //.$Tuple $Index) $Value (list)])
+ (<| _.with-label (function (_ @loop))
+ _.with-label (function (_ @recursive))
+ (let [left-accessI (|>> (_.ALOAD 0) left-indexI _.AALOAD)])
+ (|>> (_.label @loop)
+ leftsI last-rightI (_.IF_ICMPGE @recursive)
+ left-accessI
+ _.ARETURN
+ (_.label @recursive)
+ ## Recursive
+ (recurI @loop))))
+ ($d.method #$.Public $.staticM "tuple_right" (type.method [(list //.$Tuple $Index) $Value (list)])
+ (<| _.with-label (function (_ @loop))
+ _.with-label (function (_ @not-tail))
+ _.with-label (function (_ @slice))
+ (let [right-indexI (|>> leftsI
+ (_.int +1)
+ _.IADD)
+ right-accessI (|>> (_.ALOAD 0)
+ _.SWAP
+ _.AALOAD)
+ sub-rightI (|>> (_.ALOAD 0)
+ right-indexI
+ tuple-sizeI
+ (_.INVOKESTATIC (type.class "java.util.Arrays" (list)) "copyOfRange"
+ (type.method [(list //.$Tuple $Index $Index)
+ //.$Tuple
+ (list)])))])
+ (|>> (_.label @loop)
+ last-rightI right-indexI
+ _.DUP2 (_.IF_ICMPNE @not-tail)
+ ## _.POP
+ right-accessI
+ _.ARETURN
+ (_.label @not-tail)
+ (_.IF_ICMPGT @slice)
+ ## Must recurse
+ (recurI @loop)
+ (_.label @slice)
+ sub-rightI
+ _.ARETURN
+ )))
+ )))
+
+(def: #export try (type.method [(list //.$Function) //.$Variant (list)]))
+
+(def: io-methods
+ Def
+ (let [StringWriter (type.class "java.io.StringWriter" (list))
+ PrintWriter (type.class "java.io.PrintWriter" (list))
+ string-writerI (|>> (_.NEW StringWriter)
+ _.DUP
+ (_.INVOKESPECIAL StringWriter "<init>" nullary-init-methodT))
+ print-writerI (|>> (_.NEW PrintWriter)
+ _.SWAP
+ _.DUP2
+ _.POP
+ _.SWAP
+ (_.boolean true)
+ (_.INVOKESPECIAL PrintWriter "<init>" (type.method [(list (type.class "java.io.Writer" (list)) type.boolean) type.void (list)]))
+ )]
+ (|>> ($d.method #$.Public $.staticM "try" ..try
+ (<| _.with-label (function (_ @from))
+ _.with-label (function (_ @to))
+ _.with-label (function (_ @handler))
+ (|>> (_.try @from @to @handler $Throwable)
+ (_.label @from)
+ (_.ALOAD 0)
+ _.NULL
+ (_.INVOKEVIRTUAL //.$Function apply-method (apply-signature 1))
+ rightI
+ _.ARETURN
+ (_.label @to)
+ (_.label @handler)
+ string-writerI ## TW
+ _.DUP2 ## TWTW
+ print-writerI ## TWTP
+ (_.INVOKEVIRTUAL $Throwable "printStackTrace" (type.method [(list (type.class "java.io.PrintWriter" (list))) type.void (list)])) ## TW
+ (_.INVOKEVIRTUAL StringWriter "toString" (type.method [(list) $Text (list)])) ## TS
+ _.SWAP _.POP leftI
+ _.ARETURN)))
+ )))
+
+(def: reflection
+ (All [category]
+ (-> (Type (<| Return' Value' category)) Text))
+ (|>> type.reflection reflection.reflection))
+
+(def: translate-runtime
+ (Operation [Text Binary])
+ (let [runtime-class (..reflection //.$Runtime)
+ bytecode ($d.class #$.V1_6 #$.Public $.finalC runtime-class (list) (type.class "java.lang.Object" (list)) (list)
+ (|>> adt-methods
+ frac-methods
+ pm-methods
+ io-methods))
+ payload ["0" bytecode]]
+ (do phase.monad
+ [_ (generation.execute! runtime-class [runtime-class bytecode])
+ _ (generation.save! false ["" "0"] payload)]
+ (wrap payload))))
+
+(def: translate-function
+ (Operation [Text Binary])
+ (let [applyI (|> (list.n/range 2 num-apply-variants)
+ (list@map (function (_ arity)
+ ($d.method #$.Public $.noneM apply-method (apply-signature arity)
+ (let [preI (|> (list.n/range 0 (dec arity))
+ (list@map _.ALOAD)
+ _.fuse)]
+ (|>> preI
+ (_.INVOKEVIRTUAL //.$Function apply-method (apply-signature (dec arity)))
+ (_.CHECKCAST //.$Function)
+ (_.ALOAD arity)
+ (_.INVOKEVIRTUAL //.$Function apply-method (apply-signature 1))
+ _.ARETURN)))))
+ (list& ($d.abstract-method #$.Public $.noneM apply-method (apply-signature 1)))
+ $d.fuse)
+ $Object (type.class "java.lang.Object" (list))
+ function-class (..reflection //.$Function)
+ bytecode ($d.abstract #$.V1_6 #$.Public $.noneC function-class (list) $Object (list)
+ (|>> ($d.field #$.Public $.finalF partials-field type.int)
+ ($d.method #$.Public $.noneM "<init>" (type.method [(list type.int) type.void (list)])
+ (|>> (_.ALOAD 0)
+ (_.INVOKESPECIAL $Object "<init>" nullary-init-methodT)
+ (_.ALOAD 0)
+ (_.ILOAD 1)
+ (_.PUTFIELD //.$Function partials-field type.int)
+ _.RETURN))
+ applyI))
+ payload ["1" bytecode]]
+ (do phase.monad
+ [_ (generation.execute! function-class [function-class bytecode])
+ _ (generation.save! false ["" "1"] payload)]
+ (wrap payload))))
+
+(def: #export translate
+ (Operation [Registry Output])
+ (do phase.monad
+ [runtime-payload ..translate-runtime
+ function-payload ..translate-function]
+ (wrap [(|> artifact.empty
+ artifact.resource
+ product.right
+ artifact.resource
+ product.right)
+ (row.row runtime-payload
+ function-payload)])))
diff --git a/lux-jvm/source/luxc/lang/translation/jvm/structure.lux b/lux-jvm/source/luxc/lang/translation/jvm/structure.lux
new file mode 100644
index 000000000..46f87142a
--- /dev/null
+++ b/lux-jvm/source/luxc/lang/translation/jvm/structure.lux
@@ -0,0 +1,79 @@
+(.module:
+ [lux (#- Type)
+ [abstract
+ ["." monad (#+ do)]]
+ [control
+ ["ex" exception (#+ exception:)]]
+ [data
+ [number
+ ["n" nat]]
+ [text
+ ["%" format (#+ format)]]
+ [collection
+ ["." list]]]
+ [target
+ [jvm
+ ["." type (#+ Type)
+ ["." category (#+ Void Value Return Primitive Object Class Array Var Parameter Method)]
+ ["." descriptor (#+ Descriptor)]
+ ["." signature (#+ Signature)]]]]
+ [tool
+ [compiler
+ ["." phase]
+ [meta
+ [archive (#+ Archive)]]
+ [language
+ [lux
+ [synthesis (#+ Synthesis)]]]]]]
+ [luxc
+ [lang
+ [host
+ [jvm (#+ Inst Operation Phase Generator)
+ ["_" inst]]]]]
+ ["." //
+ ["#." runtime]])
+
+(exception: #export (not-a-tuple {size Nat})
+ (ex.report ["Expected size" ">= 2"]
+ ["Actual size" (%.nat size)]))
+
+(def: #export (tuple generate archive members)
+ (Generator (List Synthesis))
+ (do {@ phase.monad}
+ [#let [size (list.size members)]
+ _ (phase.assert not-a-tuple size
+ (n.>= 2 size))
+ membersI (|> members
+ list.enumerate
+ (monad.map @ (function (_ [idx member])
+ (do @
+ [memberI (generate archive member)]
+ (wrap (|>> _.DUP
+ (_.int (.int idx))
+ memberI
+ _.AASTORE)))))
+ (:: @ map _.fuse))]
+ (wrap (|>> (_.int (.int size))
+ (_.array //runtime.$Value)
+ membersI))))
+
+(def: (flagI right?)
+ (-> Bit Inst)
+ (if right?
+ (_.string "")
+ _.NULL))
+
+(def: #export (variant generate archive [lefts right? member])
+ (Generator [Nat Bit Synthesis])
+ (do phase.monad
+ [memberI (generate archive member)]
+ (wrap (|>> (_.int (.int (if right?
+ (.inc lefts)
+ lefts)))
+ (flagI right?)
+ memberI
+ (_.INVOKESTATIC //.$Runtime
+ "variant_make"
+ (type.method [(list //runtime.$Tag //runtime.$Flag //runtime.$Value)
+ //.$Variant
+ (list)]))))))
diff --git a/lux-jvm/source/program.lux b/lux-jvm/source/program.lux
new file mode 100644
index 000000000..e2cf047e9
--- /dev/null
+++ b/lux-jvm/source/program.lux
@@ -0,0 +1,180 @@
+(.module:
+ [lux (#- Definition)
+ ["@" target]
+ ["." host (#+ import:)]
+ [abstract
+ [monad (#+ do)]]
+ [control
+ ["." io (#+ IO)]
+ ["." try (#+ Try)]
+ [parser
+ [cli (#+ program:)]]
+ [concurrency
+ ["." promise (#+ Promise)]]]
+ [data
+ ["." product]
+ [text
+ ["%" format (#+ format)]]
+ [collection
+ [array (#+ Array)]
+ ["." dictionary]]]
+ [world
+ ["." file]]
+ [target
+ [jvm
+ [bytecode (#+ Bytecode)]]]
+ [tool
+ [compiler
+ [default
+ ["." platform (#+ Platform)]]
+ [language
+ [lux
+ [analysis
+ ["." macro (#+ Expander)]]
+ [phase
+ [extension (#+ Phase Bundle Operation Handler Extender)
+ ["." analysis #_
+ ["#" jvm]]
+ ["." generation #_
+ ["#" jvm]]
+ ## ["." directive #_
+ ## ["#" jvm]]
+ ]
+ [generation
+ ["." jvm #_
+ ## ["." runtime (#+ Anchor Definition)]
+ ["." packager]
+ ## ["#/." host]
+ ]]]]]]]]
+ [program
+ ["/" compositor
+ ["/." cli]
+ ["/." static]]]
+ [luxc
+ [lang
+ [host
+ ["_" jvm]]
+ ["." directive #_
+ ["#" jvm]]
+ [translation
+ ["." jvm
+ ["." runtime]
+ ["." expression]
+ ["#/." program]
+ ["translation" extension]]]]])
+
+(import: #long java/lang/reflect/Method
+ (invoke [java/lang/Object [java/lang/Object]] #try java/lang/Object))
+
+(import: #long (java/lang/Class c)
+ (getMethod [java/lang/String [(java/lang/Class java/lang/Object)]] #try java/lang/reflect/Method))
+
+(import: #long java/lang/Object
+ (getClass [] (java/lang/Class java/lang/Object)))
+
+(def: _object-class
+ (java/lang/Class java/lang/Object)
+ (host.class-for java/lang/Object))
+
+(def: _apply2-args
+ (Array (java/lang/Class java/lang/Object))
+ (|> (host.array (java/lang/Class java/lang/Object) 2)
+ (host.array-write 0 _object-class)
+ (host.array-write 1 _object-class)))
+
+(def: _apply4-args
+ (Array (java/lang/Class java/lang/Object))
+ (|> (host.array (java/lang/Class java/lang/Object) 4)
+ (host.array-write 0 _object-class)
+ (host.array-write 1 _object-class)
+ (host.array-write 2 _object-class)
+ (host.array-write 3 _object-class)))
+
+(def: #export (expander macro inputs lux)
+ Expander
+ (do try.monad
+ [apply-method (|> macro
+ (:coerce java/lang/Object)
+ (java/lang/Object::getClass)
+ (java/lang/Class::getMethod "apply" _apply2-args))]
+ (:coerce (Try (Try [Lux (List Code)]))
+ (java/lang/reflect/Method::invoke
+ (:coerce java/lang/Object macro)
+ (|> (host.array java/lang/Object 2)
+ (host.array-write 0 (:coerce java/lang/Object inputs))
+ (host.array-write 1 (:coerce java/lang/Object lux)))
+ apply-method))))
+
+(def: #export platform
+ ## (IO (Platform Anchor (Bytecode Any) Definition))
+ (IO (Platform _.Anchor _.Inst _.Definition))
+ (do io.monad
+ [## host jvm/host.host
+ host jvm.host]
+ (wrap {#platform.&file-system (file.async file.system)
+ #platform.host host
+ ## #platform.phase jvm.generate
+ #platform.phase expression.translate
+ ## #platform.runtime runtime.generate
+ #platform.runtime runtime.translate
+ #platform.write product.right})))
+
+(def: extender
+ Extender
+ ## TODO: Stop relying on coercions ASAP.
+ (<| (:coerce Extender)
+ (function (@self handler))
+ (:coerce Handler)
+ (function (@self name phase))
+ (:coerce Phase)
+ (function (@self parameters))
+ (:coerce Operation)
+ (function (@self state))
+ (:coerce Try)
+ try.assume
+ (:coerce Try)
+ (do try.monad
+ [method (|> handler
+ (:coerce java/lang/Object)
+ (java/lang/Object::getClass)
+ (java/lang/Class::getMethod "apply" _apply4-args))]
+ (java/lang/reflect/Method::invoke
+ (:coerce java/lang/Object handler)
+ (|> (host.array java/lang/Object 4)
+ (host.array-write 0 (:coerce java/lang/Object name))
+ (host.array-write 1 (:coerce java/lang/Object phase))
+ (host.array-write 2 (:coerce java/lang/Object parameters))
+ (host.array-write 3 (:coerce java/lang/Object state)))
+ method))))
+
+(def: (target service)
+ (-> /cli.Service /cli.Target)
+ (case service
+ (^or (#/cli.Compilation [sources libraries target module])
+ (#/cli.Interpretation [sources libraries target module])
+ (#/cli.Export [sources target]))
+ target))
+
+(def: (declare-success! _)
+ (-> Any (Promise Any))
+ (promise.future (io.exit +0)))
+
+(program: [{service /cli.service}]
+ (let [jar-path (format (..target service) (:: file.system separator) "program.jar")]
+ (exec (do promise.monad
+ [_ (/.compiler {#/static.host @.jvm
+ #/static.host-module-extension ".jvm"
+ #/static.target (..target service)
+ #/static.artifact-extension ".class"}
+ ..expander
+ analysis.bundle
+ ..platform
+ ## generation.bundle
+ translation.bundle
+ (directive.bundle ..extender)
+ jvm/program.program
+ ..extender
+ service
+ [(packager.package jvm/program.class) jar-path])]
+ (..declare-success! []))
+ (io.io []))))
diff --git a/lux-jvm/source/test/program.lux b/lux-jvm/source/test/program.lux
new file mode 100644
index 000000000..270f9005d
--- /dev/null
+++ b/lux-jvm/source/test/program.lux
@@ -0,0 +1,18 @@
+(.module:
+ [lux #*
+ ["_" test (#+ Test)]
+ [control
+ ["." io]
+ [parser
+ [cli (#+ program:)]]]]
+ [spec
+ ["." compositor]]
+ {1
+ ["." /]})
+
+(program: args
+ (<| io.io
+ _.run!
+ ## (_.times 100)
+ (_.seed 1985013625126912890)
+ (compositor.spec /.jvm /.bundle /.expander /.program)))
diff --git a/lux-jvm/test/test/luxc/lang/analysis/host.jvm.lux b/lux-jvm/test/test/luxc/lang/analysis/host.jvm.lux
new file mode 100644
index 000000000..f9905c8bc
--- /dev/null
+++ b/lux-jvm/test/test/luxc/lang/analysis/host.jvm.lux
@@ -0,0 +1,549 @@
+(.module:
+ [lux #*
+ [control
+ [monad (#+ do)]
+ pipe]
+ [data
+ ["e" error]
+ ["." product]
+ ["." maybe]
+ [text ("text/" Equivalence<Text>)
+ format]
+ [collection
+ ["." array]
+ [list ("list/" Fold<List>)]
+ ["dict" dictionary]]]
+ [math
+ ["r" random "r/" Monad<Random>]]
+ ["." type]
+ [macro (#+ Monad<Meta>)
+ ["." code]]
+ [compiler
+ ["." default
+ [".L" init]
+ [phase
+ [analysis
+ [".A" type]]
+ [extension
+ [analysis
+ [".AE" host]]]]]]
+ test]
+ [///
+ ["_." primitive]])
+
+(template [<name> <success> <failure>]
+ [(def: (<name> procedure params output-type)
+ (-> Text (List Code) Type Bit)
+ (|> (do Monad<Meta>
+ [## runtime-bytecode @runtime.translate
+ ]
+ (default.with-scope
+ (typeA.with-type output-type
+ (_primitive.analyse (` ((~ (code.text procedure)) (~+ params)))))))
+ (analysis.with-current-module "")
+ (macro.run (initL.compiler []))
+ (case> (#e.Success _)
+ <success>
+
+ (#e.Error error)
+ <failure>)))]
+
+ [success #1 #0]
+ [failure #0 #1]
+ )
+
+(template [<name> <success> <failure>]
+ [(def: (<name> syntax output-type)
+ (-> Code Type Bit)
+ (|> (do Monad<Meta>
+ [## runtime-bytecode @runtime.translate
+ ]
+ (default.with-scope
+ (typeA.with-type output-type
+ (_primitive.analyse syntax))))
+ (analysis.with-current-module "")
+ (macro.run (initL.compiler []))
+ (case> (#e.Success _)
+ <success>
+
+ (#e.Error error)
+ <failure>)))]
+
+ [success' #1 #0]
+ [failure' #0 #1]
+ )
+
+(context: "Conversions [double + float]."
+ (with-expansions [<conversions> (template [<procedure> <from> <to>]
+ [(test (format <procedure> " SUCCESS")
+ (success <procedure> (list (' ("lux coerce" (+0 <from> (+0)) []))) <to>))
+ (test (format <procedure> " FAILURE")
+ (failure <procedure> (list (' [])) <to>))]
+
+ ["jvm convert double-to-float" "java.lang.Double" hostAE.Float]
+ ["jvm convert double-to-int" "java.lang.Double" hostAE.Integer]
+ ["jvm convert double-to-long" "java.lang.Double" hostAE.Long]
+ ["jvm convert float-to-double" "java.lang.Float" hostAE.Double]
+ ["jvm convert float-to-int" "java.lang.Float" hostAE.Integer]
+ ["jvm convert float-to-long" "java.lang.Float" hostAE.Long]
+ )]
+ ($_ seq
+ <conversions>
+ )))
+
+(context: "Conversions [int]."
+ (with-expansions [<conversions> (template [<procedure> <from> <to>]
+ [(test (format <procedure> " SUCCESS")
+ (success <procedure> (list (' ("lux coerce" (+0 <from> (+0)) []))) <to>))
+ (test (format <procedure> " FAILURE")
+ (failure <procedure> (list (' [])) <to>))]
+
+ ["jvm convert int-to-byte" "java.lang.Integer" hostAE.Byte]
+ ["jvm convert int-to-char" "java.lang.Integer" hostAE.Character]
+ ["jvm convert int-to-double" "java.lang.Integer" hostAE.Double]
+ ["jvm convert int-to-float" "java.lang.Integer" hostAE.Float]
+ ["jvm convert int-to-long" "java.lang.Integer" hostAE.Long]
+ ["jvm convert int-to-short" "java.lang.Integer" hostAE.Short]
+ )]
+ ($_ seq
+ <conversions>
+ )))
+
+(context: "Conversions [long]."
+ (with-expansions [<conversions> (template [<procedure> <from> <to>]
+ [(test (format <procedure> " SUCCESS")
+ (success <procedure> (list (' ("lux coerce" (+0 <from> (+0)) []))) <to>))
+ (test (format <procedure> " FAILURE")
+ (failure <procedure> (list (' [])) <to>))]
+
+ ["jvm convert long-to-double" "java.lang.Long" hostAE.Double]
+ ["jvm convert long-to-float" "java.lang.Long" hostAE.Float]
+ ["jvm convert long-to-int" "java.lang.Long" hostAE.Integer]
+ ["jvm convert long-to-short" "java.lang.Long" hostAE.Short]
+ ["jvm convert long-to-byte" "java.lang.Long" hostAE.Byte]
+ )]
+ ($_ seq
+ <conversions>
+ )))
+
+(context: "Conversions [char + byte + short]."
+ (with-expansions [<conversions> (template [<procedure> <from> <to>]
+ [(test (format <procedure> " SUCCESS")
+ (success <procedure> (list (' ("lux coerce" (+0 <from> (+0)) []))) <to>))
+ (test (format <procedure> " FAILURE")
+ (failure <procedure> (list (' [])) <to>))]
+
+ ["jvm convert char-to-byte" "java.lang.Character" hostAE.Byte]
+ ["jvm convert char-to-short" "java.lang.Character" hostAE.Short]
+ ["jvm convert char-to-int" "java.lang.Character" hostAE.Integer]
+ ["jvm convert char-to-long" "java.lang.Character" hostAE.Long]
+ ["jvm convert byte-to-long" "java.lang.Byte" hostAE.Long]
+ ["jvm convert short-to-long" "java.lang.Short" hostAE.Long]
+ )]
+ ($_ seq
+ <conversions>
+ )))
+
+(template [<domain> <boxed> <type>]
+ [(context: (format "Arithmetic " "[" <domain> "].")
+ (with-expansions [<instructions> (template [<procedure> <subject> <param> <output>]
+ [(test <procedure>
+ (success <procedure>
+ (list (' ("lux coerce" (+0 <subject> (+0)) []))
+ (' ("lux coerce" (+0 <param> (+0)) [])))
+ <output>))]
+
+ [(format "jvm " <domain> " +") <boxed> <boxed> <type>]
+ [(format "jvm " <domain> " -") <boxed> <boxed> <type>]
+ [(format "jvm " <domain> " *") <boxed> <boxed> <type>]
+ [(format "jvm " <domain> " /") <boxed> <boxed> <type>]
+ [(format "jvm " <domain> " %") <boxed> <boxed> <type>]
+ )]
+ ($_ seq
+ <instructions>
+ )))
+
+ (context: (format "Order " "[" <domain> "].")
+ (with-expansions [<instructions> (template [<procedure> <subject> <param> <output>]
+ [(test <procedure>
+ (success <procedure>
+ (list (' ("lux coerce" (+0 <subject> (+0)) []))
+ (' ("lux coerce" (+0 <param> (+0)) [])))
+ <output>))]
+
+ [(format "jvm " <domain> " =") <boxed> <boxed> hostAE.Boolean]
+ [(format "jvm " <domain> " <") <boxed> <boxed> hostAE.Boolean]
+ )]
+ ($_ seq
+ <instructions>
+ )))
+
+ (context: (format "Bitwise " "[" <domain> "].")
+ (with-expansions [<instructions> (template [<procedure> <subject> <param> <output>]
+ [(test <procedure>
+ (success <procedure>
+ (list (' ("lux coerce" (+0 <subject> (+0)) []))
+ (' ("lux coerce" (+0 <param> (+0)) [])))
+ <output>))]
+
+ [(format "jvm " <domain> " and") <boxed> <boxed> <type>]
+ [(format "jvm " <domain> " or") <boxed> <boxed> <type>]
+ [(format "jvm " <domain> " xor") <boxed> <boxed> <type>]
+ [(format "jvm " <domain> " shl") <boxed> "java.lang.Integer" <type>]
+ [(format "jvm " <domain> " shr") <boxed> "java.lang.Integer" <type>]
+ [(format "jvm " <domain> " ushr") <boxed> "java.lang.Integer" <type>]
+ )]
+ ($_ seq
+ <instructions>
+ )))]
+
+
+ ["int" "java.lang.Integer" hostAE.Integer]
+ ["long" "java.lang.Long" hostAE.Long]
+ )
+
+(template [<domain> <boxed> <type>]
+ [(context: (format "Arithmetic " "[" <domain> "].")
+ (with-expansions [<instructions> (template [<procedure> <subject> <param> <output>]
+ [(test <procedure>
+ (success <procedure>
+ (list (' ("lux coerce" (+0 <subject> (+0)) []))
+ (' ("lux coerce" (+0 <param> (+0)) [])))
+ <output>))]
+
+ [(format "jvm " <domain> " +") <boxed> <boxed> <type>]
+ [(format "jvm " <domain> " -") <boxed> <boxed> <type>]
+ [(format "jvm " <domain> " *") <boxed> <boxed> <type>]
+ [(format "jvm " <domain> " /") <boxed> <boxed> <type>]
+ [(format "jvm " <domain> " %") <boxed> <boxed> <type>]
+ )]
+ ($_ seq
+ <instructions>
+ )))
+
+ (context: (format "Order " "[" <domain> "].")
+ (with-expansions [<instructions> (template [<procedure> <subject> <param> <output>]
+ [(test <procedure>
+ (success <procedure>
+ (list (' ("lux coerce" (+0 <subject> (+0)) []))
+ (' ("lux coerce" (+0 <param> (+0)) [])))
+ <output>))]
+
+ [(format "jvm " <domain> " =") <boxed> <boxed> hostAE.Boolean]
+ [(format "jvm " <domain> " <") <boxed> <boxed> hostAE.Boolean]
+ )]
+ ($_ seq
+ <instructions>
+ )))]
+
+
+ ["float" "java.lang.Float" hostAE.Float]
+ ["double" "java.lang.Double" hostAE.Double]
+ )
+
+(template [<domain> <boxed> <type>]
+ [(context: (format "Order " "[" <domain> "].")
+ (with-expansions [<instructions> (template [<procedure> <subject> <param> <output>]
+ [(test <procedure>
+ (success <procedure>
+ (list (' ("lux coerce" (+0 <subject> (+0)) []))
+ (' ("lux coerce" (+0 <param> (+0)) [])))
+ <output>))]
+
+ [(format "jvm " <domain> " =") <boxed> <boxed> hostAE.Boolean]
+ [(format "jvm " <domain> " <") <boxed> <boxed> hostAE.Boolean]
+ )]
+ ($_ seq
+ <instructions>
+ )))]
+
+
+ ["char" "java.lang.Character" hostAE.Character]
+ )
+
+(def: array-type
+ (r.Random [Text Text])
+ (let [entries (dict.entries hostAE.boxes)
+ num-entries (list.size entries)]
+ (do r.Monad<Random>
+ [choice (|> r.nat (:: @ map (n/% (inc num-entries))))
+ #let [[unboxed boxed] (: [Text Text]
+ (|> entries
+ (list.nth choice)
+ (maybe.default ["java.lang.Object" "java.lang.Object"])))]]
+ (wrap [unboxed boxed]))))
+
+(context: "Array."
+ (<| (times +100)
+ (do @
+ [#let [cap (|>> (n/% +10) (n/max +1))]
+ [unboxed boxed] array-type
+ size (|> r.nat (:: @ map cap))
+ idx (|> r.nat (:: @ map (n/% size)))
+ level (|> r.nat (:: @ map cap))
+ #let [unboxedT (#.Primitive unboxed (list))
+ arrayT (#.Primitive "#Array" (list unboxedT))
+ arrayC (`' ("lux check" (+0 "#Array" (+1 (+0 (~ (code.text unboxed)) (+0)) (+0)))
+ ("jvm array new" (~ (code.nat size)))))
+ boxedT (#.Primitive boxed (list))
+ boxedTC (` (+0 (~ (code.text boxed)) (+0)))
+ multi-arrayT (list/fold (function (_ _ innerT)
+ (|> innerT (list) (#.Primitive "#Array")))
+ boxedT
+ (list.n/range +1 level))]]
+ ($_ seq
+ (test "jvm array new"
+ (success "jvm array new"
+ (list (code.nat size))
+ arrayT))
+ (test "jvm array new (no nesting)"
+ (failure "jvm array new"
+ (list (code.nat size))
+ unboxedT))
+ (test "jvm array new (nested/multi-level)"
+ (success "jvm array new"
+ (list (code.nat size))
+ multi-arrayT))
+ (test "jvm array length"
+ (success "jvm array length"
+ (list arrayC)
+ Nat))
+ (test "jvm array read"
+ (success' (` ("jvm object cast"
+ ("jvm array read" (~ arrayC) (~ (code.nat idx)))))
+ boxedT))
+ (test "jvm array write"
+ (success "jvm array write"
+ (list arrayC (code.nat idx) (`' ("lux coerce" (~ boxedTC) [])))
+ arrayT))
+ ))))
+
+(def: throwables
+ (List Text)
+ (list "java.lang.Throwable"
+ "java.lang.Error"
+ "java.io.IOError"
+ "java.lang.VirtualMachineError"
+ "java.lang.Exception"
+ "java.io.IOException"
+ "java.lang.RuntimeException"))
+
+(context: "Object."
+ (<| (times +100)
+ (do @
+ [[unboxed boxed] array-type
+ [!unboxed !boxed] (|> array-type
+ (r.filter (function (_ [!unboxed !boxed])
+ (not (text/= boxed !boxed)))))
+ #let [boxedT (#.Primitive boxed (list))
+ boxedC (`' ("lux check" (+0 (~ (code.text boxed)) (+0))
+ ("jvm object null")))
+ !boxedC (`' ("lux check" (+0 (~ (code.text !boxed)) (+0))
+ ("jvm object null")))
+ unboxedC (`' ("lux check" (+0 (~ (code.text unboxed)) (+0))
+ ("jvm object null")))]
+ throwable (|> r.nat
+ (:: @ map (n/% (inc (list.size throwables))))
+ (:: @ map (function (_ idx)
+ (|> throwables
+ (list.nth idx)
+ (maybe.default "java.lang.Object")))))
+ #let [throwableC (`' ("lux check" (+0 (~ (code.text throwable)) (+0))
+ ("jvm object null")))]]
+ ($_ seq
+ (test "jvm object null"
+ (success "jvm object null"
+ (list)
+ (#.Primitive boxed (list))))
+ (test "jvm object null (no primitives)"
+ (or (text/= "java.lang.Object" boxed)
+ (failure "jvm object null"
+ (list)
+ (#.Primitive unboxed (list)))))
+ (test "jvm object null?"
+ (success "jvm object null?"
+ (list boxedC)
+ Bit))
+ (test "jvm object synchronized"
+ (success "jvm object synchronized"
+ (list boxedC boxedC)
+ boxedT))
+ (test "jvm object synchronized (no primitives)"
+ (or (text/= "java.lang.Object" boxed)
+ (failure "jvm object synchronized"
+ (list unboxedC boxedC)
+ boxedT)))
+ (test "jvm object throw"
+ (or (text/= "java.lang.Object" throwable)
+ (success "jvm object throw"
+ (list throwableC)
+ Nothing)))
+ (test "jvm object class"
+ (success "jvm object class"
+ (list (code.text boxed))
+ (#.Primitive "java.lang.Class" (list boxedT))))
+ (test "jvm object instance?"
+ (success "jvm object instance?"
+ (list (code.text boxed)
+ boxedC)
+ Bit))
+ (test "jvm object instance? (lineage)"
+ (success "jvm object instance?"
+ (list (' "java.lang.Object")
+ boxedC)
+ Bit))
+ (test "jvm object instance? (no lineage)"
+ (or (text/= "java.lang.Object" boxed)
+ (failure "jvm object instance?"
+ (list (code.text boxed)
+ !boxedC)
+ Bit)))
+ ))))
+
+(context: "Member [Static Field]."
+ ($_ seq
+ (test "jvm member static get"
+ (success "jvm member static get"
+ (list (code.text "java.lang.System")
+ (code.text "out"))
+ (#.Primitive "java.io.PrintStream" (list))))
+ (test "jvm member static get (inheritance out)"
+ (success "jvm member static get"
+ (list (code.text "java.lang.System")
+ (code.text "out"))
+ (#.Primitive "java.lang.Object" (list))))
+ (test "jvm member static put"
+ (success "jvm member static put"
+ (list (code.text "java.awt.datatransfer.DataFlavor")
+ (code.text "allHtmlFlavor")
+ (`' ("lux check" (+0 "java.awt.datatransfer.DataFlavor" (+0))
+ ("jvm object null"))))
+ Any))
+ (test "jvm member static put (final)"
+ (failure "jvm member static put"
+ (list (code.text "java.lang.System")
+ (code.text "out")
+ (`' ("lux check" (+0 "java.io.PrintStream" (+0))
+ ("jvm object null"))))
+ Any))
+ (test "jvm member static put (inheritance in)"
+ (success "jvm member static put"
+ (list (code.text "java.awt.datatransfer.DataFlavor")
+ (code.text "allHtmlFlavor")
+ (`' ("jvm object cast"
+ ("lux check" (+0 "javax.activation.ActivationDataFlavor" (+0))
+ ("jvm object null")))))
+ Any))
+ ))
+
+(context: "Member [Virtual Field]."
+ ($_ seq
+ (test "jvm member virtual get"
+ (success "jvm member virtual get"
+ (list (code.text "org.omg.CORBA.ValueMember")
+ (code.text "id")
+ (`' ("lux check" (+0 "org.omg.CORBA.ValueMember" (+0))
+ ("jvm object null"))))
+ (#.Primitive "java.lang.String" (list))))
+ (test "jvm member virtual get (inheritance out)"
+ (success "jvm member virtual get"
+ (list (code.text "org.omg.CORBA.ValueMember")
+ (code.text "id")
+ (`' ("lux check" (+0 "org.omg.CORBA.ValueMember" (+0))
+ ("jvm object null"))))
+ (#.Primitive "java.lang.Object" (list))))
+ (test "jvm member virtual put"
+ (success "jvm member virtual put"
+ (list (code.text "org.omg.CORBA.ValueMember")
+ (code.text "id")
+ (`' ("lux check" (+0 "java.lang.String" (+0))
+ ("jvm object null")))
+ (`' ("lux check" (+0 "org.omg.CORBA.ValueMember" (+0))
+ ("jvm object null"))))
+ (primitive "org.omg.CORBA.ValueMember")))
+ (test "jvm member virtual put (final)"
+ (failure "jvm member virtual put"
+ (list (code.text "javax.swing.text.html.parser.DTD")
+ (code.text "applet")
+ (`' ("lux check" (+0 "javax.swing.text.html.parser.Element" (+0))
+ ("jvm object null")))
+ (`' ("lux check" (+0 "javax.swing.text.html.parser.DTD" (+0))
+ ("jvm object null"))))
+ (primitive "javax.swing.text.html.parser.DTD")))
+ (test "jvm member virtual put (inheritance in)"
+ (success "jvm member virtual put"
+ (list (code.text "java.awt.GridBagConstraints")
+ (code.text "insets")
+ (`' ("jvm object cast"
+ ("lux check" (+0 "javax.swing.plaf.InsetsUIResource" (+0))
+ ("jvm object null"))))
+ (`' ("lux check" (+0 "java.awt.GridBagConstraints" (+0))
+ ("jvm object null"))))
+ (primitive "java.awt.GridBagConstraints")))
+ ))
+
+(context: "Boxing/Unboxing."
+ ($_ seq
+ (test "jvm member static get"
+ (success "jvm member static get"
+ (list (code.text "java.util.GregorianCalendar")
+ (code.text "AD"))
+ (#.Primitive "java.lang.Integer" (list))))
+ (test "jvm member virtual get"
+ (success "jvm member virtual get"
+ (list (code.text "javax.accessibility.AccessibleAttributeSequence")
+ (code.text "startIndex")
+ (`' ("lux check" (+0 "javax.accessibility.AccessibleAttributeSequence" (+0))
+ ("jvm object null"))))
+ (#.Primitive "java.lang.Integer" (list))))
+ (test "jvm member virtual put"
+ (success "jvm member virtual put"
+ (list (code.text "javax.accessibility.AccessibleAttributeSequence")
+ (code.text "startIndex")
+ (`' ("jvm object cast"
+ ("lux check" (+0 "java.lang.Integer" (+0))
+ ("jvm object null"))))
+ (`' ("lux check" (+0 "javax.accessibility.AccessibleAttributeSequence" (+0))
+ ("jvm object null"))))
+ (primitive "javax.accessibility.AccessibleAttributeSequence")))
+ ))
+
+(context: "Member [Method]."
+ (let [longC (' ("lux coerce" (+0 "java.lang.Long" (+0))
+ +123))
+ intC (`' ("jvm convert long-to-int" (~ longC)))
+ stringC (' ("lux coerce" (+0 "java.lang.String" (+0))
+ "YOLO"))
+ objectC (`' ("lux check" (+0 "java.util.ArrayList" (+1 (+0 "java.lang.Long" (+0)) (+0)))
+ ("jvm member invoke constructor" "java.util.ArrayList"
+ ["int" ("jvm object cast" (~ intC))])))]
+ ($_ seq
+ (test "jvm member invoke static"
+ (success' (` ("jvm member invoke static"
+ "java.lang.Long" "decode"
+ ["java.lang.String" (~ stringC)]))
+ (#.Primitive "java.lang.Long" (list))))
+ (test "jvm member invoke virtual"
+ (success' (` ("jvm object cast"
+ ("jvm member invoke virtual"
+ "java.lang.Object" "equals"
+ ("jvm object cast" (~ longC)) ["java.lang.Object" ("jvm object cast" (~ longC))])))
+ (#.Primitive "java.lang.Boolean" (list))))
+ (test "jvm member invoke special"
+ (success' (` ("jvm object cast"
+ ("jvm member invoke special"
+ "java.lang.Long" "equals"
+ ("jvm object cast" (~ longC)) ["java.lang.Object" ("jvm object cast" (~ longC))])))
+ (#.Primitive "java.lang.Boolean" (list))))
+ (test "jvm member invoke interface"
+ (success' (` ("jvm object cast"
+ ("jvm member invoke interface"
+ "java.util.Collection" "add"
+ ("jvm object cast" (~ objectC)) ["java.lang.Object" ("jvm object cast" (~ longC))])))
+ (#.Primitive "java.lang.Boolean" (list))))
+ (test "jvm member invoke constructor"
+ (success' (` ("jvm member invoke constructor"
+ "java.util.ArrayList"
+ ["int" ("jvm object cast" (~ intC))]))
+ (All [a] (#.Primitive "java.util.ArrayList" (list a)))))
+ )))
diff --git a/lux-jvm/test/test/luxc/lang/synthesis/loop.lux b/lux-jvm/test/test/luxc/lang/synthesis/loop.lux
new file mode 100644
index 000000000..c6efa7dbf
--- /dev/null
+++ b/lux-jvm/test/test/luxc/lang/synthesis/loop.lux
@@ -0,0 +1,162 @@
+(.module:
+ lux
+ (lux [io]
+ (control [monad #+ do])
+ (data [bit "bit/" Eq<Bit>]
+ [number]
+ (coll [list "list/" Functor<List> Fold<List>]
+ (set ["set" unordered]))
+ text/format)
+ (macro [code])
+ ["r" math/random "r/" Monad<Random>]
+ test)
+ (luxc (lang ["la" analysis]
+ ["ls" synthesis]
+ (synthesis [".S" expression]
+ [".S" loop])
+ [".L" extension]))
+ (// common))
+
+(def: (does-recursion? arity exprS)
+ (-> ls.Arity ls.Synthesis Bit)
+ (loop [exprS exprS]
+ (case exprS
+ (^ [_ (#.Form (list [_ (#.Text "lux case")] inputS pathS))])
+ (loop [pathS pathS]
+ (case pathS
+ (^ [_ (#.Form (list [_ (#.Text "lux case alt")] leftS rightS))])
+ (or (recur leftS)
+ (recur rightS))
+
+ (^ [_ (#.Form (list [_ (#.Text "lux case seq")] leftS rightS))])
+ (recur rightS)
+
+ (^ [_ (#.Form (list [_ (#.Text "lux case exec")] bodyS))])
+ (does-recursion? arity bodyS)
+
+ _
+ #0))
+
+ (^ [_ (#.Form (list& [_ (#.Text "lux recur")] argsS))])
+ (n/= arity (list.size argsS))
+
+ (^ [_ (#.Form (list [_ (#.Text "lux let")] register inputS bodyS))])
+ (recur bodyS)
+
+ (^ [_ (#.Form (list [_ (#.Text "lux if")] inputS thenS elseS))])
+ (or (recur thenS)
+ (recur elseS))
+
+ _
+ #0
+ )))
+
+(def: (gen-body arity output)
+ (-> Nat la.Analysis (r.Random la.Analysis))
+ (r.either (r.either (r/wrap output)
+ (do r.Monad<Random>
+ [inputA (|> r.nat (:: @ map code.nat))
+ num-cases (|> r.nat (:: @ map (|>> (n/% +10) (n/max +1))))
+ tests (|> (r.set number.Hash<Nat> num-cases r.nat)
+ (:: @ map (|>> set.to-list (list/map code.nat))))
+ #let [bad-bodies (list.repeat num-cases (' []))]
+ good-body (gen-body arity output)
+ where-to-set (|> r.nat (:: @ map (n/% num-cases)))
+ #let [bodies (list.concat (list (list.take where-to-set bad-bodies)
+ (list good-body)
+ (list.drop (n/inc where-to-set) bad-bodies)))]]
+ (wrap (` ("lux case" (~ inputA)
+ (~ (code.record (list.zip2 tests bodies))))))))
+ (r.either (do r.Monad<Random>
+ [valueS r.bit
+ output' (gen-body (n/inc arity) output)]
+ (wrap (` ("lux case" (~ (code.bit valueS))
+ {("lux case bind" (~ (code.nat arity))) (~ output')}))))
+ (do r.Monad<Random>
+ [valueS r.bit
+ then|else r.bit
+ output' (gen-body arity output)
+ #let [thenA (if then|else output' (' []))
+ elseA (if (not then|else) output' (' []))]]
+ (wrap (` ("lux case" (~ (code.bit valueS))
+ {(~ (code.bit then|else)) (~ thenA)
+ (~ (code.bit (not then|else))) (~ elseA)})))))
+ ))
+
+(def: (make-function arity body)
+ (-> ls.Arity la.Analysis la.Analysis)
+ (case arity
+ +0 body
+ _ (` ("lux function" [] (~ (make-function (n/dec arity) body))))))
+
+(def: gen-recursion
+ (r.Random [Bit Nat la.Analysis])
+ (do r.Monad<Random>
+ [arity (|> r.nat (:: @ map (|>> (n/% +10) (n/max +1))))
+ recur? r.bit
+ outputS (if recur?
+ (wrap (la.apply (list.repeat arity (' [])) (la.var 0)))
+ (do @
+ [plus-or-minus? r.bit
+ how-much (|> r.nat (:: @ map (|>> (n/% arity) (n/max +1))))
+ #let [shift (if plus-or-minus? n/+ n/-)]]
+ (wrap (la.apply (list.repeat (shift how-much arity) (' [])) (la.var 0)))))
+ bodyS (gen-body arity outputS)]
+ (wrap [recur? arity (make-function arity bodyS)])))
+
+(def: gen-loop
+ (r.Random [Bit Nat la.Analysis])
+ (do r.Monad<Random>
+ [arity (|> r.nat (:: @ map (|>> (n/% +10) (n/max +1))))
+ recur? r.bit
+ self-ref? r.bit
+ #let [selfA (la.var 0)
+ argA (if self-ref? selfA (' []))]
+ outputS (if recur?
+ (wrap (la.apply (list.repeat arity argA) selfA))
+ (do @
+ [plus-or-minus? r.bit
+ how-much (|> r.nat (:: @ map (|>> (n/% arity) (n/max +1))))
+ #let [shift (if plus-or-minus? n/+ n/-)]]
+ (wrap (la.apply (list.repeat (shift how-much arity) (' [])) selfA))))
+ bodyS (gen-body arity outputS)]
+ (wrap [(and recur? (not self-ref?))
+ arity
+ (make-function arity bodyS)])))
+
+(context: "Recursion."
+ (<| (times +100)
+ (do @
+ [[prediction arity analysis] gen-recursion]
+ ($_ seq
+ (test "Can accurately identify (and then reify) tail recursion."
+ (case (expressionS.synthesize extensionL.no-syntheses
+ analysis)
+ (^ [_ (#.Form (list [_ (#.Text "lux function")] [_ (#.Nat _arity)] [_ (#.Tuple _env)] _body))])
+ (|> _body
+ (does-recursion? arity)
+ (bit/= prediction)
+ (and (n/= arity _arity)))
+
+ _
+ #0))))))
+
+(context: "Loop."
+ (<| (times +100)
+ (do @
+ [[prediction arity analysis] gen-recursion]
+ ($_ seq
+ (test "Can reify loops."
+ (case (expressionS.synthesize extensionL.no-syntheses
+ (la.apply (list.repeat arity (' [])) analysis))
+ (^ [_ (#.Form (list [_ (#.Text "lux loop")] [_ (#.Nat in_register)] [_ (#.Tuple _inits)] _body))])
+ (and (n/= arity (list.size _inits))
+ (not (loopS.contains-self-reference? _body)))
+
+ (^ [_ (#.Form (list& [_ (#.Text "lux call")]
+ [_ (#.Form (list [_ (#.Text "lux function")] _arity _env _bodyS))]
+ argsS))])
+ (loopS.contains-self-reference? _bodyS)
+
+ _
+ #0))))))
diff --git a/lux-jvm/test/test/luxc/lang/synthesis/procedure.lux b/lux-jvm/test/test/luxc/lang/synthesis/procedure.lux
new file mode 100644
index 000000000..ab6c9de6f
--- /dev/null
+++ b/lux-jvm/test/test/luxc/lang/synthesis/procedure.lux
@@ -0,0 +1,34 @@
+(.module:
+ lux
+ (lux [io]
+ (control [monad #+ do]
+ pipe)
+ (data [text "text/" Eq<Text>]
+ [product]
+ (coll [list]))
+ ["r" math/random "r/" Monad<Random>]
+ test)
+ (luxc (lang ["la" analysis]
+ ["ls" synthesis]
+ (synthesis [".S" expression])
+ [".L" extension]))
+ (// common))
+
+(context: "Procedures"
+ (<| (times +100)
+ (do @
+ [num-args (|> r.nat (:: @ map (n/% +10)))
+ nameA (r.text +5)
+ argsA (r.list num-args gen-primitive)]
+ ($_ seq
+ (test "Can synthesize procedure calls."
+ (|> (expressionS.synthesize extensionL.no-syntheses
+ (la.procedure nameA argsA))
+ (case> (^ [_ (#.Form (list& [_ (#.Text procedure)] argsS))])
+ (and (text/= nameA procedure)
+ (list.every? (product.uncurry corresponds?)
+ (list.zip2 argsA argsS)))
+
+ _
+ #0)))
+ ))))
diff --git a/lux-jvm/test/test/luxc/lang/translation/js.lux b/lux-jvm/test/test/luxc/lang/translation/js.lux
new file mode 100644
index 000000000..83108c594
--- /dev/null
+++ b/lux-jvm/test/test/luxc/lang/translation/js.lux
@@ -0,0 +1,160 @@
+(.module:
+ lux
+ (lux [io #+ IO]
+ (control [monad #+ do]
+ pipe)
+ (data ["e" error]
+ text/format
+ [number]
+ (coll [list "list/" Functor<List>]
+ [set]))
+ [math]
+ ["r" math/random]
+ (macro [code])
+ test)
+ (luxc (lang [synthesis #+ Synthesis]))
+ (test/luxc common))
+
+(def: upper-alpha-ascii
+ (r.Random Nat)
+ (|> r.nat (:: r.Functor<Random> map (|>> (n/% +91) (n/max +65)))))
+
+(def: (test-primitive-identity synthesis)
+ (-> Synthesis Bit)
+ (|> (run-js (` ("lux is" (~ synthesis) (~ synthesis))))
+ (case> (#e.Success valueV)
+ (:coerce Bit valueV)
+
+ _
+ #0)))
+
+(type: Check (-> (e.Error Any) Bit))
+
+(template [<name> <type> <pre> <=>]
+ [(def: (<name> angle)
+ (-> <type> Check)
+ (|>> (case> (#e.Success valueV)
+ (<=> (<pre> angle) (:coerce <type> valueV))
+
+ (#e.Error error)
+ #0)))]
+
+ [sin-check Frac math.sin f/=]
+ [length-check Nat id n/=]
+ )
+
+(context: "[JS] Primitives."
+ ($_ seq
+ (test "Null is equal to itself."
+ (test-primitive-identity (` ("js null"))))
+ (test "Undefined is equal to itself."
+ (test-primitive-identity (` ("js undefined"))))
+ (test "Object comparison is by reference, not by value."
+ (not (test-primitive-identity (` ("js object")))))
+ (test "Values are equal to themselves."
+ (test-primitive-identity (` ("js global" "Math"))))
+ (<| (times +100)
+ (do @
+ [value r.int
+ #let [frac-value (int-to-frac value)]]
+ (test "Can call primitive functions."
+ (|> (run-js (` ("js call" ("js global" "Math.sin") (~ (code.text (%f frac-value))))))
+ (sin-check frac-value)))))
+ ))
+
+(context: "[JS] Objects."
+ (<| (times +100)
+ (do @
+ [field (:: @ map code.text (r.text' upper-alpha-ascii +5))
+ value r.int
+ #let [empty-object (` ("js object"))
+ object (` ("js object set" (~ field) (~ (code.int value)) (~ empty-object)))
+ frac-value (int-to-frac value)]]
+ ($_ seq
+ (test "Cannot get non-existing fields from objects."
+ (|> (run-js (` ("js object get" (~ field) (~ empty-object))))
+ (case> (^multi (#e.Success valueV)
+ [(:coerce (Maybe Int) valueV) #.None])
+ #1
+
+ _
+ #0)))
+ (test "Can get fields from objects."
+ (|> (run-js (` ("js object get" (~ field) (~ object))))
+ (case> (^multi (#e.Success valueV)
+ [(:coerce (Maybe Int) valueV) (#.Some valueV)])
+ (i/= value (:coerce Int valueV))
+
+ _
+ #0)))
+ (test "Can delete fields from objects."
+ (|> (run-js (let [post-delete (` ("js object delete" (~ field) (~ object)))]
+ (` ("js object get" (~ field) (~ post-delete)))))
+ (case> (^multi (#e.Success valueV)
+ [(:coerce (Maybe Int) valueV) #.None])
+ #1
+
+ _
+ #0)))
+ (test "Can instance new objects."
+ (let [base (` ("js object new" ("js global" "Number") (~ (code.text (%f frac-value)))))]
+ (|> (run-js (` ("lux frac +" (~ base) 0.0)))
+ (case> (#e.Success valueV)
+ (f/= frac-value (:coerce Frac valueV))
+
+ (#e.Error error)
+ #0))))
+ (test "Can call methods on objects."
+ (|> (run-js (` ("js object call" ("js global" "Math") "sin" (~ (code.text (%f frac-value))))))
+ (sin-check frac-value)))
+ ))))
+
+(context: "[JS] Arrays."
+ (<| (times +100)
+ (do @
+ [length (|> r.nat (:: @ map (|>> (n/% +10) (n/max +1))))
+ idx (|> r.nat (:: @ map (n/% length)))
+ overwrite r.nat
+ elems (|> (r.set number.Hash<Nat> length r.nat)
+ (:: @ map set.to-list))
+ #let [arrayS (` ("js array literal" (~+ (list/map code.nat elems))))]]
+ ($_ seq
+ (test "Can get the length of an array."
+ (|> (run-js (` ("js array length" (~ arrayS))))
+ (length-check length)))
+ (test "Can get an element from an array."
+ (|> (run-js (` ("js array read" (~ (code.nat idx)) (~ arrayS))))
+ (case> (^multi (#e.Success elemV)
+ [[(list.nth idx elems) (:coerce (Maybe Nat) elemV)]
+ [(#.Some reference) (#.Some sample)]])
+ (n/= reference sample)
+
+ _
+ #0)))
+ (test "Can write an element into an array."
+ (let [idxS (code.nat idx)
+ overwriteS (code.nat overwrite)]
+ (|> (run-js (` ("js array read" (~ idxS)
+ ("js array write" (~ idxS) (~ overwriteS) (~ arrayS)))))
+ (case> (^multi (#e.Success elemV)
+ [(:coerce (Maybe Nat) elemV)
+ (#.Some sample)])
+ (n/= overwrite sample)
+
+ _
+ #0))))
+ (test "Can delete an element from an array."
+ (let [idxS (code.nat idx)
+ deleteS (` ("js array delete" (~ idxS) (~ arrayS)))]
+ (and (|> (run-js (` ("js array length" (~ deleteS))))
+ (length-check length))
+ (|> (run-js (` ("js array read" (~ idxS) (~ deleteS))))
+ (case> (^multi (#e.Success elemV)
+ [(:coerce (Maybe Nat) elemV)
+ #.None])
+ #1
+
+ _
+ #0))
+ )))
+ ))))
diff --git a/lux-jvm/test/test/luxc/lang/translation/jvm.lux b/lux-jvm/test/test/luxc/lang/translation/jvm.lux
new file mode 100644
index 000000000..7c97b1e78
--- /dev/null
+++ b/lux-jvm/test/test/luxc/lang/translation/jvm.lux
@@ -0,0 +1,641 @@
+(.module:
+ lux
+ (lux [io]
+ (control [monad #+ do]
+ pipe)
+ (data [maybe]
+ ["e" error]
+ [bit]
+ [bit "bit/" Eq<Bit>]
+ [number "int/" Number<Int> Codec<Text,Int>]
+ [text "text/" Eq<Text>]
+ text/format
+ (coll [list]))
+ ["r" math/random "r/" Monad<Random>]
+ [macro]
+ (macro [code])
+ [host]
+ test)
+ (luxc [lang]
+ (lang [".L" host]
+ ["ls" synthesis]
+ (translation (jvm [".T" expression]
+ [".T" eval]
+ [".T" runtime]))))
+ (test/luxc common))
+
+(context: "Conversions [Part 1]"
+ (<| (times +100)
+ (do @
+ [int-sample (|> r.int (:: @ map (i/% 128)))
+ #let [frac-sample (int-to-frac int-sample)]]
+ (with-expansions [<2step> (template [<step1> <step2> <tag> <sample> <cast> <test>]
+ [(test (format <step1> " / " <step2>)
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (|> (~ (<tag> <sample>)) <step1> <step2> (`)))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success valueT)
+ (<test> <sample> (:coerce <cast> valueT))
+
+ (#e.Error error)
+ #0)))]
+
+ ["jvm convert double-to-float" "jvm convert float-to-double" code.frac frac-sample Frac f/=]
+ ["jvm convert double-to-int" "jvm convert int-to-double" code.frac frac-sample Frac f/=]
+ ["jvm convert double-to-long" "jvm convert long-to-double" code.frac frac-sample Frac f/=]
+
+ ["jvm convert long-to-float" "jvm convert float-to-long" code.int int-sample Int i/=]
+ ["jvm convert long-to-int" "jvm convert int-to-long" code.int int-sample Int i/=]
+ ["jvm convert long-to-short" "jvm convert short-to-long" code.int int-sample Int i/=]
+ ["jvm convert long-to-byte" "jvm convert byte-to-long" code.int int-sample Int i/=]
+ )]
+ ($_ seq
+ <2step>
+ )))))
+
+(context: "Conversions [Part 2]"
+ (<| (times +100)
+ (do @
+ [int-sample (|> r.int (:: @ map (|>> (i/% 128) int/abs)))
+ #let [frac-sample (int-to-frac int-sample)]]
+ (`` ($_ seq
+ (~~ (template [<step1> <step2> <step3> <tag> <sample> <cast> <test>]
+ [(test (format <step1> " / " <step2> " / " <step3>)
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (|> (~ (<tag> <sample>)) <step1> <step2> <step3> (`)))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success valueT)
+ (<test> <sample> (:coerce <cast> valueT))
+
+ (#e.Error error)
+ #0)))]
+
+ ["jvm convert long-to-int" "jvm convert int-to-char" "jvm convert char-to-long" code.int int-sample Int i/=]
+ ["jvm convert long-to-int" "jvm convert int-to-byte" "jvm convert byte-to-long" code.int int-sample Int i/=]
+ ["jvm convert long-to-int" "jvm convert int-to-short" "jvm convert short-to-long" code.int int-sample Int i/=]
+ ["jvm convert long-to-float" "jvm convert float-to-int" "jvm convert int-to-long" code.int int-sample Int i/=]
+ ["jvm convert long-to-int" "jvm convert int-to-float" "jvm convert float-to-long" code.int int-sample Int i/=]
+ ))
+ )))))
+
+(context: "Conversions [Part 3]"
+ (<| (times +100)
+ (do @
+ [int-sample (|> r.int (:: @ map (|>> (i/% 128) int/abs)))
+ #let [frac-sample (int-to-frac int-sample)]]
+ (`` ($_ seq
+ (~~ (template [<step1> <step2> <step3> <step4> <tag> <sample> <cast> <test>]
+ [(test (format <step1> " / " <step2> " / " <step3>)
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (|> (~ (<tag> <sample>)) <step1> <step2> <step3> <step4> (`)))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success valueT)
+ (<test> <sample> (:coerce <cast> valueT))
+
+ (#e.Error error)
+ #0)))]
+
+ ["jvm convert long-to-int" "jvm convert int-to-char" "jvm convert char-to-byte" "jvm convert byte-to-long" code.int int-sample Int i/=]
+ ["jvm convert long-to-int" "jvm convert int-to-char" "jvm convert char-to-short" "jvm convert short-to-long" code.int int-sample Int i/=]
+ ["jvm convert long-to-int" "jvm convert int-to-char" "jvm convert char-to-int" "jvm convert int-to-long" code.int int-sample Int i/=]
+ ))
+ )))))
+
+(def: gen-nat
+ (r.Random Nat)
+ (|> r.nat
+ (r/map (n/% +128))
+ (r.filter (|>> (n/= +0) not))))
+
+(def: gen-int
+ (r.Random Int)
+ (|> gen-nat (r/map nat-to-int)))
+
+(def: gen-frac
+ (r.Random Frac)
+ (|> gen-int (r/map int-to-frac)))
+
+(template [<domain> <generator> <tag> <type> <test> <augmentation> <+> <-> <*> </> <%> <pre> <post>]
+ [(context: (format "Arithmetic [" <domain> "]")
+ (<| (times +100)
+ (do @
+ [param <generator>
+ #let [subject (<augmentation> param)]]
+ (with-expansions [<tests> (template [<procedure> <reference>]
+ [(test <procedure>
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (<post> ((code.text <procedure>)
+ (<pre> (<tag> subject))
+ (<pre> (<tag> param)))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success valueT)
+ (<test> (<reference> param subject)
+ (:coerce <type> valueT))
+
+ (#e.Error error)
+ #0)))]
+
+ [(format "jvm " <domain> " +") <+>]
+ [(format "jvm " <domain> " -") <->]
+ [(format "jvm " <domain> " *") <*>]
+ [(format "jvm " <domain> " /") </>]
+ [(format "jvm " <domain> " %") <%>]
+ )]
+ ($_ seq
+ <tests>
+ )))))]
+
+ ["int" gen-int code.int Int i/= (i/* 10) i/+ i/- i/* i// i/% "jvm convert long-to-int" "jvm convert int-to-long"]
+ ["long" gen-int code.int Int i/= (i/* 10) i/+ i/- i/* i// i/% id id]
+ ["float" gen-frac code.frac Frac f/= (f/* 10.0) f/+ f/- f/* f// f/% "jvm convert double-to-float" "jvm convert float-to-double"]
+ ["double" gen-frac code.frac Frac f/= (f/* 10.0) f/+ f/- f/* f// f/% id id]
+ )
+
+(template [<domain> <post> <convert>]
+ [(context: (format "Bit-wise [" <domain> "] { Combiners ]")
+ (<| (times +100)
+ (do @
+ [param gen-nat
+ subject gen-nat]
+ (`` ($_ seq
+ (~~ (template [<procedure> <reference>]
+ [(test <procedure>
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (<post> ((code.text <procedure>)
+ (<convert> (code.nat subject))
+ (<convert> (code.nat param)))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success valueT)
+ (n/= (<reference> param subject)
+ (:coerce Nat valueT))
+
+ (#e.Error error)
+ #0)))]
+
+ [(format "jvm " <domain> " and") bit.and]
+ [(format "jvm " <domain> " or") bit.or]
+ [(format "jvm " <domain> " xor") bit.xor]
+ ))
+ )))))]
+
+ ["int" "jvm convert int-to-long" "jvm convert long-to-int"]
+ ["long" id id]
+ )
+
+(template [<domain> <post> <convert>]
+ [(context: (format "Bit-wise [" <domain> "] { Shifters }")
+ (<| (times +100)
+ (do @
+ [param gen-nat
+ subject gen-nat
+ #let [shift (n/% +10 param)]]
+ (`` ($_ seq
+ (~~ (template [<procedure> <reference> <type> <test> <pre-subject> <pre>]
+ [(test <procedure>
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (<post> ((code.text <procedure>)
+ (<convert> (<pre> subject))
+ ("jvm convert long-to-int" (code.nat shift)))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success valueT)
+ (<test> (<reference> shift (<pre-subject> subject))
+ (:coerce <type> valueT))
+
+ (#e.Error error)
+ #0)))]
+
+ [(format "jvm " <domain> " shl") bit.left-shift Nat n/= id code.nat]
+ [(format "jvm " <domain> " shr") bit.arithmetic-right-shift Int i/= nat-to-int (|>> nat-to-int code.int)]
+ [(format "jvm " <domain> " ushr") bit.logical-right-shift Nat n/= id code.nat]
+ ))
+ )))))]
+
+ ["int" "jvm convert int-to-long" "jvm convert long-to-int"]
+ ["long" id id]
+ )
+
+(template [<domain> <generator> <tag> <=> <<> <pre>]
+ [(context: (format "Order [" <domain> "]")
+ (<| (times +100)
+ (do @
+ [param <generator>
+ subject <generator>]
+ (with-expansions [<tests> (template [<procedure> <reference>]
+ [(test <procedure>
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate ((code.text <procedure>)
+ (<pre> (<tag> subject))
+ (<pre> (<tag> param))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success valueT)
+ (bit/= (<reference> param subject)
+ (:coerce Bit valueT))
+
+ (#e.Error error)
+ #0)))]
+
+ [(format "jvm " <domain> " =") <=>]
+ [(format "jvm " <domain> " <") <<>]
+ )]
+ ($_ seq
+ <tests>
+ )))))]
+
+ ["int" gen-int code.int i/= i/< "jvm convert long-to-int"]
+ ["long" gen-int code.int i/= i/< id]
+ ["float" gen-frac code.frac f/= f/< "jvm convert double-to-float"]
+ ["double" gen-frac code.frac f/= f/< id]
+ ["char" gen-int code.int i/= i/< "jvm convert long-to-char"]
+ )
+
+(def: (jvm//array//new dimension class size)
+ (-> Nat Text Nat ls.Synthesis)
+ (` ("jvm array new" (~ (code.nat dimension)) (~ (code.text class)) (~ (code.nat size)))))
+
+(def: (jvm//array//write class idx inputS arrayS)
+ (-> Text Nat ls.Synthesis ls.Synthesis ls.Synthesis)
+ (` ("jvm array write" (~ (code.text class)) (~ (code.nat idx)) (~ inputS) (~ arrayS))))
+
+(def: (jvm//array//read class idx arrayS)
+ (-> Text Nat ls.Synthesis ls.Synthesis)
+ (` ("jvm array read" (~ (code.text class)) (~ (code.nat idx)) (~ arrayS))))
+
+(context: "Array [Part 1]"
+ (<| (times +100)
+ (do @
+ [size (|> r.nat (:: @ map (|>> (n/% +10) (n/max +1))))
+ idx (|> r.nat (:: @ map (n/% size)))
+ valueZ r.bit
+ valueB gen-int
+ valueS gen-int
+ valueI gen-int
+ valueL r.int
+ valueF gen-frac
+ valueD r.frac
+ valueC gen-int]
+ (with-expansions [<array> (template [<class> <type> <value> <test> <input> <post>]
+ [(test <class>
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (|> (jvm//array//new +0 <class> size)
+ (jvm//array//write <class> idx <input>)
+ (jvm//array//read <class> idx)
+ <post>))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputZ)
+ (<test> <value> (:coerce <type> outputZ))
+
+ (#e.Error error)
+ #0)))]
+
+ ["boolean" Bit valueZ bit/= (code.bit valueZ)
+ id]
+ ["byte" Int valueB i/= (|> (code.int valueB) (~) "jvm convert long-to-byte" (`))
+ "jvm convert byte-to-long"]
+ ["short" Int valueS i/= (|> (code.int valueS) (~) "jvm convert long-to-short" (`))
+ "jvm convert short-to-long"]
+ ["int" Int valueI i/= (|> (code.int valueI) (~) "jvm convert long-to-int" (`))
+ "jvm convert int-to-long"]
+ ["long" Int valueL i/= (code.int valueL)
+ id]
+ ["float" Frac valueF f/= (|> (code.frac valueF) (~) "jvm convert double-to-float" (`))
+ "jvm convert float-to-double"]
+ ["double" Frac valueD f/= (code.frac valueD)
+ id]
+ )]
+ ($_ seq
+ <array>
+ )))))
+
+(context: "Array [Part 2]"
+ (<| (times +100)
+ (do @
+ [size (|> r.nat (:: @ map (|>> (n/% +10) (n/max +1))))
+ idx (|> r.nat (:: @ map (n/% size)))
+ valueZ r.bit
+ valueB gen-int
+ valueS gen-int
+ valueI gen-int
+ valueL r.int
+ valueF gen-frac
+ valueD r.frac
+ valueC gen-int]
+ (with-expansions [<array> (template [<class> <type> <value> <test> <input> <post>]
+ [(test <class>
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (|> (jvm//array//new +0 <class> size)
+ (jvm//array//write <class> idx <input>)
+ (jvm//array//read <class> idx)
+ <post>))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (<test> <value> (:coerce <type> outputT))
+
+ (#e.Error error)
+ #0)))]
+
+ ["char" Int valueC i/=
+ (|> (code.int valueC) (~) "jvm convert long-to-int" "jvm convert int-to-char" (`))
+ "jvm convert char-to-long"]
+ ["java.lang.Long" Int valueL i/=
+ (code.int valueL)
+ id]
+ )]
+ ($_ seq
+ <array>
+ (test "java.lang.Double (level 1)"
+ (|> (do macro.Monad<Meta>
+ [#let [inner (|> ("jvm array new" +0 "java.lang.Double" (~ (code.nat size)))
+ ("jvm array write" "java.lang.Double" (~ (code.nat idx)) (~ (code.frac valueD)))
+ (`))]
+ sampleI (expressionT.translate (|> ("jvm array new" +1 "java.lang.Double" (~ (code.nat size)))
+ ("jvm array write" "#Array" (~ (code.nat idx)) (~ inner))
+ ("jvm array read" "#Array" (~ (code.nat idx)))
+ ("jvm array read" "java.lang.Double" (~ (code.nat idx)))
+ (`)))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (f/= valueD (:coerce Frac outputT))
+
+ (#e.Error error)
+ #0)))
+ (test "jvm array length"
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (` ("jvm array length" ("jvm array new" +0 "java.lang.Object" (~ (code.nat size))))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (n/= size (:coerce Nat outputT))
+
+ (#e.Error error)
+ #0)))
+ )))))
+
+(host.import: java/lang/Class
+ (getName [] String))
+
+(def: classes
+ (List Text)
+ (list "java.lang.Object" "java.lang.Class"
+ "java.lang.String" "java.lang.Number"))
+
+(def: instances
+ (List [Text (r.Random ls.Synthesis)])
+ (let [gen-boolean (|> r.bit (:: r.Functor<Random> map code.bit))
+ gen-integer (|> r.int (:: r.Functor<Random> map code.int))
+ gen-double (|> r.frac (:: r.Functor<Random> map code.frac))
+ gen-string (|> (r.text +5) (:: r.Functor<Random> map code.text))]
+ (list ["java.lang.Boolean" gen-boolean]
+ ["java.lang.Long" gen-integer]
+ ["java.lang.Double" gen-double]
+ ["java.lang.String" gen-string]
+ ["java.lang.Object" (r.either (r.either gen-boolean
+ gen-integer)
+ (r.either gen-double
+ gen-string))])))
+
+(context: "Object."
+ (<| (times +100)
+ (do @
+ [#let [num-classes (list.size classes)]
+ #let [num-instances (list.size instances)]
+ class-idx (|> r.nat (:: @ map (n/% num-classes)))
+ instance-idx (|> r.nat (:: @ map (n/% num-instances)))
+ exception-message (r.text +5)
+ #let [class (maybe.assume (list.nth class-idx classes))
+ [instance-class instance-gen] (maybe.assume (list.nth instance-idx instances))
+ exception-message$ (` ["java.lang.String" (~ (code.text exception-message))])]
+ sample r.int
+ monitor r.int
+ instance instance-gen]
+ ($_ seq
+ (test "jvm object null"
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (` ("jvm object null?" ("jvm object null"))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (:coerce Bit outputT)
+
+ (#e.Error error)
+ #0)))
+ (test "jvm object null?"
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (` ("jvm object null?" (~ (code.int sample)))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (not (:coerce Bit outputT))
+
+ (#e.Error error)
+ #0)))
+ (test "jvm object synchronized"
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (` ("jvm object synchronized" (~ (code.int monitor)) (~ (code.int sample)))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (i/= sample (:coerce Int outputT))
+
+ (#e.Error error)
+ #0)))
+ (test "jvm object throw"
+ (|> (do macro.Monad<Meta>
+ [_ runtimeT.translate
+ sampleI (expressionT.translate (` ("lux try" ("lux function" +1 []
+ ("jvm object throw" ("jvm member invoke constructor"
+ "java.lang.Throwable"
+ (~ exception-message$)))))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (case (:coerce (e.Error Any) outputT)
+ (#e.Error error)
+ (text.contains? exception-message error)
+
+ (#e.Success outputT)
+ #0)
+
+ (#e.Error error)
+ #0)))
+ (test "jvm object class"
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (` ("jvm object class" (~ (code.text class)))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (|> outputT (:coerce Class) (Class::getName []) (text/= class))
+
+ (#e.Error error)
+ #0)))
+ (test "jvm object instance?"
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (` ("jvm object instance?" (~ (code.text instance-class)) (~ instance))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (:coerce Bit outputT)
+
+ (#e.Error error)
+ #0)))
+ ))))
+
+(host.import: java/util/GregorianCalendar
+ (#static AD int))
+
+(context: "Member [Field]"
+ (<| (times +100)
+ (do @
+ [sample-short (|> r.int (:: @ map (|>> int/abs (i/% 100))))
+ sample-string (r.text +5)
+ other-sample-string (r.text +5)
+ #let [shortS (` ["short" ("jvm object cast" "java.lang.Short" "short"
+ ("jvm convert long-to-short" (~ (code.int sample-short))))])
+ stringS (` ["java.lang.String" (~ (code.text sample-string))])
+ type-codeS (` ["org.omg.CORBA.TypeCode" ("jvm object null")])
+ idl-typeS (` ["org.omg.CORBA.IDLType" ("jvm object null")])
+ value-memberS (` ("jvm member invoke constructor"
+ "org.omg.CORBA.ValueMember"
+ (~ stringS) (~ stringS) (~ stringS) (~ stringS)
+ (~ type-codeS) (~ idl-typeS) (~ shortS)))]]
+ ($_ seq
+ (test "jvm member static get"
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (` ("jvm convert int-to-long" ("jvm member static get" "java.util.GregorianCalendar" "AD" "int"))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (i/= GregorianCalendar::AD (:coerce Int outputT))
+
+ (#e.Error error)
+ #0)))
+ (test "jvm member static put"
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (` ("jvm member static put" "java.awt.datatransfer.DataFlavor" "allHtmlFlavor" "java.awt.datatransfer.DataFlavor"
+ ("jvm member static get" "java.awt.datatransfer.DataFlavor" "allHtmlFlavor" "java.awt.datatransfer.DataFlavor"))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (is? hostL.unit (:coerce Text outputT))
+
+ (#e.Error error)
+ #0)))
+ (test "jvm member virtual get"
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (` ("jvm member virtual get" "org.omg.CORBA.ValueMember" "name" "java.lang.String" (~ value-memberS))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (text/= sample-string (:coerce Text outputT))
+
+ (#e.Error error)
+ #0)))
+ (test "jvm member virtual put"
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (` ("jvm member virtual get" "org.omg.CORBA.ValueMember" "name" "java.lang.String"
+ ("jvm member virtual put" "org.omg.CORBA.ValueMember" "name" "java.lang.String"
+ (~ (code.text other-sample-string)) (~ value-memberS)))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (text/= other-sample-string (:coerce Text outputT))
+
+ (#e.Error error)
+ #0)))
+ ))))
+
+(host.import: java/lang/Object)
+
+(host.import: (java/util/ArrayList a))
+
+(context: "Member [Method]"
+ (<| (times +100)
+ (do @
+ [sample (|> r.int (:: @ map (|>> int/abs (i/% 100))))
+ #let [object-longS (` ["java.lang.Object" (~ (code.int sample))])
+ intS (` ["int" ("jvm object cast" "java.lang.Integer" "int"
+ ("jvm convert long-to-int" (~ (code.int sample))))])
+ coded-intS (` ["java.lang.String" (~ (code.text (int/encode sample)))])
+ array-listS (` ("jvm member invoke constructor" "java.util.ArrayList" (~ intS)))]]
+ ($_ seq
+ (test "jvm member invoke static"
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (` ("jvm member invoke static" "java.lang.Long"
+ "decode" "java.lang.Long"
+ (~ coded-intS))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (i/= sample (:coerce Int outputT))
+
+ (#e.Error error)
+ #0)))
+ (test "jvm member invoke virtual"
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (` ("jvm object cast" "boolean" "java.lang.Boolean"
+ ("jvm member invoke virtual" "java.lang.Object" "equals" "boolean"
+ (~ (code.int sample)) (~ object-longS)))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (:coerce Bit outputT)
+
+ (#e.Error error)
+ #0)))
+ (test "jvm member invoke interface"
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate (` ("jvm object cast" "boolean" "java.lang.Boolean"
+ ("jvm member invoke interface" "java.util.Collection" "add" "boolean"
+ (~ array-listS) (~ object-longS)))))]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (:coerce Bit outputT)
+
+ (#e.Error error)
+ #0)))
+ (test "jvm member invoke constructor"
+ (|> (do macro.Monad<Meta>
+ [sampleI (expressionT.translate array-listS)]
+ (evalT.eval sampleI))
+ (lang.with-current-module "")
+ (macro.run (io.run init-jvm))
+ (case> (#e.Success outputT)
+ (host.instance? ArrayList (:coerce Object outputT))
+
+ (#e.Error error)
+ #0)))
+ ))))