Moved package-related code to namespace.lisp, added back *enable-package-system*.
[clinton/parenscript.git] / src / js-source-model.lisp
CommitLineData
cc4f1551
RD
1(in-package :parenscript)
2
9da682ca
RD
3(defgeneric script-equal (compiled-ast-node1 compiled-ast-node2)
4 (:documentation "Determines if the AST nodes are equal."))
5
cc4f1551 6;;; AST node equality
9da682ca 7(defmethod script-equal ((obj1 list) (obj2 list))
cc4f1551 8 (and (= (length obj1) (length obj2))
9da682ca 9 (every #'script-equal obj1 obj2)))
cc4f1551 10
9da682ca 11(defmethod script-equal ((obj1 t) (obj2 t))
cc4f1551
RD
12 (equal obj1 obj2))
13
9da682ca 14(defmacro defscriptclass (name superclasses slots &rest class-options)
cc4f1551
RD
15 (let ((slot-names (mapcar #'(lambda (slot) (if (atom slot) slot (first slot))) slots)))
16 `(progn
17 (defclass ,name ,superclasses
18 ,slots ,@class-options)
9da682ca 19 (defmethod script-equal ((obj1 ,name) (obj2 ,name))
cc4f1551 20 (every #'(lambda (slot)
9da682ca 21 (script-equal (slot-value obj1 slot)
cc4f1551
RD
22 (slot-value obj2 slot)))
23 ',slot-names)))))
24
5aa10005
RD
25(in-package :parenscript.javascript)
26
27(defgeneric expression-precedence (expression)
28 (:documentation "Returns the precedence of an enscript-javascript expression"))
29
30;;;; define Javascript language types
cc4f1551
RD
31(defclass statement ()
32 ((value :initarg :value :accessor value :initform nil))
33 (:documentation "A Javascript entity without a value."))
34
35(defclass expression (statement)
36 ()
37 (:documentation "A Javascript entity with a value."))
38
39;;; array literals
9da682ca 40(defscriptclass array-literal (expression)
cc4f1551
RD
41 ((values :initarg :values :accessor array-values)))
42
5aa10005 43(defscriptclass js-aref (expression)
cc4f1551
RD
44 ((array :initarg :array
45 :accessor aref-array)
46 (index :initarg :index
47 :accessor aref-index)))
48
49;;; object literals (maps and hash-tables)
9da682ca 50(defscriptclass object-literal (expression)
cc4f1551
RD
51 ((values :initarg :values :accessor object-values)))
52
53;;; string literals
9da682ca 54(defscriptclass string-literal (expression)
cc4f1551
RD
55 (value))
56
57
58;;; number literals
9da682ca 59(defscriptclass number-literal (expression)
cc4f1551
RD
60 (value))
61
62;;; variables
5aa10005 63(defscriptclass js-variable (expression)
cc4f1551
RD
64 (value))
65
cc4f1551 66;;; operators
9da682ca 67(defscriptclass op-form (expression)
cc4f1551
RD
68 ((operator :initarg :operator :accessor operator)
69 (args :initarg :args :accessor op-args)))
70
71(eval-when (:compile-toplevel :load-toplevel :execute)
cc4f1551
RD
72 (defparameter *op-precedence-hash* (make-hash-table :test #'equal))
73
74 ;;; generate the operator precedences from *OP-PRECEDENCES*
75 (let ((precedence 1))
76 (dolist (ops '((aref)
77 (slot-value)
78 (! not ~)
79 (* / %)
80 (+ -)
81 (<< >>)
82 (>>>)
83 (< > <= >=)
84 (in if)
85 (eql == != =)
86 (=== !==)
87 (&)
88 (^)
89 (\|)
90 (\&\& and)
91 (\|\| or)
92 (setf *= /= %= += -= <<= >>= >>>= \&= ^= \|=)
93 (comma)))
94 (dolist (op ops)
95 (let ((op-name (symbol-name op)))
96 (setf (gethash op-name *op-precedence-hash*) precedence)))
97 (incf precedence)))
98
99 (defun op-precedence (op)
100 (gethash (if (symbolp op)
101 (symbol-name op)
102 op)
103 *op-precedence-hash*)))
104
9da682ca 105(defscriptclass one-op (expression)
cc4f1551
RD
106 ((pre-p :initarg :pre-p
107 :initform nil
108 :accessor one-op-pre-p)
109 (op :initarg :op
110 :accessor one-op)))
111
112;;; function calls
9da682ca 113(defscriptclass function-call (expression)
cc4f1551
RD
114 ((function :initarg :function :accessor f-function)
115 (args :initarg :args :accessor f-args)))
116
9da682ca 117(defscriptclass method-call (expression)
cc4f1551
RD
118 ((method :initarg :method :accessor m-method)
119 (object :initarg :object :accessor m-object)
120 (args :initarg :args :accessor m-args)))
121
122;;; body forms
5aa10005
RD
123(defscriptclass js-block (expression)
124 ((statements :initarg :statements :accessor block-statements)
125 (indent :initarg :indent :initform "" :accessor block-indent)))
cc4f1551 126
5aa10005 127(defmethod initialize-instance :after ((block js-block) &rest initargs)
cc4f1551 128 (declare (ignore initargs))
5aa10005 129 (let* ((statements (block-statements block))
9da682ca 130 (last (last statements))
cc4f1551 131 (last-stmt (car last)))
5aa10005
RD
132 (when (typep last-stmt 'js-block)
133 (setf (block-statements block)
9da682ca 134 (nconc (butlast statements)
5aa10005 135 (block-statements last-stmt))))))
cc4f1551 136
5aa10005 137(defscriptclass js-sub-block (js-block)
9da682ca 138 (statements indent))
cc4f1551
RD
139
140;;; function definition
5aa10005 141(defscriptclass js-lambda (expression)
cc4f1551
RD
142 ((args :initarg :args :accessor lambda-args)
143 (body :initarg :body :accessor lambda-body)))
144
5aa10005 145(defscriptclass js-defun (js-lambda)
cc4f1551
RD
146 ((name :initarg :name :accessor defun-name)))
147
148;;; object creation
5aa10005 149(defscriptclass js-object (expression)
cc4f1551
RD
150 ((slots :initarg :slots
151 :accessor o-slots)))
152
5aa10005 153(defscriptclass js-slot-value (expression)
cc4f1551
RD
154 ((object :initarg :object
155 :accessor sv-object)
156 (slot :initarg :slot
157 :accessor sv-slot)))
158
159;;; cond
5aa10005 160(defscriptclass js-cond (expression)
cc4f1551
RD
161 ((tests :initarg :tests
162 :accessor cond-tests)
163 (bodies :initarg :bodies
164 :accessor cond-bodies)))
165
5aa10005 166(defscriptclass js-if (expression)
cc4f1551
RD
167 ((test :initarg :test
168 :accessor if-test)
169 (then :initarg :then
170 :accessor if-then)
171 (else :initarg :else
172 :accessor if-else)))
173
5aa10005 174(defmethod initialize-instance :after ((if js-if) &rest initargs)
cc4f1551
RD
175 (declare (ignore initargs))
176 (when (and (if-then if)
5aa10005
RD
177 (typep (if-then if) 'js-sub-block))
178 (change-class (if-then if) 'js-block))
cc4f1551 179 (when (and (if-else if)
5aa10005
RD
180 (typep (if-else if) 'js-sub-block))
181 (change-class (if-else if) 'js-block)))
cc4f1551
RD
182
183;;; switch
5aa10005 184(defscriptclass js-switch (statement)
cc4f1551
RD
185 ((value :initarg :value :accessor case-value)
186 (clauses :initarg :clauses :accessor case-clauses)))
187
188;;; assignment
189
5aa10005 190(defscriptclass js-setf (expression)
cc4f1551
RD
191 ((lhs :initarg :lhs :accessor setf-lhs)
192 (rhsides :initarg :rhsides :accessor setf-rhsides)))
193
194;;; defvar
5aa10005 195(defscriptclass js-defvar (statement)
cc4f1551
RD
196 ((names :initarg :names :accessor var-names)
197 (value :initarg :value :accessor var-value)))
198
199;;; iteration
5aa10005 200(defscriptclass js-for (statement)
cc4f1551
RD
201 ((vars :initarg :vars :accessor for-vars)
202 (steps :initarg :steps :accessor for-steps)
203 (check :initarg :check :accessor for-check)
204 (body :initarg :body :accessor for-body)))
205
9da682ca 206(defscriptclass for-each (statement)
cc4f1551
RD
207 ((name :initarg :name :accessor fe-name)
208 (value :initarg :value :accessor fe-value)
209 (body :initarg :body :accessor fe-body)))
210
5aa10005 211(defscriptclass js-while (statement)
cc4f1551
RD
212 ((check :initarg :check :accessor while-check)
213 (body :initarg :body :accessor while-body)))
214
215;;; with
5aa10005 216(defscriptclass js-with (statement)
cc4f1551
RD
217 ((obj :initarg :obj :accessor with-obj)
218 (body :initarg :body :accessor with-body)))
219
220;;; try-catch
5aa10005 221(defscriptclass js-try (statement)
cc4f1551
RD
222 ((body :initarg :body :accessor try-body)
223 (catch :initarg :catch :accessor try-catch)
224 (finally :initarg :finally :accessor try-finally)))
225
226;;; regular expressions
9da682ca 227(defscriptclass regex (expression)
cc4f1551
RD
228 (value))
229
230;;; conditional compilation
9da682ca 231(defscriptclass cc-if ()
cc4f1551
RD
232 ((test :initarg :test :accessor cc-if-test)
233 (body :initarg :body :accessor cc-if-body)))
234
235;; TODO this may not be the best integrated implementation of
236;; instanceof into the rest of the code
5aa10005 237(defscriptclass js-instanceof (expression)
cc4f1551
RD
238 ((value)
239 (type :initarg :type)))
240
5aa10005
RD
241(defmacro define-js-single-op (name &optional (superclass 'expression))
242 (let ((js-name (intern (concatenate 'string "JS-" (symbol-name name)) #.*package*)))
cc4f1551 243 `(progn
5aa10005 244 (defscriptclass ,js-name (,superclass)
cc4f1551
RD
245 (value)))))
246
5aa10005
RD
247(define-js-single-op return statement)
248(define-js-single-op throw statement)
249(define-js-single-op delete)
250(define-js-single-op void)
251(define-js-single-op typeof)
252(define-js-single-op new)