Skip to content

Instantly share code, notes, and snippets.

@mkremins
Created September 4, 2015 03:14
Show Gist options
  • Save mkremins/41fe6db467c5bd3ce334 to your computer and use it in GitHub Desktop.
Save mkremins/41fe6db467c5bd3ce334 to your computer and use it in GitHub Desktop.
Parse arglists for fn-like forms
(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