Commit | Line | Data |
---|---|---|
4a987e2b | 1 | (in-package :parenscript) |
9da682ca | 2 | |
4a987e2b | 3 | (defgeneric ps-print% (special-form-name special-form-args %start-pos%)) |
9da682ca | 4 | |
4a987e2b VS |
5 | (defmacro defprinter (special-form content-args &body body) |
6 | "Given a special-form name and a destructuring lambda-list for its | |
7 | arguments, defines a printer for that form using the given body." | |
8 | (let ((sf (gensym)) | |
9 | (sf-args (gensym))) | |
10 | `(defmethod ps-print% ((,sf (eql ',special-form)) ,sf-args %start-pos%) | |
11 | (declare (ignore ,sf)) | |
12 | (destructuring-bind ,content-args | |
13 | ,sf-args | |
14 | ,@body)))) | |
15 | ||
16 | (defvar %start-pos%) | |
17 | ||
18 | (defgeneric ps-print (compiled-form %start-pos%)) | |
19 | ||
20 | (defmethod ps-print ((compiled-form cons) %start-pos%) | |
21 | "Prints the given compiled ParenScript form starting at the given | |
22 | indent position." | |
23 | (ps-print% (car compiled-form) (cdr compiled-form) %start-pos%)) | |
24 | ||
25 | ;;; string literals | |
26 | (defvar *js-quote-char* #\' | |
27 | "Specifies which character JS should use for delimiting strings. | |
28 | ||
29 | This variable is useful when have to embed some javascript code | |
30 | in an html attribute delimited by #\\\" as opposed to #\\', or | |
31 | vice-versa.") | |
32 | ||
33 | (defparameter *js-lisp-escaped-chars* | |
34 | '((#\' . #\') | |
35 | (#\\ . #\\) | |
36 | (#\b . #\Backspace) | |
37 | (#\f . #.(code-char 12)) | |
38 | (#\n . #\Newline) | |
39 | (#\r . #\Return) | |
40 | (#\t . #\Tab))) | |
41 | ||
42 | (defmethod ps-print ((string string) %start-pos%) | |
43 | (flet ((lisp-special-char-to-js (lisp-char) | |
44 | (car (rassoc lisp-char *js-lisp-escaped-chars*)))) | |
45 | (list (with-output-to-string (escaped) | |
46 | (write-char *js-quote-char* escaped) | |
47 | (loop for char across string | |
48 | for code = (char-code char) | |
49 | for special = (lisp-special-char-to-js char) | |
50 | do (cond | |
51 | (special | |
52 | (write-char #\\ escaped) | |
53 | (write-char special escaped)) | |
54 | ((or (<= code #x1f) (>= code #x80)) | |
55 | (format escaped "\\u~4,'0x" code)) | |
56 | (t (write-char char escaped))) | |
57 | finally (write-char *js-quote-char* escaped)))))) | |
58 | ||
59 | (defmethod ps-print ((number number) %start-pos%) | |
60 | (list (format nil (if (integerp number) "~S" "~F") number))) | |
61 | ||
62 | ;;; expression and operator precedence rules | |
63 | ||
64 | (defun expression-precedence (expr) | |
65 | (if (consp expr) | |
66 | (case (car expr) | |
67 | (js-block (if (= (length (cdr expr)) 1) | |
68 | (expression-precedence (first (cdr expr))) | |
69 | (op-precedence 'comma))) | |
70 | (js-expression-if (op-precedence 'js-expression-if)) | |
71 | (js-assign (op-precedence '=)) | |
72 | (operator (op-precedence (second expr))) | |
73 | (otherwise 0)) | |
74 | 0)) | |
75 | ||
76 | (eval-when (:compile-toplevel :load-toplevel :execute) | |
77 | (defparameter *op-precedence-hash* (make-hash-table :test #'equal)) | |
78 | ||
79 | ;;; generate the operator precedences from *OP-PRECEDENCES* | |
80 | (let ((precedence 1)) | |
81 | (dolist (ops '((js-aref) | |
82 | (js-slot-value) | |
83 | (! not ~) | |
84 | (* / %) | |
85 | (+ -) | |
86 | (<< >>) | |
87 | (>>>) | |
88 | (< > <= >=) | |
89 | (in js-expression-if) | |
90 | (eql == != =) | |
91 | (=== !==) | |
92 | (&) | |
93 | (^) | |
94 | (\|) | |
95 | (\&\& and) | |
96 | (\|\| or) | |
97 | (js-assign *= /= %= += -= <<= >>= >>>= \&= ^= \|=) | |
98 | (comma))) | |
99 | (dolist (op ops) | |
100 | (let ((op-name (symbol-name op))) | |
101 | (setf (gethash op-name *op-precedence-hash*) precedence))) | |
102 | (incf precedence))) | |
103 | ||
104 | (defun op-precedence (op) | |
105 | (gethash (if (symbolp op) | |
106 | (symbol-name op) | |
107 | op) | |
108 | *op-precedence-hash*))) | |
9da682ca | 109 | |
cc4f1551 RD |
110 | ;;; indenter |
111 | ||
4a987e2b VS |
112 | (defmacro max-length () '(- 80 %start-pos% 2)) |
113 | ||
114 | (defun ps-print-indent (ps-form) | |
115 | (ps-print ps-form (+ %start-pos% 2))) | |
116 | ||
cc4f1551 RD |
117 | (defun special-append-to-last (form elt) |
118 | (flet ((special-append (form elt) | |
119 | (let ((len (length form))) | |
120 | (if (and (> len 0) | |
121 | (string= (char form (1- len)) elt)) | |
122 | form | |
123 | (concatenate 'string form elt))))) | |
124 | (cond ((stringp form) | |
125 | (special-append form elt)) | |
126 | ((consp form) | |
127 | (let ((last (last form))) | |
128 | (if (stringp (car last)) | |
129 | (rplaca last (special-append (car last) elt)) | |
130 | (append-to-last (car last) elt)) | |
131 | form)) | |
4a987e2b | 132 | (t (error "Wrong argument type to indent appender: ~S" form))))) |
cc4f1551 RD |
133 | |
134 | (defun dwim-join (value-string-lists max-length | |
135 | &key (start "") | |
136 | end | |
137 | (join-before "") | |
138 | join-after | |
139 | (white-space (make-string (length start) :initial-element #\Space)) | |
140 | (separator " ") | |
141 | (append-to-last #'append-to-last) | |
142 | (collect t)) | |
143 | #+nil | |
144 | (format t "value-string-lists: ~S~%" value-string-lists) | |
145 | ||
4a987e2b | 146 | ;;; collect single value-string-lists until the line is full |
cc4f1551 RD |
147 | |
148 | (do* ((string-lists value-string-lists (cdr string-lists)) | |
149 | (string-list (car string-lists) (car string-lists)) | |
150 | (cur-elt start) | |
151 | (is-first t nil) | |
152 | (cur-empty t) | |
153 | (res nil)) | |
154 | ((null string-lists) | |
155 | (unless cur-empty | |
156 | (push cur-elt res)) | |
157 | (if (null res) | |
158 | (list (concatenate 'string start end)) | |
159 | (progn | |
160 | (when end | |
161 | (setf (first res) | |
162 | (funcall append-to-last (first res) end))) | |
163 | (nreverse res)))) | |
164 | #+nil | |
165 | (format t "string-list: ~S~%" string-list) | |
166 | ||
167 | (when join-after | |
168 | (unless (null (cdr string-lists)) | |
169 | (funcall append-to-last string-list join-after))) | |
170 | ||
171 | (if (and collect (= (length string-list) 1)) | |
172 | (progn | |
173 | #+nil | |
174 | (format t "cur-elt: ~S line-length ~D, max-length ~D, string: ~S~%" | |
175 | cur-elt | |
176 | (+ (length (first string-list)) | |
177 | (length cur-elt)) | |
178 | max-length | |
179 | (first string-list)) | |
180 | (if (or cur-empty | |
181 | (< (+ (length (first string-list)) | |
182 | (length cur-elt)) max-length)) | |
183 | (setf cur-elt | |
184 | (concatenate 'string cur-elt | |
185 | (if (or is-first (and cur-empty (string= join-before ""))) | |
186 | "" (concatenate 'string separator join-before)) | |
187 | (first string-list)) | |
188 | cur-empty nil) | |
189 | (progn | |
190 | (push cur-elt res) | |
191 | (setf cur-elt (concatenate 'string white-space | |
192 | join-before (first string-list)) | |
193 | cur-empty nil)))) | |
194 | ||
195 | (progn | |
196 | (unless cur-empty | |
197 | (push cur-elt res) | |
198 | (setf cur-elt white-space | |
199 | cur-empty t)) | |
200 | (setf res (nconc (nreverse | |
201 | (cons (concatenate 'string | |
202 | cur-elt | |
203 | (if (null res) | |
204 | "" join-before) | |
205 | (first string-list)) | |
206 | (mapcar #'(lambda (x) (concatenate 'string white-space x)) | |
207 | (cdr string-list)))) | |
208 | res)) | |
209 | (setf cur-elt white-space cur-empty t))))) | |
210 | ||
4a987e2b VS |
211 | (defprinter script-quote (val) |
212 | (if (null val) | |
213 | (list "null") | |
214 | (error "Cannot translate quoted value ~S to javascript" val))) | |
cc4f1551 | 215 | |
4a987e2b VS |
216 | (defprinter js-literal (str) |
217 | (list str)) | |
cc4f1551 | 218 | |
4a987e2b VS |
219 | (defprinter js-keyword (str) |
220 | (list str)) | |
46f794a4 | 221 | |
cc4f1551 RD |
222 | ;;; array literals |
223 | ||
4a987e2b VS |
224 | (defprinter array-literal (&rest initial-contents) |
225 | (let ((initial-contents-strings (mapcar #'ps-print-indent initial-contents))) | |
226 | (dwim-join initial-contents-strings (max-length) | |
cc4f1551 RD |
227 | :start "[ " :end " ]" |
228 | :join-after ","))) | |
229 | ||
4a987e2b VS |
230 | (defprinter js-aref (array coords) |
231 | (dwim-join (cons (ps-print array %start-pos%) | |
232 | (mapcar (lambda (x) (dwim-join (list (ps-print-indent x)) | |
233 | (max-length) | |
234 | :start "[" :end "]")) | |
235 | coords)) | |
236 | (max-length) | |
237 | :white-space " " | |
238 | :separator "")) | |
239 | ||
240 | (defprinter object-literal (&rest arrows) | |
241 | (dwim-join (loop for (key . value) in arrows appending | |
242 | (list (dwim-join (list (list (format nil "~A:" (js-translate-symbol key))) | |
243 | (ps-print-indent value)) | |
244 | (max-length) | |
245 | :start "" :end "" :join-after ""))) | |
246 | (max-length) | |
247 | :start "{ " :end " }" | |
248 | :join-after ",")) | |
249 | ||
250 | (defprinter js-variable (var) | |
251 | (list (js-translate-symbol var))) | |
cc4f1551 RD |
252 | |
253 | ;;; arithmetic operators | |
9da682ca | 254 | (defun script-convert-op-name (op) |
cc4f1551 RD |
255 | (case op |
256 | (and '\&\&) | |
257 | (or '\|\|) | |
258 | (not '!) | |
259 | (eql '\=\=) | |
260 | (= '\=\=) | |
261 | (t op))) | |
262 | ||
4a987e2b | 263 | (defun parenthesize (string-list) |
cc4f1551 RD |
264 | (prepend-to-first string-list "(") |
265 | (append-to-last string-list ")") | |
266 | string-list) | |
267 | ||
4a987e2b VS |
268 | (defprinter operator (op args) |
269 | (let* ((precedence (op-precedence op)) | |
270 | (arg-strings (mapcar (lambda (arg) | |
271 | (let ((arg-strings (ps-print-indent arg))) | |
272 | (if (>= (expression-precedence arg) precedence) | |
273 | (parenthesize arg-strings) | |
274 | arg-strings))) | |
275 | args)) | |
276 | (op-string (format nil "~A " op))) | |
277 | (dwim-join arg-strings (max-length) :join-before op-string))) | |
278 | ||
279 | (defprinter unary-operator (op arg &key prefix) | |
280 | (let ((arg-string (ps-print arg %start-pos%))) | |
281 | (when (eql 'operator (car arg)) | |
282 | (setf arg-string (parenthesize arg-string))) | |
283 | (if prefix | |
284 | (prepend-to-first arg-string op) | |
285 | (append-to-last arg-string op)))) | |
286 | ||
287 | ;;; function and method calls | |
288 | (defprinter js-funcall (fun-designator args) | |
289 | (let* ((arg-strings (mapcar #'ps-print-indent args)) | |
290 | (args (dwim-join arg-strings (max-length) | |
cc4f1551 | 291 | :start "(" :end ")" :join-after ","))) |
4a987e2b VS |
292 | (cond ((eql 'js-lambda (car fun-designator)) |
293 | (dwim-join (list (append (dwim-join (list (ps-print-indent fun-designator)) | |
294 | (max-length) | |
295 | :start "(" :end ")" :separator "") | |
296 | args)) | |
297 | (max-length) | |
298 | :separator "")) | |
299 | ((member (car fun-designator) '(js-variable js-aref js-slot-value)) | |
300 | (dwim-join (list (ps-print-indent fun-designator) args) | |
301 | (max-length) | |
302 | :separator "")) | |
303 | ((eql 'js-funcall (car fun-designator)) | |
304 | ;; TODO it adds superfluous newlines after each () | |
305 | ;; and it's nearly the same as the js-lambda case above | |
306 | (dwim-join (list (append (dwim-join (list (ps-print-indent fun-designator)) | |
307 | (max-length) :separator "") | |
308 | args)) | |
309 | (max-length) :separator ""))))) | |
310 | ||
311 | (defprinter js-method-call (method object args) | |
312 | (let ((printed-object (ps-print object (+ %start-pos% 2)))) | |
cc4f1551 RD |
313 | ;; TODO: this may not be the best way to add ()'s around lambdas |
314 | ;; probably there is or should be a more general solution working | |
315 | ;; in other situations involving lambda's | |
4a987e2b VS |
316 | (when (or (numberp object) (and (consp object) (member (car object) '(js-lambda js-object operator)))) |
317 | (setf printed-object (append (list "(") printed-object (list ")")))) | |
318 | (let* ((fname (dwim-join (list printed-object (list (js-translate-symbol method))) | |
319 | (max-length) | |
cc4f1551 RD |
320 | :end "(" |
321 | :separator "")) | |
322 | (butlast (butlast fname)) | |
323 | (last (car (last fname))) | |
4a987e2b VS |
324 | (method-and-args (dwim-join (mapcar #'ps-print-indent args) |
325 | (max-length) | |
cc4f1551 RD |
326 | :start last |
327 | :end ")" | |
328 | :join-after ",")) | |
329 | (ensure-no-newline-before-dot (concatenate 'string | |
330 | (car (last butlast)) | |
331 | (first method-and-args)))) | |
4a987e2b | 332 | (append (butlast butlast) (list ensure-no-newline-before-dot) (cdr method-and-args))))) |
cc4f1551 | 333 | |
4a987e2b VS |
334 | (defprinter js-block (statement-p statements) |
335 | (dwim-join (mapcar #'ps-print-indent statements) | |
336 | (max-length) | |
337 | :join-after (if statement-p ";" ",") | |
cc4f1551 | 338 | :append-to-last #'special-append-to-last |
4a987e2b VS |
339 | :start (if statement-p " " "") |
340 | :collect nil | |
341 | :end (if statement-p ";" ""))) | |
342 | ||
343 | (defprinter js-lambda (args body) | |
344 | (print-fun-def nil args body %start-pos%)) | |
345 | ||
346 | (defprinter js-defun (name args body) | |
347 | (print-fun-def name args body %start-pos%)) | |
348 | ||
349 | (defun print-fun-def (name args body %start-pos%) | |
350 | (let ((fun-header (dwim-join (mapcar (lambda (x) (list (js-translate-symbol x))) | |
351 | args) | |
352 | (max-length) | |
353 | :start (format nil "function ~:[~;~A~](" name (js-translate-symbol name)) | |
354 | :join-after "," | |
355 | :end ") {")) | |
356 | (fun-body (ps-print-indent body))) | |
357 | (append fun-header fun-body (list "}")))) | |
cc4f1551 RD |
358 | |
359 | ;;; object creation | |
4a987e2b VS |
360 | (defprinter js-object (slot-defs) |
361 | (let ((value-string-lists (mapcar (lambda (slot) | |
362 | (let* ((slot-name (first slot)) | |
363 | (slot-string-name | |
364 | (if (and (listp slot-name) (eql 'script-quote (car slot-name))) | |
365 | (format nil "~A" (if (symbolp (second slot-name)) | |
366 | (js-translate-symbol (second slot-name)) | |
367 | (car (ps-print slot-name 0)))) | |
368 | (car (ps-print slot-name 0))))) | |
369 | (dwim-join (list (ps-print (second slot) (+ %start-pos% 4))) | |
370 | (max-length) | |
371 | :start (concatenate 'string slot-string-name " : ") | |
372 | :white-space " "))) | |
373 | slot-defs))) | |
374 | (dwim-join value-string-lists (max-length) | |
cc4f1551 RD |
375 | :start "{ " |
376 | :end " }" | |
377 | :join-after ", " | |
378 | :white-space " " | |
379 | :collect nil))) | |
380 | ||
4a987e2b | 381 | (defprinter js-slot-value (obj slot) |
a805b30d | 382 | (append-to-last (if (and (listp obj) (eql 'js-variable (car obj))) |
4a987e2b VS |
383 | (ps-print obj %start-pos%) |
384 | (list (format nil "~A" (ps-print obj %start-pos%)))) | |
a805b30d | 385 | (if (and (listp slot) (eql 'script-quote (car slot))) |
4a987e2b VS |
386 | (format nil ".~A" (if (symbolp (second slot)) |
387 | (js-translate-symbol (second slot)) | |
388 | (first (ps-print slot 0)))) | |
389 | (format nil "[~A]" (first (ps-print slot 0)))))) | |
cc4f1551 RD |
390 | |
391 | ;;; cond | |
4a987e2b VS |
392 | (defprinter js-cond (clauses) |
393 | (loop for (test body-forms) in clauses | |
394 | for start = "if (" then "else if (" | |
395 | append (if (string= test "true") | |
396 | '("else {") | |
397 | (dwim-join (list (ps-print test 0)) (max-length) | |
398 | :start start :end ") {")) | |
399 | append (mapcar #'ps-print-indent body-forms) | |
400 | collect "}")) | |
401 | ||
402 | (defprinter js-statement-if (test then else) | |
403 | (let ((if-strings (dwim-join (list (ps-print test 0)) | |
404 | (- 80 %start-pos% 2) | |
cc4f1551 RD |
405 | :start "if (" |
406 | :end ") {")) | |
4a987e2b VS |
407 | (then-strings (ps-print-indent then)) |
408 | (else-strings (when else | |
409 | (ps-print-indent else)))) | |
410 | (append if-strings then-strings (if else-strings | |
411 | (append (list "} else {") else-strings (list "}")) | |
412 | (list "}"))))) | |
413 | ||
414 | (defprinter js-expression-if (test then else) | |
415 | (dwim-join (list (append-to-last (ps-print test %start-pos%) " ?") | |
416 | (let ((then-string (ps-print then %start-pos%))) | |
417 | (if (>= (expression-precedence then) (op-precedence 'js-expression-if)) | |
418 | (parenthesize then-string) | |
419 | then-string)) | |
cc4f1551 | 420 | (list ":") |
4a987e2b VS |
421 | (if else |
422 | (let ((else-string (ps-print else %start-pos%))) | |
423 | (if (>= (expression-precedence else) (op-precedence 'js-expression-if)) | |
424 | (parenthesize else-string) | |
425 | else-string)) | |
cc4f1551 | 426 | (list "undefined"))) |
4a987e2b | 427 | (max-length) |
cc4f1551 RD |
428 | :white-space " ")) |
429 | ||
4a987e2b VS |
430 | (defprinter js-assign (lhs rhs) |
431 | (dwim-join (list (ps-print lhs %start-pos%) (ps-print rhs %start-pos%)) | |
432 | (max-length) | |
cc4f1551 RD |
433 | :join-after " =")) |
434 | ||
4a987e2b VS |
435 | (defprinter js-defvar (var-name &rest var-value) |
436 | (dwim-join (append (list (list (js-translate-symbol var-name))) | |
437 | (when var-value | |
438 | (list (ps-print (car var-value) %start-pos%)))) | |
439 | (max-length) | |
cc4f1551 RD |
440 | :join-after " =" |
441 | :start "var " :end ";")) | |
442 | ||
443 | ;;; iteration | |
4a987e2b VS |
444 | (defprinter js-for (vars steps test body-block) |
445 | (let* ((init (dwim-join (mapcar (lambda (var-form) | |
446 | (dwim-join (list (list (js-translate-symbol (car var-form))) | |
447 | (ps-print-indent (cdr var-form))) | |
448 | (max-length) | |
449 | :join-after " =")) | |
450 | vars) | |
451 | (max-length) | |
cc4f1551 | 452 | :start "var " :join-after ",")) |
4a987e2b VS |
453 | (test-string (ps-print-indent test)) |
454 | (step-strings (dwim-join (mapcar (lambda (x var-form) | |
455 | (dwim-join | |
456 | (list (list (js-translate-symbol (car var-form))) | |
457 | (ps-print x (- %start-pos% 2))) | |
458 | (max-length) | |
459 | :join-after " =")) | |
460 | steps | |
461 | vars) | |
462 | (max-length) | |
463 | :join-after ",")) | |
464 | (header (dwim-join (list init test-string step-strings) | |
465 | (max-length) | |
cc4f1551 RD |
466 | :start "for (" :end ") {" |
467 | :join-after ";")) | |
4a987e2b VS |
468 | (body (ps-print-indent body-block))) |
469 | (append header body (list "}")))) | |
cc4f1551 | 470 | |
4a987e2b VS |
471 | (defprinter js-for-each (var object body-block) |
472 | (let ((header (dwim-join (list (list (js-translate-symbol var)) | |
cc4f1551 | 473 | (list "in") |
4a987e2b VS |
474 | (ps-print-indent object)) |
475 | (max-length) | |
cc4f1551 RD |
476 | :start "for (var " |
477 | :end ") {")) | |
4a987e2b VS |
478 | (body (ps-print-indent body-block))) |
479 | (append header body (list "}")))) | |
cc4f1551 | 480 | |
4a987e2b VS |
481 | (defprinter js-while (test body-block) |
482 | (let ((header-strings (dwim-join (list (ps-print-indent test)) | |
483 | (max-length) | |
cc4f1551 RD |
484 | :start "while (" |
485 | :end ") {")) | |
4a987e2b VS |
486 | (body-strings (ps-print-indent body-block))) |
487 | (append header-strings body-strings (list "}")))) | |
488 | ||
489 | (defprinter js-with (expression body-block) | |
490 | (append (dwim-join (list (ps-print-indent expression)) | |
491 | (max-length) | |
492 | :start "with (" :end ") {") | |
493 | (ps-print-indent body-block) | |
494 | (list "}"))) | |
495 | ||
496 | (defprinter js-switch (test clauses) | |
497 | (let ((body-strings (mapcar (lambda (clause) | |
498 | (let ((val (first clause)) | |
499 | (body-block (second clause))) | |
500 | (dwim-join (list (if (eql val 'default) | |
501 | (list "") | |
502 | (ps-print-indent val)) | |
503 | (ps-print-indent body-block)) | |
504 | (max-length) | |
505 | :start (if (eql val 'default) " default" " case ") | |
506 | :white-space " " | |
507 | :join-after ":"))) | |
508 | clauses))) | |
509 | (append (dwim-join (list (ps-print-indent test)) | |
510 | (max-length) | |
511 | :start "switch (" :end ") {") | |
512 | (reduce #'append body-strings) | |
513 | (list "}")))) | |
514 | ||
515 | (defprinter js-try (body &key catch finally) | |
516 | (let ((catch-strings (when catch | |
517 | (append (dwim-join (list (list (js-translate-symbol (first catch)))) | |
518 | (max-length) | |
519 | :start "} catch (" | |
520 | :end ") {") | |
521 | (ps-print-indent (second catch))))) | |
522 | (finally-strings (when finally | |
523 | (append (list "} finally {") | |
524 | (ps-print-indent finally))))) | |
525 | (append (list "try {") | |
526 | (ps-print-indent body) | |
527 | catch-strings | |
528 | finally-strings | |
529 | (list "}")))) | |
cc4f1551 RD |
530 | |
531 | ;;; regex | |
4a987e2b VS |
532 | (defprinter js-regex (regex) |
533 | (flet ((first-slash-p (string) | |
534 | (and (> (length string) 0) (eql (char string 0) '#\/)))) | |
535 | (let ((slash (unless (first-slash-p regex) "/"))) | |
536 | (list (format nil (concatenate 'string slash "~A" slash) regex))))) | |
cc4f1551 | 537 | |
4a987e2b VS |
538 | (defprinter js-return (value) |
539 | (let ((printed-value (ps-print value 0))) | |
540 | (cons (concatenate 'string "return " (car printed-value)) (cdr printed-value)))) | |
cc4f1551 RD |
541 | |
542 | ;;; conditional compilation | |
4a987e2b VS |
543 | (defprinter cc-if (test body-forms) |
544 | (append (list (format nil "/*@if ~A" test)) | |
545 | (mapcar (lambda (x) (ps-print x %start-pos%)) body-forms) | |
546 | (list "@end @*/"))) | |
cc4f1551 RD |
547 | |
548 | ;;; TODO instanceof | |
4a987e2b VS |
549 | (defprinter js-instanceof (value type) |
550 | (dwim-join (list (ps-print-indent value) | |
551 | (list "instanceof") | |
552 | (ps-print-indent type)) | |
553 | (max-length) | |
554 | :start "(" | |
555 | :end ")" | |
556 | :white-space " ")) | |
557 | ||
558 | (defprinter js-named-operator (op value) | |
559 | (dwim-join (list (ps-print-indent value)) | |
560 | (max-length) | |
561 | :start (concatenate 'string (string-downcase (symbol-name op)) " ") | |
562 | :white-space " ")) |