aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEduardo Julian2015-01-11 13:37:34 -0400
committerEduardo Julian2015-01-11 13:37:34 -0400
commitcda3a2d7ddf375dff83132351ff406f5d5cb8db8 (patch)
treeb925f51b3f505923767f1e617253e3a9aacb771e /src
parent9e39423ab1eec0486e752bfdd06e34a64b6cfdd8 (diff)
- Compiler now handles automatic partial applications and calls to statically-known functions (global ones) better.
Diffstat (limited to '')
-rw-r--r--src/lux/analyser.clj62
-rw-r--r--src/lux/compiler.clj63
2 files changed, 74 insertions, 51 deletions
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
@@ -180,34 +180,42 @@
(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 "<init>" 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>" 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