(.module: [lux (#- Type) ["." host (#+ import: do-to)] [control ["." function]] [data ["." text format] ["." product] [collection ["." array (#+ Array)] ["." list ("#/." functor)]]] [target [jvm ["$t" type (#+ Method Class Type Parameter) ["." reflection]]]]] ["." //]) (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: (exception-class-name type) (-> Type Text) (case type (#$t.Primitive prim) (case prim #$t.Boolean reflection.boolean #$t.Byte reflection.byte #$t.Short reflection.short #$t.Int reflection.int #$t.Long reflection.long #$t.Float reflection.float #$t.Double reflection.double #$t.Char reflection.char) (#$t.Array sub) (format $t.array-prefix (exception-class-name sub)) (#$t.Generic generic) (case generic (#$t.Class class params) ($t.binary-name class) (^or (#$t.Var _) (#$t.Wildcard _)) ($t.binary-name $t.object-class)) )) (def: exceptions-array (-> Method (Array Text)) (|>> (get@ #$t.exceptions) (list/map (|>> #$t.Generic ..exception-class-name)) string-array)) (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: class-to-type (-> Class Type) (|>> #$t.Class #$t.Generic)) (def: param-signature (-> Class Text) (|>> class-to-type $t.signature (format ":"))) (def: (formal-param [name super interfaces]) (-> Parameter Text) (format name (param-signature super) (|> interfaces (list/map param-signature) (text.join-with "")))) (def: (parameters-signature parameters super interfaces) (-> (List Parameter) Class (List Class) Text) (let [formal-params (if (list.empty? parameters) "" (format "<" (|> parameters (list/map formal-param) (text.join-with "")) ">"))] (format formal-params (|> super class-to-type $t.signature) (|> interfaces (list/map (|>> class-to-type $t.signature)) (text.join-with ""))))) (def: class-computes Int ($_ i/+ (ClassWriter::COMPUTE_MAXS) ## (ClassWriter::COMPUTE_FRAMES) )) (template [ ] [(def: #export ( version visibility config name parameters super interfaces definitions) (-> //.Version //.Visibility //.Class-Config Text (List Parameter) Class (List Class) //.Def (host.type [byte])) (let [writer (|> (do-to (ClassWriter::new class-computes) (ClassWriter::visit (version-flag version) ($_ i/+ (Opcodes::ACC_SUPER) (visibility-flag visibility) (class-flags config)) ($t.binary-name name) (parameters-signature parameters super interfaces) (|> super product.left $t.binary-name) (|> interfaces (list/map (|>> product.left $t.binary-name)) string-array))) definitions) _ (ClassWriter::visitEnd writer)] (ClassWriter::toByteArray writer)))] [class +0] [abstract (Opcodes::ACC_ABSTRACT)] ) (def: $Object Class ["java.lang.Object" (list)]) (def: #export (interface version visibility config name parameters interfaces definitions) (-> //.Version //.Visibility //.Class-Config Text (List Parameter) (List 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)) ($t.binary-name name) (parameters-signature parameters $Object interfaces) (|> $Object product.left $t.binary-name) (|> interfaces (list/map (|>> product.left $t.binary-name)) string-array))) definitions) _ (ClassWriter::visitEnd writer)] (ClassWriter::toByteArray writer))) (def: #export (method visibility config name type then) (-> //.Visibility //.Method-Config Text Method //.Inst //.Def) (function (_ writer) (let [=method (ClassWriter::visitMethod ($_ i/+ (visibility-flag visibility) (method-flags config)) ($t.binary-name name) ($t.method-descriptor type) ($t.method-signature type) (exceptions-array type) 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 Method //.Def) (function (_ writer) (let [=method (ClassWriter::visitMethod ($_ i/+ (visibility-flag visibility) (method-flags config) (Opcodes::ACC_ABSTRACT)) ($t.binary-name name) ($t.method-descriptor type) ($t.method-signature type) (exceptions-array type) writer) _ (MethodVisitor::visitEnd =method)] writer))) (def: #export (field visibility config name type) (-> //.Visibility //.Field-Config Text Type //.Def) (function (_ writer) (let [=field (do-to (ClassWriter::visitField ($_ i/+ (visibility-flag visibility) (field-flags config)) ($t.binary-name name) ($t.descriptor type) ($t.signature type) (host.null) writer) (FieldVisitor::visitEnd))] writer))) (template [ ] [(def: #export ( visibility config name value) (-> //.Visibility //.Field-Config Text //.Def) (function (_ writer) (let [=field (do-to (ClassWriter::visitField ($_ i/+ (visibility-flag visibility) (field-flags config)) ($t.binary-name name) ($t.descriptor ) ($t.signature ) ( value) writer) (FieldVisitor::visitEnd))] writer)))] [boolean-field Bit $t.boolean function.identity] [byte-field Int $t.byte host.long-to-byte] [short-field Int $t.short host.long-to-short] [int-field Int $t.int host.long-to-int] [long-field Int $t.long function.identity] [float-field Frac $t.float host.double-to-float] [double-field Frac $t.double function.identity] [char-field Nat $t.char (|>> .int host.long-to-int host.int-to-char)] [string-field Text ($t.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)))