summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--stdlib/keyparams.tl55
-rw-r--r--tests/011/keyparams.tl38
2 files changed, 59 insertions, 34 deletions
diff --git a/stdlib/keyparams.tl b/stdlib/keyparams.tl
index eaaebc6c..6e161643 100644
--- a/stdlib/keyparams.tl
+++ b/stdlib/keyparams.tl
@@ -24,28 +24,23 @@
;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
;; POSSIBILITY OF SUCH DAMAGE.
-(defun sys:extract-keys (keys args)
- (build
- (each ((k keys))
- (iflet ((f (memp (car k) args)))
- (add (cadr f))
- (add (cdr k))))))
-(defun sys:extract-keys-p (keys args)
- (build
- (each ((k keys))
- (add (if (memp k args) t)))))
-
-(defun sys:build-key-list-expr (key-params menv)
- (let ((exprs (collect-each ((kp key-params))
- (let ((kw (intern (symbol-name (first kp)) 'keyword))
- (ex (second kp)))
- (if (constantp ex menv)
- ^(quote (,kw . ,(second kp)))
- ^(cons ,kw ,(second kp)))))))
- (if [all exprs (op eq 'quote) car]
- ^(quote ,[mapcar cadr exprs])
- ^(list ,*exprs))))
+(defun sys:stuff-key-params (keys args)
+ (with-gensyms (cell)
+ (collect-each ((k keys))
+ (tree-bind (sym : init sym-p) k
+ (let ((kw (intern (symbol-name sym) :keyword)))
+ ^(let ((,cell (memp ,kw ,args)))
+ ,(if init
+ ^(cond
+ (,cell
+ (set ,sym (cadr ,cell))
+ ,*(if sym-p ^((set ,sym-p t))))
+ (t
+ (set ,sym ,init)))
+ ^(when ,cell
+ (set ,sym (cadr ,cell))
+ ,*(if sym-p ^((set ,sym-p t)))))))))))
(define-param-expander :key (param body menv form)
(let* ((excluding-rest (butlastn 0 param))
@@ -74,17 +69,9 @@
(compile-error form "invalid dotted form ~s" key-spec))
(unless (bindable sym)
(compile-error form "~s isn't a bindable symbol" sym)))))
- (let* ((key-params-p [keep-if third key-params])
- (key-vars [mapcar first key-params])
- (key-vars-p [mapcar third key-params-p])
- (keys (sys:build-key-list-expr key-params menv))
- (keys-p (mapcar (op intern (symbol-name (first @1)) 'keyword)
- key-params-p)))
+ (let* ((key-syms [mapcar first key-params])
+ (key-syms-p (remq nil [mapcar third key-params])))
(list eff-param
- ^(tree-bind ,key-vars
- (sys:extract-keys ,keys ,rest-param)
- ,*(if keys-p
- ^((tree-bind ,key-vars-p
- (sys:extract-keys-p ',keys-p ,rest-param)
- ,*body))
- body))))))
+ ^(let (,*key-syms ,*key-syms-p)
+ ,*(sys:stuff-key-params key-params rest-param)
+ ,*body)))))
diff --git a/tests/011/keyparams.tl b/tests/011/keyparams.tl
new file mode 100644
index 00000000..e2f8baf2
--- /dev/null
+++ b/tests/011/keyparams.tl
@@ -0,0 +1,38 @@
+(load "../common")
+
+(defvarl v :v)
+(defsymacro u (identity :u))
+
+(mtest
+ [(lambda (:key))] nil
+ [(lambda (:key a))] :error
+ [(lambda (:key a) a) 1] 1)
+
+(mtest
+ [(lambda (:key -- (a v)) a)] :v
+ [(lambda (:key -- (a 'v)) a)] v
+ [(lambda (:key -- (a v a-p)) (list a a-p))] (:v nil)
+ [(lambda (:key -- (a 'v a-p)) (list a a-p))] (v nil))
+
+(mtest
+ [(lambda (:key -- (a v)) a) :a 1] 1
+ [(lambda (:key -- (a 'v)) a) :a 1] 1
+ [(lambda (:key -- (a v a-p)) (list a a-p)) :a 1] (1 t)
+ [(lambda (:key -- (a 'v a-p)) (list a a-p)) :a 1] (1 t))
+
+(mtest
+ [(lambda (:key -- (a v) (b u)) (list a b)) :a 1] (1 :u)
+ [(lambda (:key -- (a 'v) (b 'u)) (list a b)) :b 1] (v 1)
+ [(lambda (:key -- (a v a-p) (b u b-p)) (list a a-p b b-p)) :a 1] (1 t :u nil)
+ [(lambda (:key -- (a v a-p) (b u b-p)) (list a a-p b b-p)) :b 1] (:v nil 1 t))
+
+(test
+ [(lambda (:key -- (a v) . r) (list a r)) :a 1] (1 (:a 1)))
+
+(defun key-place (:key -- x y (s nil s-p)) ^(,x ,y ,s ,s-p))
+
+(defset key-place (:key -- x y) s
+ ^(key-place :x ,x :y ,y :s ,s))
+
+(test
+ (set (key-place :x 3 :y 4) 42) (3 4 42 t))