From 8e00142b18d06dfb93f3ee34aa7d28b7618b5393 Mon Sep 17 00:00:00 2001 From: Eduardo Julian Date: Sun, 14 Dec 2014 17:24:51 -0400 Subject: Added module imports. --- src/lang.clj | 2 +- src/lang/analyser.clj | 31 ++++++++++++++++---- src/lang/compiler.clj | 80 +++++++++++++++++++++++++++++++++------------------ src/lang/parser.clj | 7 ++++- 4 files changed, 84 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/lang.clj b/src/lang.clj index 5d5dd0c66..7e71a1a62 100644 --- a/src/lang.clj +++ b/src/lang.clj @@ -96,7 +96,6 @@ (STATIC-METHOD w x y z))))))))) - ;; TODO: Allow using other modules. ;; TODO: Define functions as classes inheriting Function. ;; TODO: Add tuples. ;; TODO: Add pattern-matching. @@ -115,4 +114,5 @@ ;; jar cvf test2.jar test2 test2.class ;; java -cp "test2.jar" test2 ;; jar cvf test2.jar test2 test2.class && java -cp "test2.jar" test2 + ;; jar cvf test2.jar test2 test2.class another.class && java -cp "test2.jar" test2 ) diff --git a/src/lang/analyser.clj b/src/lang/analyser.clj index abf8fa638..115204570 100644 --- a/src/lang/analyser.clj +++ b/src/lang/analyser.clj @@ -1,7 +1,7 @@ (ns lang.analyser (:refer-clojure :exclude [resolve]) - (:require [clojure.core.match :refer [match]] - [clojure.string :as string] + (:require [clojure.string :as string] + [clojure.core.match :refer [match]] (lang [util :as &util :refer [exec return* return fail fail* repeat-m try-m try-all-m map-m apply-m within]] @@ -48,11 +48,20 @@ short-name =class}) nil]]))) +(defn ^:private require-module [name alias] + (fn [state] + [::&util/ok [(assoc-in state [:deps alias] name) + nil]])) + (defn ^:private resolve [ident] (fn [state] - (if-let [resolved (get-in state [:env :mappings ident])] - [::&util/ok [state resolved]] - [::&util/failure (str "Unresolved identifier: " ident)]))) + (if-let [[_ ?alias ?binding] (re-find #"^(.*)/(.*)$" ident)] + (let [?module (get-in state [:deps ?alias])] + (prn 'resolve ?module ?alias ?binding) + [::&util/ok [state (annotated [::global ?module ?binding] ::&type/nothing)]]) + (if-let [resolved (get-in state [:env :mappings ident])] + [::&util/ok [state resolved]] + [::&util/failure (str "Unresolved identifier: " ident)])))) (defmacro ^:private defanalyser [name match return] `(def ~name @@ -190,6 +199,14 @@ (exec [_ (import-class ?class (last (string/split ?class #"\.")))] (return (annotated [::import ?class] ::&type/nothing)))) +(defanalyser analyse-require + [::&parser/require ?file ?alias] + (let [_ (prn `[require ~?file ~?alias]) + module-name (re-find #"[^/]+$" ?file) + _ (prn 'module-name module-name)] + (exec [_ (require-module module-name ?alias)] + (return (annotated [::require ?file ?alias] ::&type/nothing))))) + (def ^:private analyse-form (try-all-m [analyse-boolean analyse-string @@ -204,12 +221,14 @@ analyse-defclass analyse-definterface analyse-def - analyse-import])) + analyse-import + analyse-require])) ;; [Interface] (defn analyse [module-name tokens] (match ((repeat-m analyse-form) {:name module-name, :forms tokens + :deps {} :env {:counter 0 :mappings {}} :types &type/+init+}) diff --git a/src/lang/compiler.clj b/src/lang/compiler.clj index d6a6f5125..8ef129dc0 100644 --- a/src/lang/compiler.clj +++ b/src/lang/compiler.clj @@ -3,6 +3,7 @@ (:require [clojure.string :as string] [clojure.core.match :refer [match]] (lang [type :as &type] + [lexer :as &lexer] [parser :as &parser] [analyser :as &analyser]) :reload) @@ -11,9 +12,14 @@ ClassWriter MethodVisitor))) -(declare compile-form) +(declare compile-form + compile) ;; [Utils/General] +(defn ^:private write-file [file data] + (with-open [stream (java.io.BufferedOutputStream. (java.io.FileOutputStream. file))] + (.write stream data))) + (def ^:private +variant-class+ "test2.Tagged") (defmacro ^:private defcompiler [name match body] @@ -86,7 +92,7 @@ (defcompiler ^:private compile-call [::&analyser/call ?fn ?args] - (do ;; (prn 'compile-call ?fn) + (do (prn 'compile-call (:form ?fn) ?fn ?args) (doseq [arg ?args] (compile-form (assoc *state* :form arg))) (match (:form ?fn) @@ -142,32 +148,33 @@ (defcompiler ^:private compile-def [::&analyser/def ?form ?body] - (match ?form - (?name :guard string?) - (let [=type (:type ?body) - ;; _ (prn '?body ?body) - ] - (doto (.visitField *writer* (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) ?name (->java-sig =type) nil nil) - (.visitEnd))) - - [?name ?args] - (if (= "main" ?name) - (let [=method (doto (.visitMethod *writer* (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) ?name "([Ljava/lang/String;)V" nil nil) - (.visitCode))] - ;; (prn 'FN/?body ?body) - (assert (compile-form (assoc *state* :writer =method :form ?body)) (str "Body couldn't compile: " (pr-str ?body))) - (doto =method - (.visitInsn Opcodes/RETURN) - (.visitMaxs 0 0) + (do (prn 'compile-def ?form) + (match ?form + (?name :guard string?) + (let [=type (:type ?body) + ;; _ (prn '?body ?body) + ] + (doto (.visitField *writer* (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) ?name (->java-sig =type) nil nil) (.visitEnd))) - (let [=method (doto (.visitMethod *writer* (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) ?name "(Ljava/lang/Object;)Ljava/lang/Object;" nil nil) - (.visitCode))] - (compile-form (assoc *state* :writer =method :form ?body)) - (doto =method - (.visitInsn Opcodes/ARETURN) - (.visitMaxs 0 0) - (.visitEnd)))) - )) + + [?name ?args] + (if (= "main" ?name) + (let [=method (doto (.visitMethod *writer* (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) ?name "([Ljava/lang/String;)V" nil nil) + (.visitCode))] + ;; (prn 'FN/?body ?body) + (assert (compile-form (assoc *state* :writer =method :form ?body)) (str "Body couldn't compile: " (pr-str ?body))) + (doto =method + (.visitInsn Opcodes/RETURN) + (.visitMaxs 0 0) + (.visitEnd))) + (let [=method (doto (.visitMethod *writer* (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) ?name "(Ljava/lang/Object;)Ljava/lang/Object;" nil nil) + (.visitCode))] + (compile-form (assoc *state* :writer =method :form ?body)) + (doto =method + (.visitInsn Opcodes/ARETURN) + (.visitMaxs 0 0) + (.visitEnd)))) + ))) (defcompiler ^:private compile-defclass [::&analyser/defclass [?package ?name] ?members] @@ -226,6 +233,22 @@ [::&analyser/import ?class] nil) +(defcompiler compile-require + [::&analyser/require ?file ?alias] + (let [module-name (re-find #"[^/]+$" ?file) + _ (prn 'module-name module-name) + source-code (slurp (str module-name ".lang")) + _ (prn 'source-code source-code) + tokens (&lexer/lex source-code) + _ (prn 'tokens tokens) + syntax (&parser/parse tokens) + _ (prn 'syntax syntax) + ann-syntax (&analyser/analyse module-name syntax) + _ (prn 'ann-syntax ann-syntax) + class-data (compile module-name ann-syntax)] + (write-file (str module-name ".class") class-data) + nil)) + (let [+compilers+ [compile-literal compile-variant compile-local @@ -239,7 +262,8 @@ compile-def compile-defclass compile-definterface - compile-import]] + compile-import + compile-require]] (defn ^:private compile-form [state] ;; (prn 'compile-form/state state) (or (some #(% state) +compilers+) diff --git a/src/lang/parser.clj b/src/lang/parser.clj index f756a8b14..3149cf5d4 100644 --- a/src/lang/parser.clj +++ b/src/lang/parser.clj @@ -102,6 +102,10 @@ [::&lexer/list ([[::&lexer/ident "import"] [::&lexer/ident ?class]] :seq)] (return [::import ?class])) +(defparser ^:private parse-require + [::&lexer/list ([[::&lexer/ident "require"] [::&lexer/string ?file] [::&lexer/ident "as"] [::&lexer/ident ?alias]] :seq)] + (return [::require ?file ?alias])) + (defparser ^:private parse-defclass [::&lexer/list ([[::&lexer/ident "defclass"] [::&lexer/ident ?name] [::&lexer/tuple ?fields]] :seq)] (let [fields (for [field ?fields] @@ -200,9 +204,10 @@ parse-static-access parse-dynamic-access parse-ann-class - parse-import parse-defclass parse-definterface + parse-import + parse-require parse-fn-call])) ;; [Interface] -- cgit v1.2.3