Skip to content

Commit

Permalink
Disassociate fn arity choice from order of defined arities inline wit…
Browse files Browse the repository at this point in the history
…h clojure.
  • Loading branch information
GreshamDanielStephens committed Feb 16, 2021
1 parent 7425611 commit 4b2861a
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 9 deletions.
31 changes: 22 additions & 9 deletions src/sci/impl/fns.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,22 @@
{:sci.impl/fixed-arity fixed-arity}))
f)))

(defn lookup-by-arity [arities arity]
(some (fn [f]
(let [{:sci.impl/keys [fixed-arity min-var-args-arity]} (meta f)]
(when (or (= arity fixed-arity )
(and min-var-args-arity
(>= arity min-var-args-arity)))
f))) arities))
(defn lookup-by-arity [fixed-arities min-var-args-arity variadic-arity
arity]
(or (get fixed-arities arity)
(when (and min-var-args-arity
(>= arity min-var-args-arity))
variadic-arity)))

(defn- fixed-arities [arities]
(->> arities
(map (juxt (comp :sci.impl/fixed-arity meta) identity))
(into {})))

(defn- variadic-arity [arities]
(->> arities
(filter (comp :sci.impl/min-var-args-arity meta))
first))

(defn eval-fn [ctx interpret {:sci.impl/keys [fn-bodies fn-name
var] :as f}]
Expand All @@ -242,10 +251,14 @@
single-arity? (= 1 (count fn-bodies))
f (if single-arity?
(fun ctx interpret (first fn-bodies) fn-name macro? false)
(let [arities (map #(fun ctx interpret % fn-name macro? true) fn-bodies)]
(let [arities (map #(fun ctx interpret % fn-name macro? true) fn-bodies)
fixed-arities (fixed-arities arities)
variadic-arity (variadic-arity arities)
min-var-args-arity (:sci.impl/min-var-args-arity (meta variadic-arity))]
(fn [& args]
(let [arg-count (count args)]
(if-let [f (lookup-by-arity arities arg-count)]
(if-let [f (lookup-by-arity fixed-arities min-var-args-arity variadic-arity
arg-count)]
(apply f args)
(throw (new #?(:clj Exception
:cljs js/Error)
Expand Down
3 changes: 3 additions & 0 deletions test/sci/core_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@
(is (= 2 (eval* '((fn foo [x & [y]] y) 1 2 3))))
(is (= 1 (eval* '((fn ([x] x) ([x y] y)) 1))))
(is (= 2 (eval* '((fn ([x] x) ([x y] y)) 1 2))))
(is (= "otherwise" (eval* '((fn ([x & xs] "variadic") ([x] "otherwise")) 1))))
(is (= "otherwise" (eval* '((fn ([x] "otherwise") ([x & xs] "variadic")) 1))))
(is (= "variadic" (eval* '((fn ([x] "otherwise") ([x & xs] "variadic")) 1 2))))
(is (= '(2 3 4) (eval* '(apply (fn [x & xs] xs) 1 2 [3 4]))))
(is (thrown-with-msg? #?(:clj Exception :cljs js/Error)
#"Can't have fixed arity function with more params than variadic function"
Expand Down

0 comments on commit 4b2861a

Please sign in to comment.