Changed op-precedence back to a memoized table (performance tweaks).
[clinton/parenscript.git] / src / compilation-interface.lisp
CommitLineData
4525e3cd
VS
1(in-package "PARENSCRIPT")
2
62ddca23 3(defparameter *js-target-version* 1.3)
9da682ca 4
d434e1d5
VS
5(defvar *parenscript-stream* nil)
6
4a987e2b 7(defmacro ps (&body body)
cb8f8e58
VS
8 "Given Parenscript forms (an implicit progn), compiles those forms
9to a JavaScript string at macro-expansion time."
d434e1d5
VS
10 (let ((printed-forms (parenscript-print
11 (ps-compile-statement `(progn ,@body))
12 nil)))
13 (if (and (not (cdr printed-forms))
14 (stringp (car printed-forms)))
15 (car printed-forms)
16 (let ((s (gensym)))
17 `(with-output-to-string (,s)
18 ,@(mapcar (lambda (x) `(write-string ,x ,s)) printed-forms))))))
19
20(defmacro ps-to-stream (stream &body body)
21 (let ((printed-forms (parenscript-print
22 (ps-compile-statement `(progn ,@body))
23 nil)))
24 `(let ((*parenscript-stream* ,stream))
25 ,@(mapcar (lambda (x) `(write-string ,x *parenscript-stream*)) printed-forms))))
26
5a69278c
VS
27(defun ps* (&rest body)
28 "Compiles BODY to a JavaScript string.
29Body is evaluated."
d434e1d5
VS
30 (let ((*psw-stream* (or *parenscript-stream*
31 (make-string-output-stream))))
32 (parenscript-print (ps-compile-statement `(progn ,@body)) t)
33 (unless *parenscript-stream*
34 (get-output-stream-string *psw-stream*))))
5a69278c 35
c11d6a09
TC
36(defmacro ps-doc (&body body)
37 "Expands Parenscript forms in a clean environment."
cb8f8e58
VS
38 (let ((*ps-gensym-counter* 0)
39 (*ps-special-variables* nil))
40 (macroexpand-1 `(ps ,@body))))
41
157cb2d6
VS
42(defun ps-doc* (ps-form)
43 (let ((*ps-gensym-counter* 0)
44 (*ps-special-variables* nil))
5a69278c 45 (ps* ps-form)))
8877a380 46
c639fe7f
VS
47(defvar *js-inline-string-delimiter* #\"
48 "Controls the string delimiter char used when compiling Parenscript in ps-inline.")
33c100f0 49
c639fe7f 50(defun ps-inline* (form &optional (*js-string-delimiter* *js-inline-string-delimiter*))
5a69278c 51 (concatenate 'string "javascript:" (ps* form)))
c639fe7f 52
e69d0a12
VS
53(defmacro/ps ps-inline (form &optional (string-delimiter *js-inline-string-delimiter*))
54 `(concatenate 'string "javascript:"
55 ,@(let ((*js-string-delimiter* string-delimiter))
d434e1d5 56 (parenscript-print (ps-compile form) nil))))
5a69278c
VS
57
58(defvar *ps-read-function* #'read
59 "This should be a function that takes the same inputs and returns the same
60outputs as the common lisp read function. We declare it as a variable to allow
61a user-supplied reader instead of the default lisp reader.")
62
d434e1d5
VS
63(defun compiled-form-to-string (ps-compiled-form)
64 (with-output-to-string (*psw-stream*)
65 (parenscript-print ps-compiled-form t)))
66
5a69278c
VS
67(defun ps-compile-stream (stream)
68 "Compiles a source stream as if it were a file. Outputs a Javascript string."
69 (let ((*ps-compilation-level* :toplevel)
70 (*package* *package*)
71 (end-read-form '#:unique))
72 (flet ((read-form () (funcall *ps-read-function* stream nil end-read-form)))
73 (let* ((js-string
74 ;; cons up the forms, compiling as we go, and print the result
75 (do ((form (read-form) (read-form))
76 (compiled-forms nil))
77 ((eql form end-read-form)
78 (format nil "~{~A~^;~%~}"
79 (remove-if
80 #'(lambda (x) (or (null x) (= 0 (length x))))
81 (mapcar 'compiled-form-to-string (nreverse compiled-forms)))))
4e6c3ba1 82 (push (ps-compile-statement form) compiled-forms))))
5a69278c
VS
83 js-string))))
84
85(defun ps-compile-file (source-file)
86 "Compiles the given Parenscript source file and returns a Javascript string."
87 (with-open-file (stream source-file :direction :input)
88 (ps-compile-stream stream)))