1 (in-package :parenscript
)
4 (defmethod js-equal ((obj1 list
) (obj2 list
))
5 (and (= (length obj1
) (length obj2
))
6 (every #'js-equal obj1 obj2
)))
8 (defmethod js-equal ((obj1 t
) (obj2 t
))
11 (defmacro defjsclass
(name superclasses slots
&rest class-options
)
12 (let ((slot-names (mapcar #'(lambda (slot) (if (atom slot
) slot
(first slot
))) slots
)))
14 (defclass ,name
,superclasses
15 ,slots
,@class-options
)
16 (defmethod js-equal ((obj1 ,name
) (obj2 ,name
))
17 (every #'(lambda (slot)
18 (js-equal (slot-value obj1 slot
)
19 (slot-value obj2 slot
)))
23 (defclass statement
()
24 ((value :initarg
:value
:accessor value
:initform nil
))
25 (:documentation
"A Javascript entity without a value."))
27 (defclass expression
(statement)
29 (:documentation
"A Javascript entity with a value."))
32 (defjsclass array-literal
(expression)
33 ((values :initarg
:values
:accessor array-values
)))
35 (defjsclass js-aref
(expression)
36 ((array :initarg
:array
38 (index :initarg
:index
39 :accessor aref-index
)))
41 ;;; object literals (maps and hash-tables)
42 (defjsclass object-literal
(expression)
43 ((values :initarg
:values
:accessor object-values
)))
46 (defjsclass string-literal
(expression)
51 (defjsclass number-literal
(expression)
55 (defjsclass js-variable
(expression)
59 (defjsclass js-quote
(expression)
63 (defjsclass op-form
(expression)
64 ((operator :initarg
:operator
:accessor operator
)
65 (args :initarg
:args
:accessor op-args
)))
67 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
69 (defparameter *op-precedence-hash
* (make-hash-table :test
#'equal
))
71 ;;; generate the operator precedences from *OP-PRECEDENCES*
89 (setf *= /= %
= += -
= <<= >>= >>>= \
&= ^
= \|
=)
92 (let ((op-name (symbol-name op
)))
93 (setf (gethash op-name
*op-precedence-hash
*) precedence
)))
96 (defun op-precedence (op)
97 (gethash (if (symbolp op
)
100 *op-precedence-hash
*)))
102 (defjsclass one-op
(expression)
103 ((pre-p :initarg
:pre-p
105 :accessor one-op-pre-p
)
110 (defjsclass function-call
(expression)
111 ((function :initarg
:function
:accessor f-function
)
112 (args :initarg
:args
:accessor f-args
)))
114 (defjsclass method-call
(expression)
115 ((method :initarg
:method
:accessor m-method
)
116 (object :initarg
:object
:accessor m-object
)
117 (args :initarg
:args
:accessor m-args
)))
120 (defjsclass js-body
(expression)
121 ((stmts :initarg
:stmts
:accessor b-stmts
)
122 (indent :initarg
:indent
:initform
"" :accessor b-indent
)))
124 (defmethod initialize-instance :after
((body js-body
) &rest initargs
)
125 (declare (ignore initargs
))
126 (let* ((stmts (b-stmts body
))
128 (last-stmt (car last
)))
129 (when (typep last-stmt
'js-body
)
131 (nconc (butlast stmts
)
132 (b-stmts last-stmt
))))))
134 (defjsclass js-sub-body
(js-body)
137 ;;; function definition
138 (defjsclass js-lambda
(expression)
139 ((args :initarg
:args
:accessor lambda-args
)
140 (body :initarg
:body
:accessor lambda-body
)))
142 (defjsclass js-defun
(js-lambda)
143 ((name :initarg
:name
:accessor defun-name
)))
146 (defjsclass js-object
(expression)
147 ((slots :initarg
:slots
150 (defjsclass js-slot-value
(expression)
151 ((object :initarg
:object
157 (defjsclass js-cond
(expression)
158 ((tests :initarg
:tests
159 :accessor cond-tests
)
160 (bodies :initarg
:bodies
161 :accessor cond-bodies
)))
163 (defjsclass js-if
(expression)
164 ((test :initarg
:test
171 (defmethod initialize-instance :after
((if js-if
) &rest initargs
)
172 (declare (ignore initargs
))
173 (when (and (if-then if
)
174 (typep (if-then if
) 'js-sub-body
))
175 (change-class (if-then if
) 'js-body
))
176 (when (and (if-else if
)
177 (typep (if-else if
) 'js-sub-body
))
178 (change-class (if-else if
) 'js-body
)))
181 (defjsclass js-switch
(statement)
182 ((value :initarg
:value
:accessor case-value
)
183 (clauses :initarg
:clauses
:accessor case-clauses
)))
187 (defjsclass js-setf
(expression)
188 ((lhs :initarg
:lhs
:accessor setf-lhs
)
189 (rhsides :initarg
:rhsides
:accessor setf-rhsides
)))
192 (defjsclass js-defvar
(statement)
193 ((names :initarg
:names
:accessor var-names
)
194 (value :initarg
:value
:accessor var-value
)))
197 (defjsclass js-for
(statement)
198 ((vars :initarg
:vars
:accessor for-vars
)
199 (steps :initarg
:steps
:accessor for-steps
)
200 (check :initarg
:check
:accessor for-check
)
201 (body :initarg
:body
:accessor for-body
)))
203 (defjsclass for-each
(statement)
204 ((name :initarg
:name
:accessor fe-name
)
205 (value :initarg
:value
:accessor fe-value
)
206 (body :initarg
:body
:accessor fe-body
)))
208 (defjsclass js-while
(statement)
209 ((check :initarg
:check
:accessor while-check
)
210 (body :initarg
:body
:accessor while-body
)))
213 (defjsclass js-with
(statement)
214 ((obj :initarg
:obj
:accessor with-obj
)
215 (body :initarg
:body
:accessor with-body
)))
218 (defjsclass js-try
(statement)
219 ((body :initarg
:body
:accessor try-body
)
220 (catch :initarg
:catch
:accessor try-catch
)
221 (finally :initarg
:finally
:accessor try-finally
)))
223 ;;; regular expressions
224 (defjsclass regex
(expression)
227 ;;; conditional compilation
229 ((test :initarg
:test
:accessor cc-if-test
)
230 (body :initarg
:body
:accessor cc-if-body
)))
232 ;; TODO this may not be the best integrated implementation of
233 ;; instanceof into the rest of the code
234 (defjsclass js-instanceof
(expression)
236 (type :initarg
:type
)))
238 (defmacro define-js-single-op
(name &optional
(superclass 'expression
))
239 (let ((js-name (intern (concatenate 'string
"JS-" (symbol-name name
)) #.
*package
*)))
241 (defjsclass ,js-name
(,superclass
)
244 (define-js-single-op return statement
)
245 (define-js-single-op throw statement
)
246 (define-js-single-op delete
)
247 (define-js-single-op void
)
248 (define-js-single-op typeof
)
249 (define-js-single-op new
)