(defpsmacro chain (&rest method-calls)
(labels ((do-chain (method-calls)
(if (cdr method-calls)
- `((@ ,(do-chain (cdr method-calls)) ,(caar method-calls)) ,@(cdar method-calls))
+ (if (listp (car method-calls))
+ `((@ ,(do-chain (cdr method-calls)) ,(caar method-calls)) ,@(cdar method-calls))
+ `(@ ,(do-chain (cdr method-calls)) ,(car method-calls)))
(car method-calls))))
(do-chain (reverse method-calls))))
(defpsmacro append (arr1 &rest arrs)
(if arrs
- `((@ ,arr1 :concat) ,@arrs)
+ `((@ ,arr1 concat) ,@arrs)
arr1))
(defpsmacro apply (fn &rest args)
(let ((arglist (if (> (length args) 1)
`(append (list ,@(butlast args)) ,(car (last args)))
(first args))))
- `((@ ,fn :apply) this ,arglist)))
-
-(defpsmacro destructuring-bind (vars expr &body body)
- ;; a simple implementation that for now only supports flat lists,
- ;; but does allow NIL bindings to indicate ignore (a la LOOP)
+ `((@ ,fn apply) this ,arglist)))
+
+(defun destructuring-wrap (arr n bindings body &key setf?)
+ (flet ((bind-rest (sym)
+ `(let ((,sym (when (> (length ,arr) ,n)
+ ((@ ,arr slice) ,n))))
+ ,body)))
+ (cond ((null bindings)
+ body)
+ ((atom bindings) ;; dotted destructuring list
+ (bind-rest bindings))
+ ((eq (car bindings) '&rest)
+ (if (and (= (length bindings) 2)
+ (atom (second bindings)))
+ (bind-rest (second bindings))
+ (error "~a is invalid in destructuring list." bindings)))
+ ((eq (car bindings) '&optional)
+ (destructuring-wrap arr n (cdr bindings) body :setf? setf?))
+ (t (let ((var (car bindings))
+ (inner-body (destructuring-wrap arr (1+ n) (cdr bindings) body :setf? setf?)))
+ (cond ((null var) inner-body)
+ ((atom var) (if setf?
+ `(progn (setf ,var (aref ,arr ,n))
+ ,inner-body)
+ `(let ((,var (aref ,arr ,n)))
+ ,inner-body)))
+ (t `(,(if setf? 'dset 'destructuring-bind)
+ ,var (aref ,arr ,n)
+ ,inner-body))))))))
+
+(defpsmacro dset (bindings expr &body body)
+ (let ((arr (if (complex-js-expr? expr) (ps-gensym) expr)))
+ `(progn
+ ,@(unless (eq arr expr) `((setf ,arr ,expr)))
+ ,(destructuring-wrap arr 0 bindings (cons 'progn body) :setf? t))))
+
+(defpsmacro destructuring-bind (bindings expr &body body)
(let* ((arr (if (complex-js-expr? expr) (ps-gensym) expr))
- (n -1)
- (bindings
- (append (unless (equal arr expr) `((,arr ,expr)))
- (mapcan (lambda (var)
- (incf n)
- (when var `((,var (aref ,arr ,n))))) vars))))
- `(let* ,bindings ,@body)))
+ (bound (destructuring-wrap arr 0 bindings (cons 'progn body))))
+ (if (eq arr expr)
+ bound
+ `(let ((,arr ,expr)) ,bound))))