From cda3a2d7ddf375dff83132351ff406f5d5cb8db8 Mon Sep 17 00:00:00 2001 From: Eduardo Julian Date: Sun, 11 Jan 2015 13:37:34 -0400 Subject: - Compiler now handles automatic partial applications and calls to statically-known functions (global ones) better. --- src/lux/analyser.clj | 62 +++++++++++++++++++++++++++++++-------------------- src/lux/compiler.clj | 63 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 74 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/lux/analyser.clj b/src/lux/analyser.clj index f45ed4c2d..7cea2ef5c 100644 --- a/src/lux/analyser.clj +++ b/src/lux/analyser.clj @@ -37,6 +37,13 @@ (assoc-in [:defs-env name] (annotated [::global (:name state) name] (:type desc)))) nil]])) +(defn ^:private define-fn [name desc] + (fn [state] + [::&util/ok [(-> state + (assoc-in [:defs (:name state) name] desc) + (assoc-in [:defs-env name] (annotated [::global-fn (:name state) name] (:type desc)))) + nil]])) + (defn ^:private is-macro? [name] (fn [state] ;; (prn 'is-macro? (nth name 1) @@ -453,24 +460,31 @@ (defanalyser analyse-fn-call [::&parser/fn-call ?fn ?args] - (exec [;; :let [_ (prn 'PRE '?fn ?fn)] - macro? (is-macro? ?fn) - scoped? (in-scope? ?fn) - :let [;; _ (prn 'macro? ?fn macro?) - ;; _ (prn 'scoped? scoped?) - ] - =fn (analyse-form* ?fn) - ;; :let [_ (prn '=fn =fn)] - ;; :let [_ (prn '=args =args)] - ] - (if (and macro? (not scoped?)) - (do ;; (prn "MACRO CALL!" ?fn ?args =fn) - (let [macro (match (:form =fn) - [::global ?module ?name] - (.newInstance (.loadClass loader (str ?module "$" (normalize-ident ?name))))) - output (->clojure-token (.apply macro (->tokens ?args)))] - ;; (prn "MACRO CALL!" macro output) - (analyse-form* output))) + (exec [=fn (analyse-form* ?fn)] + (match (:form =fn) + [::global-fn ?module ?name] + (exec [macro? (is-macro? ?fn) + scoped? (in-scope? ?fn)] + (if (and macro? (not scoped?)) + (let [macro-class (str ?module "$" (normalize-ident ?name))] + (-> (.loadClass loader macro-class) + .newInstance + (.apply (->tokens ?args)) + ->clojure-token + analyse-form*)) + (exec [=args (map-m analyse-form* ?args) + :let [[needs-num =return-type] (match (:type =fn) + [::&type/function ?fargs ?freturn] + (let [needs-num (count ?fargs) + provides-num (count =args)] + (if (> needs-num provides-num) + [needs-num [::&type/function (drop provides-num ?fargs) ?freturn]] + [needs-num [::&type/object "java.lang.Object" []]]))) + ;; _ (prn '[needs-num =return-type] [needs-num =return-type]) + ]] + (return (annotated [::static-call needs-num =fn =args] =return-type))))) + + _ (exec [=args (map-m analyse-form* ?args)] (return (annotated [::call =fn =args] [::&type/object "java.lang.Object" []])))) )) @@ -709,9 +723,9 @@ =function (within :types (exec [_ (&type/solve =return (:type =value))] (&type/clean =function))) ;; :let [_ (prn '=function =function)] - _ (define ?name {:mode ::function - :access ::public - :type =function})] + _ (define-fn ?name {:mode ::function + :access ::public + :type =function})] (return (annotated [::def [?name args] =value] ::&type/nothing)))) )) @@ -724,9 +738,9 @@ (analyse-form* ?value)))) =function (within :types (exec [_ (&type/solve =return (:type =value))] (&type/clean =function))) - _ (define ?name {:mode ::macro - :access ::public - :type =function})] + _ (define-fn ?name {:mode ::macro + :access ::public + :type =function})] (return (annotated [::def [?name (list ?tokens)] =value] ::&type/nothing)))) (defanalyser analyse-lambda diff --git a/src/lux/compiler.clj b/src/lux/compiler.clj index c95beeb7f..e91e10f77 100644 --- a/src/lux/compiler.clj +++ b/src/lux/compiler.clj @@ -179,35 +179,43 @@ (defcompiler ^:private compile-call [::&analyser/call ?fn ?args] + (do ;; (prn 'compile-call (:form ?fn) ?fn ?args) + (do (compile-form (assoc *state* :form ?fn)) + (let [apply-signature "(Ljava/lang/Object;)Ljava/lang/Object;"] + (doseq [arg ?args] + (compile-form (assoc *state* :form arg)) + (.visitMethodInsn *writer* Opcodes/INVOKEINTERFACE "test2/Function" "apply" apply-signature)))))) + +(defcompiler ^:private compile-static-call + [::&analyser/static-call ?needs-num ?fn ?args] (do ;; (prn 'compile-call (:form ?fn) ?fn ?args) (match (:form ?fn) - [::&analyser/global ?owner-class ?fn-name] - (let [apply-signature "(Ljava/lang/Object;)Ljava/lang/Object;" - clo-field-sig (->type-signature "java.lang.Object") - counter-sig "I" - num-args (count ?args) - signature (if (> (count ?args) 1) - (str "(" (apply str counter-sig (repeat (dec num-args) clo-field-sig)) ")" "V") - (str "()" "V")) - call-class (str (->class ?owner-class) "$" (normalize-ident ?fn-name))] - (doto *writer* - (.visitTypeInsn Opcodes/NEW call-class) - (.visitInsn Opcodes/DUP) - (-> (doto (.visitLdcInsn (-> ?args count dec int)) - ;; (.visitInsn Opcodes/ICONST_0) - (-> (do (compile-form (assoc *state* :form arg))) - (->> (doseq [arg (butlast ?args)])))) - (->> (when (> (count ?args) 1)))) - (.visitMethodInsn Opcodes/INVOKESPECIAL call-class "" signature) - (do (compile-form (assoc *state* :form (last ?args)))) - (.visitMethodInsn Opcodes/INVOKEINTERFACE "test2/Function" "apply" apply-signature))) - - _ - (do (compile-form (assoc *state* :form ?fn)) - (let [apply-signature "(Ljava/lang/Object;)Ljava/lang/Object;"] - (doseq [arg ?args] - (compile-form (assoc *state* :form arg)) - (.visitMethodInsn *writer* Opcodes/INVOKEINTERFACE "test2/Function" "apply" apply-signature)))) + [::&analyser/global-fn ?owner-class ?fn-name] + (let [arg-sig (->type-signature "java.lang.Object") + call-class (str (->class ?owner-class) "$" (normalize-ident ?fn-name)) + provides-num (count ?args)] + (if (>= provides-num ?needs-num) + (let [apply-signature "(Ljava/lang/Object;)Ljava/lang/Object;" + impl-sig (str "(" (reduce str "" (repeat ?needs-num arg-sig)) ")" arg-sig)] + (doto *writer* + (-> (do (compile-form (assoc *state* :form arg))) + (->> (doseq [arg (take ?needs-num ?args)]))) + (.visitMethodInsn Opcodes/INVOKESTATIC call-class "impl" impl-sig) + (-> (doto (do (compile-form (assoc *state* :form arg))) + (.visitMethodInsn Opcodes/INVOKEINTERFACE "test2/Function" "apply" apply-signature)) + (->> (doseq [arg (drop ?needs-num ?args)]))))) + (let [counter-sig "I" + init-signature (str "(" (apply str counter-sig (repeat (dec ?needs-num) arg-sig)) ")" "V")] + (doto *writer* + (.visitTypeInsn Opcodes/NEW call-class) + (.visitInsn Opcodes/DUP) + (.visitLdcInsn (int provides-num)) + (-> (do (compile-form (assoc *state* :form arg))) + (->> (doseq [arg ?args]))) + (-> (.visitInsn Opcodes/ACONST_NULL) + (->> (dotimes [_ (dec (- ?needs-num provides-num))]))) + (.visitMethodInsn Opcodes/INVOKESPECIAL call-class "" init-signature))) + )) ))) (defcompiler ^:private compile-static-field @@ -907,6 +915,7 @@ compile-local compile-captured compile-global + compile-static-call compile-call compile-static-field compile-dynamic-field -- cgit v1.2.3