##// END OF EJS Templates
Bugfixes
naryl -
r51:cdf03d3e default
parent child Browse files
Show More
@@ -1,170 +1,170 b''
1 1
2 2 (in-package txt2web.lib)
3 3
4 4 ;;;; Macros implementing some intrinsics where it makes sense
5 5 ;;;; E.g. an equivalent JS function exists, or it's a direct API call
6 6
7 7 ;;; 1loc
8 8
9 9 ;;; 2var
10 10
11 11 (defpsmacro killvar (varname &optional index)
12 12 `(api-call kill-var ,varname ,index))
13 13
14 14 (defpsmacro killall ()
15 15 `(api-call kill-all))
16 16
17 17 ;;; 3expr
18 18
19 19 (defpsmacro no (arg)
20 20 `(- -1 ,arg))
21 21
22 22 ;;; 4code
23 23
24 24 (defpsmacro qspver ()
25 25 "0.0.1")
26 26
27 27 (defpsmacro curloc ()
28 28 `*current-location)
29 29
30 30 (defpsmacro rnd ()
31 31 `(funcall rand 1 1000))
32 32
33 33 (defpsmacro qspmax (&rest args)
34 34 (if (= 1 (length args))
35 35 `(*math.max.apply nil ,@args)
36 36 `(*math.max ,@args)))
37 37
38 38 (defpsmacro qspmin (&rest args)
39 39 (if (= 1 (length args))
40 40 `(*math.min.apply nil ,@args)
41 41 `(*math.min ,@args)))
42 42
43 43 ;;; 5arrays
44 44
45 45 (defpsmacro arrsize (name)
46 46 `(api-call array-size ,name))
47 47
48 48 ;;; 6str
49 49
50 50 (defpsmacro len (s)
51 51 `(length ,s))
52 52
53 53 (defpsmacro mid (s from &optional count)
54 54 `(chain ,s (substring ,from ,count)))
55 55
56 56 (defpsmacro ucase (s)
57 57 `(chain ,s (to-upper-case)))
58 58
59 59 (defpsmacro lcase (s)
60 60 `(chain ,s (to-lower-case)))
61 61
62 62 (defpsmacro trim (s)
63 63 `(chain ,s (trim)))
64 64
65 (defpsmacro replace (s from to)
65 (defpsmacro qspreplace (s from to)
66 66 `(chain ,s (replace ,from ,to)))
67 67
68 68 (defpsmacro val (s)
69 69 `(parse-int ,s 10))
70 70
71 71 (defpsmacro qspstr (n)
72 72 `(chain ,n (to-string)))
73 73
74 74 ;;; 7if
75 75
76 76 ;;; 8sub
77 77
78 78 ;;; 9loops
79 79
80 80 ;; JUMP is in ps-macros.lisp (because it's a part of a huge kludge)
81 81
82 82 (defpsmacro exit ()
83 83 `(return-from nil (values)))
84 84
85 85 ;;; 10dynamic
86 86
87 87 ;;; 11main
88 88
89 89 (defpsmacro desc (s)
90 90 (declare (ignore s))
91 91 "")
92 92
93 93 ;;; 12stat
94 94
95 95 (defpsmacro showstat (enable)
96 96 `(api-call enable-frame :stat ,enable))
97 97
98 98 ;;; 13diag
99 99
100 100 (defpsmacro msg (text)
101 101 `(alert ,text))
102 102
103 103 ;;; 14act
104 104
105 105 (defpsmacro showacts (enable)
106 106 `(api-call enable-frame :acts ,enable))
107 107
108 108 (defpsmacro delact (&optional name)
109 109 (if name
110 110 `(api-call del-act ,name)
111 111 `(api-call del-act)))
112 112
113 113 (defpsmacro cla ()
114 114 `(api-call clear-act))
115 115
116 116 ;;; 15objs
117 117
118 118 (defpsmacro showobjs (enable)
119 119 `(api-call enable-frame :objs ,enable))
120 120
121 121 (defpsmacro countobj ()
122 122 `(length *objs))
123 123
124 124 (defpsmacro getobj (index)
125 125 `(or (elt *objs ,index) ""))
126 126
127 127 ;;; 16menu
128 128
129 129 ;;; 17sound
130 130
131 131 (defpsmacro isplay (filename)
132 132 `(funcall (@ playing includes) ,filename))
133 133
134 134 ;;; 18img
135 135
136 136 (defpsmacro view (&optional path)
137 137 `(api-call show-image ,path))
138 138
139 139 (defpsmacro img (&rest images)
140 140 `(api-call show-inline-images :stat (list ,@images)))
141 141
142 142 (defpsmacro *img (&rest images)
143 143 `(api-call show-inline-images :main (list ,@images)))
144 144
145 145 ;;; 19input
146 146
147 147 (defpsmacro showinput (enable)
148 148 `(api-call enable-frame :input ,enable))
149 149
150 150 ;;; 20time
151 151
152 152 (defpsmacro wait (msec)
153 153 `(await (api-call sleep ,msec)))
154 154
155 155 (defpsmacro settimer (interval)
156 156 `(api-call set-timer ,interval))
157 157
158 158 ;;; 21local
159 159
160 160 ;;; 22for
161 161
162 162 ;;; misc
163 163
164 164 (defpsmacro opengame (&optional filename)
165 165 (declare (ignore filename))
166 166 `(api-call opengame))
167 167
168 168 (defpsmacro savegame (&optional filename)
169 169 (declare (ignore filename))
170 170 `(api-call savegame))
@@ -1,154 +1,153 b''
1 1
2 2 (in-package txt2web)
3 3
4 4 (defvar *app-name* "")
5 5
6 6 (defun entry-point-no-args ()
7 (format t "~A~%" uiop:*command-line-arguments*)
8 7 (entry-point uiop:*command-line-arguments*))
9 8
10 9 (defun entry-point (args)
11 10 (setf *app-name* (uiop:argv0))
12 11 (let ((*package* (find-package :txt2web)))
13 12 (catch :terminate
14 13 (let ((compiler (apply #'make-instance 'compiler (parse-opts args))))
15 14 (write-compiled-file compiler))))
16 15 (values))
17 16
18 17 (defun parse-opts (args)
19 18 (let ((mode :sources)
20 19 (data (list :sources nil :target nil :js nil :css nil :body nil :compile nil :beautify nil)))
21 20 (loop :for arg :in args
22 21 :do (alexandria:switch (arg :test #'string=)
23 22 ("-o" (setf mode :target))
24 23 ("--js" (setf mode :js))
25 24 ("--css" (setf mode :css))
26 25 ("--body" (setf mode :body))
27 26 ("-c" (setf (getf data :compile) t))
28 27 ("--beautify" (setf (getf data :beautify) t))
29 28 (t (push arg (getf data mode)))))
30 29 (unless (< 0 (length (getf data :sources)))
31 30 (report-error "There should be at least one source"))
32 31 (unless (> 1 (length (getf data :target)))
33 32 (report-error "There should be no more than one target"))
34 33 (unless (> 1 (length (getf data :body)))
35 34 (report-error "There should be no more than one body"))
36 35 (unless (getf data :target)
37 36 (setf (getf data :target)
38 37 (let* ((sources (first (getf data :sources)))
39 38 (tokens (uiop:split-string sources :separator "."))
40 39 (target (format nil "~{~A~^.~}.html"
41 40 (butlast tokens))))
42 41 (list target))))
43 42 (list :sources (getf data :sources)
44 43 :target (first (getf data :target))
45 44 :js (getf data :js)
46 45 :css (getf data :css)
47 46 :body (first (getf data :body))
48 47 :compile (getf data :compile)
49 48 :beautify (getf data :beautify))))
50 49
51 50 (defun print-usage ()
52 51 (lformat t :usage *app-name*))
53 52
54 53 (defun parse-file (filename)
55 54 (p:parse 'txt2web-grammar
56 55 (alexandria:read-file-into-string filename)))
57 56
58 57 (defun report-error (fmt &rest args)
59 58 (format t "ERROR: ~A~%" (apply #'format nil fmt args))
60 59 (print-usage)
61 60 (throw :terminate nil))
62 61
63 62 ;;; JS
64 63
65 64 (defun minify-package (package-designator minify prefix)
66 65 (setf (ps:ps-package-prefix package-designator) prefix)
67 66 (if minify
68 67 (ps:obfuscate-package package-designator)
69 68 (ps:unobfuscate-package package-designator)))
70 69
71 70 (defmethod js-sources ((compiler compiler))
72 71 (let ((ps:*ps-print-pretty* (beautify compiler)))
73 72 (cond ((beautify compiler)
74 73 (minify-package "TXT2WEB.MAIN" nil "qsp_")
75 74 (minify-package "TXT2WEB.API" nil "qsp_api_")
76 75 (minify-package "TXT2WEB.LIB" nil "qsp_lib_"))
77 76 (t
78 77 (minify-package "TXT2WEB.MAIN" t "_")
79 78 (minify-package "TXT2WEB.API" t "a_")
80 79 (minify-package "TXT2WEB.LIB" t "l_")))
81 80 (format nil "~{~A~^~%~%~}" (mapcar #'ps:ps* (reverse (js compiler))))))
82 81
83 82 ;;; CSS
84 83
85 84 (defmethod css-sources ((compiler compiler))
86 85 (format nil "~{~A~^~%~%~}" (css compiler)))
87 86
88 87 ;;; HTML
89 88
90 89 (defmethod html-sources ((compiler compiler))
91 90 (let ((flute:*escape-html* nil)
92 91 (body-template (body compiler))
93 92 (js (js-sources compiler))
94 93 (css (css-sources compiler)))
95 94 (with-output-to-string (out)
96 95 (write
97 96 (flute:h
98 97 (html
99 98 (head
100 99 (title "SugarQSP"))
101 100 (body
102 101 body-template
103 102 (style css)
104 103 (script js))))
105 104 :stream out
106 105 :pretty nil))))
107 106
108 107 (defun filename-game (filename)
109 108 (let ((filename (alexandria:lastcar (uiop:split-string filename :separator "/"))))
110 109 (format nil "~{~A~^.~}" (butlast (uiop:split-string filename :separator ".")))))
111 110
112 111 (defmethod initialize-instance ((compiler compiler) &key sources ((:js js-files)) ((:css css-files)) ((:body body-file)) compile &allow-other-keys)
113 112 (call-next-method)
114 113 (with-slots (body css js)
115 114 compiler
116 115 ;; Compile the game's JS
117 116 (dolist (source sources)
118 117 (let ((ps (parse-file source))
119 118 (game-name (filename-game source)))
120 119 (destructuring-bind (kw &rest locations)
121 120 ps
122 121 (unless (eq kw 'lib:game)
123 122 (report-error "Internal error!"))
124 123 (push
125 124 `(lib:game (,game-name) ,@locations)
126 125 js))))
127 126 ;; Does the user need us to do anything else
128 127 (unless compile
129 128 ;; Read in body
130 129 (when body-file
131 130 (setf body
132 131 (alexandria:read-file-into-string body-file)))
133 132 ;; Include js files
134 133 (dolist (js-file js-files)
135 134 (push (format nil "////// Included file ~A~%~A" js-file
136 135 (alexandria:read-file-into-string js-file))
137 136 js))
138 137 ;; Include css files
139 138 (when css-files
140 139 ;; User option overrides the default css
141 140 (setf css nil)
142 141 (dolist (css-file css-files)
143 142 (push (format nil "////// Included file ~A~%~A" css-file
144 143 (alexandria:read-file-into-string css-file))
145 144 css))))))
146 145
147 146 (defmethod write-compiled-file ((compiler compiler))
148 147 (alexandria:write-string-into-file
149 148 (if (compile-only compiler)
150 149 ;; Just the JS
151 150 (js-sources compiler)
152 151 ;; All of it
153 152 (html-sources compiler))
154 153 (target compiler) :if-exists :supersede))
@@ -1,624 +1,624 b''
1 1
2 2 (in-package txt2web)
3 3
4 4 ;;;; Parses TXT source to an intermediate representation
5 5
6 6 (eval-when (:compile-toplevel :load-toplevel :execute)
7 7 (defparameter *max-args* 10))
8 8
9 9 ;;; Utility
10 10
11 11 (defun remove-nth (list nth)
12 12 (append (subseq list 0 nth)
13 13 (subseq list (1+ nth))))
14 14
15 15 (defun not-quote (char)
16 16 (not (eql #\' char)))
17 17
18 18 (defun not-doublequote (char)
19 19 (not (eql #\" char)))
20 20
21 21 (defun not-brace (char)
22 22 (not (eql #\} char)))
23 23
24 24 (defun not-integer (string)
25 25 (when (find-if-not #'digit-char-p string)
26 26 t))
27 27
28 28 (defun not-newline (char)
29 29 (not (eql #\newline char)))
30 30
31 31 (defun id-any-char (char)
32 32 (and
33 33 (not (digit-char-p char))
34 34 (not (eql #\newline char))
35 35 (not (find char " !:&=<>+-*/,'\"()[]{}"))))
36 36
37 37 (defun intern-first (list)
38 38 (list* (intern (string-upcase (first list)) "TXT2WEB.LIB")
39 39 (rest list)))
40 40
41 41 (eval-when (:compile-toplevel :load-toplevel :execute)
42 42 (defun remove-nil (list)
43 43 (remove nil list)))
44 44
45 45 (defun binop-rest (list)
46 46 (destructuring-bind (ws1 operator ws2 operand2)
47 47 list
48 48 (declare (ignore ws1 ws2))
49 49 (list (intern (string-upcase operator) "TXT2WEB.LIB") operand2)))
50 50
51 51 (defun do-binop% (left-op other-ops)
52 52 (if (null other-ops)
53 53 left-op
54 54 (destructuring-bind ((operator right-op) &rest rest-ops)
55 55 other-ops
56 56 (if (and (listp left-op)
57 57 (eq (first left-op)
58 58 operator))
59 59 (do-binop% (append left-op (list right-op)) rest-ops)
60 60 (do-binop% (list operator left-op right-op) rest-ops)))))
61 61
62 62 (defun do-binop (list)
63 63 (destructuring-bind (left-op rest-ops)
64 64 list
65 65 (do-binop% left-op
66 66 (mapcar #'binop-rest rest-ops))))
67 67
68 68 (p:defrule line-continuation (and #\_ #\newline)
69 69 (:constant nil))
70 70
71 71 (p:defrule text-spaces (+ (or #\space #\tab line-continuation))
72 72 (:text t))
73 73
74 74 (p:defrule spaces (+ (or #\space #\tab line-continuation))
75 75 (:constant nil)
76 76 (:error-report nil))
77 77
78 78 (p:defrule spaces? (* (or #\space #\tab line-continuation))
79 79 (:constant nil)
80 80 (:error-report nil))
81 81
82 82 (p:defrule colon #\:
83 83 (:constant nil))
84 84
85 85 (p:defrule equal #\=
86 86 (:constant nil))
87 87
88 88 (p:defrule alphanumeric (alphanumericp character))
89 89
90 90 (p:defrule not-newline (not-newline character))
91 91
92 92 (p:defrule squote-esc "''"
93 93 (:lambda (list)
94 94 (p:text (elt list 0))))
95 95
96 96 (p:defrule dquote-esc "\"\""
97 97 (:lambda (list)
98 98 (p:text (elt list 0))))
99 99
100 100 (p:defrule sstring-chars (+ (and (and (p:! "<<") (p:! (p:~ "\"exec:")))
101 101 (or squote-esc (not-quote character))))
102 102 (:lambda (list)
103 103 (p:text (mapcar #'second list))))
104 104
105 105 (p:defrule dstring-chars (+ (and (and (p:! "<<") (p:! (p:~ "'exec:")))
106 106 (or dquote-esc (not-doublequote character))))
107 107 (:lambda (list)
108 108 (p:text (mapcar #'second list))))
109 109
110 110 ;;; Identifiers
111 111
112 112 (defparameter *keywords* '(act addlib addobj addqst and arrcomp arrpos arrsize cla clear *clear close clr *clr cls cmdclear cmdclr copyarr counter countobj curact curacts curloc debug delact dellib delobj desc disablescroll disablesubex dynamic dyneval else elseif end exit for freelib func getobj gosub goto gs gt if iif img *img inclib input instr isnum isplay jump killall killobj killqst killvar lcase lcolor len let loc local maintxt max menu mid min mod msecscount msg nl *nl no nosave obj opengame openqst or p *p pl *pl play qspver rand refint replace rgb rnd savegame selact selobj set settimer showacts showinput showobjs showstat stattxt step str strcomp strfind strpos to trim ucase unsel unselect usercom user_text usrtxt val view wait xgoto xgt))
113 113
114 114 (defun trim-$ (str)
115 115 (if (char= #\$ (elt str 0))
116 116 (subseq str 1)
117 117 str))
118 118
119 119 (defun qsp-keyword-p (id)
120 120 (member (intern (trim-$ (string-upcase id))) *keywords*))
121 121
122 122 (defun not-qsp-keyword-p (id)
123 123 (not (member (intern (trim-$ (string-upcase id))) *keywords*)))
124 124
125 125 (p:defrule qsp-keyword (qsp-keyword-p identifier-raw))
126 126
127 127 (p:defrule id-first (id-any-char character))
128 128 (p:defrule id-next (or (id-any-char character)
129 129 (digit-char-p character)))
130 130 (p:defrule identifier-raw (and id-first (* id-next))
131 131 (:lambda (list)
132 132 (intern (string-upcase (p:text list)) "TXT2WEB.LIB")))
133 133
134 134 (p:defrule identifier (not-qsp-keyword-p identifier-raw))
135 135
136 136 ;;; Strings
137 137
138 138 (p:defrule qsp-string (or normal-string brace-string))
139 139
140 140 (p:defrule normal-string (or sstring dstring)
141 141 (:lambda (str)
142 142 (list* 'lib:str (or str (list "")))))
143 143
144 144 (p:defrule sstring (and #\' (* (or string-interpol
145 145 sstring-exec
146 146 sstring-chars))
147 147 #\')
148 148 (:function second))
149 149
150 150 (p:defrule dstring (and #\" (* (or string-interpol
151 151 dstring-exec
152 152 dstring-chars))
153 153 #\")
154 154 (:function second))
155 155
156 156 (p:defrule string-interpol (and "<<" expression ">>")
157 157 (:function second))
158 158
159 159 (p:defrule sstring-exec-body (+ (or squote-esc (not-doublequote character)))
160 160 (:text t))
161 161
162 162 (p:defrule dstring-exec-body (+ (or dquote-esc (not-quote character)))
163 163 (:text t))
164 164
165 165 (p:defrule sstring-exec (and (p:~ "\"exec:") sstring-exec-body #\")
166 166 (:lambda (list)
167 167 (list* 'lib:exec (p:parse 'exec-body (second list)))))
168 168
169 169 (p:defrule dstring-exec (and (p:~ "'exec:") dstring-exec-body #\')
170 170 (:lambda (list)
171 171 (list* 'lib:exec (p:parse 'exec-body (second list)))))
172 172
173 173 (p:defrule brace-string (and #\{ before-statement block-body #\})
174 174 (:lambda (list)
175 175 (list* 'lib:qspblock (third list))))
176 176
177 177 ;;; Location
178 178
179 179 (p:defrule txt2web-grammar (and (* (or spaces #\newline))
180 180 (* location))
181 181 (:lambda (list)
182 182 `(lib:game ,@(second list))))
183 183
184 184 (p:defrule location (and location-header block-body location-end)
185 185 (:destructure (header body end)
186 186 (declare (ignore end))
187 187 `(lib:location (,header) ,@body)))
188 188
189 189 (p:defrule location-header (and #\#
190 190 (+ not-newline)
191 191 (and #\newline spaces? before-statement))
192 192 (:destructure (spaces1 name spaces2)
193 193 (declare (ignore spaces1 spaces2))
194 194 (string-upcase (string-trim " " (p:text name)))))
195 195
196 196 (p:defrule location-end (and #\- (* not-newline) #\newline before-statement)
197 197 (:constant nil))
198 198
199 199 ;;; Block body
200 200
201 201 (p:defrule newline-block-body (and #\newline spaces? block-body)
202 202 (:function third))
203 203
204 204 (p:defrule block-body (* statement)
205 205 (:function remove-nil))
206 206
207 207 ;; Just for <a href="exec:...'>
208 208 ;; Explicitly called from that rule's production
209 209 (p:defrule exec-body (and before-statement line-body)
210 210 (:function second))
211 211
212 212 (p:defrule line-body (and inline-statement (* next-inline-statement))
213 213 (:lambda (list)
214 214 (list* (first list) (second list))))
215 215
216 216 (p:defrule before-statement (* (or #\newline spaces))
217 217 (:constant nil))
218 218
219 219 (p:defrule statement-end (or statement-end-real statement-end-block-close))
220 220
221 221 (p:defrule statement-end-real (and (or #\newline
222 222 (and #\& spaces? (p:& statement%)))
223 223 before-statement)
224 224 (:constant nil))
225 225
226 226 (p:defrule statement-end-block-close (or (p:& #\}))
227 227 (:constant nil))
228 228
229 229 (p:defrule inline-statement (and statement% spaces?)
230 230 (:function first))
231 231
232 232 (p:defrule next-inline-statement (and #\& spaces? inline-statement)
233 233 (:function third))
234 234
235 235 (p:defrule not-a-non-statement (and (p:! (p:~ "elseif"))
236 236 (p:! (p:~ "else"))
237 237 (p:! (p:~ "end"))))
238 238
239 239 (p:defrule statement (and inline-statement statement-end)
240 240 (:function first))
241 241
242 242 (p:defrule statement% (and not-a-non-statement
243 243 (or label comment string-output
244 244 block non-returning-intrinsic local
245 245 assignment expression-output))
246 246 (:function second))
247 247
248 248 (p:defrule expr-stopper (or comment block non-returning-intrinsic))
249 249
250 250 (p:defrule string-output qsp-string
251 251 (:lambda (string)
252 252 (list 'lib:main-pl string)))
253 253
254 254 (p:defrule expression-output expression
255 255 (:lambda (list)
256 256 (list 'lib:main-pl list)))
257 257
258 258 (p:defrule label (and colon identifier)
259 259 (:lambda (list)
260 260 (intern (string (second list)) :keyword)))
261 261
262 262 (p:defrule comment (and #\! (* (or qsp-string brace-comment text-spaces not-newline)))
263 263 (:constant nil))
264 264
265 265 (p:defrule brace-comment (and #\{ (* (not-brace character)) #\})
266 266 (:constant nil))
267 267
268 268 (p:defrule local (and (p:~ "local") spaces variable (p:? (and spaces? #\= spaces? expression)))
269 269 (:lambda (list)
270 270 (list* 'lib:local (third list)
271 271 (when (fourth list)
272 272 (list (fourth (fourth list)))))))
273 273
274 274 ;;; Blocks
275 275
276 276 (p:defrule block (or block-act block-if block-for))
277 277
278 278 (p:defrule block-if (and block-if-head block-if-body)
279 279 (:destructure (head body)
280 280 `(lib:qspcond (,@head ,@(first body))
281 281 ,@(rest body))))
282 282
283 283 (p:defrule block-if-head (and (p:~ "if") spaces expression spaces? colon spaces?)
284 284 (:function remove-nil)
285 285 (:function cdr))
286 286
287 287 (p:defrule block-if-body (or block-if-ml block-if-sl)
288 288 (:destructure (if-body elseifs else &rest ws)
289 289 (declare (ignore ws))
290 290 `(,(remove-nil if-body) ,@elseifs ,@(when else `((else ,@else))))))
291 291
292 292 (p:defrule block-if-sl (and line-body
293 293 (p:? block-if-elseif-inline)
294 294 (p:? block-if-else-inline)
295 295 spaces?))
296 296
297 297 (p:defrule block-if-ml (and (and #\newline spaces?)
298 298 block-body
299 299 (p:? block-if-elseif)
300 300 (p:? block-if-else)
301 301 block-if-end)
302 302 (:lambda (list)
303 303 (cdr list)))
304 304
305 305 (p:defrule block-if-elseif-inline (and block-if-elseif-head line-body (p:? block-if-elseif-inline))
306 306 (:destructure (head statements elseif)
307 307 `((,@(rest head) ,@(remove-nil statements)) ,@elseif)))
308 308
309 309 (p:defrule block-if-elseif (and block-if-elseif-head statement-end block-body (p:? block-if-elseif))
310 310 (:destructure (head ws statements elseif)
311 311 (declare (ignore ws))
312 312 `((,@(rest head) ,@(remove-nil statements)) ,@elseif)))
313 313
314 314 (p:defrule block-if-elseif-head (and (p:~ "elseif") spaces expression spaces? colon spaces?)
315 315 (:function remove-nil)
316 316 (:function intern-first))
317 317
318 318 (p:defrule block-if-else-inline (and block-if-else-head line-body)
319 319 (:function second))
320 320
321 321 (p:defrule block-if-else (and block-if-else-head #\newline spaces? block-body)
322 322 (:function fourth))
323 323
324 324 (p:defrule block-if-else-head (and (p:~ "else") spaces?)
325 325 (:constant nil))
326 326
327 327 (p:defrule block-if-end (and (p:~ "end")
328 328 (p:? (and spaces (p:~ "if"))))
329 329 (:constant nil))
330 330
331 331 (p:defrule block-act (and block-act-head (or block-ml block-sl))
332 332 (:lambda (list)
333 333 (apply #'append list)))
334 334
335 335 (p:defrule block-act-head (and (p:~ "act") spaces? qsp-string spaces?
336 336 (p:? block-act-head-img)
337 337 colon spaces?)
338 338 (:lambda (list)
339 339 (intern-first (list (first list)
340 340 (third list)
341 341 (or (fifth list) '(lib:str ""))))))
342 342
343 343 (p:defrule block-act-head-img (and #\, spaces? qsp-string spaces?)
344 344 (:lambda (list)
345 345 (or (third list) "")))
346 346
347 347 (p:defrule block-for (and block-for-head (or block-ml block-sl))
348 348 (:lambda (list)
349 349 (apply #'append list)))
350 350
351 351 (p:defrule block-for-head (and (p:~ "for") spaces variable spaces? equal spaces? expression
352 352 (p:~ "to") spaces expression
353 353 block-for-head-step
354 354 colon spaces?)
355 355 (:lambda (list)
356 356 (list 'lib:qspfor
357 357 (elt list 2)
358 358 (elt list 6)
359 359 (elt list 9)
360 360 (elt list 10))))
361 361
362 362 (p:defrule block-for-head-step (p:? (and (p:~ "step") spaces expression spaces?))
363 363 (:lambda (list)
364 364 (if list
365 365 (third list)
366 366 1)))
367 367
368 368 (p:defrule block-sl line-body)
369 369
370 370 (p:defrule block-ml (and newline-block-body block-end)
371 371 (:lambda (list)
372 372 (apply #'list* (butlast list))))
373 373
374 374 (p:defrule block-end (and (p:~ "end"))
375 375 (:constant nil))
376 376
377 377 ;;; Calls
378 378
379 379 (p:defrule first-argument (and expression spaces?)
380 380 (:function first))
381 381 (p:defrule next-argument (and "," spaces? expression)
382 382 (:function third))
383 383 (p:defrule arguments (or parenthesized-arguments plain-arguments no-arguments))
384 384 (p:defrule parenthesized-arguments (and spaces? #\( base-arguments #\))
385 385 (:function third))
386 386 (p:defrule plain-arguments (and spaces? base-arguments)
387 387 (:function second))
388 388 (p:defrule no-arguments (or (and spaces? (p:& #\newline))
389 389 (and spaces? (p:& #\&))
390 390 spaces?)
391 391 (:constant nil))
392 392 (p:defrule base-arguments (or (and first-argument (* next-argument)) spaces?)
393 393 (:lambda (list)
394 394 (if (null list)
395 395 nil
396 396 (list* (first list) (second list)))))
397 397
398 398 ;;; Intrinsics
399 399
400 400 (defmacro defintrinsics ((rule-name returning-rule-name non-returning-rule-name) &body clauses)
401 401 `(progn
402 402 ,@(loop :for clause :in clauses
403 403 :collect `(defintrinsic ,@clause))
404 404 (p:defrule ,returning-rule-name (or ,@(remove-nil
405 405 (mapcar (lambda (clause)
406 406 (when (second clause)
407 407 (alexandria:symbolicate
408 408 'intrinsic- (first clause))))
409 409 clauses))))
410 410 (p:defrule ,non-returning-rule-name (or ,@(remove-nil
411 411 (mapcar (lambda (clause)
412 412 (unless (second clause)
413 413 (alexandria:symbolicate
414 414 'intrinsic- (first clause))))
415 415 clauses))))
416 416 (p:defrule ,rule-name (or ,returning-rule-name ,non-returning-rule-name))))
417 417
418 418 (defmacro defintrinsic (sym returning &optional (min-arity 0) max-arity &rest names)
419 419 (declare (ignore returning))
420 420 (unless max-arity
421 421 (setf max-arity *max-args*))
422 422 (setf names
423 423 (if names
424 424 (mapcar #'string-upcase names)
425 425 (list (string sym))))
426 426 `(p:defrule ,(alexandria:symbolicate 'intrinsic- sym)
427 427 (and (p:? #\$) (or ,@(loop :for name :in names :collect `(p:~ ,name)))
428 428 arguments)
429 429 (:destructure (dollar name arguments)
430 430 (declare (ignore dollar))
431 431 (unless (<= ,min-arity (length arguments) ,max-arity)
432 432 (error "Intrinsic ~A expects between ~A and ~A arguments but ~A were provided:~%~S"
433 433 name ,min-arity ,max-arity (length arguments) arguments))
434 434 (list* ',(intern (string sym) "TXT2WEB.LIB") arguments))))
435 435
436 436 (defintrinsics (intrinsic returning-intrinsic non-returning-intrinsic)
437 437 ;; Transitions
438 438 (goto% nil 0 nil "gt" "goto")
439 439 (xgoto% nil 0 nil "xgt" "xgoto")
440 440 ;; Variables
441 441 (killvar nil 0 2)
442 442 ;; Expressions
443 443 (obj t 1 1)
444 444 (loc t 1 1)
445 445 (no t 1 1)
446 446 ;; Basic
447 447 (qspver t 0 0)
448 448 (curloc t 0 0)
449 449 (rand t 1 2)
450 450 (rnd t 0 0)
451 451 (qspmax t 1 nil "max")
452 452 (qspmin t 1 nil "min")
453 453 ;; Arrays
454 454 (killall nil 0 0)
455 455 (copyarr nil 2 4)
456 456 (arrsize t 1 1)
457 457 (arrpos t 2 3)
458 458 (arrcomp t 2 3)
459 459 ;; Strings
460 460 (len t 1 1)
461 461 (mid t 2 3)
462 462 (ucase t 1 1)
463 463 (lcase t 1 1)
464 464 (trim t 1 1)
465 (replace t 2 3)
465 (qspreplace t 2 3 "replace")
466 466 (instr t 2 3)
467 467 (isnum t 1 1)
468 468 (val t 1 1)
469 469 (qspstr t 1 1 "str")
470 470 (strcomp t 2 2)
471 471 (strfind t 2 3)
472 472 (strpos t 2 3)
473 473 ;; IF
474 474 (iif t 2 3)
475 475 ;; Subs
476 476 (gosub nil 1 nil "gosub" "gs")
477 477 (func t 1 nil)
478 478 (exit nil 0 0)
479 479 ;; Jump
480 480 (jump nil 1 1)
481 481 ;; Dynamic
482 482 (dynamic nil 1 nil)
483 483 (dyneval t 1 nil)
484 484 ;; Sound
485 485 (play nil 1 2)
486 486 (isplay t 1 1)
487 487 (close nil 1 1)
488 488 (closeall nil 0 0 "close all")
489 489 ;; Main window
490 490 (main-pl nil 1 1 "*pl")
491 491 (main-nl nil 0 1 "*nl")
492 492 (main-p nil 1 1 "*p")
493 493 (maintxt t 0 0)
494 494 (desc t 1 1)
495 495 (main-clear nil 0 0 "*clear" "*clr")
496 496 ;; Aux window
497 497 (showstat nil 1 1)
498 498 (stat-pl nil 1 1 "pl")
499 499 (stat-nl nil 0 1 "nl")
500 500 (stat-p nil 1 1 "p")
501 501 (stattxt t 0 0)
502 502 (stat-clear nil 0 0 "clear" "clr")
503 503 (cls nil 0 0)
504 504 ;; Dialog
505 505 (msg nil 1 1)
506 506 ;; Acts
507 507 (showacts nil 1 1)
508 508 (delact nil 1 1 "delact" "del act")
509 509 (curacts t 0 0)
510 510 (selact t 0 0)
511 511 (cla nil 0 0)
512 512 ;; Objects
513 513 (showobjs nil 1 1)
514 514 (addobj nil 1 3 "addobj" "add obj")
515 515 (delobj nil 1 1 "delobj" "del obj")
516 516 (killobj nil 0 1)
517 517 (countobj t 0 0)
518 518 (getobj t 1 1)
519 519 (selobj t 0 0)
520 520 ;; Menu
521 521 (menu nil 1 1)
522 522 ;; Images
523 523 (refint nil 0 0)
524 524 (view nil 0 1)
525 525 (img nil 1)
526 526 (*img nil 1)
527 527 ;; Fonts
528 528 (rgb t 3 3)
529 529 ;; Input
530 530 (showinput nil 1 1)
531 531 (usertxt t 0 0 "user_text" "usrtxt")
532 532 (cmdclear nil 0 0 "cmdclear" "cmdclr")
533 533 (input t 1 1)
534 534 ;; Files
535 535 (openqst nil 1 1)
536 536 (addqst nil 1 1 "addqst" "addlib" "inclib")
537 537 (killqst nil 1 1 "killqst" "dellib" "freelib")
538 538 (opengame nil 0 0)
539 539 (savegame nil 0 0)
540 540 ;; Real time
541 541 (wait nil 1 1)
542 542 (msecscount t 0 0)
543 543 (settimer nil 1 1))
544 544
545 545 ;;; Expression
546 546
547 547 (p:defrule expression or-expr)
548 548
549 549 (p:defrule or-expr (and and-expr (* (and spaces? or-op spaces? and-expr)))
550 550 (:function do-binop))
551 551
552 552 (p:defrule and-expr (and eq-expr (* (and spaces? and-op spaces? eq-expr)))
553 553 (:function do-binop))
554 554
555 555 (p:defrule eq-expr (and sum-expr (* (and spaces? (or "<=" ">=" "=<" "=>" "<>"
556 556 "=" "<" ">" "!")
557 557 spaces? sum-expr)))
558 558 (:function do-binop))
559 559
560 560 (p:defrule sum-expr (and mod-expr (* (and spaces? (or #\+ #\-) spaces? mod-expr)))
561 561 (:function do-binop))
562 562
563 563 (p:defrule mod-expr (and mul-expr (* (and spaces? (p:~ "mod") spaces? mul-expr)))
564 564 (:function do-binop))
565 565
566 566 (p:defrule mul-expr (and unary-expr (* (and spaces? (or #\* #\/) spaces? unary-expr)))
567 567 (:function do-binop))
568 568
569 569 (p:defrule unary-expr (and (p:? (or #\+ #\-)) atom-expr)
570 570 (:lambda (list)
571 571 (let ((expr (remove-nil list)))
572 572 (if (= 1 (length expr))
573 573 (first expr)
574 574 (intern-first expr)))))
575 575
576 576 (p:defrule atom-expr (and (or variable literal returning-intrinsic paren-expr) spaces?)
577 577 (:function first))
578 578
579 579 (p:defrule paren-expr (and #\( spaces? expression spaces? #\))
580 580 (:function third))
581 581
582 582 (p:defrule or-op (p:~ "or")
583 583 (:constant "or"))
584 584
585 585 (p:defrule and-op (p:~ "and")
586 586 (:constant "and"))
587 587
588 588 ;;; Variables
589 589
590 590 (p:defrule variable (and identifier (p:? array-index))
591 591 (:destructure (id idx-raw)
592 592 (let ((idx (case idx-raw
593 593 ((nil) 0)
594 594 (:last nil)
595 595 (t idx-raw))))
596 596 (list 'lib:qspvar id idx))))
597 597
598 598 (p:defrule array-index (and #\[ spaces? (p:? expression) spaces? #\])
599 599 (:lambda (list)
600 600 (or (third list) :last)))
601 601
602 602 (p:defrule assignment (or kw-assignment plain-assignment op-assignment)
603 603 (:destructure (qspvar eq expr)
604 604 (declare (ignore eq))
605 605 (list 'lib:set qspvar expr)))
606 606
607 607 (p:defrule kw-assignment (and (or (p:~ "let") (p:~ "set")) spaces? (or op-assignment plain-assignment))
608 608 (:function third))
609 609
610 610 (p:defrule op-assignment (and variable spaces? (or "+" "-" "*" "/") #\= spaces? expression)
611 611 (:destructure (qspvar ws1 op eq ws2 expr)
612 612 (declare (ignore ws1 ws2))
613 613 (list qspvar eq (intern-first (list op qspvar expr)))))
614 614
615 615 (p:defrule plain-assignment (and variable spaces? #\= spaces? expression)
616 616 (:function remove-nil))
617 617
618 618 ;;; Non-string literals
619 619
620 620 (p:defrule literal (or qsp-string brace-string number))
621 621
622 622 (p:defrule number (+ (or #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))
623 623 (:lambda (list)
624 624 (parse-integer (p:text list))))
@@ -1,74 +1,74 b''
1 1
2 2 (in-package parenscript)
3 3
4 4 ;;; async/await
5 5
6 6 (defprinter ps-js::await (x)
7 7 (psw (string-downcase "await "))
8 8 (print-op-argument 'ps-js::await x))
9 9
10 10 (define-trivial-special-ops await ps-js::await)
11 11
12 12 (define-statement-operator async-defun (name lambda-list &rest body)
13 13 (multiple-value-bind (effective-args body-block docstring)
14 14 (compile-named-function-body name lambda-list body)
15 15 (list 'ps-js::async-defun name effective-args docstring body-block)))
16 16
17 17 (defprinter ps-js::async-defun (name args docstring body-block)
18 18 (when docstring (print-comment docstring))
19 19 (psw "async ")
20 20 (print-fun-def name args body-block))
21 21
22 22 (define-expression-operator async-lambda (lambda-list &rest body)
23 23 (multiple-value-bind (effective-args effective-body)
24 24 (parse-extended-function lambda-list body)
25 25 `(ps-js::async-lambda
26 26 ,effective-args
27 27 ,(let ((*function-block-names* ()))
28 28 (compile-function-body effective-args effective-body)))))
29 29
30 30 (defprinter ps-js::async-lambda (args body-block)
31 31 (psw "async ")
32 32 (print-fun-def nil args body-block))
33 33
34 34 (cl:export 'await)
35 35 (cl:export 'async-defun)
36 36 (cl:export 'async-lambda)
37 37
38 38 ;;; ES6
39 39
40 40 (define-expression-operator => (lambda-list &rest body)
41 41 (unless (listp lambda-list)
42 42 (setf lambda-list (list lambda-list)))
43 43 (multiple-value-bind (effective-args effective-body)
44 44 (parse-extended-function lambda-list body)
45 45 `(ps-js::=>
46 46 ,effective-args
47 47 ,(let ((*function-block-names* ()))
48 48 (compile-function-body effective-args effective-body)))))
49 49
50 50 (defprinter ps-js::=> (args body)
51 51 (unless (= 1 (length args))
52 52 (psw "("))
53 53 (loop for (arg . remaining) on args do
54 54 (psw (symbol-to-js-string arg)) (when remaining (psw ", ")))
55 55 (unless (= 1 (length args))
56 56 (psw ")"))
57 57 (psw " => ")
58 58 (ps-print body))
59 59
60 60 (cl:export '=>)
61 61
62 62 ;;; Actually return nothing (with no empty return)
63 63 (defvar *old-return-result-of* (function return-result-of))
64 64
65 65 (defun return-result-of (tag form)
66 66 (if (equal form '(void))
67 67 nil
68 68 (funcall *old-return-result-of* tag form)))
69 (export 'void)
69 (cl:export 'void)
70 70
71 71 ;;; Bitwise stuff
72 72 ;; No idea why these are not exported
73 73 (export '<<)
74 74 (export '>>)
General Comments 0
You need to be logged in to leave comments. Login now