Created
September 4, 2015 03:14
-
-
Save mkremins/41fe6db467c5bd3ce334 to your computer and use it in GitHub Desktop.
Parse arglists for fn-like forms
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(def valid-name? | |
"Returns truthy if argument is a non-namespaced symbol." | |
(every-pred symbol? (complement namespace))) | |
(defn parse-arglist | |
"Given an `arglist` (a vector of parameter names for a function method), | |
returns a map of information about the method. May throw an exception if | |
`arglist` cannot be parsed." | |
[arglist] | |
(assert (every? valid-name? arglist) | |
"All parameter names must be non-namespaced symbols.") | |
(let [variadic? (= (last (butlast arglist)) '&) | |
fixed-args (cond->> arglist variadic? (drop-last 2))] | |
{:fixed-args fixed-args | |
:fixed-arity (count fixed-args) | |
:rest-arg (when variadic? (last arglist)) | |
:variadic? variadic?})) | |
(defn arity-info | |
"Given a seq of `arglists` (maps of information obtained via `parse-arglist` | |
about methods of a particular function), returns a map of information about | |
the function itself. May throw an exception if two or more `arglists` are | |
mutually incompatible and therefore cannot coexist on the same function." | |
[arglists] | |
(assert (apply distinct? (map (juxt :fixed-arity :variadic?) arglists)) | |
"No two methods of a single function may share the same arity.") | |
(let [max-fixed-arity (apply max (map :fixed-arity arglists)) | |
[variadic-arglist & more] (filter :variadic? arglists)] | |
(assert (empty? more) | |
"A function may have at most one variadic method.") | |
(assert (= (:fixed-arity variadic-arglist) max-fixed-arity) | |
(str "A variadic method may not take fewer parameters than a " | |
"fixed-arity method of the same function.")) | |
{:arglists arglists | |
:fixed-arities (set (map :fixed-arity arglists)) | |
:max-fixed-arity max-fixed-arity | |
:variadic? (boolean variadic-arglist)})) | |
(defn valid-invoke-arity? | |
"Returns truthy if it is acceptable to invoke `f` with `argc` arguments." | |
[f argc] | |
(or (contains? (:fixed-arities f) argc) | |
(and (:variadic? f) (> argc (:max-fixed-arity f))))) | |
(defn take-when [pred [x & xs :as coll]] | |
(if (pred x) [x xs] [nil coll])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment