From 2c392029d19aee4962f3b37b4f10eb79f7c01e3f Mon Sep 17 00:00:00 2001 From: Eduardo Julian Date: Wed, 2 Dec 2015 19:10:31 -0400 Subject: - Made a variety of refactorings and minor changes. - Generic class definitions are halfway done. --- src/lux.clj | 4 +- src/lux/analyser.clj | 29 +++-- src/lux/analyser/host.clj | 265 ++++++++++++++++++++++---------------------- src/lux/analyser/lux.clj | 2 +- src/lux/analyser/module.clj | 5 +- src/lux/analyser/parser.clj | 79 +++++++++++-- src/lux/compiler.clj | 3 +- src/lux/compiler/base.clj | 7 +- src/lux/compiler/cache.clj | 3 +- src/lux/compiler/host.clj | 191 ++++++++++++++++--------------- src/lux/compiler/lambda.clj | 5 +- src/lux/compiler/lux.clj | 3 +- src/lux/host.clj | 102 +++++++---------- src/lux/host/generics.clj | 76 +++++++++++-- src/lux/type.clj | 5 +- 15 files changed, 447 insertions(+), 332 deletions(-) diff --git a/src/lux.clj b/src/lux.clj index c5d192879..15ba16e5c 100644 --- a/src/lux.clj +++ b/src/lux.clj @@ -14,9 +14,7 @@ (defn -main [& args] (|case (&/->list args) (&/$Cons "compile" (&/$Cons program-module (&/$Nil))) - (if program-module - (time (&compiler/compile-program program-module)) - (println "Please provide a module name to compile.")) + (time (&compiler/compile-program program-module)) _ (println "Can't understand command."))) diff --git a/src/lux/analyser.clj b/src/lux/analyser.clj index 0f1f2ae37..ff8863003 100644 --- a/src/lux/analyser.clj +++ b/src/lux/analyser.clj @@ -152,15 +152,20 @@ (|case token ;; Classes & interfaces (&/$FormS (&/$Cons [_ (&/$SymbolS _ "_jvm_class")] - (&/$Cons [_ (&/$TextS ?name)] - (&/$Cons [_ (&/$TextS ?super-class)] + (&/$Cons ?class-decl + (&/$Cons ?super-class (&/$Cons [_ (&/$TupleS ?interfaces)] (&/$Cons [_ (&/$TupleS ?anns)] (&/$Cons [_ (&/$TupleS ?fields)] (&/$Cons [_ (&/$TupleS ?methods)] (&/$Nil))))))))) - (|do [=interfaces (&/map% &&a-parser/parse-text ?interfaces)] - (&&host/analyse-jvm-class analyse compile-token ?name ?super-class =interfaces ?anns ?fields ?methods)) + (|do [=gclass-decl (&&a-parser/parse-gclass-decl ?class-decl) + =super-class (&&a-parser/parse-gclass-super ?super-class) + =interfaces (&/map% &&a-parser/parse-gclass-super ?interfaces) + =anns (&/map% &&a-parser/parse-ann ?anns) + =fields (&/map% &&a-parser/parse-field ?fields) + =methods (&/map% &&a-parser/parse-method-def ?methods)] + (&&host/analyse-jvm-class analyse compile-token =gclass-decl =super-class =interfaces =anns =fields =methods)) (&/$FormS (&/$Cons [_ (&/$SymbolS _ "_jvm_interface")] (&/$Cons ?class-decl @@ -168,18 +173,22 @@ (&/$Cons [_ (&/$TupleS ?anns)] ?methods))))) (|do [=gclass-decl (&&a-parser/parse-gclass-decl ?class-decl) - =supers (&/map% &&a-parser/parse-gclass-super ?supers)] - (&&host/analyse-jvm-interface analyse compile-token =gclass-decl =supers ?anns ?methods)) + =supers (&/map% &&a-parser/parse-gclass-super ?supers) + =anns (&/map% &&a-parser/parse-ann ?anns) + =methods (&/map% &&a-parser/parse-method-decl ?methods)] + (&&host/analyse-jvm-interface analyse compile-token =gclass-decl =supers =anns =methods)) (&/$FormS (&/$Cons [_ (&/$SymbolS _ "_jvm_anon-class")] - (&/$Cons [_ (&/$TextS ?super-class)] + (&/$Cons ?super-class (&/$Cons [_ (&/$TupleS ?interfaces)] (&/$Cons [_ (&/$TupleS ?ctor-args)] (&/$Cons [_ (&/$TupleS ?methods)] (&/$Nil))))))) - (|do [=interfaces (&/map% &&a-parser/parse-text ?interfaces) - =ctor-args (&/map% &&a-parser/parse-ctor-arg ?ctor-args)] - (&&host/analyse-jvm-anon-class analyse compile-token exo-type ?super-class =interfaces =ctor-args ?methods)) + (|do [=super-class (&&a-parser/parse-gclass-super ?super-class) + =interfaces (&/map% &&a-parser/parse-gclass-super ?interfaces) + =ctor-args (&/map% &&a-parser/parse-ctor-arg ?ctor-args) + =methods (&/map% &&a-parser/parse-method-def ?methods)] + (&&host/analyse-jvm-anon-class analyse compile-token exo-type =super-class =interfaces =ctor-args =methods)) ;; Programs (&/$FormS (&/$Cons [_ (&/$SymbolS _ "_jvm_program")] diff --git a/src/lux/analyser/host.clj b/src/lux/analyser/host.clj index b51dc21e7..b4d862be2 100644 --- a/src/lux/analyser/host.clj +++ b/src/lux/analyser/host.clj @@ -451,149 +451,143 @@ (&/V &&/$jvm-arraylength =array) ))))) -(defn ^:private analyse-field [field] - (|case field - [_ (&/$FormS (&/$Cons [_ (&/$TextS ?field-name)] - (&/$Cons [_ (&/$TupleS ?field-modifiers)] - (&/$Cons [_ (&/$TupleS ?anns)] - (&/$Cons [_ (&/$TextS ?field-type)] - (&/$Nil))))))] - (|do [=field-modifiers (&&a-parser/parse-modifiers ?field-modifiers) - =anns (&/map% &&a-parser/parse-ann ?anns)] - (return {:name ?field-name - :modifiers =field-modifiers - :anns =anns - :type ?field-type})) +(defn generic-class->simple-class [gclass] + "(-> GenericClass Text)" + (|case gclass + (&/$GenericTypeVar var-name) + "java.lang.Object" - _ - (fail "[Analyser Error] Wrong syntax for field."))) - -(defn ^:private dummy-method-desc [method] - (|case method - [_ (&/$FormS (&/$Cons [_ (&/$TextS method-name)] - (&/$Cons [_ (&/$TupleS method-modifiers)] - (&/$Cons [_ (&/$TupleS method-anns)] - (&/$Cons [_ (&/$TupleS method-exs)] - (&/$Cons [_ (&/$TupleS method-inputs)] - (&/$Cons [_ (&/$TextS method-output)] - (&/$Cons method-body - (&/$Nil)))))))))] - (|do [=method-modifiers (&&a-parser/parse-modifiers method-modifiers) - =method-exs (&/map% &&a-parser/parse-text method-exs) - =method-inputs (&/map% (fn [minput] - (|case minput - [_ (&/$FormS (&/$Cons [_ (&/$SymbolS "" input-name)] - (&/$Cons [_ (&/$TextS input-type)] - (&/$Nil))))] - (return (&/T input-name input-type)) - - _ - (fail "[Analyser Error] Wrong syntax for method input."))) - method-inputs)] - (return {:name method-name - :modifiers =method-modifiers - :anns (&/|list) - :exceptions =method-exs - :inputs (&/|map &/|second =method-inputs) - :output method-output})) - - _ - (fail (str "[Analyser Error] Wrong syntax for method: " (&/show-ast method))))) - -(defn ^:private analyse-method [analyse owner-class method] - (|case method - [_ (&/$FormS (&/$Cons [_ (&/$TextS method-name)] - (&/$Cons [_ (&/$TupleS method-modifiers)] - (&/$Cons [_ (&/$TupleS method-anns)] - (&/$Cons [_ (&/$TupleS method-exs)] - (&/$Cons [_ (&/$TupleS method-inputs)] - (&/$Cons [_ (&/$TextS method-output)] - (&/$Cons method-body - (&/$Nil)))))))))] - (|do [=method-modifiers (&&a-parser/parse-modifiers method-modifiers) - =anns (&/map% &&a-parser/parse-ann method-anns) - =method-exs (&/map% &&a-parser/parse-text method-exs) - =method-inputs (&/map% (fn [minput] - (|case minput - [_ (&/$FormS (&/$Cons [_ (&/$SymbolS "" input-name)] - (&/$Cons [_ (&/$TextS input-type)] - (&/$Nil))))] - (return (&/T input-name input-type)) - - _ - (fail "[Analyser Error] Wrong syntax for method input."))) - method-inputs) - =method-body (&/fold (fn [body* input*] - (|let [[iname itype] input*] - (&&env/with-local iname (&type/Data$ (as-otype itype) &/Nil$) - body*))) - (if (= "void" method-output) - (&&/analyse-1+ analyse method-body) - (&&/analyse-1 analyse (&type/Data$ (as-otype method-output) &/Nil$) method-body)) - (&/|reverse (&/Cons$ (&/T &&/jvm-this owner-class) - =method-inputs)))] - (return {:name method-name - :modifiers =method-modifiers - :anns =anns - :exceptions =method-exs - :inputs (&/|map &/|second =method-inputs) - :output method-output - :body =method-body})) + (&/$GenericClass name params) + name + + (&/$GenericArray param) + (|case param + (&/$GenericArray _) + (str "[" (generic-class->simple-class param)) + + (&/$GenericClass "boolean" _) + "[Z" + + (&/$GenericClass "byte" _) + "[B" + + (&/$GenericClass "short" _) + "[S" + + (&/$GenericClass "int" _) + "[I" + + (&/$GenericClass "long" _) + "[J" + + (&/$GenericClass "float" _) + "[F" + + (&/$GenericClass "double" _) + "[D" + + (&/$GenericClass "char" _) + "[C" + + (&/$GenericClass name params) + (str "[L" name ";") + + (&/$GenericTypeVar var-name) + "[Ljava.lang.Object;") + )) + +(defn generic-class->type [gclass] + "(-> GenericClass (Lux Type))" + (|case gclass + (&/$GenericTypeVar var-name) + (return (&type/Data$ "java.lang.Object" &/Nil$)) - _ - (fail (str "[Analyser Error] Wrong syntax for method: " (&/show-ast method))))) + (&/$GenericClass name params) + (case name + "boolean" (return (&type/Data$ "java.lang.Boolean" (&/|list))) + "byte" (return (&type/Data$ "java.lang.Byte" (&/|list))) + "short" (return (&type/Data$ "java.lang.Short" (&/|list))) + "int" (return (&type/Data$ "java.lang.Integer" (&/|list))) + "long" (return (&type/Data$ "java.lang.Long" (&/|list))) + "float" (return (&type/Data$ "java.lang.Float" (&/|list))) + "double" (return (&type/Data$ "java.lang.Double" (&/|list))) + "char" (return (&type/Data$ "java.lang.Character" (&/|list))) + "void" (return &type/Unit) + ;; else + (|do [=params (&/map% generic-class->type params)] + (return (&type/Data$ name =params)))) + + (&/$GenericArray param) + (|do [=param (generic-class->type param)] + (return (&type/Data$ &host-type/array-data-tag (&/|list =param)))) + )) + +(defn ^:private analyse-method [analyse class-decl method] + (|do [:let [[?cname ?cparams] class-decl + class-type (&type/Data$ ?cname &/Nil$) + [?decl ?body] method + [_ _ _ _ _ ?inputs ?output] ?decl] + output-type (generic-class->type ?output) + =body (&/fold (fn [body* input*] + (|do [:let [[iname itype*] input*] + itype (generic-class->type itype*)] + (&&env/with-local iname itype + body*))) + (&&/analyse-1 analyse output-type ?body) + (&/|reverse (&/Cons$ (&/T &&/jvm-this class-type) + ?inputs)))] + (return (&/T ?decl =body)))) (defn ^:private mandatory-methods [supers] (|do [class-loader &/loader] (&/flat-map% (partial &host/abstract-methods class-loader) supers))) (defn ^:private check-method-completion [supers methods] - "(-> (List ClassName) (List MethodDesc) (Lux (,)))" + "(-> (List SuperClassDecl) (List (, MethodDecl Analysis)) (Lux (,)))" (|do [abstract-methods (mandatory-methods supers) :let [methods-map (&/fold (fn [mmap mentry] - (assoc mmap (:name mentry) mentry)) + (prn 'methods-map (count mentry) mentry) + (|let [[[=name =modifiers =anns =gvars =exceptions =inputs =output] _] mentry] + (assoc mmap =name mentry))) {} methods) missing-method (&/fold (fn [missing abs-meth] (|let [[am-name am-inputs] abs-meth] (or missing (if-let [meth-struct (get methods-map am-name)] - (let [meth-inputs (:inputs meth-struct)] - (if (and (= (&/|length meth-inputs) (&/|length am-inputs)) - (&/fold2 (fn [prev mi ai] (and prev (= mi ai))) + (|let [[[=name =modifiers =anns =gvars =exceptions =inputs =output] _] meth-struct] + (if (and (= (&/|length =inputs) (&/|length am-inputs)) + (&/fold2 (fn [prev mi ai] + (|let [[iname itype] mi] + (and prev (= (generic-class->simple-class itype) ai)))) true - meth-inputs am-inputs)) + =inputs am-inputs)) nil - am-name)) - am-name)))) + abs-meth)) + abs-meth)))) nil abstract-methods)]] (if (nil? missing-method) (return nil) - (fail (str "[Analyser Error] Missing method: " missing-method))))) + (|let [[am-name am-inputs] missing-method] + (fail (str "[Analyser Error] Missing method: " am-name " " "(" (->> am-inputs (&/|interpose " ") (&/fold str "")) ")")))))) -(defn analyse-jvm-class [analyse compile-token name super-class interfaces anns fields methods] +(defn analyse-jvm-class [analyse compile-token class-decl super-class interfaces =anns =fields methods] (&/with-closure (|do [module &/get-module-name - :let [full-name (str module "." name)] - ;; :let [_ (prn 'analyse-jvm-class/_0)] - =anns (&/map% &&a-parser/parse-ann anns) - =fields (&/map% analyse-field fields) - ;; :let [_ (prn 'analyse-jvm-class/_1)] - =method-descs (&/map% dummy-method-desc methods) - _ (&host/use-dummy-class name super-class interfaces &/None$ =fields =method-descs) - =methods (&/map% (partial analyse-method analyse full-name) methods) + :let [[?name ?params] class-decl + full-name (str module "." ?name)] + _ (&host/use-dummy-class class-decl super-class interfaces &/None$ =fields methods) + =methods (&/map% (partial analyse-method analyse class-decl) methods) ;; :let [_ (prn 'analyse-jvm-class/_2)] _ (check-method-completion (&/Cons$ super-class interfaces) =methods) ;; :let [_ (prn 'analyse-jvm-class/_3)] - _ (compile-token (&/V &&/$jvm-class (&/T name super-class interfaces =anns =fields =methods nil))) - :let [_ (println 'DEF (str module "." name))]] + _ (compile-token (&/V &&/$jvm-class (&/T class-decl super-class interfaces =anns =fields =methods nil))) + :let [_ (println 'DEF full-name)]] (return &/Nil$)))) -(defn analyse-jvm-interface [analyse compile-token interface-decl supers anns methods] +(defn analyse-jvm-interface [analyse compile-token interface-decl supers =anns =methods] (|do [module &/get-module-name - =anns (&/map% &&a-parser/parse-ann anns) - =methods (&/map% &&a-parser/parse-method-decl methods) _ (compile-token (&/V &&/$jvm-interface (&/T interface-decl supers =anns =methods))) :let [_ (println 'DEF (str module "." (&/|first interface-decl)))]] (return &/Nil$))) @@ -608,45 +602,50 @@ :final? false :abstract? false :concurrency nil} - default- {:name "" - :modifiers {:visibility "public" - :static? false - :final? false - :abstract? false - :concurrency nil} - :anns (&/|list) - :exceptions (&/|list) - :inputs (&/|list) - :output "void"} + default- (&/T "" + {:visibility "public" + :static? false + :final? false + :abstract? false + :concurrency nil} + (&/|list) + (&/|list) + (&/|list) + (&/|list) + (&/V &/$GenericClass (&/T "void" (&/|list)))) captured-slot-type "java.lang.Object"] (defn analyse-jvm-anon-class [analyse compile-token exo-type super-class interfaces ctor-args methods] (&/with-closure (|do [module &/get-module-name scope &/get-scope-name :let [name (&host/location (&/|tail scope)) - anon-class (str module "." name)] + class-decl (&/T name (&/|list)) + anon-class (str module "." name) + _ (prn 'analyse-jvm-anon-class/_0 anon-class) + _ (prn 'analyse-jvm-anon-class/_1 class-decl) + anon-class-type (&type/Data$ anon-class (&/|list))] =ctor-args (&/map% (fn [ctor-arg] (|let [[arg-type arg-term] ctor-arg] (|do [=arg-term (&&/analyse-1+ analyse arg-term)] (return (&/T arg-type =arg-term))))) ctor-args) - =method-descs (&/map% dummy-method-desc methods) - _ (->> =method-descs + _ (->> methods + (&/|map &/|first) (&/Cons$ default-) - (&host/use-dummy-class name super-class interfaces (&/Some$ =ctor-args) (&/|list))) - =methods (&/map% (partial analyse-method analyse anon-class) methods) + (&host/use-dummy-class class-decl super-class interfaces (&/Some$ =ctor-args) (&/|list))) + =methods (&/map% (partial analyse-method analyse class-decl) methods) _ (check-method-completion (&/Cons$ super-class interfaces) =methods) =captured &&env/captured-vars :let [=fields (&/|map (fn [^objects idx+capt] - {:name (str &c!base/closure-prefix (aget idx+capt 0)) - :modifiers captured-slot-modifier - :anns (&/|list) - :type captured-slot-type}) + (&/T (str &c!base/closure-prefix (aget idx+capt 0)) + captured-slot-modifier + (&/|list) + captured-slot-type)) (&/enumerate =captured))] :let [sources (&/|map captured-source =captured)] - _ (compile-token (&/V &&/$jvm-class (&/T name super-class interfaces (&/|list) =fields =methods =captured (&/Some$ =ctor-args)))) + _ (compile-token (&/V &&/$jvm-class (&/T class-decl super-class interfaces (&/|list) =fields =methods =captured (&/Some$ =ctor-args)))) _cursor &/cursor] - (return (&/|list (&&/|meta (&type/Data$ anon-class (&/|list)) _cursor + (return (&/|list (&&/|meta anon-class-type _cursor (&/V &&/$jvm-new (&/T anon-class (&/|repeat (&/|length sources) captured-slot-type) sources)) ))) )))) diff --git a/src/lux/analyser/lux.clj b/src/lux/analyser/lux.clj index 3b65d77b1..846b7192b 100644 --- a/src/lux/analyser/lux.clj +++ b/src/lux/analyser/lux.clj @@ -461,7 +461,7 @@ _ (fail ""))) (fn [err] - (fail (str "[Analyser Error] Functions require function types: " (&type/show-type exo-type))))) + (fail (str err "\n" "[Analyser Error] Functions require function types: " (&type/show-type exo-type))))) )) (defn analyse-lambda** [analyse exo-type ?self ?arg ?body] diff --git a/src/lux/analyser/module.clj b/src/lux/analyser/module.clj index 192e80153..d0ce0e9c1 100644 --- a/src/lux/analyser/module.clj +++ b/src/lux/analyser/module.clj @@ -11,7 +11,8 @@ clojure.core.match.array (lux [base :as & :refer [deftags |let |do return return* fail fail* |case]] [type :as &type] - [host :as &host]))) + [host :as &host]) + [lux.host.generics :as &host-generics])) ;; [Utils] (deftags @@ -200,7 +201,7 @@ [exported? (&/$ValueD ?type _)] ((|do [_ (&type/check &type/Macro ?type) ^ClassLoader loader &/loader - :let [macro (-> (.loadClass loader (str (&host/->class-name module) "." (&/normalize-name name))) + :let [macro (-> (.loadClass loader (str (&host-generics/->class-name module) "." (&/normalize-name name))) (.getField &/datum-field) (.get nil))]] (fn [state*] diff --git a/src/lux/analyser/parser.clj b/src/lux/analyser/parser.clj index 238defe69..3625db30c 100644 --- a/src/lux/analyser/parser.clj +++ b/src/lux/analyser/parser.clj @@ -148,23 +148,78 @@ _ (fail (str "[Analyser Error] Invalid annotation: " (&/show-ast ast))))) -(defn parse-method-decl [ast] +(defn ^:private parse-arg-decl [ast] (|case ast - [_ (&/$FormS (&/$Cons [_ (&/$TextS method-name)] - (&/$Cons [_ (&/$TupleS modifiers)] - (&/$Cons [_ (&/$TupleS anns)] - (&/$Cons [_ (&/$TupleS gvars)] - (&/$Cons [_ (&/$TupleS method-exs)] - (&/$Cons [_ (&/$TupleS inputs)] - (&/$Cons output - (&/$Nil)))))))))] + [_ (&/$FormS (&/$Cons [_ (&/$SymbolS ["" arg-name])] + (&/$Cons gclass + (&/$Nil))))] + (|do [=gclass (parse-gclass gclass)] + (return (&/T arg-name =gclass))) + + _ + (fail (str "[Analyser Error] Invalid argument declaration: " (&/show-ast ast))))) + +(defn ^:private parse-method-decl* [asts] + (|case asts + (&/$Cons [_ (&/$TextS method-name)] + (&/$Cons [_ (&/$TupleS modifiers)] + (&/$Cons [_ (&/$TupleS anns)] + (&/$Cons [_ (&/$TupleS gvars)] + (&/$Cons [_ (&/$TupleS exceptions)] + (&/$Cons [_ (&/$TupleS inputs)] + (&/$Cons output + *tail*))))))) (|do [=modifiers (parse-modifiers modifiers) =anns (&/map% parse-ann anns) =gvars (&/map% parse-text gvars) - =method-exs (&/map% parse-gclass method-exs) - =inputs (&/map% parse-gclass inputs) + =exceptions (&/map% parse-gclass exceptions) + =inputs (&/map% parse-arg-decl inputs) =output (parse-gclass output)] - (return (&/T method-name =modifiers =anns =gvars =method-exs =inputs =output))) + (return (&/T (&/T method-name =modifiers =anns =gvars =exceptions =inputs =output) + *tail*))) + + _ + (fail (str "[Analyser Error] Invalid method declaration: " (->> asts (&/|map &/show-ast) (&/|interpose " ") (&/fold str "")))))) + +(defn parse-method-decl [ast] + (|case ast + [_ (&/$FormS tokens)] + (|do [[decl *tail*] (parse-method-decl* tokens)] + (|case *tail* + (&/$Nil) + (return decl) + + _ + (fail (str "[Analyser Error] Invalid method declaration: " (&/show-ast ast))))) _ (fail (str "[Analyser Error] Invalid method declaration: " (&/show-ast ast))))) + +(defn parse-method-def [ast] + (|case ast + [_ (&/$FormS tokens)] + (|do [[decl *tail*] (parse-method-decl* tokens)] + (|case *tail* + (&/$Cons body (&/$Nil)) + (return (&/T decl body)) + + _ + (fail (str "[Analyser Error] Invalid method definition: " (&/show-ast ast))))) + + _ + (fail (str "[Analyser Error] Invalid method definition: " (&/show-ast ast))))) + +(defn parse-field [ast] + (|case ast + [_ (&/$FormS (&/$Cons [_ (&/$TextS ?name)] + (&/$Cons [_ (&/$TupleS ?modifiers)] + (&/$Cons [_ (&/$TupleS ?anns)] + (&/$Cons [_ (&/$TextS ?type)] + (&/$Nil))))))] + (|do [=modifiers (parse-modifiers ?modifiers) + =anns (&/map% parse-ann ?anns) + =type (parse-gclass ?type)] + (return (&/T ?name =modifiers =anns =type))) + + _ + (fail (str "[Analyser Error] Invalid field declaration: " (&/show-ast ast))))) diff --git a/src/lux/compiler.clj b/src/lux/compiler.clj index 579d6b33e..baf6bf549 100644 --- a/src/lux/compiler.clj +++ b/src/lux/compiler.clj @@ -18,6 +18,7 @@ [analyser :as &analyser] [optimizer :as &optimizer] [host :as &host]) + [lux.host.generics :as &host-generics] [lux.optimizer :as &o] [lux.analyser.base :as &a] [lux.analyser.module :as &a-module] @@ -467,7 +468,7 @@ .visitEnd))] _ (&&/save-class! (str id) bytecode) loader &/loader] - (-> (.loadClass ^ClassLoader loader (str (&host/->class-name module) "." id)) + (-> (.loadClass ^ClassLoader loader (str (&host-generics/->class-name module) "." id)) (.getField &/eval-field) (.get nil) return)))) diff --git a/src/lux/compiler/base.clj b/src/lux/compiler/base.clj index e677406a5..0d9a29d79 100644 --- a/src/lux/compiler/base.clj +++ b/src/lux/compiler/base.clj @@ -13,7 +13,8 @@ [type :as &type] [host :as &host]) (lux.analyser [base :as &a] - [module :as &a-module])) + [module :as &a-module]) + [lux.host.generics :as &host-generics]) (:import (org.objectweb.asm Opcodes Label ClassWriter @@ -69,7 +70,7 @@ module &/get-module-name loader &/loader !classes &/classes - :let [real-name (str (&host/->class-name module) "." name) + :let [real-name (str (&host-generics/->class-name module) "." name) _ (swap! !classes assoc real-name bytecode) _ (when (not eval?) (write-output module name bytecode)) @@ -79,7 +80,7 @@ (do-template [ ] (do (defn [^MethodVisitor writer] (doto writer - (.visitMethodInsn Opcodes/INVOKESTATIC "valueOf" (str "(" ")" (&host/->type-signature ))))) + (.visitMethodInsn Opcodes/INVOKESTATIC "valueOf" (str "(" ")" (&host-generics/->type-signature ))))) (defn [^MethodVisitor writer] (doto writer (.visitTypeInsn Opcodes/CHECKCAST ) diff --git a/src/lux/compiler/cache.clj b/src/lux/compiler/cache.clj index b2cc65203..4f5a4b02d 100644 --- a/src/lux/compiler/cache.clj +++ b/src/lux/compiler/cache.clj @@ -12,6 +12,7 @@ (lux [base :as & :refer [|do return* return fail fail* |case |let]] [type :as &type] [host :as &host]) + [lux.host.generics :as &host-generics] (lux.analyser [base :as &a] [module :as &a-module]) (lux.compiler [base :as &&] @@ -81,7 +82,7 @@ (if already-loaded? (return true) (if (cached? module) - (let [module* (&host/->class-name module) + (let [module* (&host-generics/->class-name module) module-path (str &&/output-dir module) class-name (str module* "._") ^Class module-meta (do (swap! !classes assoc class-name (read-file (File. (str module-path "/_.class")))) diff --git a/src/lux/compiler/host.clj b/src/lux/compiler/host.clj index a02022228..ea12ecc96 100644 --- a/src/lux/compiler/host.clj +++ b/src/lux/compiler/host.clj @@ -26,20 +26,20 @@ AnnotationVisitor))) ;; [Utils] -(let [class+method+sig {"boolean" [(&host/->class "java.lang.Boolean") "booleanValue" "()Z"] - "byte" [(&host/->class "java.lang.Byte") "byteValue" "()B"] - "short" [(&host/->class "java.lang.Short") "shortValue" "()S"] - "int" [(&host/->class "java.lang.Integer") "intValue" "()I"] - "long" [(&host/->class "java.lang.Long") "longValue" "()J"] - "float" [(&host/->class "java.lang.Float") "floatValue" "()F"] - "double" [(&host/->class "java.lang.Double") "doubleValue" "()D"] - "char" [(&host/->class "java.lang.Character") "charValue" "()C"]}] +(let [class+method+sig {"boolean" [(&host-generics/->bytecode-class-name "java.lang.Boolean") "booleanValue" "()Z"] + "byte" [(&host-generics/->bytecode-class-name "java.lang.Byte") "byteValue" "()B"] + "short" [(&host-generics/->bytecode-class-name "java.lang.Short") "shortValue" "()S"] + "int" [(&host-generics/->bytecode-class-name "java.lang.Integer") "intValue" "()I"] + "long" [(&host-generics/->bytecode-class-name "java.lang.Long") "longValue" "()J"] + "float" [(&host-generics/->bytecode-class-name "java.lang.Float") "floatValue" "()F"] + "double" [(&host-generics/->bytecode-class-name "java.lang.Double") "doubleValue" "()D"] + "char" [(&host-generics/->bytecode-class-name "java.lang.Character") "charValue" "()C"]}] (defn ^:private prepare-arg! [^MethodVisitor *writer* class-name] (if-let [[class method sig] (get class+method+sig class-name)] (doto *writer* (.visitTypeInsn Opcodes/CHECKCAST class) (.visitMethodInsn Opcodes/INVOKEVIRTUAL class method sig)) - (.visitTypeInsn *writer* Opcodes/CHECKCAST (&host/->class class-name))))) + (.visitTypeInsn *writer* Opcodes/CHECKCAST (&host-generics/->bytecode-class-name class-name))))) (let [boolean-class "java.lang.Boolean" byte-class "java.lang.Byte" @@ -55,28 +55,28 @@ (.visitInsn *writer* Opcodes/ACONST_NULL) (&/$DataT "boolean" (&/$Nil)) - (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host/->class boolean-class) "valueOf" (str "(Z)" (&host/->type-signature boolean-class))) + (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host-generics/->bytecode-class-name boolean-class) "valueOf" (str "(Z)" (&host-generics/->type-signature boolean-class))) (&/$DataT "byte" (&/$Nil)) - (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host/->class byte-class) "valueOf" (str "(B)" (&host/->type-signature byte-class))) + (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host-generics/->bytecode-class-name byte-class) "valueOf" (str "(B)" (&host-generics/->type-signature byte-class))) (&/$DataT "short" (&/$Nil)) - (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host/->class short-class) "valueOf" (str "(S)" (&host/->type-signature short-class))) + (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host-generics/->bytecode-class-name short-class) "valueOf" (str "(S)" (&host-generics/->type-signature short-class))) (&/$DataT "int" (&/$Nil)) - (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host/->class int-class) "valueOf" (str "(I)" (&host/->type-signature int-class))) + (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host-generics/->bytecode-class-name int-class) "valueOf" (str "(I)" (&host-generics/->type-signature int-class))) (&/$DataT "long" (&/$Nil)) - (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host/->class long-class) "valueOf" (str "(J)" (&host/->type-signature long-class))) + (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host-generics/->bytecode-class-name long-class) "valueOf" (str "(J)" (&host-generics/->type-signature long-class))) (&/$DataT "float" (&/$Nil)) - (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host/->class float-class) "valueOf" (str "(F)" (&host/->type-signature float-class))) + (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host-generics/->bytecode-class-name float-class) "valueOf" (str "(F)" (&host-generics/->type-signature float-class))) (&/$DataT "double" (&/$Nil)) - (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host/->class double-class) "valueOf" (str "(D)" (&host/->type-signature double-class))) + (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host-generics/->bytecode-class-name double-class) "valueOf" (str "(D)" (&host-generics/->type-signature double-class))) (&/$DataT "char" (&/$Nil)) - (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host/->class char-class) "valueOf" (str "(C)" (&host/->type-signature char-class))) + (.visitMethodInsn *writer* Opcodes/INVOKESTATIC (&host-generics/->bytecode-class-name char-class) "valueOf" (str "(C)" (&host-generics/->type-signature char-class))) (&/$DataT _ _) nil @@ -94,7 +94,7 @@ ;; [Resources] (do-template [ ] (defn [compile ?x ?y] - (|do [:let [+wrapper-class+ (&host/->class )] + (|do [:let [+wrapper-class+ (&host-generics/->bytecode-class-name )] ^MethodVisitor *writer* &/get-writer _ (compile ?x) :let [_ (doto *writer* @@ -136,7 +136,7 @@ (do-template [ ] (defn [compile ?x ?y] - (|do [:let [+wrapper-class+ (&host/->class )] + (|do [:let [+wrapper-class+ (&host-generics/->bytecode-class-name )] ^MethodVisitor *writer* &/get-writer _ (compile ?y) :let [_ (doto *writer* @@ -150,10 +150,10 @@ $end (new Label) _ (doto *writer* (.visitJumpInsn $then) - (.visitFieldInsn Opcodes/GETSTATIC (&host/->class "java.lang.Boolean") "TRUE" (&host/->type-signature "java.lang.Boolean")) + (.visitFieldInsn Opcodes/GETSTATIC (&host-generics/->bytecode-class-name "java.lang.Boolean") "TRUE" (&host-generics/->type-signature "java.lang.Boolean")) (.visitJumpInsn Opcodes/GOTO $end) (.visitLabel $then) - (.visitFieldInsn Opcodes/GETSTATIC (&host/->class "java.lang.Boolean") "FALSE" (&host/->type-signature "java.lang.Boolean")) + (.visitFieldInsn Opcodes/GETSTATIC (&host-generics/->bytecode-class-name "java.lang.Boolean") "FALSE" (&host-generics/->type-signature "java.lang.Boolean")) (.visitLabel $end))]] (return nil))) @@ -168,7 +168,7 @@ (do-template [ ] (defn [compile ?x ?y] - (|do [:let [+wrapper-class+ (&host/->class )] + (|do [:let [+wrapper-class+ (&host-generics/->bytecode-class-name )] ^MethodVisitor *writer* &/get-writer _ (compile ?y) :let [_ (doto *writer* @@ -184,10 +184,10 @@ (.visitInsn ) (.visitLdcInsn (int )) (.visitJumpInsn Opcodes/IF_ICMPEQ $then) - (.visitFieldInsn Opcodes/GETSTATIC (&host/->class "java.lang.Boolean") "FALSE" (&host/->type-signature "java.lang.Boolean")) + (.visitFieldInsn Opcodes/GETSTATIC (&host-generics/->bytecode-class-name "java.lang.Boolean") "FALSE" (&host-generics/->type-signature "java.lang.Boolean")) (.visitJumpInsn Opcodes/GOTO $end) (.visitLabel $then) - (.visitFieldInsn Opcodes/GETSTATIC (&host/->class "java.lang.Boolean") "TRUE" (&host/->type-signature "java.lang.Boolean")) + (.visitFieldInsn Opcodes/GETSTATIC (&host-generics/->bytecode-class-name "java.lang.Boolean") "TRUE" (&host-generics/->type-signature "java.lang.Boolean")) (.visitLabel $end))]] (return nil))) @@ -207,23 +207,23 @@ (defn compile-jvm-invokestatic [compile ?class ?method ?classes ?args ?output-type] (|do [^MethodVisitor *writer* &/get-writer =output-type (&host/->java-sig ?output-type) - :let [method-sig (str "(" (&/fold str "" (&/|map &host/->type-signature ?classes)) ")" =output-type)] + :let [method-sig (str "(" (&/fold str "" (&/|map &host-generics/->type-signature ?classes)) ")" =output-type)] _ (&/map2% (fn [class-name arg] (|do [ret (compile arg) :let [_ (prepare-arg! *writer* class-name)]] (return ret))) ?classes ?args) :let [_ (doto *writer* - (.visitMethodInsn Opcodes/INVOKESTATIC (&host/->class (&host-type/as-obj ?class)) ?method method-sig) + (.visitMethodInsn Opcodes/INVOKESTATIC (&host-generics/->bytecode-class-name (&host-type/as-obj ?class)) ?method method-sig) (prepare-return! ?output-type))]] (return nil))) (do-template [ ] (defn [compile ?class ?method ?classes ?object ?args ?output-type] - (|do [:let [?class* (&host/->class (&host-type/as-obj ?class))] + (|do [:let [?class* (&host-generics/->bytecode-class-name (&host-type/as-obj ?class))] ^MethodVisitor *writer* &/get-writer =output-type (&host/->java-sig ?output-type) - :let [method-sig (str "(" (&/fold str "" (&/|map &host/->type-signature ?classes)) ")" =output-type)] + :let [method-sig (str "(" (&/fold str "" (&/|map &host-generics/->type-signature ?classes)) ")" =output-type)] _ (compile ?object) :let [_ (when (not= "" ?method) (.visitTypeInsn *writer* Opcodes/CHECKCAST ?class*))] @@ -254,17 +254,17 @@ $end (new Label) _ (doto *writer* (.visitJumpInsn Opcodes/IFNULL $then) - (.visitFieldInsn Opcodes/GETSTATIC (&host/->class "java.lang.Boolean") "FALSE" (&host/->type-signature "java.lang.Boolean")) + (.visitFieldInsn Opcodes/GETSTATIC (&host-generics/->bytecode-class-name "java.lang.Boolean") "FALSE" (&host-generics/->type-signature "java.lang.Boolean")) (.visitJumpInsn Opcodes/GOTO $end) (.visitLabel $then) - (.visitFieldInsn Opcodes/GETSTATIC (&host/->class "java.lang.Boolean") "TRUE" (&host/->type-signature "java.lang.Boolean")) + (.visitFieldInsn Opcodes/GETSTATIC (&host-generics/->bytecode-class-name "java.lang.Boolean") "TRUE" (&host-generics/->type-signature "java.lang.Boolean")) (.visitLabel $end))]] (return nil))) (defn compile-jvm-new [compile ?class ?classes ?args] (|do [^MethodVisitor *writer* &/get-writer - :let [init-sig (str "(" (&/fold str "" (&/|map &host/->type-signature ?classes)) ")V") - class* (&host/->class ?class) + :let [init-sig (str "(" (&/fold str "" (&/|map &host-generics/->type-signature ?classes)) ")V") + class* (&host-generics/->bytecode-class-name ?class) _ (doto *writer* (.visitTypeInsn Opcodes/NEW class*) (.visitInsn Opcodes/DUP))] @@ -328,7 +328,7 @@ (|do [^MethodVisitor *writer* &/get-writer _ (compile ?length) :let [_ (.visitInsn *writer* Opcodes/L2I)] - :let [_ (.visitTypeInsn *writer* Opcodes/ANEWARRAY (&host/->class ?class))]] + :let [_ (.visitTypeInsn *writer* Opcodes/ANEWARRAY (&host-generics/->bytecode-class-name ?class))]] (return nil))) (defn compile-jvm-aaload [compile ?array ?idx] @@ -372,12 +372,12 @@ (|do [^MethodVisitor *writer* &/get-writer =output-type (&host/->java-sig ?output-type) :let [_ (doto *writer* - (.visitFieldInsn Opcodes/GETSTATIC (&host/->class (&host-type/as-obj ?class)) ?field =output-type) + (.visitFieldInsn Opcodes/GETSTATIC (&host-generics/->bytecode-class-name (&host-type/as-obj ?class)) ?field =output-type) (prepare-return! ?output-type))]] (return nil))) (defn compile-jvm-getfield [compile ?class ?field ?object ?output-type] - (|do [:let [class* (&host/->class (&host-type/as-obj ?class))] + (|do [:let [class* (&host-generics/->bytecode-class-name (&host-type/as-obj ?class))] ^MethodVisitor *writer* &/get-writer _ (compile ?object) =output-type (&host/->java-sig ?output-type) @@ -391,12 +391,12 @@ (|do [^MethodVisitor *writer* &/get-writer _ (compile ?value) =output-type (&host/->java-sig ?output-type) - :let [_ (.visitFieldInsn *writer* Opcodes/PUTSTATIC (&host/->class (&host-type/as-obj ?class)) ?field =output-type)] + :let [_ (.visitFieldInsn *writer* Opcodes/PUTSTATIC (&host-generics/->bytecode-class-name (&host-type/as-obj ?class)) ?field =output-type)] :let [_ (.visitInsn *writer* Opcodes/ACONST_NULL)]] (return nil))) (defn compile-jvm-putfield [compile ?class ?field ?object ?value ?output-type] - (|do [:let [class* (&host/->class (&host-type/as-obj ?class))] + (|do [:let [class* (&host-generics/->bytecode-class-name (&host-type/as-obj ?class))] ^MethodVisitor *writer* &/get-writer _ (compile ?object) :let [_ (.visitInsn *writer* Opcodes/DUP)] @@ -407,7 +407,7 @@ (return nil))) (defn compile-jvm-instanceof [compile class object] - (|do [:let [class* (&host/->class class)] + (|do [:let [class* (&host-generics/->bytecode-class-name class)] ^MethodVisitor *writer* &/get-writer _ (compile object) :let [_ (doto *writer* @@ -416,7 +416,7 @@ (return nil))) (defn ^:private compile-annotation [writer ann] - (doto ^AnnotationVisitor (.visitAnnotation writer (&host/->class (:name ann)) true) + (doto ^AnnotationVisitor (.visitAnnotation writer (&host-generics/->bytecode-class-name (:name ann)) true) (-> (.visit param-name param-value) (->> (|let [[param-name param-value] param]) (doseq [param (&/->seq (:params ann))]))) @@ -424,11 +424,12 @@ nil) (defn ^:private compile-field [^ClassWriter writer field] - (let [=field (.visitField writer (&host/modifiers->int (:modifiers field)) (:name field) - (&host/->type-signature (:type field)) nil nil)] - (&/|map (partial compile-annotation =field) (:anns field)) - (.visitEnd =field) - nil)) + (|let [[=name =modifiers =anns =type] field + =field (.visitField writer (&host/modifiers->int =modifiers) =name + (&host-generics/->type-signature =type) nil nil)] + (do (&/|map (partial compile-annotation =field) =anns) + (.visitEnd =field) + nil))) (defn ^:private compile-method-return [^MethodVisitor writer output] (case output @@ -460,32 +461,34 @@ ;; else (.visitInsn writer Opcodes/ARETURN))) -(defn ^:private compile-method [compile ^ClassWriter class-writer method] - (|let [signature (str "(" (&/fold str "" (&/|map &host/->type-signature (:inputs method))) ")" - (&host/->type-signature (:output method)))] - (&/with-writer (.visitMethod class-writer (&host/modifiers->int (:modifiers method)) - (:name method) - signature - nil - (->> (:exceptions method) (&/|map &host/->class) &/->seq (into-array java.lang.String))) +(defn ^:private compile-method-def [compile ^ClassWriter class-writer method-def] + (|let [[=method-decl =body] method-def + [=name =modifiers =anns =gvars =exceptions =inputs =output] =method-decl + [simple-signature generic-signature] (&host-generics/method-signatures =method-decl)] + (&/with-writer (.visitMethod class-writer (&host/modifiers->int =modifiers) + =name + simple-signature + generic-signature + (->> =exceptions (&/|map &host-generics/->bytecode-class-name) &/->seq (into-array java.lang.String))) (|do [^MethodVisitor =method &/get-writer - :let [_ (&/|map (partial compile-annotation =method) (:anns method)) + :let [_ (&/|map (partial compile-annotation =method) =anns) _ (.visitCode =method)] - _ (compile (:body method)) + _ (compile =body) :let [_ (doto =method - (compile-method-return (:output method)) + (compile-method-return =output) (.visitMaxs 0 0) (.visitEnd))]] (return nil))))) -(defn ^:private compile-method-decl [^ClassWriter class-writer method] - (|let [[=name =modifiers =anns =gvars =exceptions =inputs =output] method - simple-signature (str "(" (&/fold str "" (&/|map &host-generics/gclass->simple-signature =inputs)) ")" (&host-generics/gclass->simple-signature =output)) - generic-signature (str "<" (->> =gvars (&/|interpose " ") (&/fold str "")) ">" - "(" (&/fold str "" (&/|map &host-generics/gclass->signature =inputs)) ")" - (&host-generics/gclass->signature =output) - (->> =exceptions (&/|map &host-generics/gclass->signature) (&/|interpose " ") (&/fold str ""))) - =method (.visitMethod class-writer (&host/modifiers->int =modifiers) =name simple-signature generic-signature (->> =exceptions (&/|map &host-generics/gclass->simple-signature) &/->seq (into-array java.lang.String))) +(defn ^:private compile-method-decl [^ClassWriter class-writer =method-decl] + (|let [[=name =modifiers =anns =gvars =exceptions =inputs =output] =method-decl + [simple-signature generic-signature] (&host-generics/method-signatures =method-decl) + =method (.visitMethod class-writer + (&host/modifiers->int =modifiers) + =name + simple-signature + generic-signature + (->> =exceptions (&/|map &host-generics/gclass->simple-signature) &/->seq (into-array java.lang.String))) _ (&/|map (partial compile-annotation =method) =anns) _ (.visitEnd =method)] nil)) @@ -493,34 +496,34 @@ (defn ^:private prepare-ctor-arg [^MethodVisitor writer type] (case type "boolean" (doto writer - (.visitTypeInsn Opcodes/CHECKCAST (&host/->class "java.lang.Boolean")) + (.visitTypeInsn Opcodes/CHECKCAST (&host-generics/->bytecode-class-name "java.lang.Boolean")) &&/unwrap-boolean) "byte" (doto writer - (.visitTypeInsn Opcodes/CHECKCAST (&host/->class "java.lang.Byte")) + (.visitTypeInsn Opcodes/CHECKCAST (&host-generics/->bytecode-class-name "java.lang.Byte")) &&/unwrap-byte) "short" (doto writer - (.visitTypeInsn Opcodes/CHECKCAST (&host/->class "java.lang.Short")) + (.visitTypeInsn Opcodes/CHECKCAST (&host-generics/->bytecode-class-name "java.lang.Short")) &&/unwrap-short) "int" (doto writer - (.visitTypeInsn Opcodes/CHECKCAST (&host/->class "java.lang.Integer")) + (.visitTypeInsn Opcodes/CHECKCAST (&host-generics/->bytecode-class-name "java.lang.Integer")) &&/unwrap-int) "long" (doto writer - (.visitTypeInsn Opcodes/CHECKCAST (&host/->class "java.lang.Long")) + (.visitTypeInsn Opcodes/CHECKCAST (&host-generics/->bytecode-class-name "java.lang.Long")) &&/unwrap-long) "float" (doto writer - (.visitTypeInsn Opcodes/CHECKCAST (&host/->class "java.lang.Float")) + (.visitTypeInsn Opcodes/CHECKCAST (&host-generics/->bytecode-class-name "java.lang.Float")) &&/unwrap-float) "double" (doto writer - (.visitTypeInsn Opcodes/CHECKCAST (&host/->class "java.lang.Double")) + (.visitTypeInsn Opcodes/CHECKCAST (&host-generics/->bytecode-class-name "java.lang.Double")) &&/unwrap-double) "char" (doto writer - (.visitTypeInsn Opcodes/CHECKCAST (&host/->class "java.lang.Character")) + (.visitTypeInsn Opcodes/CHECKCAST (&host-generics/->bytecode-class-name "java.lang.Character")) &&/unwrap-char) ;; else (doto writer - (.visitTypeInsn Opcodes/CHECKCAST (&host/->class type))))) + (.visitTypeInsn Opcodes/CHECKCAST (&host-generics/->bytecode-class-name type))))) -(let [clo-field-sig (&host/->type-signature "java.lang.Object") +(let [clo-field-sig (&host-generics/->type-signature "java.lang.Object") init-method "" -return "V"] (defn ^:private anon-class--signature [env] @@ -528,7 +531,7 @@ -return)) (defn ^:private add-anon-class- [^ClassWriter class-writer compile class-name super-class env ctor-args] - (let [init-types (->> ctor-args (&/|map (comp &host/->type-signature &/|first)) (&/fold str ""))] + (let [init-types (->> ctor-args (&/|map (comp &host-generics/->type-signature &/|first)) (&/fold str ""))] (&/with-writer (.visitMethod class-writer Opcodes/ACC_PUBLIC init-method (anon-class--signature env) nil nil) (|do [^MethodVisitor =method &/get-writer :let [_ (doto =method (.visitCode) @@ -540,7 +543,7 @@ (return nil)))) ctor-args) :let [_ (doto =method - (.visitMethodInsn Opcodes/INVOKESPECIAL (&host/->class super-class) init-method (str "(" init-types ")" -return)) + (.visitMethodInsn Opcodes/INVOKESPECIAL (&host-generics/->bytecode-class-name super-class) init-method (str "(" init-types ")" -return)) (-> (doto (.visitVarInsn Opcodes/ALOAD 0) (.visitVarInsn Opcodes/ALOAD (inc ?captured-id)) (.visitFieldInsn Opcodes/PUTFIELD class-name captured-name clo-field-sig)) @@ -554,19 +557,23 @@ (return nil))))) ) -(defn compile-jvm-class [compile ?name ?super-class ?interfaces ?anns ?fields ?methods env ??ctor-args] +(defn compile-jvm-class [compile class-decl ?super-class ?interfaces ?anns ?fields ?methods env ??ctor-args] (|do [module &/get-module-name [file-name _ _] &/cursor - :let [full-name (str module "/" ?name) - super-class* (&host/->class ?super-class) + :let [[?name ?params] class-decl + _ (prn 'compile-jvm-class/_0 class-decl ?name) + class-signature (&host-generics/gclass-decl->signature class-decl (&/Cons$ ?super-class ?interfaces)) + full-name (str module "/" ?name) + _ (prn 'compile-jvm-class/_1 full-name class-signature) + super-class* (&host-generics/->bytecode-class-name (&host-generics/super-class-name ?super-class)) =class (doto (new ClassWriter ClassWriter/COMPUTE_MAXS) (.visit &host/bytecode-version (+ Opcodes/ACC_PUBLIC Opcodes/ACC_SUPER) - full-name nil super-class* (->> ?interfaces (&/|map &host/->class) &/->seq (into-array String))) + full-name nil super-class* (->> ?interfaces (&/|map (comp &host-generics/->bytecode-class-name &host-generics/super-class-name)) &/->seq (into-array String))) (.visitSource file-name nil)) _ (&/|map (partial compile-annotation =class) ?anns) _ (&/|map (partial compile-field =class) ?fields)] - _ (&/map% (partial compile-method compile =class) ?methods) + _ (&/map% (partial compile-method-def compile =class) ?methods) _ (|case ??ctor-args (&/$Some ctor-args) (add-anon-class- =class compile full-name ?super-class env ctor-args) @@ -584,7 +591,7 @@ (str module "/" interface-name) (&host-generics/gclass-decl->signature interface-decl ?supers) "java/lang/Object" - (->> ?supers (&/|map (comp &host/->class &host-generics/super-class-name)) &/->seq (into-array String))) + (->> ?supers (&/|map (comp &host-generics/->bytecode-class-name &host-generics/super-class-name)) &/->seq (into-array String))) (.visitSource file-name nil)) _ (&/|map (partial compile-annotation =interface) ?anns) _ (do (&/|map (partial compile-method-decl =interface) ?methods) @@ -611,7 +618,7 @@ ?catches) _ (doseq [[?ex-class $handler-start $handler-end] (&/->seq catch-boundaries)] (doto *writer* - (.visitTryCatchBlock $from $to $handler-start (&host/->class ?ex-class)) + (.visitTryCatchBlock $from $to $handler-start (&host-generics/->bytecode-class-name ?ex-class)) (.visitTryCatchBlock $handler-start $handler-end $catch-finally nil))) _ (.visitTryCatchBlock *writer* $from $to $catch-finally nil)] :let [_ (.visitLabel *writer* $from)] @@ -663,14 +670,14 @@ (defn [compile ?value] (|do [^MethodVisitor *writer* &/get-writer :let [_ (doto *writer* - (.visitTypeInsn Opcodes/NEW (&host/->class )) + (.visitTypeInsn Opcodes/NEW (&host-generics/->bytecode-class-name )) (.visitInsn Opcodes/DUP))] _ (compile ?value) :let [_ (doto *writer* - (.visitTypeInsn Opcodes/CHECKCAST (&host/->class )) - (.visitMethodInsn Opcodes/INVOKEVIRTUAL (&host/->class ) ) + (.visitTypeInsn Opcodes/CHECKCAST (&host-generics/->bytecode-class-name )) + (.visitMethodInsn Opcodes/INVOKEVIRTUAL (&host-generics/->bytecode-class-name ) ) (.visitInsn ) - (.visitMethodInsn Opcodes/INVOKESPECIAL (&host/->class ) "" ))]] + (.visitMethodInsn Opcodes/INVOKESPECIAL (&host-generics/->bytecode-class-name ) "" ))]] (return nil))) compile-jvm-d2f Opcodes/D2F "java.lang.Double" "doubleValue" "()D" "java.lang.Float" "(F)V" @@ -697,19 +704,19 @@ (defn [compile ?x ?y] (|do [^MethodVisitor *writer* &/get-writer :let [_ (doto *writer* - (.visitTypeInsn Opcodes/NEW (&host/->class )) + (.visitTypeInsn Opcodes/NEW (&host-generics/->bytecode-class-name )) (.visitInsn Opcodes/DUP))] _ (compile ?x) :let [_ (doto *writer* - (.visitTypeInsn Opcodes/CHECKCAST (&host/->class )) - (.visitMethodInsn Opcodes/INVOKEVIRTUAL (&host/->class ) ))] + (.visitTypeInsn Opcodes/CHECKCAST (&host-generics/->bytecode-class-name )) + (.visitMethodInsn Opcodes/INVOKEVIRTUAL (&host-generics/->bytecode-class-name ) ))] _ (compile ?y) :let [_ (doto *writer* - (.visitTypeInsn Opcodes/CHECKCAST (&host/->class )) - (.visitMethodInsn Opcodes/INVOKEVIRTUAL (&host/->class ) ))] + (.visitTypeInsn Opcodes/CHECKCAST (&host-generics/->bytecode-class-name )) + (.visitMethodInsn Opcodes/INVOKEVIRTUAL (&host-generics/->bytecode-class-name ) ))] :let [_ (doto *writer* (.visitInsn ) - (.visitMethodInsn Opcodes/INVOKESPECIAL (&host/->class ) "" ))]] + (.visitMethodInsn Opcodes/INVOKESPECIAL (&host-generics/->bytecode-class-name ) "" ))]] (return nil))) compile-jvm-iand Opcodes/IAND "intValue" "()I" "java.lang.Integer" "intValue" "()I" "java.lang.Integer" "java.lang.Integer" "(I)V" diff --git a/src/lux/compiler/lambda.clj b/src/lux/compiler/lambda.clj index a719084ab..83714517f 100644 --- a/src/lux/compiler/lambda.clj +++ b/src/lux/compiler/lambda.clj @@ -15,6 +15,7 @@ [parser :as &parser] [analyser :as &analyser] [host :as &host]) + [lux.host.generics :as &host-generics] [lux.analyser.base :as &a] (lux.compiler [base :as &&])) (:import (org.objectweb.asm Opcodes @@ -23,8 +24,8 @@ MethodVisitor))) ;; [Utils] -(def ^:private clo-field-sig (&host/->type-signature "java.lang.Object")) -(def ^:private lambda-return-sig (&host/->type-signature "java.lang.Object")) +(def ^:private clo-field-sig (&host-generics/->type-signature "java.lang.Object")) +(def ^:private lambda-return-sig (&host-generics/->type-signature "java.lang.Object")) (def ^:private -return "V") (def ^:private lambda-impl-signature diff --git a/src/lux/compiler/lux.clj b/src/lux/compiler/lux.clj index 4548f2bc4..21494908a 100644 --- a/src/lux/compiler/lux.clj +++ b/src/lux/compiler/lux.clj @@ -15,6 +15,7 @@ [parser :as &parser] [analyser :as &analyser] [host :as &host]) + [lux.host.generics :as &host-generics] (lux.analyser [base :as &a] [module :as &a-module]) (lux.compiler [base :as &&] @@ -211,7 +212,7 @@ :let [_ (.visitEnd *writer*)] _ (&&/save-class! def-name (.toByteArray =class)) class-loader &/loader - :let [def-class (&&/load-class! class-loader (&host/->class-name current-class))] + :let [def-class (&&/load-class! class-loader (&host-generics/->class-name current-class))] _ (&a-module/define module-name ?name (-> def-class (.getField &/meta-field) (.get nil)) =value-type)] (return nil)))) diff --git a/src/lux/host.clj b/src/lux/host.clj index 8c73246c7..5807d711a 100644 --- a/src/lux/host.clj +++ b/src/lux/host.clj @@ -10,9 +10,9 @@ clojure.core.match.array (lux [base :as & :refer [|do return* return fail fail* |let |case]] [type :as &type]) - [lux.type.host :as &host-type]) + [lux.type.host :as &host-type] + [lux.host.generics :as &host-generics]) (:import (java.lang.reflect Field Method Constructor Modifier Type) - java.util.regex.Pattern (org.objectweb.asm Opcodes Label ClassWriter @@ -27,37 +27,11 @@ (def bytecode-version Opcodes/V1_6) ;; [Resources] -(do-template [ ] - (let [regex (-> Pattern/quote re-pattern)] - (defn [old] - (string/replace old regex ))) - - ^String ->class class-name-separator class-separator - ^String ->class-name module-separator class-name-separator - ^String ->module-class module-separator class-separator - ) +(defn ^String ->module-class [old] + old) (def ->package ->module-class) -(defn ->type-signature [class] - ;; (assert (string? class)) - (case class - "void" "V" - "boolean" "Z" - "byte" "B" - "short" "S" - "int" "I" - "long" "J" - "float" "F" - "double" "D" - "char" "C" - ;; else - (let [class* (->class class)] - (if (.startsWith class* "[") - class* - (str "L" class* ";"))) - )) - (defn unfold-array [type] "(-> Type (, Int Type))" (|case type @@ -68,8 +42,8 @@ _ (&/T 0 type))) -(let [ex-type-class (str "L" (->class "java.lang.Object") ";") - object-array (str "[" "L" (->class "java.lang.Object") ";")] +(let [ex-type-class (str "L" (&host-generics/->bytecode-class-name "java.lang.Object") ";") + object-array (str "[" "L" (&host-generics/->bytecode-class-name "java.lang.Object") ";")] (defn ->java-sig [^objects type] "(-> Type (Lux Text))" (|case type @@ -77,17 +51,17 @@ (cond (= &host-type/array-data-tag ?name) (|do [:let [[level base] (unfold-array type)] base-sig (|case base (&/$DataT base-class _) - (return (->type-signature base-class)) + (return (&host-generics/->type-signature base-class)) _ (->java-sig base))] (return (str (->> (&/|repeat level "[") (&/fold str "")) base-sig))) - (= &host-type/null-data-tag ?name) (return (->type-signature "java.lang.Object")) - :else (return (->type-signature ?name))) + (= &host-type/null-data-tag ?name) (return (&host-generics/->type-signature "java.lang.Object")) + :else (return (&host-generics/->type-signature ?name))) (&/$LambdaT _ _) - (return (->type-signature function-class)) + (return (&host-generics/->type-signature function-class)) (&/$TupleT (&/$Nil)) (return "V") @@ -171,10 +145,12 @@ (return (&/T exs gvars gargs))) (fail (str "[Host Error] Constructor does not exist: " target))))) -(defn abstract-methods [class-loader class] - (return (&/->list (for [^Method =method (.getDeclaredMethods (Class/forName (&host-type/as-obj class) true class-loader)) - :when (Modifier/isAbstract (.getModifiers =method))] - (&/T (.getName =method) (&/|map #(.getName ^Class %) (&/->list (seq (.getParameterTypes =method))))))))) +(defn abstract-methods [class-loader super-class] + "(-> ClassLoader SuperClassDecl (Lux (List (, Text (List Text)))))" + (|let [[super-name super-params] super-class] + (return (&/->list (for [^Method =method (.getDeclaredMethods (Class/forName (&host-type/as-obj super-name) true class-loader)) + :when (Modifier/isAbstract (.getModifiers =method))] + (&/T (.getName =method) (&/|map #(.getName ^Class %) (&/->list (seq (.getParameterTypes =method)))))))))) (defn location [scope] (->> scope (&/|map &/normalize-name) (&/|interpose "$") (&/fold str ""))) @@ -227,16 +203,16 @@ (case output "void" (if (= "" name) (|let [(&/$Some ctor-args) ??ctor-args - ctor-arg-types (->> ctor-args (&/|map (comp ->type-signature &/|first)) (&/fold str ""))] + ctor-arg-types (->> ctor-args (&/|map (comp &host-generics/->type-signature &/|first)) (&/fold str ""))] (doto writer (.visitVarInsn Opcodes/ALOAD 0) (-> (doto (dummy-value arg-type) - (-> (.visitTypeInsn Opcodes/CHECKCAST (->class arg-type)) + (-> (.visitTypeInsn Opcodes/CHECKCAST (&host-generics/->bytecode-class-name arg-type)) (->> (when (not (primitive-jvm-type? arg-type)))))) (->> (doseq [ctor-arg (&/->seq ctor-args) :let [;; arg-term (&/|first ctor-arg) arg-type (&/|first ctor-arg)]]))) - (.visitMethodInsn Opcodes/INVOKESPECIAL (->class super-class) "" (str "(" ctor-arg-types ")V")) + (.visitMethodInsn Opcodes/INVOKESPECIAL (&host-generics/->bytecode-class-name super-class) "" (str "(" ctor-arg-types ")V")) (.visitInsn Opcodes/RETURN))) (.visitInsn writer Opcodes/RETURN)) "boolean" (doto writer @@ -268,34 +244,42 @@ (.visitInsn Opcodes/ACONST_NULL) (.visitInsn Opcodes/ARETURN)))) -(defn use-dummy-class [name super-class interfaces ctor-args fields methods] +(defn use-dummy-class [class-decl super-class interfaces ctor-args fields methods] (|do [module &/get-module-name - :let [full-name (str module "/" name) + :let [[?name ?params] class-decl + full-name (str module "/" ?name) + class-signature (&host-generics/gclass-decl->signature class-decl interfaces) =class (doto (new ClassWriter ClassWriter/COMPUTE_MAXS) (.visit bytecode-version (+ Opcodes/ACC_PUBLIC Opcodes/ACC_SUPER) - full-name nil (->class super-class) (->> interfaces (&/|map ->class) &/->seq (into-array String)))) + full-name + class-signature + (&host-generics/->bytecode-class-name (&host-generics/super-class-name super-class)) + (->> interfaces (&/|map (comp &host-generics/->bytecode-class-name &host-generics/super-class-name)) &/->seq (into-array String)))) _ (&/|map (fn [field] - (doto (.visitField =class (modifiers->int (:modifiers field)) (:name field) - (->type-signature (:type field)) nil nil) - (.visitEnd))) + (|let [[=name =modifiers =anns =type] field] + (doto (.visitField =class (modifiers->int =modifiers) =name + (&host-generics/->type-signature =type) nil nil) + (.visitEnd)))) fields) - _ (&/|map (fn [method] - (|let [signature (str "(" (&/fold str "" (&/|map ->type-signature (:inputs method))) ")" - (->type-signature (:output method)))] - (doto (.visitMethod =class (modifiers->int (:modifiers method)) - (:name method) - signature - nil - (->> (:exceptions method) (&/|map ->class) &/->seq (into-array java.lang.String))) + _ (&/|map (fn [method-decl] + (prn 'use-dummy-class (count method-decl) method-decl) + (|let [[=name =modifiers =anns =gvars =exceptions =inputs =output] method-decl + [simple-signature generic-signature] (&host-generics/method-signatures method-decl)] + (doto (.visitMethod =class (modifiers->int =modifiers) + =name + simple-signature + generic-signature + (->> =exceptions (&/|map &host-generics/gclass->bytecode-class-name) &/->seq (into-array java.lang.String))) .visitCode - (dummy-return super-class ctor-args (:name method) (:output method)) + (dummy-return super-class ctor-args =name =output) (.visitMaxs 0 0) (.visitEnd)))) methods) bytecode (.toByteArray (doto =class .visitEnd))] ^ClassLoader loader &/loader !classes &/classes - :let [real-name (str (->class-name module) "." name) + :let [real-name (str (&host-generics/->class-name module) "." ?name) + _ (prn 'use-dummy-class/_0 ?name real-name) _ (swap! !classes assoc real-name bytecode) _ (.loadClass loader real-name)]] (return nil))) diff --git a/src/lux/host/generics.clj b/src/lux/host/generics.clj index 9ec451ed6..4fd2c3269 100644 --- a/src/lux/host/generics.clj +++ b/src/lux/host/generics.clj @@ -4,17 +4,51 @@ ;; You can obtain one at http://mozilla.org/MPL/2.0/. (ns lux.host.generics - (:require (clojure [template :refer [do-template]]) + (:require (clojure [string :as string] + [template :refer [do-template]]) clojure.core.match clojure.core.match.array - (lux [base :as & :refer [|do return* return fail fail* |let |case]] - [host :as &host]))) + (lux [base :as & :refer [|do return* return fail fail* |let |case]])) + (:import java.util.regex.Pattern)) + +(do-template [ ] + (let [regex (-> Pattern/quote re-pattern)] + (defn [old] + (string/replace old regex ))) + + ;; ->class + ^String ->bytecode-class-name "." "/" + ;; ->class-name + ^String ->class-name "/" "." + ) + +;; ->type-signature +(defn ->type-signature [class] + (case class + "void" "V" + "boolean" "Z" + "byte" "B" + "short" "S" + "int" "I" + "long" "J" + "float" "F" + "double" "D" + "char" "C" + ;; else + (let [class* (->bytecode-class-name class)] + (if (.startsWith class* "[") + class* + (str "L" class* ";"))) + )) (defn super-class-name [super] "(-> GenericSuperClassDecl Text)" (|let [[super-name super-params] super] super-name)) +(defn class-decl-params->signature [params] + (str "<" (->> params (&/|interpose " ") (&/fold str "")) ">")) + (defn gclass->signature [super] "(-> GenericClass Text)" (|case super @@ -22,8 +56,8 @@ (str "T" name ";") (&/$GenericClass name params) - (|let [params-sigs (->> params (&/|map gclass->signature) (&/|interpose " ") (&/fold str ""))] - (str "L" (&host/->class name) "<" params-sigs ">" ";")) + (let [params* (str "<" (->> params (&/|map gclass->signature) (&/|interpose " ") (&/fold str "")) ">")] + (str "L" (->bytecode-class-name name) params* ";")) (&/$GenericArray param) (str "[" (gclass->signature param)))) @@ -31,17 +65,17 @@ (defn gsuper-decl->signature [super] "(-> GenericSuperClassDecl Text)" (|let [[super-name super-params] super - params-sigs (->> super-params (&/|map gclass->signature) (&/|interpose " ") (&/fold str ""))] - (str "L" (&host/->class super-name) "<" params-sigs ">" ";"))) + params* (str "<" (->> super-params (&/|map gclass->signature) (&/|interpose " ") (&/fold str "")) ">")] + (str "L" (->bytecode-class-name super-name) params* ";"))) (defn gclass-decl->signature [class-decl supers] "(-> GenericClassDecl (List GenericSuperClassDecl) Text)" (|let [[class-name class-vars] class-decl - vars-section (str "<" (->> class-vars (&/|interpose " ") (&/fold str "")) ">") + vars-section (class-decl-params->signature class-vars) super-section (->> (&/|map gsuper-decl->signature supers) (&/|interpose " ") (&/fold str ""))] (str vars-section super-section))) -(let [object-simple-signature (&host/->type-signature "java.lang.Object")] +(let [object-simple-signature (->type-signature "java.lang.Object")] (defn gclass->simple-signature [gclass] "(-> GenericClass Text)" (|case gclass @@ -49,7 +83,29 @@ object-simple-signature (&/$GenericClass name params) - (&host/->type-signature name) + (->type-signature name) (&/$GenericArray param) (str "[" (gclass->simple-signature param))))) + +(let [object-bc-name (->bytecode-class-name "java.lang.Object")] + (defn gclass->bytecode-class-name [gclass] + "(-> GenericClass Text)" + (|case gclass + (&/$GenericTypeVar name) + object-bc-name + + (&/$GenericClass name params) + (->bytecode-class-name name) + + (&/$GenericArray param) + (assert false "gclass->bytecode-class-name doesn't work on arrays.")))) + +(defn method-signatures [method-decl] + (|let [[=name =modifiers =anns =gvars =exceptions =inputs =output] method-decl + simple-signature (str "(" (&/fold str "" (&/|map (comp gclass->simple-signature &/|second) =inputs)) ")" (gclass->simple-signature =output)) + generic-signature (str "<" (->> =gvars (&/|interpose " ") (&/fold str "")) ">" + "(" (&/fold str "" (&/|map (comp gclass->signature &/|second) =inputs)) ")" + (gclass->signature =output) + (->> =exceptions (&/|map gclass->signature) (&/|interpose " ") (&/fold str "")))] + (&/T simple-signature generic-signature))) diff --git a/src/lux/type.clj b/src/lux/type.clj index 491e81b3b..07ab0be1c 100644 --- a/src/lux/type.clj +++ b/src/lux/type.clj @@ -401,8 +401,9 @@ (&/Cons$ (&/T k v) fixpoints)) (defn ^:private check-error [expected actual] - (str "[Type Checker]\nExpected: " (show-type expected) - "\n\nActual: " (show-type actual) + (str "[Type Checker]\n" + "Expected: " (show-type expected) "\n\n" + "Actual: " (show-type actual) "\n")) (defn beta-reduce [env type] -- cgit v1.2.3