What I would like to see is optional, keyword, and rest arguments. Imagine something like this:
(def foo (k v)
'type (k int)
(+ k v)) (dsb (r1 &o o1 &r rest &k k1) data ....)
If data was (1 2 'k1 3) then most params would be bound as expected and then rest would be bound to (k1 3).But now the data (1 2 'k1 3 4) causes an error "Key list is not even", ie, once you say &k you undertake certain obligations as the caller. Even if you even up the list:
(1 2 'k1 2 3 5)
...you get an error "3 is an invalid keyword", because 3 appears in a keyword position. This can be avoided by announcing your intention to have undeclared keywords: (a b &rest rest &key k1 &allow-other-keys)
That of course is CL, and it kinda makes my day that if I were crazy enough to extend dsb in Arc I would end up with: (a b &r rest &k k1 &aok)-----
Was there ever any doubt? :)
Still requiring extensions from earlier posts:
(def dsb-params-parse (params)
(withs (reqs nil key? nil opt? nil keys nil opts nil
rest (mem '&r params)
rest-var (cadr rest)
aok? (find '&aok cddr.rest)
resting? nil
no-mas nil)
(each p params
(if no-mas (assert nil "No params &aok, OK?" ',params)
(is p '&o) (do (assert ~opt? "Duplicate &o:" ',params)
(assert ~key? "&k cannot precede &o:" ',params)
(= opt? t))
(is p '&k) (do (assert ~key? "Duplicate &k:" ',params)
(= key? t))
(is p '&r) (= resting? t)
(is p '&aok) (= no-mas t)
key? (push-end p keys)
(and opt? (no resting?)) (push-end p opts)
(no resting?) (do (assert (~acons p) "Reqd parameters need not be defaulted:" p)
(push-end p reqs))))
(prt 're-obj!!!!! reqs opts rest-var keys aok?)
(obj reqs reqs opts opts rst rest-var keys keys aok? aok?)))
And man was I happy to have the above as a breakout from the macro itself: (mac dsb (params data . body)
(w/uniq (tree kvs valid-keys aok?)
`(withs (,tree ,data
,@(let plist (dsb-params-parse params)
(prn `(reqs ,plist!reqs))
(prn `(rst ,plist!rst))
(prn `(keys ,plist!keys))
(prn `(&aok ,plist!aok?))
(with (n -1)
(+ (mappend [list _ `(nth ,(++ n) ,tree)] plist!reqs)
(mappend [list (carif _) `(if (< ,(++ n) (len ,tree))
(nth ,n ,tree)
,(cadrif _))] plist!opts)
`(,plist!rst (nthcdr ,(++ n) ,tree))
`(,valid-keys ',plist!keys)
`(,aok? ',plist!aok?)
`(,kvs (do (prt 'foing ,valid-keys)
(when (and ,plist!rst ,valid-keys)
(assert (even (len ,plist!rst)) "Keyword list not even" ,plist!rst)
(let ,kvs (pair ,plist!rst)
(prt 'vetting ,valid-keys 'againt ,kvs)
(unless ,aok?
(assert (all [find (car _) ,valid-keys] ,kvs)
"Invalid key in" (map car ,kvs)))
(prt 'kvs!!!!! ,kvs)
,kvs))))
(mappend [list (carif _)
`(do (prt 'kvs!!! ',(carif _) ,kvs)
(aif (assoc ',(carif _) ,kvs)
cadr.it
,(cadrif _)))] plist!keys)))))
,@body)))
What is missing (largely) is graceful handling of invalid use.-----
Lock and load! Add the keywords!! :)
-----