diff options
Diffstat (limited to '')
-rw-r--r-- | src/lux/compiler.clj | 529 |
1 files changed, 311 insertions, 218 deletions
diff --git a/src/lux/compiler.clj b/src/lux/compiler.clj index a62f66c35..daf2f1e09 100644 --- a/src/lux/compiler.clj +++ b/src/lux/compiler.clj @@ -18,9 +18,10 @@ ClassWriter MethodVisitor))) -(def +prefix+ "lux") - ;; [Utils/General] +(defn ^:private storage-id [scope] + (->> scope reverse (map normalize-ident) (interpose "$") (reduce str ""))) + (defn ^:private write-file [file data] (with-open [stream (java.io.BufferedOutputStream. (java.io.FileOutputStream. file))] (.write stream data))) @@ -31,31 +32,19 @@ (defn ^:private load-class! [loader name] (.loadClass loader name)) -(defn save-class! [name bytecode] +(defn ^:private save-class! [name bytecode] (exec [loader &util/loader :let [_ (write-class name bytecode) _ (load-class! loader (string/replace name #"/" "."))]] (return nil))) -(def ^:private +variant-class+ (str +prefix+ ".Variant")) -(def ^:private +tuple-class+ (str +prefix+ ".Tuple")) - -(defn ^:private unwrap-ident [ident] - (match ident - [::&parser/ident ?label] - ?label)) - -(defn ^:private with-writer [writer body] - (fn [state] - ;; (prn 'with-writer/_0 body) - (let [result (body (assoc state ::&util/writer writer))] - ;; (prn 'with-writer/_1 result) - (match result - [::&util/ok [?state ?value]] - [::&util/ok [(assoc ?state ::&util/writer (::&util/writer state)) ?value]] - - _ - result)))) +(def ^:private +prefix+ "lux.") +(def ^:private +variant-class+ (str +prefix+ "Variant")) +(def ^:private +tuple-class+ (str +prefix+ "Tuple")) +(def ^:private +function-class+ (str +prefix+ "Function")) +(def ^:private +local-prefix+ "l") +(def ^:private +partial-prefix+ "p") +(def ^:private +closure-prefix+ "c") (def ^:private ->package ->class) @@ -92,7 +81,7 @@ (->type-signature +variant-class+) [::&type/Lambda _ _] - (->type-signature (str +prefix+ "/Function")))) + (->type-signature +function-class+))) ;; [Utils/Compilers] (let [+class+ (->class "java.lang.Boolean") @@ -113,8 +102,8 @@ (.visitMethodInsn Opcodes/INVOKESPECIAL <class> "<init>" <sig>))]] (return nil)))) - ^:private compile-int "java.lang.Integer" "(I)V" - ^:private compile-real "java.lang.Float" "(F)V" + ^:private compile-int "java.lang.Long" "(J)V" + ^:private compile-real "java.lang.Double" "(D)V" ^:private compile-char "java.lang.Character" "(C)V" ) @@ -126,7 +115,7 @@ (defn ^:private compile-tuple [compile *type* ?elems] (exec [*writer* &util/get-writer :let [num-elems (count ?elems) - tuple-class (str +prefix+ "/Tuple" num-elems) + tuple-class (->class (str +tuple-class+ num-elems)) _ (doto *writer* (.visitTypeInsn Opcodes/NEW tuple-class) (.visitInsn Opcodes/DUP) @@ -134,14 +123,32 @@ _ (map-m (fn [idx] (exec [:let [_ (.visitInsn *writer* Opcodes/DUP)] ret (compile (nth ?elems idx)) - :let [_ (.visitFieldInsn *writer* Opcodes/PUTFIELD tuple-class (str "_" (inc idx)) "Ljava/lang/Object;")]] + :let [_ (.visitFieldInsn *writer* Opcodes/PUTFIELD tuple-class (str +partial-prefix+ idx) "Ljava/lang/Object;")]] (return ret))) (range num-elems))] (return nil))) +(defn ^:private compile-variant [compile *type* ?tag ?members] + (exec [*writer* &util/get-writer + :let [variant-class* (str (->class +variant-class+) (count ?members)) + _ (doto *writer* + (.visitTypeInsn Opcodes/NEW variant-class*) + (.visitInsn Opcodes/DUP) + (.visitMethodInsn Opcodes/INVOKESPECIAL variant-class* "<init>" "()V") + (.visitInsn Opcodes/DUP) + (.visitLdcInsn ?tag) + (.visitFieldInsn Opcodes/PUTFIELD variant-class* "tag" (->type-signature "java.lang.String")))] + _ (map-m (fn [[?tfield ?member]] + (exec [:let [_ (.visitInsn *writer* Opcodes/DUP)] + ret (compile ?member) + :let [_ (.visitFieldInsn *writer* Opcodes/PUTFIELD variant-class* (str +partial-prefix+ ?tfield) "Ljava/lang/Object;")]] + (return ret))) + (map vector (range (count ?members)) ?members))] + (return nil))) + (defn ^:private compile-local [compile *type* ?idx] (exec [*writer* &util/get-writer - :let [_ (.visitVarInsn *writer* Opcodes/ALOAD (int (inc ?idx)))]] + :let [_ (.visitVarInsn *writer* Opcodes/ALOAD (int ?idx))]] (return nil))) (defn ^:private compile-captured [compile *type* ?scope ?captured-id ?source] @@ -150,13 +157,13 @@ (.visitVarInsn Opcodes/ALOAD 0) (.visitFieldInsn Opcodes/GETFIELD (normalize-ident ?scope) - (str "__" ?captured-id) + (str +closure-prefix+ ?captured-id) "Ljava/lang/Object;"))]] (return nil))) (defn ^:private compile-global [compile *type* ?owner-class ?name] (exec [*writer* &util/get-writer - :let [_ (.visitFieldInsn *writer* Opcodes/GETSTATIC (->class (str ?owner-class "$" (normalize-ident ?name))) "_datum" "Ljava/lang/Object;")]] + :let [_ (.visitFieldInsn *writer* Opcodes/GETSTATIC (->class (storage-id (list ?name ?owner-class))) "_datum" "Ljava/lang/Object;")]] (return nil))) (def +apply-signature+ "(Ljava/lang/Object;)Ljava/lang/Object;") @@ -166,7 +173,7 @@ _ (compile ?fn) _ (map-m (fn [arg] (exec [ret (compile arg) - :let [_ (.visitMethodInsn *writer* Opcodes/INVOKEINTERFACE (str +prefix+ "/Function") "apply" +apply-signature+)]] + :let [_ (.visitMethodInsn *writer* Opcodes/INVOKEINTERFACE (->class +function-class+) "apply" +apply-signature+)]] (return ret))) ?args)] (return nil))) @@ -177,7 +184,7 @@ :let [_ (match (:form ?fn) [::&analyser/global ?owner-class ?fn-name] (let [arg-sig (->type-signature "java.lang.Object") - call-class (str (->class ?owner-class) "$" (normalize-ident ?fn-name)) + call-class (storage-id (list ?fn-name ?owner-class)) provides-num (count ?args)] (if (>= provides-num ?needs-num) (let [impl-sig (str "(" (reduce str "" (repeat ?needs-num arg-sig)) ")" arg-sig)] @@ -186,7 +193,7 @@ (->> (doseq [arg (take ?needs-num ?args)]))) (.visitMethodInsn Opcodes/INVOKESTATIC call-class "impl" impl-sig) (-> (doto (do (compile arg)) - (.visitMethodInsn Opcodes/INVOKEINTERFACE (str +prefix+ "/Function") "apply" +apply-signature+)) + (.visitMethodInsn Opcodes/INVOKEINTERFACE (->class +function-class+) "apply" +apply-signature+)) (->> (doseq [arg (drop ?needs-num ?args)]))))) (let [counter-sig "I" init-signature (str "(" (apply str counter-sig (repeat (dec ?needs-num) arg-sig)) ")" "V")] @@ -196,8 +203,7 @@ (.visitLdcInsn (int provides-num)) (-> (do (compile arg)) (->> (doseq [arg ?args]))) - (-> (.visitInsn Opcodes/ACONST_NULL) - (->> (dotimes [_ (dec (- ?needs-num provides-num))]))) + (add-nulls (dec (- ?needs-num provides-num))) (.visitMethodInsn Opcodes/INVOKESPECIAL call-class "<init>" init-signature))) )) )]] @@ -329,29 +335,59 @@ _ (compile (last ?exprs))] (return nil))) -(let [oclass (->class "java.lang.Object") - equals-sig (str "(" (->type-signature "java.lang.Object") ")Z")] - (defn ^:private compile-compare-primitive [writer mappings default-label ?pairs wrapper-class signature] - (let [wrapper-class (->class wrapper-class)] - (doseq [[?token $body] ?pairs - :let [$else (new Label)]] - (doto writer - ;; object - (.visitInsn Opcodes/DUP) ;; object, object - (-> (doto (.visitTypeInsn Opcodes/NEW wrapper-class) - (.visitInsn Opcodes/DUP) - (.visitLdcInsn ?token) - (.visitMethodInsn Opcodes/INVOKESPECIAL wrapper-class "<init>" signature)) - (->> (if (nil? wrapper-class) - (.visitLdcInsn writer ?token)))) - (.visitMethodInsn Opcodes/INVOKEVIRTUAL oclass "equals" equals-sig) ;; object, B - (.visitJumpInsn Opcodes/IFEQ $else) ;; object - (.visitInsn Opcodes/POP) - (.visitJumpInsn Opcodes/GOTO (get mappings $body)) - (.visitLabel $else))) +(do-template [<name> <wrapper-class> <value-method> <method-sig>] + (defn <name> [writer mappings default-label ?pairs] + (doseq [[?token $body] ?pairs + :let [$else (new Label)]] + (doto writer + (.visitMethodInsn Opcodes/INVOKEVIRTUAL (->class <wrapper-class>) <value-method> <method-sig>) + (.visitLdcInsn ?token) + (.visitJumpInsn Opcodes/IF_ICMPNE $else) + (.visitInsn Opcodes/POP) + (.visitJumpInsn Opcodes/GOTO (get mappings $body)) + (.visitLabel $else))) + (doto writer + (.visitInsn Opcodes/POP) + (.visitJumpInsn Opcodes/GOTO default-label))) + + ^:private compile-compare-bools "java.lang.Boolean" "booleanValue" "()Z" + ^:private compile-compare-chars "java.lang.Character" "charValue" "()C" + ) + +(do-template [<name> <wrapper-class> <value-method> <method-sig> <cmp-op>] + (defn <name> [writer mappings default-label ?pairs] + (doseq [[?token $body] ?pairs + :let [$else (new Label)]] (doto writer + (.visitMethodInsn Opcodes/INVOKEVIRTUAL (->class <wrapper-class>) <value-method> <method-sig>) + (.visitLdcInsn ?token) + (.visitInsn <cmp-op>) + (.visitJumpInsn Opcodes/IFNE $else) (.visitInsn Opcodes/POP) - (.visitJumpInsn Opcodes/GOTO default-label))))) + (.visitJumpInsn Opcodes/GOTO (get mappings $body)) + (.visitLabel $else))) + (doto writer + (.visitInsn Opcodes/POP) + (.visitJumpInsn Opcodes/GOTO default-label))) + + ^:private compile-compare-ints "java.lang.Long" "longValue" "()J" Opcodes/LCMP + ^:private compile-compare-reals "java.lang.Double" "doubleValue" "()D" Opcodes/DCMPL + ) + +(defn ^:private compile-compare-texts [writer mappings default-label ?pairs] + (doseq [[?token $body] ?pairs + :let [$else (new Label)]] + (doto writer + (.visitInsn Opcodes/DUP) + (.visitLdcInsn ?token) + (.visitMethodInsn Opcodes/INVOKEVIRTUAL (->class "java.lang.Object") "equals" (str "(" (->type-signature "java.lang.Object") ")Z")) + (.visitJumpInsn Opcodes/IFEQ $else) + (.visitInsn Opcodes/POP) + (.visitJumpInsn Opcodes/GOTO (get mappings $body)) + (.visitLabel $else))) + (doto writer + (.visitInsn Opcodes/POP) + (.visitJumpInsn Opcodes/GOTO default-label))) (let [+tag-sig+ (->type-signature "java.lang.String") variant-class* (->class +variant-class+) @@ -362,23 +398,23 @@ (defn ^:private compile-decision-tree [writer mappings default-label decision-tree] (match decision-tree [::test-bool ?pairs] - (compile-compare-primitive writer mappings default-label ?pairs "java.lang.Boolean" "(Z)V") + (compile-compare-bools writer mappings default-label ?pairs) - [::test-int ?pairs] - (compile-compare-primitive writer mappings default-label ?pairs "java.lang.Integer" "(I)V") + [::test-int ?pairs] + (compile-compare-ints writer mappings default-label ?pairs) [::test-real ?pairs] - (compile-compare-primitive writer mappings default-label ?pairs "java.lang.Float" "(F)V") + (compile-compare-reals writer mappings default-label ?pairs) [::test-char ?pairs] - (compile-compare-primitive writer mappings default-label ?pairs "java.lang.Character" "(C)V") + (compile-compare-chars writer mappings default-label ?pairs) [::test-text ?pairs] - (compile-compare-primitive writer mappings default-label ?pairs nil nil) + (compile-compare-texts writer mappings default-label ?pairs) [::store [::&analyser/local ?idx] $body] (doto writer - (.visitVarInsn Opcodes/ASTORE (inc ?idx)) + (.visitVarInsn Opcodes/ASTORE ?idx) (.visitJumpInsn Opcodes/GOTO (get mappings $body))) [::test-tuple ?branches ?cases] @@ -396,7 +432,7 @@ :let [sub-next-elem (new Label)]] (doto writer (.visitInsn Opcodes/DUP) ;; tuple, tuple - (.visitFieldInsn Opcodes/GETFIELD tuple-class** (str "_" (inc ?subidx)) +variant-field-sig+) ;; tuple, object + (.visitFieldInsn Opcodes/GETFIELD tuple-class** (str +partial-prefix+ ?subidx) +variant-field-sig+) ;; tuple, object (compile-decision-tree (assoc mappings $body sub-next-elem) next-subcase ?subpart) ;; tuple (.visitLabel sub-next-elem))) (doto writer @@ -429,7 +465,7 @@ :let [sub-next-elem (new Label)]] (doto writer (.visitInsn Opcodes/DUP) ;; variant, variant - (.visitFieldInsn Opcodes/GETFIELD variant-class** (str "_" (inc ?subidx)) +variant-field-sig+) ;; variant, object + (.visitFieldInsn Opcodes/GETFIELD variant-class** (str +partial-prefix+ ?subidx) +variant-field-sig+) ;; variant, object (compile-decision-tree (assoc mappings $body sub-next-elem) next-subcase ?subpart) ;; variant (.visitLabel sub-next-elem))) (doto writer @@ -528,7 +564,7 @@ mappings* (into {} (map first entries)) _ (dotimes [offset ?max-registers] (let [idx (+ ?base-idx offset)] - (.visitLocalVariable *writer* (str "v" idx) (->java-sig [::&type/Any]) nil start-label end-label idx)))] + (.visitLocalVariable *writer* (str +local-prefix+ idx) (->java-sig [::&type/Any]) nil start-label end-label idx)))] _ (compile ?variant) :let [_ (doto *writer* (.visitInsn Opcodes/DUP) @@ -546,7 +582,7 @@ (first (:defaults ?decision-tree)))] (doto *writer* (.visitInsn Opcodes/DUP) - (.visitVarInsn Opcodes/ASTORE (inc ?idx)) + (.visitVarInsn Opcodes/ASTORE ?idx) (.visitJumpInsn Opcodes/GOTO (get mappings* ?body))) (doto *writer* (.visitInsn Opcodes/POP) @@ -570,39 +606,13 @@ :let [start-label (new Label) end-label (new Label) _ (doto *writer* - (.visitLocalVariable (str "v" ?idx) (->java-sig (:type ?value)) nil start-label end-label ?idx) + (.visitLocalVariable (str +local-prefix+ ?idx) (->java-sig (:type ?value)) nil start-label end-label ?idx) (.visitLabel start-label) - (.visitVarInsn Opcodes/ASTORE (inc ?idx)))] + (.visitVarInsn Opcodes/ASTORE ?idx))] _ (compile ?body) :let [_ (.visitLabel *writer* end-label)]] (return nil))) -(defn ^:private compile-field [compile ?name body] - (exec [*writer* &util/get-writer - class-name &analyser/module-name - :let [outer-class (->class class-name) - datum-sig (->type-signature "java.lang.Object") - current-class (str outer-class "$" (normalize-ident ?name)) - _ (.visitInnerClass *writer* current-class outer-class nil (+ Opcodes/ACC_STATIC Opcodes/ACC_SYNTHETIC)) - =class (doto (new ClassWriter ClassWriter/COMPUTE_MAXS) - (.visit Opcodes/V1_5 (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_SUPER) - current-class nil "java/lang/Object" (into-array [(str +prefix+ "/Function")])) - (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_datum" datum-sig nil nil) - (doto (.visitEnd))))] - _ (with-writer (.visitMethod =class Opcodes/ACC_PUBLIC "<clinit>" "()V" nil nil) - (exec [*writer* &util/get-writer - :let [_ (.visitCode *writer*)] - _ (compile body) - :let [_ (doto *writer* - (.visitFieldInsn Opcodes/PUTSTATIC current-class "_datum" datum-sig) - (.visitInsn Opcodes/RETURN) - (.visitMaxs 0 0) - (.visitEnd))]] - (return nil))) - :let [_ (.visitEnd *writer*)] - _ (save-class! current-class (.toByteArray =class))] - (return nil))) - (let [clo-field-sig (->type-signature "java.lang.Object") lambda-return-sig (->type-signature "java.lang.Object") <init>-return "V" @@ -627,19 +637,19 @@ (.visitVarInsn Opcodes/ALOAD 0) (.visitMethodInsn Opcodes/INVOKESPECIAL "java/lang/Object" "<init>" "()V") (-> (doto (.visitVarInsn Opcodes/ALOAD 0) - (.visitVarInsn Opcodes/ALOAD (inc ?captured-id)) + (.visitVarInsn Opcodes/ALOAD ?captured-id) (.visitFieldInsn Opcodes/PUTFIELD class-name captured-name clo-field-sig)) - (->> (let [captured-name (str "__" ?captured-id)]) + (->> (let [captured-name (str +closure-prefix+ ?captured-id)]) (match (:form ?captured) [::&analyser/captured ?closure-id ?captured-id ?source]) (doseq [[?name ?captured] closed-over]))) (-> (doto (.visitVarInsn Opcodes/ALOAD 0) - (.visitVarInsn Opcodes/ILOAD (inc num-mappings)) + (.visitInsn Opcodes/ICONST_0) (.visitFieldInsn Opcodes/PUTFIELD class-name "_counter" counter-sig) (-> (doto (.visitVarInsn Opcodes/ALOAD 0) (.visitVarInsn Opcodes/ALOAD (+ clo_idx offset)) (.visitFieldInsn Opcodes/PUTFIELD class-name field-name clo-field-sig)) - (->> (let [field-name (str "_" clo_idx)] + (->> (let [field-name (str +partial-prefix+ clo_idx)] (doto (.visitField class (+ Opcodes/ACC_PRIVATE Opcodes/ACC_FINAL) field-name clo-field-sig nil nil) (.visitEnd))) (dotimes [clo_idx (dec num-args)]) @@ -656,8 +666,8 @@ (.visitVarInsn Opcodes/ALOAD 0) (.visitFieldInsn Opcodes/GETFIELD class-name (str <prefix> idx) clo-field-sig)))) - ^:private add-closed-over-vars "__" - ^:private add-partial-vars "_" + ^:private add-closure-vars +closure-prefix+ + ^:private add-partial-vars +partial-prefix+ ) (defn ^:private add-nulls [writer amount] @@ -678,8 +688,8 @@ (-> (doto (.visitLabel branch-label) (.visitTypeInsn Opcodes/NEW class-name) (.visitInsn Opcodes/DUP) - (add-closed-over-vars class-name closed-over) - (.visitLdcInsn (-> current-captured inc int)) + (add-closure-vars class-name closed-over) + (.visitLdcInsn (int current-captured)) (add-partial-vars class-name (take current-captured args)) (.visitVarInsn Opcodes/ALOAD 1) (add-nulls (- (dec num-captured) current-captured)) @@ -697,8 +707,8 @@ (.visitEnd)))) (defn ^:private add-lambda-impl [class compile impl-signature impl-body] - (with-writer (doto (.visitMethod class Opcodes/ACC_PUBLIC "impl" impl-signature nil nil) - (.visitCode)) + (&util/with-writer (doto (.visitMethod class Opcodes/ACC_PUBLIC "impl" impl-signature nil nil) + (.visitCode)) (exec [;; :let [_ (prn 'add-lambda-impl/_0)] *writer* &util/get-writer ;; :let [_ (prn 'add-lambda-impl/_1 *writer*)] @@ -714,9 +724,7 @@ (defn ^:private instance-closure [compile lambda-class closed-over args init-signature] (exec [*writer* &util/get-writer - :let [;; _ (prn 'instance-closure/*writer* *writer*) - num-args (count args) - _ (doto *writer* + :let [_ (doto *writer* (.visitTypeInsn Opcodes/NEW lambda-class) (.visitInsn Opcodes/DUP))] _ (->> closed-over @@ -726,10 +734,10 @@ (match (:form ?captured) [::&analyser/captured ?closure-id ?captured-id ?source] (compile ?source))))) - :let [_ (do (when (> num-args 1) + :let [num-args (count args) + _ (do (when (> num-args 1) (.visitInsn *writer* Opcodes/ICONST_0) - (dotimes [_ (dec num-args)] - (.visitInsn *writer* Opcodes/ACONST_NULL))) + (add-nulls *writer* (dec num-args))) (.visitMethodInsn *writer* Opcodes/INVOKESPECIAL lambda-class "<init>" init-signature))]] (return nil))) @@ -739,26 +747,25 @@ (.visitCode) (.visitTypeInsn Opcodes/NEW class-name) (.visitInsn Opcodes/DUP) - (-> (doto (.visitLdcInsn (int 0)) - (-> (.visitInsn Opcodes/ACONST_NULL) - (->> (dotimes [_ (dec num-args)])))) + (-> (doto (.visitInsn *writer* Opcodes/ICONST_0) + (add-nulls (dec num-args))) (->> (when (> num-args 1)))) (.visitMethodInsn Opcodes/INVOKESPECIAL class-name "<init>" <init>-sig) (.visitFieldInsn Opcodes/PUTSTATIC class-name "_datum" +datum-sig+) (.visitInsn Opcodes/RETURN) (.visitMaxs 0 0) (.visitEnd)))) - + (defn ^:private compile-lambda [compile *type* ?scope ?closure ?args ?body with-datum? instance?] - (exec [:let [lambda-class (reduce str "" (interpose "$" (map normalize-ident ?scope))) + (exec [:let [lambda-class (storage-id ?scope) impl-signature (lambda-impl-signature ?args) <init>-sig (lambda-<init>-signature ?closure ?args) =class (doto (new ClassWriter ClassWriter/COMPUTE_MAXS) (.visit Opcodes/V1_5 (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_SUPER) - lambda-class nil "java/lang/Object" (into-array [(str +prefix+ "/Function")])) + lambda-class nil "java/lang/Object" (into-array [(->class +function-class+)])) (-> (doto (.visitField (+ Opcodes/ACC_PRIVATE Opcodes/ACC_FINAL) captured-name clo-field-sig nil nil) (.visitEnd)) - (->> (let [captured-name (str "__" ?captured-id)]) + (->> (let [captured-name (str +closure-prefix+ ?captured-id)]) (match (:form ?captured) [::&analyser/captured ?closure-id ?captured-id ?source]) (doseq [[?name ?captured] ?closure]))) @@ -779,13 +786,44 @@ (return nil)))) ) -(defn ^:private compile-def [compile *type* ?name ?value] - (exec [_ (match (:form ?value) - [::&analyser/lambda ?scope ?captured ?args ?body] - (compile-lambda compile *type* ?scope ?closure ?args ?body true false) +(defn ^:private compile-field [compile *type* ?name body] + (exec [*writer* &util/get-writer + class-name &analyser/module-name + :let [outer-class (->class class-name) + datum-sig (->type-signature "java.lang.Object") + current-class (storage-id (list ?name outer-class)) + _ (.visitInnerClass *writer* current-class outer-class nil (+ Opcodes/ACC_STATIC Opcodes/ACC_SYNTHETIC)) + =class (doto (new ClassWriter ClassWriter/COMPUTE_MAXS) + (.visit Opcodes/V1_5 (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_SUPER) + current-class nil "java/lang/Object" (into-array [(->class +function-class+)])) + (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_datum" datum-sig nil nil) + (doto (.visitEnd))))] + _ (&util/with-writer (.visitMethod =class Opcodes/ACC_PUBLIC "<clinit>" "()V" nil nil) + (exec [*writer* &util/get-writer + :let [_ (.visitCode *writer*)] + _ (compile body) + :let [_ (doto *writer* + (.visitFieldInsn Opcodes/PUTSTATIC current-class "_datum" datum-sig) + (.visitInsn Opcodes/RETURN) + (.visitMaxs 0 0) + (.visitEnd))]] + (return nil))) + :let [_ (.visitEnd *writer*)] + _ (save-class! current-class (.toByteArray =class))] + (return nil))) + +(defn ^:private compile-def [compile *type* name value] + (exec [_ (match value + [::&analyser/Expression ?form _] + (match ?form + [::&analyser/lambda ?scope ?captured ?args ?body] + (compile-lambda compile *type* ?scope ?closure ?args ?body true false) + _ + (compile-field compile *type* name value)) + _ - (compile-field compile ?name ?value))] + (fail "Can only define expressions."))] (return nil))) (defn ^:private compile-jvm-class [compile *type* ?package ?name ?super-class ?fields ?methods] @@ -829,163 +867,221 @@ _ (save-class! full-name (.toByteArray =interface))] (return nil))) -(defn ^:private compile-variant [compile *type* ?tag ?members] - (exec [*writer* &util/get-writer - :let [variant-class* (str (->class +variant-class+) (count ?members)) - _ (doto *writer* - (.visitTypeInsn Opcodes/NEW variant-class*) - (.visitInsn Opcodes/DUP) - (.visitMethodInsn Opcodes/INVOKESPECIAL variant-class* "<init>" "()V") - (.visitInsn Opcodes/DUP) - (.visitLdcInsn ?tag) - (.visitFieldInsn Opcodes/PUTFIELD variant-class* "tag" (->type-signature "java.lang.String")))] - _ (map-m (fn [[?tfield ?member]] - (exec [:let [_ (.visitInsn *writer* Opcodes/DUP)] - ret (compile ?member) - :let [_ (.visitFieldInsn *writer* Opcodes/PUTFIELD variant-class* (str "_" (inc ?tfield)) "Ljava/lang/Object;")]] - (return ret))) - (map vector (range (count ?members)) ?members))] - (return nil))) +(do-template [<name> <opcode> <wrapper-class> <value-method> <value-method-sig> <wrapper-method> <wrapper-method-sig>] + (defn <name> [compile *type* ?x ?y] + (exec [:let [+wrapper-class+ (->class <wrapper-class>)] + *writer* &util/get-writer + _ (compile ?x) + :let [_ (doto *writer* + (.visitTypeInsn Opcodes/CHECKCAST +wrapper-class+) + (.visitMethodInsn Opcodes/INVOKEVIRTUAL +wrapper-class+ <value-method> <value-method-sig>))] + _ (compile ?y) + :let [_ (doto *writer* + (.visitTypeInsn Opcodes/CHECKCAST +wrapper-class+) + (.visitMethodInsn Opcodes/INVOKEVIRTUAL +wrapper-class+ <value-method> <value-method-sig>)) + _ (doto *writer* + (.visitInsn <opcode>) + (.visitMethodInsn Opcodes/INVOKESTATIC +wrapper-class+ <wrapper-method> (str <wrapper-method-sig> (->type-signature <wrapper-class>))))]] + (return nil))) -(let [+int-class+ (->class "java.lang.Integer")] - (do-template [<name> <opcode>] - (defn <name> [compile *type* ?x ?y] - (exec [*writer* &util/get-writer - _ (compile ?x) - :let [_ (doto *writer* - (.visitTypeInsn Opcodes/CHECKCAST +int-class+) - (.visitMethodInsn Opcodes/INVOKEVIRTUAL +int-class+ "intValue" "()I"))] - _ (compile ?y) - :let [_ (doto *writer* - (.visitTypeInsn Opcodes/CHECKCAST +int-class+) - (.visitMethodInsn Opcodes/INVOKEVIRTUAL +int-class+ "intValue" "()I")) - _ (doto *writer* - (.visitInsn <opcode>) - (.visitMethodInsn Opcodes/INVOKESTATIC +int-class+ "valueOf" (str "(I)" (->type-signature "java.lang.Integer"))))]] - (return nil))) - - ^:private compile-jvm-iadd Opcodes/IADD - ^:private compile-jvm-isub Opcodes/ISUB - ^:private compile-jvm-imul Opcodes/IMUL - ^:private compile-jvm-idiv Opcodes/IDIV - ^:private compile-jvm-irem Opcodes/IREM - )) + ^:private compile-jvm-iadd Opcodes/IADD "java.lang.Integer" "intValue" "()I" "valueOf" "(I)" + ^:private compile-jvm-isub Opcodes/ISUB "java.lang.Integer" "intValue" "()I" "valueOf" "(I)" + ^:private compile-jvm-imul Opcodes/IMUL "java.lang.Integer" "intValue" "()I" "valueOf" "(I)" + ^:private compile-jvm-idiv Opcodes/IDIV "java.lang.Integer" "intValue" "()I" "valueOf" "(I)" + ^:private compile-jvm-irem Opcodes/IREM "java.lang.Integer" "intValue" "()I" "valueOf" "(I)" + + ^:private compile-jvm-ladd Opcodes/LADD "java.lang.Long" "longValue" "()J" "valueOf" "(J)" + ^:private compile-jvm-lsub Opcodes/LSUB "java.lang.Long" "longValue" "()J" "valueOf" "(J)" + ^:private compile-jvm-lmul Opcodes/LMUL "java.lang.Long" "longValue" "()J" "valueOf" "(J)" + ^:private compile-jvm-ldiv Opcodes/LDIV "java.lang.Long" "longValue" "()J" "valueOf" "(J)" + ^:private compile-jvm-lrem Opcodes/LREM "java.lang.Long" "longValue" "()J" "valueOf" "(J)" + + ^:private compile-jvm-fadd Opcodes/FADD "java.lang.Float" "floatValue" "()F" "valueOf" "(F)" + ^:private compile-jvm-fsub Opcodes/FSUB "java.lang.Float" "floatValue" "()F" "valueOf" "(F)" + ^:private compile-jvm-fmul Opcodes/FMUL "java.lang.Float" "floatValue" "()F" "valueOf" "(F)" + ^:private compile-jvm-fdiv Opcodes/FDIV "java.lang.Float" "floatValue" "()F" "valueOf" "(F)" + ^:private compile-jvm-frem Opcodes/FREM "java.lang.Float" "floatValue" "()F" "valueOf" "(F)" + + ^:private compile-jvm-dadd Opcodes/DADD "java.lang.Double" "doubleValue" "()D" "valueOf" "(D)" + ^:private compile-jvm-dsub Opcodes/DSUB "java.lang.Double" "doubleValue" "()D" "valueOf" "(D)" + ^:private compile-jvm-dmul Opcodes/DMUL "java.lang.Double" "doubleValue" "()D" "valueOf" "(D)" + ^:private compile-jvm-ddiv Opcodes/DDIV "java.lang.Double" "doubleValue" "()D" "valueOf" "(D)" + ^:private compile-jvm-drem Opcodes/DREM "java.lang.Double" "doubleValue" "()D" "valueOf" "(D)" + ) -(defn compile-self-call [compile ?assumed-args] +(defn ^:private compile-self-call [compile ?assumed-args] (exec [*writer* &util/get-writer :let [_ (.visitVarInsn *writer* Opcodes/ALOAD 0)] _ (map-m (fn [arg] (exec [ret (compile arg) - :let [_ (.visitMethodInsn *writer* Opcodes/INVOKEINTERFACE (str +prefix+ "/Function") "apply" +apply-signature+)]] + :let [_ (.visitMethodInsn *writer* Opcodes/INVOKEINTERFACE (->class +function-class+) "apply" +apply-signature+)]] (return ret))) ?assumed-args)] (return nil))) -(defn ^:private compile [syntax] +(defn ^:private compile-expression [syntax] (match (:form syntax) [::&analyser/bool ?value] - (compile-bool compile (:type syntax) ?value) + (compile-bool compile-expression (:type syntax) ?value) [::&analyser/int ?value] - (compile-int compile (:type syntax) ?value) + (compile-int compile-expression (:type syntax) ?value) [::&analyser/real ?value] - (compile-real compile (:type syntax) ?value) + (compile-real compile-expression (:type syntax) ?value) [::&analyser/char ?value] - (compile-char compile (:type syntax) ?value) + (compile-char compile-expression (:type syntax) ?value) [::&analyser/text ?value] - (compile-text compile (:type syntax) ?value) + (compile-text compile-expression (:type syntax) ?value) [::&analyser/tuple ?elems] - (compile-tuple compile (:type syntax) ?elems) + (compile-tuple compile-expression (:type syntax) ?elems) [::&analyser/local ?idx] - (compile-local compile (:type syntax) ?idx) + (compile-local compile-expression (:type syntax) ?idx) [::&analyser/captured ?scope ?captured-id ?source] - (compile-captured compile (:type syntax) ?scope ?captured-id ?source) + (compile-captured compile-expression (:type syntax) ?scope ?captured-id ?source) [::&analyser/global ?owner-class ?name] - (compile-global compile (:type syntax) ?owner-class ?name) + (compile-global compile-expression (:type syntax) ?owner-class ?name) [::&analyser/call ?fn ?args] - (compile-call compile (:type syntax) ?fn ?args) + (compile-call compile-expression (:type syntax) ?fn ?args) [::&analyser/static-call ?needs-num ?fn ?args] - (compile-static-call compile (:type syntax) ?needs-num ?fn ?args) + (compile-static-call compile-expression (:type syntax) ?needs-num ?fn ?args) [::&analyser/variant ?tag ?members] - (compile-variant compile (:type syntax) ?tag ?members) + (compile-variant compile-expression (:type syntax) ?tag ?members) [::&analyser/let ?idx ?value ?body] - (compile-let compile (:type syntax) ?idx ?value ?body) + (compile-let compile-expression (:type syntax) ?idx ?value ?body) [::&analyser/case ?base-idx ?variant ?max-registers ?branch-mappings ?decision-tree] - (compile-case compile (:type syntax) ?base-idx ?variant ?max-registers ?branch-mappings ?decision-tree) + (compile-case compile-expression (:type syntax) ?base-idx ?variant ?max-registers ?branch-mappings ?decision-tree) [::&analyser/lambda ?scope ?frame ?args ?body] - (compile-lambda compile (:type syntax) ?scope ?frame ?args ?body false true) + (compile-lambda compile-expression (:type syntax) ?scope ?frame ?args ?body false true) - [::&analyser/def ?form ?body] - (compile-def compile (:type syntax) ?form ?body) - + ;; Integer arithmetic [::&analyser/jvm-iadd ?x ?y] - (compile-jvm-iadd compile (:type syntax) ?x ?y) + (compile-jvm-iadd compile-expression (:type syntax) ?x ?y) [::&analyser/jvm-isub ?x ?y] - (compile-jvm-isub compile (:type syntax) ?x ?y) + (compile-jvm-isub compile-expression (:type syntax) ?x ?y) [::&analyser/jvm-imul ?x ?y] - (compile-jvm-imul compile (:type syntax) ?x ?y) + (compile-jvm-imul compile-expression (:type syntax) ?x ?y) [::&analyser/jvm-idiv ?x ?y] - (compile-jvm-idiv compile (:type syntax) ?x ?y) + (compile-jvm-idiv compile-expression (:type syntax) ?x ?y) [::&analyser/jvm-irem ?x ?y] - (compile-jvm-irem compile (:type syntax) ?x ?y) + (compile-jvm-irem compile-expression (:type syntax) ?x ?y) + + ;; Long arithmetic + [::&analyser/jvm-ladd ?x ?y] + (compile-jvm-ladd compile-expression (:type syntax) ?x ?y) + + [::&analyser/jvm-lsub ?x ?y] + (compile-jvm-lsub compile-expression (:type syntax) ?x ?y) + + [::&analyser/jvm-lmul ?x ?y] + (compile-jvm-lmul compile-expression (:type syntax) ?x ?y) + + [::&analyser/jvm-ldiv ?x ?y] + (compile-jvm-ldiv compile-expression (:type syntax) ?x ?y) + + [::&analyser/jvm-lrem ?x ?y] + (compile-jvm-lrem compile-expression (:type syntax) ?x ?y) + ;; Float arithmetic + [::&analyser/jvm-fadd ?x ?y] + (compile-jvm-fadd compile-expression (:type syntax) ?x ?y) + + [::&analyser/jvm-fsub ?x ?y] + (compile-jvm-fsub compile-expression (:type syntax) ?x ?y) + + [::&analyser/jvm-fmul ?x ?y] + (compile-jvm-fmul compile-expression (:type syntax) ?x ?y) + + [::&analyser/jvm-fdiv ?x ?y] + (compile-jvm-fdiv compile-expression (:type syntax) ?x ?y) + + [::&analyser/jvm-frem ?x ?y] + (compile-jvm-frem compile-expression (:type syntax) ?x ?y) + + ;; Double arithmetic + [::&analyser/jvm-dadd ?x ?y] + (compile-jvm-dadd compile-expression (:type syntax) ?x ?y) + + [::&analyser/jvm-dsub ?x ?y] + (compile-jvm-dsub compile-expression (:type syntax) ?x ?y) + + [::&analyser/jvm-dmul ?x ?y] + (compile-jvm-dmul compile-expression (:type syntax) ?x ?y) + + [::&analyser/jvm-ddiv ?x ?y] + (compile-jvm-ddiv compile-expression (:type syntax) ?x ?y) + + [::&analyser/jvm-drem ?x ?y] + (compile-jvm-drem compile-expression (:type syntax) ?x ?y) + [::&analyser/do ?exprs] - (compile-do compile (:type syntax) ?exprs) + (compile-do compile-expression (:type syntax) ?exprs) [::&analyser/jvm-new ?class ?classes ?args] - (compile-jvm-new compile (:type syntax) ?class ?classes ?args) + (compile-jvm-new compile-expression (:type syntax) ?class ?classes ?args) [::&analyser/jvm-getstatic ?class ?field] - (compile-jvm-getstatic compile (:type syntax) ?class ?field) + (compile-jvm-getstatic compile-expression (:type syntax) ?class ?field) [::&analyser/jvm-getfield ?class ?field ?object] - (compile-jvm-getfield compile (:type syntax) ?class ?field ?object) + (compile-jvm-getfield compile-expression (:type syntax) ?class ?field ?object) [::&analyser/jvm-invokestatic ?class ?method ?classes ?args] - (compile-jvm-invokestatic compile (:type syntax) ?class ?method ?classes ?args) + (compile-jvm-invokestatic compile-expression (:type syntax) ?class ?method ?classes ?args) [::&analyser/jvm-invokevirtual ?class ?method ?classes ?object ?args] - (compile-jvm-invokevirtual compile (:type syntax) ?class ?method ?classes ?object ?args) + (compile-jvm-invokevirtual compile-expression (:type syntax) ?class ?method ?classes ?object ?args) [::&analyser/jvm-new-array ?class ?length] - (compile-jvm-new-array compile (:type syntax) ?class ?length) + (compile-jvm-new-array compile-expression (:type syntax) ?class ?length) [::&analyser/jvm-aastore ?array ?idx ?elem] - (compile-jvm-aastore compile (:type syntax) ?array ?idx ?elem) + (compile-jvm-aastore compile-expression (:type syntax) ?array ?idx ?elem) [::&analyser/jvm-aaload ?array ?idx] - (compile-jvm-aaload compile (:type syntax) ?array ?idx) + (compile-jvm-aaload compile-expression (:type syntax) ?array ?idx) + [::&analyser/self ?assumed-args] + (compile-self-call compile-expression ?assumed-args) + + _ + (fail "[Compiler Error] Can't compile expressions as top-level forms.") + )) + +(defn ^:private compile-statement [syntax] + (match (:form syntax) + [::&analyser/def ?form ?body] + (compile-def compile-expression (:type syntax) ?form ?body) + [::&analyser/jvm-interface [?package ?name] ?members] - (compile-jvm-interface compile (:type syntax) ?package ?name ?members) + (compile-jvm-interface compile-expression (:type syntax) ?package ?name ?members) [::&analyser/jvm-class [?package ?name] ?super-class ?members] - (compile-jvm-class compile (:type syntax) ?package ?name ?super-class ?members) + (compile-jvm-class compile-expression (:type syntax) ?package ?name ?super-class ?members) - [::&analyser/self ?assumed-args] - (compile-self-call compile ?assumed-args) + _ + (fail "[Compiler Error] Can't compile expressions as top-level forms.") )) ;; [Interface] (let [compiler-step (exec [analysis+ &analyser/analyse] - (map-m compile analysis+))] + (map-m compile-statement analysis+))] (defn compile-module [name] (exec [loader &util/loader] (fn [state] @@ -994,28 +1090,25 @@ (let [=class (doto (new ClassWriter ClassWriter/COMPUTE_MAXS) (.visit Opcodes/V1_5 (+ Opcodes/ACC_PUBLIC Opcodes/ACC_SUPER) (->class name) nil "java/lang/Object" nil))] - (match ((repeat-m compiler-step) (assoc state - ::&util/source (slurp (str "source/" name ".lux")) - ::&util/current-module name - ::&util/writer =class)) - [::&util/ok [?state ?forms]] - (if (empty? (::&util/source ?state)) - (do (.visitEnd =class) - ((save-class! name (.toByteArray =class)) ?state)) - (assert false (str "[Compiler Error] Can't compile: " (::&util/source ?state)))) + (match (&util/run-state (exhaust-m compiler-step) (assoc state + ::&util/source (slurp (str "source/" name ".lux")) + ::&util/current-module name + ::&util/writer =class)) + [::&util/ok [?state _]] + (do (.visitEnd =class) + (&util/run-state (save-class! name (.toByteArray =class)) ?state)) [::&util/failure ?message] (fail* ?message)))))))) (defn compile-all [modules] (.mkdir (java.io.File. "output")) - (let [state (&util/init-state)] - (match ((map-m compile-module modules) state) - [::&util/ok [?state ?forms]] - (println (str "Compilation complete! " (pr-str modules))) + (match (&util/run-state (map-m compile-module modules) (&util/init-state)) + [::&util/ok [?state _]] + (println (str "Compilation complete! " (pr-str modules))) - [::&util/failure ?message] - (assert false ?message)))) + [::&util/failure ?message] + (assert false ?message))) (comment (compile-all ["lux"]) |