Replaced FiveAM with EOS (EOS is a drop-in replacement with better code and no depend...
[parenscript.git] / src / compilation-interface.lisp
blob1ce28d52f33a6c6f5c82c93436ad9ec64fbc36f2
1 (in-package #:parenscript)
3 (defparameter *js-target-version* 1.3)
5 (defvar *parenscript-stream* nil)
7 (defmacro ps (&body body)
8 "Given Parenscript forms (an implicit progn), compiles those forms
9 to a JavaScript string at macro-expansion time. Expands into a form
10 which evaluates to a string."
11 (let ((printed-forms (parenscript-print (compile-statement `(progn ,@body)) nil)))
12 (if (and (not (cdr printed-forms))
13 (stringp (car printed-forms)))
14 (car printed-forms)
15 (let ((s (gensym)))
16 `(with-output-to-string (,s)
17 ,@(mapcar (lambda (x) `(write-string ,x ,s)) printed-forms))))))
19 (defmacro ps-to-stream (stream &body body)
20 "Given Parenscript forms (an implicit progn), compiles those forms
21 to a JavaScript string at macro-expansion time. Expands into a form
22 which writes the resulting code to stream."
23 (let ((printed-forms (parenscript-print (compile-statement `(progn ,@body)) nil)))
24 `(let ((*parenscript-stream* ,stream))
25 ,@(mapcar (lambda (x) `(write-string ,x *parenscript-stream*)) printed-forms))))
27 (defun ps* (&rest body)
28 "Compiles body to a JavaScript string. If *parenscript-stream* is
29 bound, writes the output to *parenscript-stream*, otherwise returns a
30 string."
31 (let ((*psw-stream* (or *parenscript-stream* (make-string-output-stream))))
32 (parenscript-print (compile-statement `(progn ,@body)) t)
33 (unless *parenscript-stream*
34 (get-output-stream-string *psw-stream*))))
36 (defmacro with-blank-compilation-environment (&body body)
37 `(let ((*ps-gensym-counter* 0)
38 (*special-variables* nil))
39 ,@body))
41 (defmacro ps-doc (&body body)
42 "Expands Parenscript forms in a clean environment."
43 (with-blank-compilation-environment
44 (macroexpand-1 `(ps ,@body))))
46 (defun ps-doc* (&rest body)
47 (with-blank-compilation-environment
48 (apply #'ps* body)))
50 (defvar *js-inline-string-delimiter* #\"
51 "Controls the string delimiter char used when compiling Parenscript in ps-inline.")
53 (defun ps-inline* (form &optional (*js-string-delimiter* *js-inline-string-delimiter*))
54 (concatenate 'string "javascript:" (ps* form)))
56 (defmacro+ps ps-inline (form &optional (string-delimiter *js-inline-string-delimiter*))
57 `(concatenate 'string "javascript:"
58 ,@(let ((*js-string-delimiter* string-delimiter))
59 (parenscript-print (compile-statement form) nil))))
61 (defvar *ps-read-function* #'read)
63 (defun ps-compile-stream (stream)
64 "Reads (using the value of *ps-read-function*, #'read by default, as
65 the read function) Parenscript forms from stream and compiles them as
66 if by ps*. If *parenscript-stream* is bound, writes the output to
67 *parenscript-stream*, otherwise and returns a string."
68 (let ((output-stream (or *parenscript-stream* (make-string-output-stream))))
69 (let ((*compilation-level* :toplevel)
70 (*readtable* *readtable*)
71 (*package* *package*)
72 (*parenscript-stream* output-stream)
73 (eof '#:eof))
74 (loop for form = (funcall *ps-read-function* stream nil eof)
75 until (eq form eof) do (ps* form) (fresh-line *parenscript-stream*)))
76 (unless *parenscript-stream*
77 (get-output-stream-string output-stream))))
79 (defun ps-compile-file (source-file &key (element-type 'character) (external-format :default))
80 "Opens file as input stream and calls ps-compile-stream on it."
81 (with-open-file (stream source-file :direction :input :element-type element-type :external-format external-format)
82 (ps-compile-stream stream)))