1 (in-package "PARENSCRIPT")
3 (define-ps-symbol-macro f js
:f
)
4 (define-ps-symbol-macro false js
:f
)
6 (macrolet ((define-trivial-mappings (&rest mappings
)
8 ,@(loop for
(macro-name ps-op
) on mappings by
#'cddr collect
9 `(defpsmacro ,macro-name
(&rest args
)
10 (cons ',ps-op args
))))))
11 (define-trivial-mappings
19 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
22 (defpsmacro values
(&optional main
&rest additional
)
25 (with-ps-gensyms (val1 valrest
)
27 (,valrest
(list ,@additional
)))
28 (when (defined (@ arguments
:callee
:caller
:mv
))
29 (setf (@ arguments
:callee
:caller
:mv
) ,valrest
))
33 (defpsmacro multiple-value-bind
(vars expr
&body body
)
34 (let ((expr (ps-macroexpand expr
)))
35 (if (and (consp expr
) (implicit-progn-form? expr
))
37 (multiple-value-bind ,vars
40 (with-ps-gensyms (mv prev-mv
)
41 `(let ((,prev-mv
(@ arguments
:callee
:mv
)))
44 (setf (@ arguments
:callee
:mv
) t
)
45 (let ((,(car vars
) ,expr
)
46 (,mv
(if (objectp (@ arguments
:callee
:mv
))
47 (@ arguments
:callee
:mv
)
48 (make-array ,(1- (length vars
))))))
49 (destructuring-bind ,(cdr vars
) ,mv
51 (:finally
(if (undefined ,prev-mv
)
52 (delete (@ arguments
:callee
:mv
))
53 (setf (@ arguments
:callee
:mv
) ,prev-mv
)))))))))
55 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
58 (defpsmacro case
(value &rest clauses
)
59 (labels ((make-clause (val body more
)
60 (cond ((and (listp val
) (not (eq (car val
) 'quote
)))
61 (append (mapcar #'list
(butlast val
))
62 (make-clause (first (last val
)) body more
)))
63 ((member val
'(t otherwise
))
64 (make-clause 'default body more
))
65 (more `((,val
,@body break
)))
66 (t `((,val
,@body
))))))
67 `(switch ,value
,@(mapcon (lambda (clause)
68 (make-clause (car (first clause
))
73 (defpsmacro when
(test &rest body
)
77 (defpsmacro unless
(test &rest body
)
81 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
82 ;;; function definition
84 (defpsmacro defun
(name lambda-list
&body body
)
85 "An extended defun macro that allows cool things like keyword arguments.
88 [&optional {var | (var [init-form [supplied-p-parameter]])}*]
90 [&key {var | ({var | (keyword-name var)} [init-form [supplied-p-parameter]])}* [&allow-other-keys]]
91 [&aux {var | (var [init-form])}*])"
93 `(defun-function ,name
,lambda-list
,@body
)
94 (progn (assert (and (listp name
) (= (length name
) 2) (eq 'setf
(car name
))) ()
95 "(defun ~s ~s ...) needs to have a symbol or (setf symbol) for a name." name lambda-list
)
96 `(defun-setf ,name
,lambda-list
,@body
))))
98 (defpsmacro defun-function
(name lambda-list
&body body
)
99 (multiple-value-bind (effective-args effective-body
)
100 (parse-extended-function lambda-list body
)
101 `(%js-defun
,name
,effective-args
104 (defpsmacro lambda
(lambda-list &body body
)
105 "An extended defun macro that allows cool things like keyword arguments.
108 [&optional {var | (var [init-form [supplied-p-parameter]])}*]
110 [&key {var | ({var | (keyword-name var)} [init-form [supplied-p-parameter]])}* [&allow-other-keys]]
111 [&aux {var | (var [init-form])}*])"
112 (multiple-value-bind (effective-args effective-body
)
113 (parse-extended-function lambda-list body
)
114 `(%js-lambda
,effective-args
117 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
118 ;;; defining setf expanders
120 (defvar *defun-setf-name-prefix
* "__setf_")
122 (defpsmacro defun-setf
(setf-name lambda-list
&body body
)
123 (let ((mangled-function-name
124 (intern (concatenate 'string
*defun-setf-name-prefix
*
125 (symbol-name (second setf-name
)))
126 (symbol-package (second setf-name
)))))
127 (setf (gethash (second setf-name
) *ps-setf-expanders
*)
130 (lambda (access-args store-form
)
131 `(,mangled-function-name
,store-form
,@access-args
))))
132 `(defun ,mangled-function-name
,lambda-list
,@body
)))
134 ;;; slightly broken WRT lambda lists
135 (defpsmacro defsetf-long
(access-fn lambda-list
(store-var) form
)
136 (setf (gethash access-fn
*ps-setf-expanders
*)
139 (let ((var-bindings (ordered-set-difference lambda-list
140 lambda-list-keywords
)))
141 `(lambda (access-fn-args store-form
)
142 (destructuring-bind ,lambda-list
144 (let* ((,store-var
(ps-gensym))
145 (gensymed-names (loop repeat
,(length var-bindings
)
146 collecting
(ps-gensym)))
147 (gensymed-arg-bindings (mapcar #'list
149 (list ,@var-bindings
))))
150 (destructuring-bind ,var-bindings
152 `(let* (,@gensymed-arg-bindings
153 (,,store-var
,store-form
))
157 (defpsmacro defsetf-short
(access-fn update-fn
&optional docstring
)
158 (declare (ignore docstring
))
159 (setf (gethash access-fn
*ps-setf-expanders
*)
160 (lambda (access-fn-args store-form
)
161 `(,update-fn
,@access-fn-args
,store-form
)))
164 (defpsmacro defsetf
(access-fn &rest args
)
165 `(,(if (= (length args
) 3) 'defsetf-long
'defsetf-short
) ,access-fn
,@args
))
167 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
170 (defpsmacro setf
(&rest args
)
171 (assert (evenp (length args
)) ()
172 "~s does not have an even number of arguments." `(setf ,args
))
173 `(progn ,@(loop for
(place value
) on args by
#'cddr collect
174 (aif (and (listp place
)
175 (gethash (car place
) *ps-setf-expanders
*))
176 (funcall it
(cdr place
) value
)
177 `(ps-assign ,place
,value
)))))
179 (defpsmacro psetf
(&rest args
)
180 (let ((places (loop for x in args by
#'cddr collect x
))
181 (vals (loop for x in
(cdr args
) by
#'cddr collect x
)))
182 (let ((gensyms (loop repeat
(length places
) collect
(ps-gensym))))
183 `(let ,(mapcar #'list gensyms vals
)
184 (setf ,@(mapcan #'list places gensyms
))))))
186 (defun check-setq-args (args)
187 (let ((vars (loop for x in args by
#'cddr collect x
)))
188 (let ((non-var (find-if (complement #'symbolp
) vars
)))
190 (error 'type-error
:datum non-var
:expected-type
'symbol
)))))
192 (defpsmacro setq
(&rest args
)
193 (check-setq-args args
)
196 (defpsmacro psetq
(&rest args
)
197 (check-setq-args args
)
200 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
203 (defpsmacro for
(init-forms cond-forms step-forms
&body body
)
204 `(labeled-for nil
,init-forms
,cond-forms
,step-forms
,@body
))
206 (defun do-make-let-bindings (decls)
215 (defun do-make-init-vars (decls)
222 (defun do-make-init-vals (decls)
224 (if (or (atom x
) (endp (cdr x
)))
229 (defun do-make-for-vars/init
(decls)
236 (defun do-make-for-steps (decls)
238 `(setf ,(first x
) ,(third x
)))
239 (remove-if (lambda (x)
240 (or (atom x
) (< (length x
) 3)))
243 (defun do-make-iter-psteps (decls)
245 ,@(mapcan (lambda (x)
246 (list (first x
) (third x
)))
247 (remove-if (lambda (x)
248 (or (atom x
) (< (length x
) 3)))
251 (defpsmacro do
* (decls (termination &optional
(result nil result?
)) &body body
)
254 (for ,(do-make-for-vars/init decls
) ((not ,termination
)) ,(do-make-for-steps decls
)
257 `(for ,(do-make-for-vars/init decls
) ((not ,termination
)) ,(do-make-for-steps decls
)
260 (defpsmacro do
(decls (termination &optional
(result nil result?
)) &body body
)
262 `((lambda ,(do-make-init-vars decls
)
263 (for () ((not ,termination
)) ()
265 ,(do-make-iter-psteps decls
))
267 ,@(do-make-init-vals decls
))
268 `(let ,(do-make-let-bindings decls
)
269 (for () ((not ,termination
)) ()
271 ,(do-make-iter-psteps decls
)))))
273 (defpsmacro dotimes
((var count
&optional
(result nil result?
)) &rest body
)
274 `(do* ((,var
0 (1+ ,var
)))
275 ((>= ,var
,count
) ,@(when result?
(list result
)))
278 (defpsmacro dolist
((var array
&optional
(result nil result?
)) &body body
)
279 (let* ((idx (ps-gensym "_js_idx"))
280 (introduce-array-var?
(not (symbolp array
)))
281 (arrvar (if introduce-array-var?
282 (ps-gensym "_js_arrvar")
285 ,@(when introduce-array-var?
286 (list (list arrvar array
)))
288 ((>= ,idx
(getprop ,arrvar
'length
))
289 ,@(when result?
(list result
)))
290 (setq ,var
(aref ,arrvar
,idx
))
293 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
296 (defpsmacro make-array
(&rest initial-values
)
297 `(new (*array
,@initial-values
)))
299 (defpsmacro funcall
(&rest arg-form
)
302 (defpsmacro defvar
(name &optional
303 (value (values) value-provided?
)
305 ;; this must be used as a top-level form, otherwise the resulting
306 ;; behavior will be undefined.
307 (declare (ignore documentation
))
308 (pushnew name
*ps-special-variables
*)
309 `(var ,name
,@(when value-provided?
(list value
))))
311 (defpsmacro let
* (bindings &body body
)
313 `(let (,(car bindings
))
314 (let* ,(cdr bindings
)
318 (defpsmacro getprop
(obj &rest slots
)
319 (if (null (rest slots
))
320 `(%js-getprop
,obj
,(first slots
))
321 `(getprop (getprop ,obj
,(first slots
)) ,@(rest slots
))))
323 (defpsmacro with-slots
(slots object
&rest body
)
324 (flet ((slot-var (slot)
332 `(symbol-macrolet ,(mapcar (lambda (slot)
333 `(,(slot-var slot
) (getprop ,object
',(slot-symbol slot
))))