bulk of package system, reader, and other refactoring
[clinton/parenscript.git] / src / compilation-interface.lisp
1 (in-package :parenscript)
2
3 (defmacro with-new-compilation-environment ((var) &body body)
4 `(let* ((,var (make-basic-compilation-environment))
5 (*compilation-environment* ,var))
6 ,@body))
7
8
9 (defun translate-ast (compiled-expr
10 &key
11 (comp-env *compilation-environment*)
12 (output-stream *standard-output*)
13 (output-spec :javascript)
14 (pretty-print t))
15 "Translates a compiled Parenscript program (compiled with COMPILE-PAREN-FORM)
16 to a Javascript string. Outputs to the stream OUTPUT-STREAM in the language given
17 by OUTPUT-SPEC, pretty printing if PRETTY-PRINT is non-null.
18
19 OUTPUT-SPEC must be :javascript at the moment."
20 (declare (ignore comp-env))
21 (when (not (eql :javascript output-spec))
22 (error "Unsupported output-spec for translation: ~A" output-spec))
23 (when (eql :javascript output-spec)
24 ; (if (not pretty-print)
25 ; (js-translate compiled-expr :statement output-stream)
26 (write-string (string-join
27 (ps-js::js-to-statement-strings compiled-expr 0)
28 (string #\Newline))
29 output-stream)))
30
31 (defun compile-script (script-form
32 &key
33 (output-spec :javascript)
34 (pretty-print t)
35 (output-stream nil)
36 (toplevel-p t)
37 (comp-env (make-basic-compilation-environment)))
38 "Compiles the Parenscript form SCRIPT-FORM into the language specified by OUTPUT-SPEC.
39 Non-null PRETTY-PRINT values result in a pretty-printed output code. If OUTPUT-STREAM
40 is NIL, then the result is a string; otherwise code is output to the OUTPUT-STREAM stream.
41 COMP-ENV is the compilation environment in which to compile the form.
42
43 This is the main function used by Parenscript users to compile their code to Javascript (and
44 potentially other languages)."
45 (macrolet ((with-output-stream ((var) &body body)
46 `(if (null output-stream)
47 (with-output-to-string (,var)
48 ,@body)
49 (let ((,var output-stream))
50 ,@body))))
51 (with-output-stream (stream)
52 (let* ((*compilation-environment* comp-env)
53 (compiled
54 (if toplevel-p
55 (compile-parenscript-form
56 comp-env
57 (compile-parenscript-form comp-env script-form :toplevel-p t))
58 (compile-parenscript-form comp-env script-form :toplevel-p nil))))
59 (translate-ast
60 compiled
61 ; (compile-script-form script-form :comp-env comp-env)
62 :comp-env comp-env
63 :output-stream stream
64 :output-spec output-spec
65 :pretty-print pretty-print)))))
66
67 (defun compile-script-file (source-file
68 &key
69 (output-spec :javascript)
70 (comp-env (or *compilation-environment*
71 (make-basic-compilation-environment)))
72 (pretty-print t)
73 (output-stream *standard-output*))
74 "Compiles the given Parenscript source file and outputs the results
75 to the given output stream."
76 (setf (comp-env-compiling-toplevel-p comp-env) t)
77 (error "NOT IMPLEMENTED."))
78
79 ;(defun compile-script-file (script-src-file
80 ; &key
81 ; (output-spec :javascript)
82 ; (output-stream *standard-out*)
83 ; (comp-env *compilation-environment*))
84
85
86 ;;; SEXPs -> Javascript string functionality
87 (defmacro script (&body body)
88 "A macro that returns a Javascript string of the supplied Parenscript forms."
89 `(js* '(progn ,@body)))
90
91 (defmacro script* (&body body)
92 "Return the javascript string representing BODY.
93
94 Body is evaluated."
95 `(compile-script (progn ,@body)))
96
97 ;; DEPRECATED
98 (defmacro js (&body body)
99 "A macro that returns a javascript string of the supplied Parenscript forms."
100 `(script ,@body))
101
102 (defmacro js* (&body body)
103 `(script* ,@body))
104
105 (defun js-to-string (expr)
106 "Given an AST node, compiles it to a Javascript string."
107 (string-join
108 (js-to-statement-strings (compile-script-form expr) 0)
109 (string #\Newline)))
110
111 (defun js-to-line (expr)
112 "Given an AST node, compiles it to a Javascript string."
113 (string-join
114 (js-to-statement-strings (compile-script-form expr) 0) " "))
115
116
117 ;;; old file compilation functions:
118 (defun compile-parenscript-file-to-string (source-file
119 &key
120 (log-stream nil)
121 (comment nil)
122 (eval-forms-p nil))
123 "Compile SOURCE-FILE (a parenscript file) to a javascript string. (in-package ...) forms
124 behave as expected and all other forms are evaluated according to the value of
125 EVAL-FORMS-P. If the result of the evaluation is not nil then it's compiled with
126 js:js* and written to the output."
127 (with-output-to-string (output)
128 (with-open-file (input source-file :direction :input)
129 (flet ((read-form ()
130 (read input nil))
131 (log-message (&rest args)
132 (when log-stream
133 (apply #'format log-stream args))))
134 (let ((*package* *package*))
135 (loop for form = (read-form)
136 while form do
137 (if (or (not (listp form))
138 (not (eq (car form) 'cl:in-package)))
139 (progn
140 (log-message "Processing form:~%~S~%" form)
141 (when comment
142 (princ "/*" output)
143 (print form output)
144 (terpri output)
145 (princ "*/" output)
146 (terpri output))
147 (when eval-forms-p
148 (setf form (eval form)))
149 (log-message "After evaluation:~%~S~%" form)
150 (when form
151 (let ((compiled (js:js* form)))
152 (log-message "Compiled into:~%~A~%~%" compiled)
153 (write-string compiled output)
154 (terpri output)
155 (terpri output))))
156 (when (and (listp form)
157 (eq (car form) 'cl:in-package))
158 (log-message "Setting package to: ~S~%" (cadr form))
159 (setf *package* (find-package (cadr form)))))))))))
160
161 (defun compile-parenscript-file (source-file &rest args &key destination-file &allow-other-keys)
162 "Compile SOURCE-FILE (a parenscript file) to a javascript file with
163 compile-parenscript-file-to-string. When DESTINATION-FILE is omitted,
164 then it will be named the same as SOURCE-FILE but with js extension."
165 (setf args (copy-list args))
166 (remf args :destination-file)
167 (unless destination-file
168 (setf destination-file (merge-pathnames (make-pathname :type "js")
169 source-file)))
170 (with-open-file (output destination-file :if-exists :supersede :direction :output)
171 (write-string (apply #'compile-parenscript-file-to-string source-file args) output)))