diff options
Diffstat (limited to '')
-rw-r--r-- | src/lux/analyser.clj | 10 | ||||
-rw-r--r-- | src/lux/analyser/host.clj | 2 | ||||
-rw-r--r-- | src/lux/analyser/lux.clj | 128 | ||||
-rw-r--r-- | src/lux/analyser/module.clj | 82 | ||||
-rw-r--r-- | src/lux/base.clj | 37 | ||||
-rw-r--r-- | src/lux/compiler.clj | 165 | ||||
-rw-r--r-- | src/lux/compiler/base.clj | 184 | ||||
-rw-r--r-- | src/lux/compiler/host.clj | 76 | ||||
-rw-r--r-- | src/lux/compiler/lambda.clj | 5 | ||||
-rw-r--r-- | src/lux/compiler/lux.clj | 12 | ||||
-rw-r--r-- | src/lux/reader.clj | 2 | ||||
-rw-r--r-- | src/lux/type.clj | 3 |
12 files changed, 466 insertions, 240 deletions
diff --git a/src/lux/analyser.clj b/src/lux/analyser.clj index 4cb1a4900..039db810a 100644 --- a/src/lux/analyser.clj +++ b/src/lux/analyser.clj @@ -108,7 +108,7 @@ ["lux;Cons" [?type ["lux;Cons" [?value ["lux;Nil" _]]]]]]]]] - (&&lux/analyse-coerce analyse eval! ?type ?value) + (&&lux/analyse-coerce analyse eval! exo-type ?type ?value) [["lux;FormS" ["lux;Cons" [["lux;Meta" [_ ["lux;SymbolS" [_ "_lux_export"]]]] ["lux;Cons" [["lux;Meta" [_ ["lux;SymbolS" ["" ?ident]]]] @@ -459,7 +459,7 @@ (if (.startsWith msg "@") msg (|let [[file line col] meta] - (str "@ " file " : " line " , " col "\n" msg)))) + (str "@ " file "," line "," col "\n" msg)))) (defn ^:private analyse-basic-ast [analyse eval! compile-module exo-type token] ;; (prn 'analyse-basic-ast (&/show-ast token)) @@ -519,7 +519,8 @@ (fail* (add-loc meta msg))) [["lux;Left" msg]] - (fail* (add-loc meta msg)))))) + (fail* (add-loc meta msg)) + )))) (defn ^:private analyse-ast [eval! compile-module exo-type token] (matchv ::M/objects [token] @@ -531,7 +532,8 @@ (fn [state] (matchv ::M/objects [((&type/with-var #(&&/analyse-1 (partial analyse-ast eval! compile-module) % ?fn)) state)] [["lux;Right" [state* =fn]]] - ((&&lux/analyse-apply (partial analyse-ast eval! compile-module) exo-type =fn ?args) state*) + (do ;; (prn 'GOT_FUN (&/show-ast ?fn) (&/show-ast token) (aget =fn 0 0) (aget =fn 1 0)) + ((&&lux/analyse-apply (partial analyse-ast eval! compile-module) exo-type =fn ?args) state*)) [_] ((analyse-basic-ast (partial analyse-ast eval! compile-module) eval! compile-module exo-type token) state))) diff --git a/src/lux/analyser/host.clj b/src/lux/analyser/host.clj index 1aa683ea6..b9361b8c3 100644 --- a/src/lux/analyser/host.clj +++ b/src/lux/analyser/host.clj @@ -353,6 +353,6 @@ (defn analyse-jvm-program [analyse ?args ?body] (|do [=body (&/with-scope "" - (&&env/with-local "" (&/V "lux;AppT" (&/T &type/List &type/Text)) + (&&env/with-local ?args (&/V "lux;AppT" (&/T &type/List &type/Text)) (&&/analyse-1 analyse (&/V "lux;AppT" (&/T &type/IO &type/Unit)) ?body)))] (return (&/|list (&/V "jvm-program" =body))))) diff --git a/src/lux/analyser/lux.clj b/src/lux/analyser/lux.clj index 242539b65..90811c77e 100644 --- a/src/lux/analyser/lux.clj +++ b/src/lux/analyser/lux.clj @@ -103,6 +103,7 @@ (|do [module-name &/get-module-name] (fn [state] (|let [[?module ?name] ident + ;; _ (prn 'analyse-symbol/_0 ?module ?name) local-ident (str ?module ";" ?name) stack (&/get$ &/$ENVS state) no-binding? #(and (->> % (&/get$ &/$LOCALS) (&/get$ &/$MAPPINGS) (&/|contains? local-ident) not) @@ -110,67 +111,77 @@ [inner outer] (&/|split-with no-binding? stack)] (matchv ::M/objects [outer] [["lux;Nil" _]] - ((|do [[[r-module r-name] $def] (&&module/find-def (if (.equals "" ?module) module-name ?module) - ?name) - endo-type (matchv ::M/objects [$def] - [["lux;ValueD" ?type]] - (return ?type) - - [["lux;MacroD" _]] - (return &type/Macro) - - [["lux;TypeD" _]] - (return &type/Type)) - _ (if (and (clojure.lang.Util/identical &type/Type endo-type) - (clojure.lang.Util/identical &type/Type exo-type)) - (return nil) - (&type/check exo-type endo-type))] - (return (&/|list (&/T (&/V "lux;Global" (&/T r-module r-name)) - endo-type)))) - state) + (do ;; (prn 'analyse-symbol/_1 + ;; [?module ?name] + ;; [(if (.equals "" ?module) module-name ?module) + ;; ?name]) + ((|do [[[r-module r-name] $def] (&&module/find-def (if (.equals "" ?module) module-name ?module) + ?name) + ;; :let [_ (prn 'analyse-symbol/_1.1 r-module r-name)] + endo-type (matchv ::M/objects [$def] + [["lux;ValueD" ?type]] + (return ?type) + + [["lux;MacroD" _]] + (return &type/Macro) + + [["lux;TypeD" _]] + (return &type/Type)) + _ (if (and (clojure.lang.Util/identical &type/Type endo-type) + (clojure.lang.Util/identical &type/Type exo-type)) + (return nil) + (&type/check exo-type endo-type))] + (return (&/|list (&/T (&/V "lux;Global" (&/T r-module r-name)) + endo-type)))) + state)) [["lux;Cons" [?genv ["lux;Nil" _]]]] - (if-let [global (->> ?genv (&/get$ &/$LOCALS) (&/get$ &/$MAPPINGS) (&/|get local-ident))] - (matchv ::M/objects [global] - [[["lux;Global" [?module* ?name*]] _]] - ((|do [[[r-module r-name] $def] (&&module/find-def ?module* ?name*) - endo-type (matchv ::M/objects [$def] - [["lux;ValueD" ?type]] - (return ?type) - - [["lux;MacroD" _]] - (return &type/Macro) - - [["lux;TypeD" _]] - (return &type/Type)) - _ (if (and (clojure.lang.Util/identical &type/Type endo-type) - (clojure.lang.Util/identical &type/Type exo-type)) - (return nil) - (&type/check exo-type endo-type))] - (return (&/|list (&/T (&/V "lux;Global" (&/T r-module r-name)) - endo-type)))) - state) - - [_] - (fail* "[Analyser Error] Can't have anything other than a global def in the global environment.")) - (fail* "_{_ analyse-symbol _}_")) - + (do ;; (prn 'analyse-symbol/_2 ?module ?name local-ident (->> ?genv (&/get$ &/$LOCALS) (&/get$ &/$MAPPINGS) &/|keys &/->seq)) + (if-let [global (->> ?genv (&/get$ &/$LOCALS) (&/get$ &/$MAPPINGS) (&/|get local-ident))] + (do ;; (prn 'analyse-symbol/_2.1 ?module ?name local-ident (aget global 0)) + (matchv ::M/objects [global] + [[["lux;Global" [?module* ?name*]] _]] + ((|do [[[r-module r-name] $def] (&&module/find-def ?module* ?name*) + ;; :let [_ (prn 'analyse-symbol/_2.1.1 r-module r-name)] + endo-type (matchv ::M/objects [$def] + [["lux;ValueD" ?type]] + (return ?type) + + [["lux;MacroD" _]] + (return &type/Macro) + + [["lux;TypeD" _]] + (return &type/Type)) + _ (if (and (clojure.lang.Util/identical &type/Type endo-type) + (clojure.lang.Util/identical &type/Type exo-type)) + (return nil) + (&type/check exo-type endo-type))] + (return (&/|list (&/T (&/V "lux;Global" (&/T r-module r-name)) + endo-type)))) + state) + + [_] + (do ;; (prn 'analyse-symbol/_2.1.2 ?module ?name local-ident) + (fail* "[Analyser Error] Can't have anything other than a global def in the global environment.")))) + (fail* "_{_ analyse-symbol _}_"))) + [["lux;Cons" [top-outer _]]] - (|let [scopes (&/|tail (&/folds #(&/|cons (&/get$ &/$NAME %2) %1) - (&/|map #(&/get$ &/$NAME %) outer) - (&/|reverse inner))) - [=local inner*] (&/fold2 (fn [register+new-inner frame in-scope] - (|let [[register new-inner] register+new-inner - [register* frame*] (&&lambda/close-over (&/|cons module-name (&/|reverse in-scope)) ident register frame)] - (&/T register* (&/|cons frame* new-inner)))) - (&/T (or (->> top-outer (&/get$ &/$LOCALS) (&/get$ &/$MAPPINGS) (&/|get local-ident)) - (->> top-outer (&/get$ &/$CLOSURE) (&/get$ &/$MAPPINGS) (&/|get local-ident))) - (&/|list)) - (&/|reverse inner) scopes)] - ((|do [btype (&&/expr-type =local) - _ (&type/check exo-type btype)] - (return (&/|list =local))) - (&/set$ &/$ENVS (&/|++ inner* outer) state))) + (do ;; (prn 'analyse-symbol/_3 ?module ?name) + (|let [scopes (&/|tail (&/folds #(&/|cons (&/get$ &/$NAME %2) %1) + (&/|map #(&/get$ &/$NAME %) outer) + (&/|reverse inner))) + [=local inner*] (&/fold2 (fn [register+new-inner frame in-scope] + (|let [[register new-inner] register+new-inner + [register* frame*] (&&lambda/close-over (&/|reverse in-scope) ident register frame)] + (&/T register* (&/|cons frame* new-inner)))) + (&/T (or (->> top-outer (&/get$ &/$LOCALS) (&/get$ &/$MAPPINGS) (&/|get local-ident)) + (->> top-outer (&/get$ &/$CLOSURE) (&/get$ &/$MAPPINGS) (&/|get local-ident))) + (&/|list)) + (&/|reverse inner) scopes)] + ((|do [btype (&&/expr-type =local) + _ (&type/check exo-type btype)] + (return (&/|list =local))) + (&/set$ &/$ENVS (&/|++ inner* outer) state)))) ))) )) @@ -345,6 +356,7 @@ (defn analyse-coerce [analyse eval! exo-type ?type ?value] (|do [=type (&&/analyse-1 analyse &type/Type ?type) ==type (eval! =type) + _ (&type/check exo-type ==type) =value (&&/analyse-1 analyse ==type ?value)] (return (&/|list (&/T (&/V "ann" (&/T =value =type)) ==type))))) diff --git a/src/lux/analyser/module.clj b/src/lux/analyser/module.clj index 1fd96ce0a..f0e5b82b4 100644 --- a/src/lux/analyser/module.clj +++ b/src/lux/analyser/module.clj @@ -56,9 +56,31 @@ nil) [_] - (fail* "[Analyser Error] Can't create a new global definition outside of a global environment.")))) + (fail* (str "[Analyser Error] Can't create a new global definition outside of a global environment: " module ";" name))))) + +(defn def-type [module name] + "(-> Text Text (Lux Type))" + (fn [state] + (if-let [$module (->> state (&/get$ &/$MODULES) (&/|get module))] + (if-let [$def (->> $module (&/get$ $DEFS) (&/|get name))] + (matchv ::M/objects [$def] + [["lux;TypeD" _]] + (return* state &type/Type) + + [["lux;MacroD" _]] + (return* state &type/Macro) + + [["lux;ValueD" _type]] + (return* state _type) + + [["lux;AliasD" [?r-module ?r-name]]] + (&/run-state (def-type ?r-module ?r-name) + state)) + (fail* (str "[Analyser Error] Unknown definition: " (str module ";" name)))) + (fail* (str "[Analyser Error] Unknown module: " module))))) (defn def-alias [a-module a-name r-module r-name type] + ;; (prn 'def-alias [a-module a-name] [r-module r-name] (&type/show-type type)) (fn [state] (matchv ::M/objects [(&/get$ &/$ENVS state)] [["lux;Cons" [?env ["lux;Nil" _]]]] @@ -75,6 +97,7 @@ (&/update$ &/$MAPPINGS (fn [mappings] (&/|put (str "" &/+name-separator+ a-name) (&/T (&/V "lux;Global" (&/T r-module r-name)) type) + ;; (aget (->> state (&/get$ &/$MODULES) (&/|get r-module) (&/get$ $DEFS) (&/|get r-name)) 1) mappings)) locals)) ?env)))) @@ -112,20 +135,24 @@ (defn find-def [module name] (|do [current-module &/get-module-name] (fn [state] + ;; (prn 'find-def/_0 module name 'current-module current-module) (if-let [$module (->> state (&/get$ &/$MODULES) (&/|get module) (&/get$ $DEFS))] - (if-let [$def (&/|get name $module)] - (matchv ::M/objects [$def] - [[exported? $$def]] - (if (or exported? (.equals ^Object current-module module)) - (matchv ::M/objects [$$def] - [["lux;AliasD" [?r-module ?r-name]]] - ((find-def ?r-module ?r-name) - state) - - [_] - (return* state (&/T (&/T module name) $$def))) - (fail* (str "[Analyser Error] Can't use unexported definition: " (str module &/+name-separator+ name))))) - (fail* (str "[Analyser Error] Definition doesn't exist: " (str module &/+name-separator+ name)))) + (do ;; (prn 'find-def/_0.1 module (&/->seq (&/|keys $module))) + (if-let [$def (&/|get name $module)] + (matchv ::M/objects [$def] + [[exported? $$def]] + (do ;; (prn 'find-def/_1 module name 'exported? exported? (.equals ^Object current-module module)) + (if (or exported? (.equals ^Object current-module module)) + (matchv ::M/objects [$$def] + [["lux;AliasD" [?r-module ?r-name]]] + (do ;; (prn 'find-def/_2 [module name] [?r-module ?r-name]) + ((find-def ?r-module ?r-name) + state)) + + [_] + (return* state (&/T (&/T module name) $$def))) + (fail* (str "[Analyser Error] Can't use unexported definition: " (str module &/+name-separator+ name)))))) + (fail* (str "[Analyser Error] Definition doesn't exist: " (str module &/+name-separator+ name))))) (do (prn [module name] (str "[Analyser Error] Module doesn't exist: " module) (->> state (&/get$ &/$MODULES) &/|keys &/->seq)) @@ -144,7 +171,7 @@ [[exported? ["lux;ValueD" ?type]]] ((|do [_ (&type/check &type/Macro ?type) ^ClassLoader loader &/loader - :let [macro (-> (.loadClass loader (&host/location (&/|list module name))) + :let [macro (-> (.loadClass loader (str module ".$" (&/normalize-ident name))) (.getField "_datum") (.get nil))]] (fn [state*] @@ -199,18 +226,19 @@ (|let [[k v] kv] (matchv ::M/objects [v] [[?exported? ?def]] - (matchv ::M/objects [?def] - [["lux;AliasD" [?r-module ?r-name]]] - (&/T ?exported? k (str "A" ?r-module ";" ?r-name)) - - [["lux;MacroD" _]] - (&/T ?exported? k "M") - - [["lux;TypeD" _]] - (&/T ?exported? k "T") - - [_] - (&/T ?exported? k "V"))))) + (do ;; (prn 'defs k ?exported?) + (matchv ::M/objects [?def] + [["lux;AliasD" [?r-module ?r-name]]] + (&/T ?exported? k (str "A" ?r-module ";" ?r-name)) + + [["lux;MacroD" _]] + (&/T ?exported? k "M") + + [["lux;TypeD" _]] + (&/T ?exported? k "T") + + [_] + (&/T ?exported? k "V")))))) (->> state (&/get$ &/$MODULES) (&/|get module) (&/get$ $DEFS))))))) (def imports diff --git a/src/lux/base.clj b/src/lux/base.clj index 657ebd51e..aecb3fd13 100644 --- a/src/lux/base.clj +++ b/src/lux/base.clj @@ -21,12 +21,13 @@ ;; CompilerState (def $ENVS 0) -(def $HOST 1) -(def $MODULES 2) -(def $SEED 3) -(def $SEEN-SOURCES 4) -(def $SOURCE 5) -(def $TYPES 6) +(def $EVAL? 1) +(def $HOST 2) +(def $MODULES 3) +(def $SEED 4) +(def $SEEN-SOURCES 5) +(def $SOURCE 6) +(def $TYPES 7) ;; [Exports] (def +name-separator+ ";") @@ -413,6 +414,7 @@ \< "_LT_" \> "_GT_" \~ "_TILDE_" + \| "_PIPE_" ;; default char)) @@ -456,7 +458,8 @@ ;; (prn 'findClass class-name) (if-let [^bytes bytecode (get @store class-name)] (.invoke define-class this (to-array [class-name bytecode (int 0) (int (alength bytecode))])) - (throw (IllegalStateException. (str "[Class Loader] Unknown class: " class-name)))))))) + (do (prn 'memory-class-loader/store (keys @store)) + (throw (IllegalStateException. (str "[Class Loader] Unknown class: " class-name))))))))) (defn host [_] (let [store (atom {})] @@ -471,6 +474,8 @@ (defn init-state [_] (R ;; "lux;envs" (|list) + ;; "lux;eval?" + false ;; "lux;host" (host nil) ;; "lux;modules" @@ -485,6 +490,19 @@ +init-bindings+ )) +(defn with-eval [body] + (fn [state] + (matchv ::M/objects [(body (set$ $EVAL? true state))] + [["lux;Right" [state* output]]] + (return* (set$ $EVAL? (get$ $EVAL? state) state*) output) + + [["lux;Left" msg]] + (fail* msg)))) + +(def get-eval + (fn [state] + (return* state (get$ $EVAL? state)))) + (def get-writer (fn [state] (let [writer* (->> state (get$ $HOST) (get$ $WRITER))] @@ -557,9 +575,8 @@ state)))))) (def get-scope-name - (|do [module-name get-module-name] - (fn [state] - (return* state (->> state (get$ $ENVS) (|map #(get$ $NAME %)) |reverse (|cons module-name)))))) + (fn [state] + (return* state (->> state (get$ $ENVS) (|map #(get$ $NAME %)) |reverse)))) (defn with-writer [writer body] (fn [state] diff --git a/src/lux/compiler.clj b/src/lux/compiler.clj index 90a382ed5..d88c33437 100644 --- a/src/lux/compiler.clj +++ b/src/lux/compiler.clj @@ -25,9 +25,6 @@ ClassWriter MethodVisitor))) -;; [Constants] -(def ^:private version "0.2") - ;; [Utils/Compilers] (defn ^:private compile-expression [syntax] (matchv ::M/objects [syntax] @@ -321,80 +318,104 @@ (&&host/compile-jvm-class compile-expression ?name ?super-class ?interfaces ?fields ?methods))) (defn ^:private eval! [expr] - (|do [id &/gen-id - :let [class-name (str id) - =class (doto (new ClassWriter ClassWriter/COMPUTE_MAXS) - (.visit Opcodes/V1_5 (+ Opcodes/ACC_PUBLIC Opcodes/ACC_SUPER) - class-name nil "java/lang/Object" nil) - (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_eval" "Ljava/lang/Object;" nil nil) - (doto (.visitEnd))))] - _ (&/with-writer (.visitMethod =class Opcodes/ACC_PUBLIC "<clinit>" "()V" nil nil) - (|do [^MethodVisitor *writer* &/get-writer - :let [_ (.visitCode *writer*)] - _ (compile-expression expr) - :let [_ (doto *writer* - (.visitFieldInsn Opcodes/PUTSTATIC class-name "_eval" "Ljava/lang/Object;") - (.visitInsn Opcodes/RETURN) - (.visitMaxs 0 0) - (.visitEnd))]] - (return nil))) - :let [bytecode (.toByteArray (doto =class - .visitEnd))] - _ (&&/save-class! class-name bytecode) - loader &/loader] - (-> (.loadClass ^ClassLoader loader class-name) - (.getField "_eval") - (.get nil) - return))) + (&/with-eval + (|do [module &/get-module-name + id &/gen-id + :let [class-name (str module "/" id) + ;; _ (prn 'eval! id class-name) + =class (doto (new ClassWriter ClassWriter/COMPUTE_MAXS) + (.visit Opcodes/V1_5 (+ Opcodes/ACC_PUBLIC Opcodes/ACC_SUPER) + class-name nil "java/lang/Object" nil) + (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_eval" "Ljava/lang/Object;" nil nil) + (doto (.visitEnd))))] + _ (&/with-writer (.visitMethod =class Opcodes/ACC_PUBLIC "<clinit>" "()V" nil nil) + (|do [^MethodVisitor *writer* &/get-writer + :let [_ (.visitCode *writer*)] + _ (compile-expression expr) + :let [_ (doto *writer* + (.visitFieldInsn Opcodes/PUTSTATIC class-name "_eval" "Ljava/lang/Object;") + (.visitInsn Opcodes/RETURN) + (.visitMaxs 0 0) + (.visitEnd))]] + (return nil))) + :let [bytecode (.toByteArray (doto =class + .visitEnd))] + _ (&&/save-class! (str id) bytecode) + loader &/loader] + (-> (.loadClass ^ClassLoader loader (str module "." id)) + (.getField "_eval") + (.get nil) + return)))) (defn ^:private compile-module [name] - (let [compiler-step (|do [analysis+ (&optimizer/optimize eval! compile-module)] - (&/map% compile-statement analysis+))] - (fn [state] - (if (->> state (&/get$ &/$MODULES) (&/|contains? name)) - (if (.equals ^Object name "lux") - (return* state nil) - (fail* "[Compiler Error] Can't redefine a module!")) - (let [file-name (str "source/" name ".lux") - file-content (slurp file-name) - =class (doto (new ClassWriter ClassWriter/COMPUTE_MAXS) - (.visit Opcodes/V1_5 (+ Opcodes/ACC_PUBLIC Opcodes/ACC_SUPER) - (&host/->class name) nil "java/lang/Object" nil) - (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_hash" "I" nil (hash file-content)) - .visitEnd) - (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_compiler" "Ljava/lang/String;" nil version) - .visitEnd))] - (matchv ::M/objects [((&/exhaust% compiler-step) - (->> state - (&/set$ &/$SOURCE (&reader/from file-name file-content)) - (&/set$ &/$ENVS (&/|list (&/env name))) - (&/update$ &/$HOST #(&/set$ &/$WRITER (&/V "lux;Some" =class) %)) - (&/update$ &/$MODULES #(&/|put name &a-module/init-module %))))] - [["lux;Right" [?state _]]] - (&/run-state (|do [defs &a-module/defs - imports &a-module/imports - :let [_ (doto =class - (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_defs" "Ljava/lang/String;" nil - (->> defs - (&/|map (fn [_def] - (|let [[?exported ?name ?ann] _def] - (str (if ?exported "1" "0") " " ?name " " ?ann)))) - (&/|interpose "\t") - (&/fold str ""))) - .visitEnd) - (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_imports" "Ljava/lang/String;" nil - (->> imports (&/|interpose ";") (&/fold str ""))) - .visitEnd) - (.visitEnd))]] - (&&/save-class! name (.toByteArray =class))) - ?state) - - [["lux;Left" ?message]] - (fail* ?message))))))) + ;; (prn 'compile-module name) + (if (&&/cached? name) + (do ;; (println "YOLO") + (let [file-name (str "input/" name ".lux") + file-content (slurp file-name)] + (&&/load-cache name (hash file-content) compile-module))) + (let [compiler-step (|do [analysis+ (&optimizer/optimize eval! compile-module)] + (&/map% compile-statement analysis+))] + (fn [state] + (if (->> state (&/get$ &/$MODULES) (&/|contains? name)) + (if (.equals ^Object name "lux") + (return* state nil) + (fail* "[Compiler Error] Can't redefine a module!")) + (let [file-name (str "input/" name ".lux") + file-content (slurp file-name) + =class (doto (new ClassWriter ClassWriter/COMPUTE_MAXS) + (.visit Opcodes/V1_5 (+ Opcodes/ACC_PUBLIC Opcodes/ACC_SUPER) + (str name "/_") nil "java/lang/Object" nil) + (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_hash" "I" nil (hash file-content)) + .visitEnd) + (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_compiler" "Ljava/lang/String;" nil &&/version) + .visitEnd))] + (matchv ::M/objects [((&/exhaust% compiler-step) + (->> state + (&/set$ &/$SOURCE (&reader/from file-name file-content)) + (&/set$ &/$ENVS (&/|list (&/env name))) + (&/update$ &/$HOST #(&/set$ &/$WRITER (&/V "lux;Some" =class) %)) + (&/update$ &/$MODULES #(&/|put name &a-module/init-module %))))] + [["lux;Right" [?state _]]] + (&/run-state (|do [defs &a-module/defs + imports &a-module/imports + :let [_ (doto =class + (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_defs" "Ljava/lang/String;" nil + (->> defs + (&/|map (fn [_def] + (|let [[?exported ?name ?ann] _def] + (str (if ?exported "1" "0") " " ?name " " ?ann)))) + (&/|interpose "\t") + (&/fold str ""))) + .visitEnd) + (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_imports" "Ljava/lang/String;" nil + (->> imports (&/|interpose "\t") (&/fold str ""))) + .visitEnd) + (.visitEnd))]] + (&&/save-class! "_" (.toByteArray =class))) + ?state) + + [["lux;Left" ?message]] + (fail* ?message)))))))) + +(defn ^:private clean-file [^java.io.File file] + (if (.isDirectory file) + (do (doseq [f (seq (.listFiles file))] + (clean-file f)) + (.delete file)) + (.delete file))) + +(defn ^:private setup-dirs! [] + (.mkdir (java.io.File. "cache")) + (.mkdir (java.io.File. "cache/jvm")) + (.mkdir (java.io.File. "output")) + (.mkdir (java.io.File. "output/jvm")) + (doseq [f (seq (.listFiles (java.io.File. "output/jvm")))] + (clean-file f))) ;; [Resources] (defn compile-all [modules] - (.mkdir (java.io.File. "output")) + (setup-dirs!) (matchv ::M/objects [((&/map% compile-module (&/|cons "lux" modules)) (&/init-state nil))] [["lux;Right" [?state _]]] (println (str "Compilation complete! " (str "[" (->> modules diff --git a/src/lux/compiler/base.clj b/src/lux/compiler/base.clj index 24f342469..7ac48e67e 100644 --- a/src/lux/compiler/base.clj +++ b/src/lux/compiler/base.clj @@ -1,40 +1,182 @@ (ns lux.compiler.base (:require [clojure.string :as string] + [clojure.java.io :as io] [clojure.core.match :as M :refer [matchv]] clojure.core.match.array - (lux [base :as & :refer [|do return* return fail fail*]]) - [lux.analyser.base :as &a]) + (lux [base :as & :refer [|do return* return fail fail*]] + [type :as &type]) + (lux.analyser [base :as &a] + [module :as &a-module])) (:import (org.objectweb.asm Opcodes Label ClassWriter MethodVisitor))) +;; [Utils] +(defn ^:private write-file [^String file ^bytes data] + (with-open [stream (java.io.BufferedOutputStream. (java.io.FileOutputStream. file))] + (.write stream data))) + +(defn ^:private write-output [module name data] + (let [module* module] + (.mkdirs (java.io.File. (str "output/jvm/" module*))) + (write-file (str "output/jvm/" module* "/" name ".class") data))) + +(defn ^:private write-cache [module name data] + (let [module* (string/replace module #"/" " ")] + (.mkdirs (java.io.File. (str "cache/jvm/" module*))) + (write-file (str "cache/jvm/" module* "/" name ".class") data))) + +(defn ^:private clean-file [^java.io.File file] + (if (.isDirectory file) + (do (doseq [f (seq (.listFiles file))] + (clean-file f)) + (.delete file)) + (.delete file))) + +(defn ^:private read-file [file] + (with-open [reader (io/input-stream file)] + (let [length (.length file) + buffer (byte-array length)] + (.read reader buffer 0 length) + buffer))) + ;; [Exports] +(def version "0.2") + (def local-prefix "l") (def partial-prefix "p") (def closure-prefix "c") (def apply-signature "(Ljava/lang/Object;)Ljava/lang/Object;") -;; (defn write-file [^String file ^bytes data] -;; (with-open [stream (java.io.BufferedOutputStream. (java.io.FileOutputStream. file))] -;; (.write stream data))) - -;; (defn write-class [name data] -;; (write-file (str "output/" name ".class") data)) - (defn load-class! [^ClassLoader loader name] (.loadClass loader name)) -;; (defn save-class! [name bytecode] -;; (|do [loader &/loader -;; :let [_ (write-class name bytecode) -;; _ (load-class! loader (string/replace name #"/" "."))]] -;; (return nil))) - (defn save-class! [name bytecode] - (let [real-name (string/replace name #"/" ".")] - (|do [loader &/loader - !classes &/classes - :let [_ (swap! !classes assoc real-name bytecode) - _ (load-class! loader real-name)]] - (return nil)))) + (|do [eval? &/get-eval + module &/get-module-name + loader &/loader + !classes &/classes + :let [real-name (str (string/replace module #"/" ".") "." name) + _ (swap! !classes assoc real-name bytecode) + _ (load-class! loader real-name) + _ (when (not eval?) + (do (write-output module name bytecode) + (write-cache module name bytecode)))]] + (return nil))) + +(defn cached? [module] + (.exists (java.io.File. (str "cache/jvm/" (string/replace module #"/" " ") "/_.class")))) + +(defn delete-cache [module] + (fn [state] + (do (clean-file (java.io.File. (str "cache/jvm/" (string/replace module #"/" " ")))) + (return* state nil)))) + +(defn ^:private replace-several [content & replacements] + (let [replacement-list (partition 2 replacements)] + (reduce #(try (let [[_pattern _rep] %2] + (string/replace %1 _pattern (string/re-quote-replacement _rep))) + (catch Exception e + (prn 'replace-several content %1 %2) + (throw e))) + content replacement-list))) + +(defn ^:private replace-cache [cache-name] + (if (.startsWith cache-name "$") + (replace-several cache-name + #"_ASTER_" "*" + #"_PLUS_" "+" + #"_DASH_" "-" + #"_SLASH_" "/" + #"_BSLASH_" "\\" + #"_UNDERS_" "_" + #"_PERCENT_" "%" + #"_DOLLAR_" "$" + #"_QUOTE_" "'" + #"_BQUOTE_" "`" + #"_AT_" "@" + #"_CARET_" "^" + #"_AMPERS_" "&" + #"_EQ_" "=" + #"_BANG_" "!" + #"_QM_" "?" + #"_COLON_" ":" + #"_PERIOD_" "." + #"_COMMA_" "," + #"_LT_" "<" + #"_GT_" ">" + #"_TILDE_" "~" + #"_PIPE_" "|") + cache-name)) + +(defn load-cache [module module-hash compile-module] + (|do [loader &/loader + !classes &/classes] + (let [module-path (str "cache/jvm/" (string/replace module #"/" " ")) + module* (string/replace module #"/" ".") + class-name (str module* "._") + module-meta (do (swap! !classes assoc class-name (read-file (java.io.File. (str module-path "/_.class")))) + (load-class! loader class-name))] + (if (and (= module-hash (-> module-meta (.getField "_hash") (.get nil))) + (= version (-> module-meta (.getField "_compiler") (.get nil)))) + (let [imports (string/split (-> module-meta (.getField "_imports") (.get nil)) #"\t") + ;; _ (prn module 'imports imports) + ] + (|do [loads (&/map% (fn [_import] + (load-cache _import (-> (str "input/" _import ".lux") slurp hash) compile-module)) + (if (= [""] imports) + (&/|list) + (&/->list imports)))] + (if (->> loads &/->seq (every? true?)) + (do (doseq [file (seq (.listFiles (java.io.File. module-path))) + :when (not= "_.class" (.getName file))] + (let [real-name (second (re-find #"^(.*)\.class$" (.getName file))) + bytecode (read-file file) + ;; _ (prn 'load-cache module real-name) + ] + ;; (swap! !classes assoc (str module* "." (replace-cache real-name)) bytecode) + (swap! !classes assoc (str module* "." real-name) bytecode) + ;; (swap! !classes assoc "__temp__" bytecode) + ;; (swap! !classes assoc (-> (load-class! loader "__temp__") (.getField "_name") (.get nil)) bytecode) + (write-output module real-name bytecode))) + ;; (swap! !classes dissoc "__temp__") + (let [defs (string/split (-> module-meta (.getField "_defs") (.get nil)) #"\t")] + (|do [_ (fn [state] + (&/run-state (&/map% (fn [_def] + (let [[_exported? _name _ann] (string/split _def #" ") + ;; _ (prn '[_exported? _name _ann] [_exported? _name _ann]) + def-class (load-class! loader (str module* ".$" (&/normalize-ident _name))) + def-name (-> def-class (.getField "_name") (.get nil))] + (|do [_ (case _ann + "T" (&a-module/define module def-name (&/V "lux;TypeD" nil) &type/Type) + "M" (|do [_ (&a-module/define module def-name (&/V "lux;ValueD" &type/Macro) &type/Macro)] + (&a-module/declare-macro module def-name)) + "V" (let [def-type (-> def-class (.getField "_meta") (.get nil))] + (matchv ::M/objects [def-type] + [["lux;ValueD" _def-type]] + (&a-module/define module def-name def-type _def-type))) + ;; else + (let [[_ __module __name] (re-find #"^A(.*);(.*)$" _ann)] + (|do [__type (&a-module/def-type __module __name)] + (do ;; (prn '__type [__module __name] (&type/show-type __type)) + (&a-module/def-alias module def-name __module __name __type)))))] + (if (= "1" _exported?) + (&a-module/export module def-name) + (return nil))) + )) + (if (= [""] defs) + (&/|list) + (&/->list defs))) + (->> state + (&/set$ &/$ENVS (&/|list (&/env module))) + (&/update$ &/$MODULES #(&/|put module &a-module/init-module %)))))] + (return true)))) + (|do [_ (delete-cache module) + _ (compile-module module)] + (return false))))) + + (|do [_ (delete-cache module) + _ (compile-module module)] + (return false))) + ))) diff --git a/src/lux/compiler/host.clj b/src/lux/compiler/host.clj index e825ca0ad..bc1ab23f1 100644 --- a/src/lux/compiler/host.clj +++ b/src/lux/compiler/host.clj @@ -319,46 +319,46 @@ 0))) (defn compile-jvm-class [compile ?name ?super-class ?interfaces ?fields ?methods] - (let [name* (&host/->class ?name) - super-class* (&host/->class ?super-class) - =class (doto (new ClassWriter ClassWriter/COMPUTE_MAXS) - (.visit Opcodes/V1_5 (+ Opcodes/ACC_PUBLIC Opcodes/ACC_SUPER) - name* nil super-class* (->> ?interfaces (&/|map &host/->class) &/->seq (into-array String)))) - _ (&/|map (fn [field] - (doto (.visitField =class (modifiers->int (:modifiers field)) (:name field) - (&host/->type-signature (:type field)) nil nil) - (.visitEnd))) - ?fields)] - (|do [_ (&/map% (fn [method] - (|let [signature (str "(" (&/fold str "" (&/|map &host/->type-signature (:inputs method))) ")" - (&host/->type-signature (:output method)))] - (&/with-writer (.visitMethod =class (modifiers->int (:modifiers method)) - (:name method) - signature nil nil) - (|do [^MethodVisitor =method &/get-writer - :let [_ (.visitCode =method)] - _ (compile (:body method)) - :let [_ (doto =method - (.visitInsn (if (= "void" (:output method)) Opcodes/RETURN Opcodes/ARETURN)) - (.visitMaxs 0 0) - (.visitEnd))]] - (return nil))))) - ?methods)] - (&&/save-class! name* (.toByteArray (doto =class .visitEnd)))))) - -(defn compile-jvm-interface [compile ?name ?supers ?methods] - (prn 'compile-jvm-interface (->> ?supers &/->seq pr-str)) - (let [name* (&host/->class ?name) - =interface (doto (new ClassWriter ClassWriter/COMPUTE_MAXS) - (.visit Opcodes/V1_5 (+ Opcodes/ACC_PUBLIC Opcodes/ACC_INTERFACE) - name* nil "java/lang/Object" (->> ?supers (&/|map &host/->class) &/->seq (into-array String)))) - _ (do (&/|map (fn [method] + (|do [module &/get-module-name] + (let [super-class* (&host/->class ?super-class) + =class (doto (new ClassWriter ClassWriter/COMPUTE_MAXS) + (.visit Opcodes/V1_5 (+ Opcodes/ACC_PUBLIC Opcodes/ACC_SUPER) + (str module "/" ?name) nil super-class* (->> ?interfaces (&/|map &host/->class) &/->seq (into-array String)))) + _ (&/|map (fn [field] + (doto (.visitField =class (modifiers->int (:modifiers field)) (:name field) + (&host/->type-signature (:type field)) nil nil) + (.visitEnd))) + ?fields)] + (|do [_ (&/map% (fn [method] (|let [signature (str "(" (&/fold str "" (&/|map &host/->type-signature (:inputs method))) ")" (&host/->type-signature (:output method)))] - (.visitMethod =interface (modifiers->int (:modifiers method)) (:name method) signature nil nil))) - ?methods) - (.visitEnd =interface))] - (&&/save-class! name* (.toByteArray =interface)))) + (&/with-writer (.visitMethod =class (modifiers->int (:modifiers method)) + (:name method) + signature nil nil) + (|do [^MethodVisitor =method &/get-writer + :let [_ (.visitCode =method)] + _ (compile (:body method)) + :let [_ (doto =method + (.visitInsn (if (= "void" (:output method)) Opcodes/RETURN Opcodes/ARETURN)) + (.visitMaxs 0 0) + (.visitEnd))]] + (return nil))))) + ?methods)] + (&&/save-class! ?name (.toByteArray (doto =class .visitEnd))))))) + +(defn compile-jvm-interface [compile ?name ?supers ?methods] + ;; (prn 'compile-jvm-interface (->> ?supers &/->seq pr-str)) + (|do [module &/get-module-name] + (let [=interface (doto (new ClassWriter ClassWriter/COMPUTE_MAXS) + (.visit Opcodes/V1_5 (+ Opcodes/ACC_PUBLIC Opcodes/ACC_INTERFACE) + (str module "/" ?name) nil "java/lang/Object" (->> ?supers (&/|map &host/->class) &/->seq (into-array String)))) + _ (do (&/|map (fn [method] + (|let [signature (str "(" (&/fold str "" (&/|map &host/->type-signature (:inputs method))) ")" + (&host/->type-signature (:output method)))] + (.visitMethod =interface (modifiers->int (:modifiers method)) (:name method) signature nil nil))) + ?methods) + (.visitEnd =interface))] + (&&/save-class! ?name (.toByteArray =interface))))) (defn compile-jvm-try [compile *type* ?body ?catches ?finally] (|do [^MethodVisitor *writer* &/get-writer diff --git a/src/lux/compiler/lambda.clj b/src/lux/compiler/lambda.clj index 42ed5459e..7b08532fe 100644 --- a/src/lux/compiler/lambda.clj +++ b/src/lux/compiler/lambda.clj @@ -84,7 +84,8 @@ ;; [Exports] (defn compile-lambda [compile ?scope ?env ?body] - (|do [:let [lambda-class (&host/location ?scope) + ;; (prn 'compile-lambda (->> ?scope &/->seq)) + (|do [:let [lambda-class (str (&/|head ?scope) "/$" (&host/location (&/|tail ?scope))) =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 ["lux/Function"])) @@ -99,5 +100,5 @@ )] _ (add-lambda-impl =class compile lambda-impl-signature ?body) :let [_ (.visitEnd =class)] - _ (&&/save-class! lambda-class (.toByteArray =class))] + _ (&&/save-class! (str "$" (&host/location (&/|tail ?scope))) (.toByteArray =class))] (instance-closure compile lambda-class ?env (lambda-<init>-signature ?env)))) diff --git a/src/lux/compiler/lux.clj b/src/lux/compiler/lux.clj index b47267d25..c8197da66 100644 --- a/src/lux/compiler/lux.clj +++ b/src/lux/compiler/lux.clj @@ -107,14 +107,14 @@ :let [_ (doto *writer* (.visitVarInsn Opcodes/ALOAD 0) (.visitFieldInsn Opcodes/GETFIELD - (&host/location ?scope) + (str (&/|head ?scope) "/$" (&host/location (&/|tail ?scope))) (str &&/closure-prefix ?captured-id) "Ljava/lang/Object;"))]] (return nil))) (defn compile-global [compile *type* ?owner-class ?name] (|do [^MethodVisitor *writer* &/get-writer - :let [_ (.visitFieldInsn *writer* Opcodes/GETSTATIC (&host/->class (&host/location (&/|list ?owner-class ?name))) "_datum" "Ljava/lang/Object;")]] + :let [_ (.visitFieldInsn *writer* Opcodes/GETSTATIC (str ?owner-class "/$" (&/normalize-ident ?name)) "_datum" "Ljava/lang/Object;")]] (return nil))) (defn compile-apply [compile *type* ?fn ?arg] @@ -270,11 +270,13 @@ module-name &/get-module-name :let [outer-class (&host/->class module-name) datum-sig "Ljava/lang/Object;" - current-class (&host/location (&/|list outer-class ?name)) - _ (.visitInnerClass *writer* current-class outer-class nil (+ Opcodes/ACC_STATIC Opcodes/ACC_SYNTHETIC)) + current-class (str outer-class "/" (str "$" (&/normalize-ident ?name))) + ;; _ (prn 'compile-def 'outer-class outer-class '?name ?name 'current-class current-class) =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 ["lux/Function"])) + (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_name" "Ljava/lang/String;" nil ?name) + (doto (.visitEnd))) (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_datum" datum-sig nil nil) (doto (.visitEnd))) (-> (.visitField (+ Opcodes/ACC_PUBLIC Opcodes/ACC_FINAL Opcodes/ACC_STATIC) "_meta" datum-sig nil nil) @@ -292,7 +294,7 @@ (.visitEnd))]] (return nil))) :let [_ (.visitEnd *writer*)] - _ (&&/save-class! current-class (.toByteArray =class))] + _ (&&/save-class! (str "$" (&/normalize-ident ?name)) (.toByteArray =class))] (return nil))) (defn compile-ann [compile *type* ?value-ex ?type-ex] diff --git a/src/lux/reader.clj b/src/lux/reader.clj index 0e8c1b710..bef093247 100644 --- a/src/lux/reader.clj +++ b/src/lux/reader.clj @@ -124,7 +124,7 @@ (&/T (&/T file-name line-num column-num*) line))))) (&/V "No" (str "[Reader Error] Text failed: " text)))))) -(def ^:private ^String +source-dir+ "source/") +(def ^:private ^String +source-dir+ "input/") (defn from [^String file-name ^String file-content] (let [lines (&/->list (string/split-lines file-content)) file-name (.substring file-name (.length +source-dir+))] diff --git a/src/lux/type.clj b/src/lux/type.clj index d82eae8fd..e0315f8e7 100644 --- a/src/lux/type.clj +++ b/src/lux/type.clj @@ -169,7 +169,8 @@ (&/T "lux;types" (&/V "lux;AppT" (&/T (&/V "lux;AppT" (&/T Bindings Int)) Type))) (&/T "lux;host" HostState) (&/T "lux;seed" Int) - (&/T "lux;seen-sources" (&/V "lux;AppT" (&/T List Text)))))) + (&/T "lux;seen-sources" (&/V "lux;AppT" (&/T List Text))) + (&/T "lux;eval?" Bool)))) $Void))) (def Macro |