aboutsummaryrefslogtreecommitdiff
path: root/src/lang/compiler.clj
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lang/compiler.clj409
1 files changed, 115 insertions, 294 deletions
diff --git a/src/lang/compiler.clj b/src/lang/compiler.clj
index d3265b5e4..1c3f634cc 100644
--- a/src/lang/compiler.clj
+++ b/src/lang/compiler.clj
@@ -2,12 +2,7 @@
(:refer-clojure :exclude [compile])
(: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]]
- [parser :as &parser]
- [lexer :as &lexer]
- [type :as &type])
+ [lang.parser :as &parser]
:reload)
(:import (org.objectweb.asm Opcodes
Label
@@ -16,320 +11,146 @@
(declare compile-form)
-;; [Utils]
-(def ^:private +state+
- {:globals {}
- :stack {}
- :forms '()
- :classes {}})
-
-(defn define-class [class members]
- (fn [state]
- (return* (assoc-in state [:classes class] members) nil)))
-
-(defn find-class [class]
- (fn [state]
- (if-let [class-data (get-in state [:classes class])]
- (return* state class-data)
- (fail* (str "Unknown class: " class)))))
-
-(defn wrap [x]
- (update-in +state+ [:forms] conj x))
-
-(defn wrap-in [state x]
- (assoc-in state [:forms] (list x)))
-
-(defn wrap* [env x]
- (-> +state+
- (update-in [:stack] merge env)
- (update-in [:forms] conj x)))
-
-(defmacro ^:private defcompiler [name match return]
- `(def ~name
- (fn [state#]
- (let [~'*token* (first (:forms state#))]
- ;; (prn '~name ~'*token*)
- (match ~'*token*
- ~match
- (let [output# (~return (update-in state# [:forms] rest))]
- ;; (prn "output#" output#)
- output#)
- _#
- (fail* (str "Unknown syntax: " (pr-str ~'*token*))))))))
-
-(defn unwrap-ident [ident]
+;; [Utils/General]
+(defmacro ^:private defcompiler [name match body]
+ `(defn ~name [~'*writer* ~'*form*]
+ (match ~'*form*
+ ~match
+ (do ~body
+ true)
+ _#
+ false)))
+
+(defn ^:private unwrap-ident [ident]
(match ident
[::&parser/ident ?label]
?label))
-(defn unwrap-tagged [ident]
+(defn ^:private unwrap-tagged [ident]
(match ident
[::&parser/tagged ?tag ?data]
[?tag ?data]))
-(defcompiler compile-int
- [::&parser/int ?int]
- (return ?int))
-
-(defcompiler compile-float
- [::&parser/float ?float]
- (return ?float))
-
-(defcompiler compile-ident
- [::&parser/ident ?name]
- (return (symbol ?name)))
-
-(defcompiler compile-tuple
- [::&parser/tuple ?elems]
- (exec [=elems (map-m (fn [elem] (apply-m compile-form (wrap elem)))
- ?elems)]
- (return (vec =elems))))
-
-(defcompiler compile-record
- [::&parser/record ?kvs]
- (exec [=kvs (map-m (fn [[?label ?value]]
- (exec [=value (apply-m compile-form (wrap ?value))]
- (return [?label =value])))
- ?kvs)]
- (return (into {} =kvs))))
-
-(defcompiler compile-tagged
- [::&parser/tagged ?tag ?data]
- (exec [=data (apply-m compile-form (wrap ?data))]
- (return {:tag ?tag :data =data})))
-
-(defcompiler compile-fn-call
- [::&parser/fn-call ?fn ?args]
- (exec [=fn (apply-m compile-form (wrap ?fn))
- =args (map-m (fn [arg] (apply-m compile-form (wrap arg)))
- ?args)]
- (return (reduce (fn [f a] `(~f ~a))
- =fn =args))))
-
-(defcompiler compile-if
- [::&parser/if ?test ?then ?else]
- (exec [=test (apply-m compile-form (wrap ?test))
- =then (apply-m compile-form (wrap ?then))
- =else (apply-m compile-form (wrap ?else))]
- (return `(if ~=test ~=then ~=else))))
-
-(defcompiler compile-case-branch
- [::&parser/case-branch [::&parser/tagged ?tag [::&parser/tuple ?bindings]] ?expr]
- (exec [:let [=bindings (map (comp symbol unwrap-ident) ?bindings)
- fn-env (into {} (for [a =bindings] [a nil]))]
- =expr (apply-m compile-form (wrap* fn-env ?expr))]
- (return [?tag =bindings =expr])))
-
-(defcompiler compile-let-binding
- [::&parser/let-binding [::&parser/ident ?name] ?expr]
- (exec [=expr (apply-m compile-form (wrap ?expr))]
- (return [(symbol ?name) =expr])))
-
-(defcompiler compile-case
- [::&parser/case ?variant ?branches]
- (exec [=variant (apply-m compile-form (wrap ?variant))
- =branches (map-m #(apply-m compile-case-branch (wrap %))
- ?branches)
- :let [g!variant (gensym "variant")
- =case `(let [~g!variant ~=variant]
- (case (:tag ~g!variant)
- ~@(apply concat (for [[tag bindings expr] =branches]
- [tag `(let [~(vec bindings) (:data ~g!variant)]
- ~expr)]))))
- ;; _ (prn '=case =case)
- ]]
- (return =case)))
-
-(defcompiler compile-let
- [::&parser/let ?bindings ?expr]
- (exec [=expr (apply-m compile-form (wrap ?expr))
- =bindings (map-m #(apply-m compile-let-binding (wrap %))
- ?bindings)
- :let [;; _ (prn '=bindings =bindings)
- =let (reduce (fn [inner [?name ?expr]]
- `(let [~?name ~?expr]
- ~inner))
- =expr
- =bindings)
- ;; _ (prn '=let =let)
- ]]
- (return =let)))
-
-(defcompiler compile-def
- [::&parser/def ?form ?body]
- (match ?form
- [::&parser/fn-call [::&parser/ident ?name] ?args]
- (exec [:let [=name (symbol ?name)
- =args (map (comp symbol unwrap-ident) ?args)
- fn-env (into {} (for [a =args] [a nil]))]
- =body (apply-m compile-form (wrap* fn-env ?body))
- :let [curled-body (reduce (fn [inner arg] `(fn [~arg] ~inner))
- =body (reverse =args))
- ;; _ (prn 'curled-body curled-body)
- fn-def (let [[_ ?arg ?body] curled-body]
- `(fn ~=name ~?arg ~?body))
- ;; _ (prn 'fn-def fn-def)
- ]]
- (return fn-def))
-
- [::&parser/ident ?name]
- (apply-m compile-form (wrap ?body))))
-
-(defcompiler compile-defdata
- [::&parser/defdata ?form ?cases]
- (match ?form
- [::&parser/fn-call ?name ?args]
- (let [=name (unwrap-ident ?name)
- ;; _ (prn '=name =name)
- =args (map unwrap-ident ?args)
- ;; _ (prn '=args =args)
- =cases (map unwrap-tagged ?cases)
- ;; _ (prn '=cases =cases)
- ]
- (return `(fn ~(symbol =name) ~(mapv symbol =args))))))
-
-;; (def compile-form
-;; (try-all-m [compile-int
-;; compile-float
-;; compile-ident
-;; compile-tuple
-;; compile-record
-;; compile-tagged
-;; compile-if
-;; compile-case
-;; compile-let
-;; compile-def
-;; compile-defdata
-;; compile-fn-call]))
-
-;; (defn compile [inputs]
-;; (assert false)
-;; (match ((repeat-m compile-form) inputs)
-;; [::&util/ok [?state ?forms]]
-;; (if (empty? (:forms ?state))
-;; ?forms
-;; (assert false (str "Unconsumed input: " ?state)))
-
-;; [::&util/failure ?message]
-;; (assert false ?message)))
+(defn ^:private ->class [class]
+ (string/replace class #"\." "/"))
-(def ^:dynamic *code*)
+(defn ^:private ->type-signature [class]
+ (case class
+ "Void" "V"
+ ;; else
+ (str "L" (->class class) ";")))
-(defcompiler compile-boolean
+;; [Utils/Compilers]
+(defcompiler ^:private compile-boolean
[::&parser/boolean ?boolean]
- (do (if ?boolean
- (.visitLdcInsn *code* (int 1))
- (.visitLdcInsn *code* (int 0)))
- (return nil)))
+ (if ?boolean
+ (.visitLdcInsn *writer* (int 1))
+ (.visitLdcInsn *writer* (int 0))))
-(defcompiler compile-string
+(defcompiler ^:private compile-string
[::&parser/string ?string]
- (do (doto *code*
- (.visitLdcInsn ?string))
- (return nil)))
+ (.visitLdcInsn *writer* ?string))
-(defn ->java-class [class]
- (string/replace class #"\." "/"))
-
-(defn ->java-class* [class]
- (case class
- "Void" "V"
- ;; else
- (str "L" (->java-class class) ";")))
+(defcompiler ^:private compile-ident
+ [::&parser/ident ?name]
+ (doto *writer*
+ (.visitVarInsn Opcodes/ALOAD (int 0))))
-(defn method->signature [method]
- (match method
- [::&type/fn ?args ?return]
- (str "(" (reduce str "" (map ->java-class* ?args)) ")" (->java-class* ?return))))
+(defcompiler ^:private compile-fn-call
+ [::&parser/fn-call [::&parser/ident ?fn] ?args]
+ (do (doseq [arg ?args]
+ (compile-form *writer* arg))
+ (doto *writer*
+ (.visitMethodInsn Opcodes/INVOKESTATIC "output" ?fn "(Ljava/lang/Object;)Ljava/lang/Object;"))))
-(defcompiler compile-static-access
+(defcompiler ^:private compile-static-access
[::&parser/static-access ?class ?member]
- (exec [=class (find-class ?class)
- :let [member-type (get-in =class [:fields ?member])
- ?field-class (match member-type
- [::&type/object ?field-class _]
- ?field-class)]]
- (do (doto *code*
- (.visitFieldInsn Opcodes/GETSTATIC (->java-class ?class) ?member (->java-class* ?field-class)))
- (return member-type))))
+ (doto *writer*
+ (.visitFieldInsn Opcodes/GETSTATIC (->class ?class) ?member (->type-signature "java.io.PrintStream"))))
-(defcompiler compile-dynamic-access
+(defcompiler ^:private compile-dynamic-access
[::&parser/dynamic-access ?object ?access]
- (exec [_state &util/get-state
- =object (apply-m compile-form (wrap-in _state ?object))
- :let [?oclass (match =object
- [::&type/object ?oclass _]
- ?oclass)]
- =class (find-class ?oclass)
- [method signature] (match ?access
- [::&parser/fn-call [::&parser/ident ?method] ?args]
- (exec [=args (map-m #(apply-m compile-form (wrap %))
- ?args)]
- (return [?method (method->signature (get-in =class [:methods ?method]))])))]
- (do (doto *code*
- (.visitMethodInsn Opcodes/INVOKEVIRTUAL (->java-class ?oclass) method signature))
- (return nil))))
-
-(defcompiler compile-ann-class
+ (let [=object (compile-form *writer* ?object)
+ method (match ?access
+ [::&parser/fn-call [::&parser/ident ?method] ?args]
+ (do (doseq [arg ?args]
+ (compile-form *writer* arg))
+ ?method))]
+ (doto *writer*
+ (.visitMethodInsn Opcodes/INVOKEVIRTUAL (->class "java.io.PrintStream") method "(Ljava/lang/String;)V"))))
+
+(defcompiler ^:private compile-ann-class
[::&parser/ann-class ?class ?members]
- (exec [_ (define-class ?class ?members)
- _state &util/get-state]
- (return nil)))
+ nil)
-(defcompiler compile-if
+(defcompiler ^:private compile-if
[::&parser/if ?test ?then ?else]
- (exec [_state &util/get-state
- =test (apply-m compile-form (wrap-in _state ?test))
- :let [else-label (new Label)
- end-label (new Label)]
- =then (do (doto *code*
- (.visitJumpInsn Opcodes/IFEQ else-label))
- (apply-m compile-form (wrap-in _state ?then)))
- :let [_ (doto *code*
- (.visitJumpInsn Opcodes/GOTO end-label)
- (.visitLabel else-label))]
- =else (apply-m compile-form (wrap-in _state ?else))]
- (do (doto *code*
- (.visitLabel end-label))
- (return nil))))
-
-(def compile-form
- (try-all-m [compile-boolean
- compile-string
- compile-static-access
- compile-dynamic-access
- compile-ann-class
- compile-if]))
-
+ (let [else-label (new Label)
+ end-label (new Label)]
+ (compile-form *writer* ?test)
+ (.visitJumpInsn *writer* Opcodes/IFEQ else-label)
+ (compile-form *writer* ?then)
+ (doto *writer*
+ (.visitJumpInsn Opcodes/GOTO end-label)
+ (.visitLabel else-label))
+ (compile-form *writer* ?else)
+ (.visitLabel *writer* end-label)))
+
+(defcompiler ^:private compile-def
+ [::&parser/def ?form ?body]
+ (match ?form
+ [::&parser/fn-call [::&parser/ident ?name] ?args]
+ (if (= "main" ?name)
+ (let [=method (doto (.visitMethod *writer* (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) ?name "([Ljava/lang/String;)V" nil nil)
+ (.visitCode))]
+ (compile-form =method ?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))]
+ ;; (doto =method
+ ;; (.visitFieldInsn Opcodes/GETSTATIC (->class "java.lang.System") "out" (->type-signature "java.io.PrintStream"))
+ ;; (.visitLdcInsn "IN")
+ ;; (.visitMethodInsn Opcodes/INVOKEVIRTUAL (->class "java.io.PrintStream") "println" "(Ljava/lang/String;)V"))
+ (compile-form =method ?body)
+ ;; (doto =method
+ ;; (.visitFieldInsn Opcodes/GETSTATIC (->class "java.lang.System") "out" (->type-signature "java.io.PrintStream"))
+ ;; (.visitLdcInsn "OUT")
+ ;; (.visitMethodInsn Opcodes/INVOKEVIRTUAL (->class "java.io.PrintStream") "println" "(Ljava/lang/String;)V"))
+ (doto =method
+ (.visitInsn Opcodes/ARETURN)
+ (.visitMaxs 0 0)
+ (.visitEnd))))
+ ))
+
+(let [+compilers+ [compile-boolean
+ compile-string
+ compile-ident
+ compile-fn-call
+ compile-static-access
+ compile-dynamic-access
+ compile-ann-class
+ compile-if
+ compile-def]]
+ (defn ^:private compile-form [writer form]
+ (prn 'compile-form/form form)
+ (some #(% writer form) +compilers+)))
+
+;; [Interface]
(defn compile [inputs]
- (let [cw (doto (new ClassWriter ClassWriter/COMPUTE_MAXS)
- (.visit Opcodes/V1_5 (+ Opcodes/ACC_PUBLIC Opcodes/ACC_SUPER)
- "output" nil "java/lang/Object" nil))]
- (doto (.visitMethod cw Opcodes/ACC_PUBLIC "<init>" "()V" nil nil)
+ (prn 'inputs inputs)
+ (let [=class (doto (new ClassWriter ClassWriter/COMPUTE_MAXS)
+ (.visit Opcodes/V1_5 (+ Opcodes/ACC_PUBLIC Opcodes/ACC_SUPER)
+ "output" nil "java/lang/Object" nil))]
+ (doto (.visitMethod =class Opcodes/ACC_PUBLIC "<init>" "()V" nil nil)
(.visitCode)
(.visitVarInsn Opcodes/ALOAD 0)
(.visitMethodInsn Opcodes/INVOKESPECIAL "java/lang/Object" "<init>" "()V")
(.visitInsn Opcodes/RETURN)
(.visitMaxs 0 0)
(.visitEnd))
- (let [_main_ (doto (.visitMethod cw (+ Opcodes/ACC_PUBLIC Opcodes/ACC_STATIC) "main" "([Ljava/lang/String;)V" nil nil)
- (.visitCode)
- ;; (.visitFieldInsn Opcodes/GETSTATIC "java/lang/System" "out" "Ljava/io/PrintStream;")
- ;; (.visitLdcInsn "Hello, World!")
- ;; (.visitMethodInsn Opcodes/INVOKEVIRTUAL "java/io/PrintStream" "println" "(Ljava/lang/String;)V")
- )]
- (binding [*code* _main_]
- (match ((repeat-m compile-form) inputs)
- [::&util/ok [?state ?forms]]
- (if (empty? (:forms ?state))
- ?forms
- (assert false (str "Unconsumed input: " ?state)))
-
- [::&util/failure ?message]
- (assert false ?message)))
- (doto _main_
- (.visitInsn Opcodes/RETURN)
- (.visitMaxs 0 0)
- (.visitEnd)))
- (.visitEnd cw)
- (.toByteArray cw)))
+ (doall (map (partial compile-form =class) inputs))
+ (.visitEnd =class)
+ (.toByteArray =class)))