##// END OF EJS Templates
Multiple sources, multiple games, openqst/addqst/killqst
naryl -
r31:5d061177 default
parent child Browse files
Show More
@@ -1,16 +1,16 b''
1
1
2 * MENU with async/await
3 * Special locations
2 * Special locations
4 * Special variables
3 * Special variables
5 * CLI build for Linux
4 * CLI build for Linux
6 * CLI build for Windows
5 * CLI build for Windows
7
6
8 * Reporting error lines in the parser
7 * Reporting error lines in the parser
9 * Report duplicate label (in the parser)
8 * Report duplicate label (in the parser)
10 * reporting error lines at runtime (by storing them in every form in the parser
9 * reporting error lines at runtime (by storing them in every form in the parser
11 * Report JUMP with missing label (in tagbody)
10 * Report JUMP with missing label (in tagbody)
12
11
13 * Build Istreblenie
12 * Build Istreblenie
13 * Build ЦвСтохимия
14 * Windows GUI (for the compiler)
14 * Windows GUI (for the compiler)
15 * Save-load game in slots
15 * Save-load game in slots
16 * Resizable frames
16 * Resizable frames
@@ -1,17 +1,15 b''
1 ql alexandria
1 ql alexandria
2 ql esrap
2 ql esrap
3 ql parenscript
3 ql parenscript
4 ql cl-uglify-js
5 ql flute
4 ql flute
6
5
7 ql cl-ppcre
6 ql cl-ppcre
8 ql anaphora
7 ql anaphora
9 ql named-readtables
8 ql named-readtables
10 ql parse-js
11 ql cl-unicode
9 ql cl-unicode
12 ql flexi-streams
10 ql flexi-streams
13 ql trivial-gray-streams
11 ql trivial-gray-streams
14 ql parse-number
12 ql parse-number
15 ql iterate
13 ql iterate
16 ql assoc-utils
14 ql assoc-utils
17 ql let-over-lambda
15 ql let-over-lambda
@@ -1,456 +1,469 b''
1
1
2 (in-package sugar-qsp.api)
2 (in-package sugar-qsp.api)
3
3
4 ;;; API deals with DOM manipulation and some bookkeeping for the
4 ;;; API deals with DOM manipulation and some bookkeeping for the
5 ;;; intrinsics, namely variables
5 ;;; intrinsics, namely variables
6 ;;; API is an implementation detail and has no QSP documentation. It
6 ;;; API is an implementation detail and has no QSP documentation. It
7 ;;; doesn't call intrinsics
7 ;;; doesn't call intrinsics
8
8
9 ;;; Utils
9 ;;; Utils
10
10
11 (defun make-act-html (title img)
11 (defun make-act-html (title img)
12 (+ "<a class='qsp-act' href='" (inline-call call-act title) "'>"
12 (+ "<a class='qsp-act' href='" (inline-call call-act title) "'>"
13 (if img (+ "<img src='" img "'>") "")
13 (if img (+ "<img src='" img "'>") "")
14 title
14 title
15 "</a>"))
15 "</a>"))
16
16
17 (defun make-menu-item-html (num title img loc)
17 (defun make-menu-item-html (num title img loc)
18 (+ "<a href='" (inline-call finish-menu loc) "'>"
18 (+ "<a href='" (inline-call finish-menu loc) "'>"
19 (if img (+ "<img src='" img "'>") "")
19 (if img (+ "<img src='" img "'>") "")
20 title
20 title
21 "</a>"))
21 "</a>"))
22
22
23 (defun make-menu-delimiter ()
23 (defun make-menu-delimiter ()
24 "<hr>")
24 "<hr>")
25
25
26 (defun report-error (text)
26 (defun report-error (text)
27 (alert text))
27 (alert text))
28
28
29 (defun start-sleeping ()
29 (defun start-sleeping ()
30 (chain (by-id "qsp") class-list (add "disable")))
30 (chain (by-id "qsp") class-list (add "disable")))
31
31
32 (defun finish-sleeping ()
32 (defun finish-sleeping ()
33 (chain (by-id "qsp") class-list (remove "disable")))
33 (chain (by-id "qsp") class-list (remove "disable")))
34
34
35 (defun sleep (msec)
35 (defun sleep (msec)
36 (with-sleep (resume)
36 (with-sleep (resume)
37 (set-timeout resume msec)))
37 (set-timeout resume msec)))
38
38
39 (defun init-dom ()
39 (defun init-dom ()
40 ;; Save/load buttons
40 ;; Save/load buttons
41 (let ((btn (by-id "qsp-btn-save")))
41 (let ((btn (by-id "qsp-btn-save")))
42 (setf (@ btn onclick) savegame)
42 (setf (@ btn onclick) savegame)
43 (setf (@ btn href) "#"))
43 (setf (@ btn href) "#"))
44 (let ((btn (by-id "qsp-btn-open")))
44 (let ((btn (by-id "qsp-btn-open")))
45 (setf (@ btn onclick) opengame)
45 (setf (@ btn onclick) opengame)
46 (setf (@ btn href) "#"))
46 (setf (@ btn href) "#"))
47 ;; Close image on click
47 ;; Close image on click
48 (setf (@ (by-id "qsp-image-container") onclick)
48 (setf (@ (by-id "qsp-image-container") onclick)
49 (show-image nil))
49 (show-image nil))
50 ;; Close the dropdown on any click
50 ;; Close the dropdown on any click
51 (setf (@ window onclick)
51 (setf (@ window onclick)
52 (lambda (event)
52 (lambda (event)
53 (setf (@ window mouse)
53 (setf (@ window mouse)
54 (list (@ event page-x)
54 (list (@ event page-x)
55 (@ event page-y)))
55 (@ event page-y)))
56 (finish-menu nil))))
56 (finish-menu nil))))
57
57
58 (defun call-serv-loc (var-name &rest args)
58 (defun call-serv-loc (var-name &rest args)
59 (let ((loc-name (get-var var-name 0 :str)))
59 (let ((loc-name (get-var var-name 0 :str)))
60 (when loc-name
60 (when loc-name
61 (let ((loc (getprop (root locs) loc-name)))
61 (let ((loc (getprop (root locs) loc-name)))
62 (when loc
62 (when loc
63 (funcall loc args))))))
63 (funcall loc args))))))
64
64
65 (defun filename-game (filename)
66 (let ((game-name (chain filename (match "(.*/)?([^.]+)(\\.[a-zA-Z]+)?") 2))))
67 (getprop (root games) game-name))
68
69 (defun run-game (name)
70 (let ((game (filename-game name)))
71 (setf (root main-game) name)
72 ;; Replace locations with the new game's
73 (setf (root locs) game)
74 (funcall (getprop game
75 (chain *object (keys game) 0))
76 (list))))
77
65 ;;; Misc
78 ;;; Misc
66
79
67 (defun newline (key)
80 (defun newline (key)
68 (append-id (key-to-id key) "<br>" t))
81 (append-id (key-to-id key) "<br>" t))
69
82
70 (defun clear-id (id)
83 (defun clear-id (id)
71 (setf (inner-html (by-id id)) ""))
84 (setf (inner-html (by-id id)) ""))
72
85
73 (defvar text-escaper (chain document (create-element :textarea)))
86 (defvar text-escaper (chain document (create-element :textarea)))
74
87
75 (defun prepare-contents (s &optional force-html)
88 (defun prepare-contents (s &optional force-html)
76 (if (or force-html (get-var "USEHTML" 0 :num))
89 (if (or force-html (get-var "USEHTML" 0 :num))
77 s
90 s
78 (progn
91 (progn
79 (setf (@ text-escaper text-content) s)
92 (setf (@ text-escaper text-content) s)
80 (inner-html text-escaper))))
93 (inner-html text-escaper))))
81
94
82 (defun get-id (id &optional force-html)
95 (defun get-id (id &optional force-html)
83 (inner-html (by-id id)))
96 (inner-html (by-id id)))
84
97
85 (defun set-id (id contents &optional force-html)
98 (defun set-id (id contents &optional force-html)
86 (setf (inner-html (by-id id)) (prepare-contents contents force-html)))
99 (setf (inner-html (by-id id)) (prepare-contents contents force-html)))
87
100
88 (defun append-id (id contents &optional force-html)
101 (defun append-id (id contents &optional force-html)
89 (when contents
102 (when contents
90 (incf (inner-html (by-id id)) (prepare-contents contents force-html))))
103 (incf (inner-html (by-id id)) (prepare-contents contents force-html))))
91
104
92 ;;; Function calls
105 ;;; Function calls
93
106
94 (defun init-args (args)
107 (defun init-args (args)
95 (dotimes (i (length args))
108 (dotimes (i (length args))
96 (let ((arg (elt args i)))
109 (let ((arg (elt args i)))
97 (if (numberp arg)
110 (if (numberp arg)
98 (set-var args i :num arg)
111 (set-var args i :num arg)
99 (set-var args i :str arg)))))
112 (set-var args i :str arg)))))
100
113
101 (defun get-result ()
114 (defun get-result ()
102 (if (not (equal "" (get-var "RESULT" 0 :str)))
115 (if (not (equal "" (get-var "RESULT" 0 :str)))
103 (get-var "RESULT" 0 :str)
116 (get-var "RESULT" 0 :str)
104 (get-var "RESULT" 0 :num)))
117 (get-var "RESULT" 0 :num)))
105
118
106 (defun call-loc (name args)
119 (defun call-loc (name args)
107 (setf name (chain name (to-upper-case)))
120 (setf name (chain name (to-upper-case)))
108 (with-frame
121 (with-frame
109 (with-call-args args
122 (with-call-args args
110 (funcall (getprop (root locs) name) args))))
123 (funcall (getprop (root locs) name) args))))
111
124
112 (defun call-act (title)
125 (defun call-act (title)
113 (with-frame
126 (with-frame
114 (funcall (getprop (root acts) title 'act))))
127 (funcall (getprop (root acts) title 'act))))
115
128
116 ;;; Text windows
129 ;;; Text windows
117
130
118 (defun key-to-id (key)
131 (defun key-to-id (key)
119 (case key
132 (case key
120 (:main "qsp-main")
133 (:main "qsp-main")
121 (:stat "qsp-stat")
134 (:stat "qsp-stat")
122 (:objs "qsp-objs")
135 (:objs "qsp-objs")
123 (:acts "qsp-acts")
136 (:acts "qsp-acts")
124 (:input "qsp-input")
137 (:input "qsp-input")
125 (:image "qsp-image")
138 (:image "qsp-image")
126 (:dropdown "qsp-dropdown")
139 (:dropdown "qsp-dropdown")
127 (t (report-error "Internal error!"))))
140 (t (report-error "Internal error!"))))
128
141
129 (defun get-frame (key)
142 (defun get-frame (key)
130 (by-id (key-to-id key)))
143 (by-id (key-to-id key)))
131
144
132 (defun add-text (key text)
145 (defun add-text (key text)
133 (append-id (key-to-id key) text))
146 (append-id (key-to-id key) text))
134
147
135 (defun get-text (key)
148 (defun get-text (key)
136 (get-id (key-to-id key)))
149 (get-id (key-to-id key)))
137
150
138 (defun clear-text (key)
151 (defun clear-text (key)
139 (clear-id (key-to-id key)))
152 (clear-id (key-to-id key)))
140
153
141 (defun enable-frame (key enable)
154 (defun enable-frame (key enable)
142 (let ((obj (get-frame key)))
155 (let ((obj (get-frame key)))
143 (setf (@ obj style display) (if enable "block" "none"))
156 (setf (@ obj style display) (if enable "block" "none"))
144 (void)))
157 (void)))
145
158
146 ;;; Actions
159 ;;; Actions
147
160
148 (defun add-act (title img act)
161 (defun add-act (title img act)
149 (setf (getprop (root acts) title)
162 (setf (getprop (root acts) title)
150 (create img img act act))
163 (create img img act act))
151 (update-acts))
164 (update-acts))
152
165
153 (defun del-act (title)
166 (defun del-act (title)
154 (delete (getprop (root acts) title))
167 (delete (getprop (root acts) title))
155 (update-acts))
168 (update-acts))
156
169
157 (defun clear-act ()
170 (defun clear-act ()
158 (setf (root acts) (create))
171 (setf (root acts) (create))
159 (clear-id "qsp-acts"))
172 (clear-id "qsp-acts"))
160
173
161 (defun update-acts ()
174 (defun update-acts ()
162 (clear-id "qsp-acts")
175 (clear-id "qsp-acts")
163 (let ((elt (by-id "qsp-acts")))
176 (let ((elt (by-id "qsp-acts")))
164 (for-in (title (root acts))
177 (for-in (title (root acts))
165 (let ((obj (getprop (root acts) title)))
178 (let ((obj (getprop (root acts) title)))
166 (incf (inner-html elt) (make-act-html title (getprop obj :img)))))))
179 (incf (inner-html elt) (make-act-html title (getprop obj :img)))))))
167
180
168
181
169 ;;; "Syntax"
182 ;;; "Syntax"
170
183
171 (defun qspfor (name index from to step body)
184 (defun qspfor (name index from to step body)
172 (for ((i from))
185 (for ((i from))
173 ((< i to))
186 ((< i to))
174 ((incf i step))
187 ((incf i step))
175 (set-var name index :num i)
188 (set-var name index :num i)
176 (unless (funcall body)
189 (unless (funcall body)
177 (return-from qspfor))))
190 (return-from qspfor))))
178
191
179 ;;; Variable class
192 ;;; Variable class
180
193
181 (defun *var (name)
194 (defun *var (name)
182 ;; From strings to numbers
195 ;; From strings to numbers
183 (setf (@ this indexes) (create))
196 (setf (@ this indexes) (create))
184 ;; From numbers to {num: 0, str: ""} objects
197 ;; From numbers to {num: 0, str: ""} objects
185 (setf (@ this values) (list))
198 (setf (@ this values) (list))
186 (void))
199 (void))
187
200
188 (defun new-value ()
201 (defun new-value ()
189 (create :num 0 :str ""))
202 (create :num 0 :str ""))
190
203
191 (setf (@ *var prototype index-num)
204 (setf (@ *var prototype index-num)
192 (lambda (index)
205 (lambda (index)
193 (let ((num-index
206 (let ((num-index
194 (if (stringp index)
207 (if (stringp index)
195 (if (in index (@ this indexes))
208 (if (in index (@ this indexes))
196 (getprop (@ this indexes) index)
209 (getprop (@ this indexes) index)
197 (let ((n (length (@ this values))))
210 (let ((n (length (@ this values))))
198 (setf (getprop (@ this indexes) index) n)
211 (setf (getprop (@ this indexes) index) n)
199 n))
212 n))
200 index)))
213 index)))
201 (unless (in num-index (@ this values))
214 (unless (in num-index (@ this values))
202 (setf (elt (@ this values) num-index) (new-value)))
215 (setf (elt (@ this values) num-index) (new-value)))
203 num-index)))
216 num-index)))
204
217
205 (setf (@ *var prototype get)
218 (setf (@ *var prototype get)
206 (lambda (index slot)
219 (lambda (index slot)
207 (unless (or index (= 0 index))
220 (unless (or index (= 0 index))
208 (setf index (1- (length (@ this values)))))
221 (setf index (1- (length (@ this values)))))
209 (getprop (@ this values) (chain this (index-num index)) slot)))
222 (getprop (@ this values) (chain this (index-num index)) slot)))
210
223
211 (setf (@ *var prototype set)
224 (setf (@ *var prototype set)
212 (lambda (index slot value)
225 (lambda (index slot value)
213 (unless (or index (= 0 index))
226 (unless (or index (= 0 index))
214 (setf index (length (@ this values))))
227 (setf index (length (@ this values))))
215 (case slot
228 (case slot
216 (:num (setf value (chain *number (parse-int value))))
229 (:num (setf value (chain *number (parse-int value))))
217 (:str (setf value (chain value (to-string)))))
230 (:str (setf value (chain value (to-string)))))
218 (setf (getprop (@ this values)
231 (setf (getprop (@ this values)
219 (chain this (index-num index))
232 (chain this (index-num index))
220 slot) value)
233 slot) value)
221 (void)))
234 (void)))
222
235
223 (setf (@ *var prototype kill)
236 (setf (@ *var prototype kill)
224 (lambda (index)
237 (lambda (index)
225 (setf (elt (@ this values) (chain this (index-num index)))
238 (setf (elt (@ this values) (chain this (index-num index)))
226 (new-value))
239 (new-value))
227 (delete (getprop 'this 'indexes index))))
240 (delete (getprop 'this 'indexes index))))
228
241
229 ;;; Variables
242 ;;; Variables
230
243
231 (defun var-real-name (name)
244 (defun var-real-name (name)
232 (if (= (@ name 0) #\$)
245 (if (= (@ name 0) #\$)
233 (values (chain name (substr 1)) :str)
246 (values (chain name (substr 1)) :str)
234 (values name :num)))
247 (values name :num)))
235
248
236 (defun ensure-var (name)
249 (defun ensure-var (name)
237 (setf name (chain name (to-upper-case)))
250 (setf name (chain name (to-upper-case)))
238 (let ((store (var-ref name)))
251 (let ((store (var-ref name)))
239 (unless store
252 (unless store
240 (setf store (new (*var name)))
253 (setf store (new (*var name)))
241 (setf (getprop (root vars) name) store))
254 (setf (getprop (root vars) name) store))
242 store))
255 store))
243
256
244 (defun var-ref (name)
257 (defun var-ref (name)
245 (let ((local-store (current-local-frame)))
258 (let ((local-store (current-local-frame)))
246 (cond ((and local-store (in name local-store))
259 (cond ((and local-store (in name local-store))
247 (getprop local-store name))
260 (getprop local-store name))
248 ((in name (root vars))
261 ((in name (root vars))
249 (getprop (root vars) name))
262 (getprop (root vars) name))
250 (t nil))))
263 (t nil))))
251
264
252 (defun get-var (name index slot)
265 (defun get-var (name index slot)
253 (chain (ensure-var name) (get index slot)))
266 (chain (ensure-var name) (get index slot)))
254
267
255 (defun set-var (name index slot value)
268 (defun set-var (name index slot value)
256 (chain (ensure-var name) (set index slot value))
269 (chain (ensure-var name) (set index slot value))
257 (void))
270 (void))
258
271
259 (defun get-array (name)
272 (defun get-array (name)
260 (setf name (chain name (to-upper-case)))
273 (setf name (chain name (to-upper-case)))
261 (var-ref name))
274 (var-ref name))
262
275
263 (defun set-array (name value)
276 (defun set-array (name value)
264 (setf name (chain name (to-upper-case)))
277 (setf name (chain name (to-upper-case)))
265 (let ((store (var-ref name)))
278 (let ((store (var-ref name)))
266 (setf (@ store values) (@ value values))
279 (setf (@ store values) (@ value values))
267 (setf (@ store indexes) (@ value indexes)))
280 (setf (@ store indexes) (@ value indexes)))
268 (void))
281 (void))
269
282
270 (defun kill-var (name &optional index)
283 (defun kill-var (name &optional index)
271 (setf name (chain name (to-upper-case)))
284 (setf name (chain name (to-upper-case)))
272 (if (and index (not (= 0 index)))
285 (if (and index (not (= 0 index)))
273 (chain (getprop (root vars) name) (kill index))
286 (chain (getprop (root vars) name) (kill index))
274 (delete (getprop (root vars) name)))
287 (delete (getprop (root vars) name)))
275 (void))
288 (void))
276
289
277 (defun array-size (name)
290 (defun array-size (name)
278 (@ (var-ref name) values length))
291 (@ (var-ref name) values length))
279
292
280 ;;; Locals
293 ;;; Locals
281
294
282 (defun push-local-frame ()
295 (defun push-local-frame ()
283 (chain (root locals) (push (create)))
296 (chain (root locals) (push (create)))
284 (void))
297 (void))
285
298
286 (defun pop-local-frame ()
299 (defun pop-local-frame ()
287 (chain (root locals) (pop))
300 (chain (root locals) (pop))
288 (void))
301 (void))
289
302
290 (defun current-local-frame ()
303 (defun current-local-frame ()
291 (elt (root locals) (1- (length (root locals)))))
304 (elt (root locals) (1- (length (root locals)))))
292
305
293 (defun new-local (name)
306 (defun new-local (name)
294 (let ((frame (current-local-frame)))
307 (let ((frame (current-local-frame)))
295 (unless (in name frame)
308 (unless (in name frame)
296 (setf (getprop frame name) (create)))
309 (setf (getprop frame name) (create)))
297 (void)))
310 (void)))
298
311
299 ;;; Objects
312 ;;; Objects
300
313
301 (defun update-objs ()
314 (defun update-objs ()
302 (let ((elt (by-id "qsp-objs")))
315 (let ((elt (by-id "qsp-objs")))
303 (setf (inner-html elt) "<ul>")
316 (setf (inner-html elt) "<ul>")
304 (loop :for obj :in (root objs)
317 (loop :for obj :in (root objs)
305 :do (incf (inner-html elt) (+ "<li>" obj)))
318 :do (incf (inner-html elt) (+ "<li>" obj)))
306 (incf (inner-html elt) "</ul>")))
319 (incf (inner-html elt) "</ul>")))
307
320
308 ;;; Menu
321 ;;; Menu
309
322
310 (defun open-menu (menu-data)
323 (defun open-menu (menu-data)
311 (let ((elt (get-frame :dropdown))
324 (let ((elt (get-frame :dropdown))
312 (i 0))
325 (i 0))
313 (loop :for item :in menu-data
326 (loop :for item :in menu-data
314 :do (incf i)
327 :do (incf i)
315 :do (incf (inner-html elt)
328 :do (incf (inner-html elt)
316 (if (eq item :delimiter)
329 (if (eq item :delimiter)
317 (make-menu-delimiter i)
330 (make-menu-delimiter i)
318 (make-menu-item-html i
331 (make-menu-item-html i
319 (@ item :text)
332 (@ item :text)
320 (@ item :icon)
333 (@ item :icon)
321 (@ item :loc)))))
334 (@ item :loc)))))
322 (let ((mouse (@ window mouse)))
335 (let ((mouse (@ window mouse)))
323 (setf (@ elt style left) (+ (elt mouse 0) "px"))
336 (setf (@ elt style left) (+ (elt mouse 0) "px"))
324 (setf (@ elt style top) (+ (elt mouse 1) "px"))
337 (setf (@ elt style top) (+ (elt mouse 1) "px"))
325 ;; Make sure it's inside the viewport
338 ;; Make sure it's inside the viewport
326 (when (> (@ document body inner-width)
339 (when (> (@ document body inner-width)
327 (+ (elt mouse 0) (@ elt inner-width)))
340 (+ (elt mouse 0) (@ elt inner-width)))
328 (incf (@ elt style left) (@ elt inner-width)))
341 (incf (@ elt style left) (@ elt inner-width)))
329 (when (> (@ document body inner-height)
342 (when (> (@ document body inner-height)
330 (+ (elt mouse 0) (@ elt inner-height)))
343 (+ (elt mouse 0) (@ elt inner-height)))
331 (incf (@ elt style top) (@ elt inner-height))))
344 (incf (@ elt style top) (@ elt inner-height))))
332 (setf (@ elt style display) "block")))
345 (setf (@ elt style display) "block")))
333
346
334 (defun finish-menu (loc)
347 (defun finish-menu (loc)
335 (when (root menu-resume)
348 (when (root menu-resume)
336 (let ((elt (get-frame :dropdown)))
349 (let ((elt (get-frame :dropdown)))
337 (setf (inner-html elt) "")
350 (setf (inner-html elt) "")
338 (setf (@ elt style display) "none")
351 (setf (@ elt style display) "none")
339 (funcall (root menu-resume))
352 (funcall (root menu-resume))
340 (setf (root menu-resume) nil))
353 (setf (root menu-resume) nil))
341 (when loc
354 (when loc
342 (call-loc loc)))
355 (call-loc loc)))
343 (void))
356 (void))
344
357
345 (defun menu (menu-data)
358 (defun menu (menu-data)
346 (with-sleep (resume)
359 (with-sleep (resume)
347 (open-menu menu-data)
360 (open-menu menu-data)
348 (setf (root menu-resume) resume))
361 (setf (root menu-resume) resume))
349 (void))
362 (void))
350
363
351 ;;; Content
364 ;;; Content
352
365
353 (defun clean-audio ()
366 (defun clean-audio ()
354 (loop :for k :in (chain *object (keys (root playing)))
367 (loop :for k :in (chain *object (keys (root playing)))
355 :for v := (getprop (root playing) k)
368 :for v := (getprop (root playing) k)
356 :do (when (@ v ended)
369 :do (when (@ v ended)
357 (delete (@ (root playing) k)))))
370 (delete (@ (root playing) k)))))
358
371
359 (defun show-image (path)
372 (defun show-image (path)
360 (let ((img (get-frame :image)))
373 (let ((img (get-frame :image)))
361 (cond (path
374 (cond (path
362 (setf (@ img src) path)
375 (setf (@ img src) path)
363 (setf (@ img style display) "flex"))
376 (setf (@ img style display) "flex"))
364 (t
377 (t
365 (setf (@ img src) "")
378 (setf (@ img src) "")
366 (setf (@ img style display) "hidden")))))
379 (setf (@ img style display) "hidden")))))
367
380
368 ;;; Saves
381 ;;; Saves
369
382
370 (defun opengame ()
383 (defun opengame ()
371 (let ((element (chain document (create-element :input))))
384 (let ((element (chain document (create-element :input))))
372 (chain element (set-attribute :type :file))
385 (chain element (set-attribute :type :file))
373 (chain element (set-attribute :id :qsp-opengame))
386 (chain element (set-attribute :id :qsp-opengame))
374 (chain element (set-attribute :tabindex -1))
387 (chain element (set-attribute :tabindex -1))
375 (chain element (set-attribute "aria-hidden" t))
388 (chain element (set-attribute "aria-hidden" t))
376 (setf (@ element style display) :block)
389 (setf (@ element style display) :block)
377 (setf (@ element style visibility) :hidden)
390 (setf (@ element style visibility) :hidden)
378 (setf (@ element style position) :fixed)
391 (setf (@ element style position) :fixed)
379 (setf (@ element onchange)
392 (setf (@ element onchange)
380 (lambda (event)
393 (lambda (event)
381 (let* ((file (@ event target files 0))
394 (let* ((file (@ event target files 0))
382 (reader (new (*file-reader))))
395 (reader (new (*file-reader))))
383 (setf (@ reader onload)
396 (setf (@ reader onload)
384 (lambda (ev)
397 (lambda (ev)
385 (block nil
398 (block nil
386 (let ((target (@ ev current-target)))
399 (let ((target (@ ev current-target)))
387 (unless (@ target result)
400 (unless (@ target result)
388 (return))
401 (return))
389 (base64-to-state (@ target result))
402 (base64-to-state (@ target result))
390 (unstash-state)))))
403 (unstash-state)))))
391 (chain reader (read-as-text file)))))
404 (chain reader (read-as-text file)))))
392 (chain document body (append-child element))
405 (chain document body (append-child element))
393 (chain element (click))
406 (chain element (click))
394 (chain document body (remove-child element))))
407 (chain document body (remove-child element))))
395
408
396 (defun savegame ()
409 (defun savegame ()
397 (let ((element (chain document (create-element :a))))
410 (let ((element (chain document (create-element :a))))
398 (chain element (set-attribute :href (+ "data:text/plain;charset=utf-8," (state-to-base64))))
411 (chain element (set-attribute :href (+ "data:text/plain;charset=utf-8," (state-to-base64))))
399 (chain element (set-attribute :download "savegame.sav"))
412 (chain element (set-attribute :download "savegame.sav"))
400 (setf (@ element style display) :none)
413 (setf (@ element style display) :none)
401 (chain document body (append-child element))
414 (chain document body (append-child element))
402 (chain element (click))
415 (chain element (click))
403 (chain document body (remove-child element))))
416 (chain document body (remove-child element))))
404
417
405 (defun stash-state (args)
418 (defun stash-state (args)
406 (call-serv-loc "ONGSAVE")
419 (call-serv-loc "ONGSAVE")
407 (setf (root state-stash)
420 (setf (root state-stash)
408 (chain *j-s-o-n (stringify
421 (chain *j-s-o-n (stringify
409 (create :vars (root vars)
422 (create :vars (root vars)
410 :objs (root objs)
423 :objs (root objs)
411 :loc-args args
424 :loc-args args
412 :msecs (- (chain *date (now)) (root started-at))
425 :msecs (- (chain *date (now)) (root started-at))
413 :timer-interval (root timer-interval)
426 :timer-interval (root timer-interval)
414 :main-html (inner-html
427 :main-html (inner-html
415 (get-frame :main))
428 (get-frame :main))
416 :stat-html (inner-html
429 :stat-html (inner-html
417 (get-frame :stat))
430 (get-frame :stat))
418 :next-location (root current-location)))))
431 :next-location (root current-location)))))
419 (void))
432 (void))
420
433
421 (defun unstash-state ()
434 (defun unstash-state ()
422 (let ((data (chain *j-s-o-n (parse (root state-stash)))))
435 (let ((data (chain *j-s-o-n (parse (root state-stash)))))
423 (clear-act)
436 (clear-act)
424 (setf (root vars) (@ data :vars))
437 (setf (root vars) (@ data :vars))
425 (loop :for k :in (chain *object (keys (root vars)))
438 (loop :for k :in (chain *object (keys (root vars)))
426 :do (chain *object (set-prototype-of (getprop (root vars) k)
439 :do (chain *object (set-prototype-of (getprop (root vars) k)
427 (@ *var prototype))))
440 (@ *var prototype))))
428 (setf (root started-at) (- (chain *date (now)) (@ data :msecs)))
441 (setf (root started-at) (- (chain *date (now)) (@ data :msecs)))
429 (setf (root objs) (@ data :objs))
442 (setf (root objs) (@ data :objs))
430 (setf (root current-location) (@ data :next-location))
443 (setf (root current-location) (@ data :next-location))
431 (setf (inner-html (get-frame :main))
444 (setf (inner-html (get-frame :main))
432 (@ data :main-html))
445 (@ data :main-html))
433 (setf (inner-html (get-frame :stat))
446 (setf (inner-html (get-frame :stat))
434 (@ data :stat-html))
447 (@ data :stat-html))
435 (update-objs)
448 (update-objs)
436 (set-timer (@ data :timer-interval))
449 (set-timer (@ data :timer-interval))
437 (call-serv-loc "ONGLOAD")
450 (call-serv-loc "ONGLOAD")
438 (call-loc (root current-location) (@ data :loc-args))
451 (call-loc (root current-location) (@ data :loc-args))
439 (void)))
452 (void)))
440
453
441 (defun state-to-base64 ()
454 (defun state-to-base64 ()
442 (btoa (encode-u-r-i-component (root state-stash))))
455 (btoa (encode-u-r-i-component (root state-stash))))
443
456
444 (defun base64-to-state (data)
457 (defun base64-to-state (data)
445 (setf (root state-stash) (decode-u-r-i-component (atob data))))
458 (setf (root state-stash) (decode-u-r-i-component (atob data))))
446
459
447 ;;; Timers
460 ;;; Timers
448
461
449 (defun set-timer (interval)
462 (defun set-timer (interval)
450 (setf (root timer-interval) interval)
463 (setf (root timer-interval) interval)
451 (clear-interval (root timer-obj))
464 (clear-interval (root timer-obj))
452 (setf (root timer-obj)
465 (setf (root timer-obj)
453 (set-interval
466 (set-interval
454 (lambda ()
467 (lambda ()
455 (call-serv-loc "COUNTER"))
468 (call-serv-loc "COUNTER"))
456 interval)))
469 interval)))
@@ -1,302 +1,310 b''
1
1
2 (in-package sugar-qsp.lib)
2 (in-package sugar-qsp.lib)
3
3
4 ;;;; Functions and procedures defined by the QSP language.
4 ;;;; Functions and procedures defined by the QSP language.
5 ;;;; They can call api and deal with locations and other data directly.
5 ;;;; They can call api and deal with locations and other data directly.
6 ;;;; Except vars. Use VAR and SET or GET-VAR and SET-VAR api calls.
6 ;;;; Except vars. Use VAR and SET or GET-VAR and SET-VAR api calls.
7
7
8 ;;; 1loc
8 ;;; 1loc
9
9
10 (defun goto (target args)
10 (defun goto (target args)
11 (api:clear-text :main)
11 (api:clear-text :main)
12 (funcall xgoto target args)
12 (funcall xgoto target args)
13 (void))
13 (void))
14
14
15 (defun xgoto (target args)
15 (defun xgoto (target args)
16 (setf args (or args (list)))
16 (api:clear-act)
17 (api:clear-act)
17 (setf (root current-location) (chain target (to-upper-case)))
18 (setf (root current-location) (chain target (to-upper-case)))
18 (api:stash-state args)
19 (api:stash-state args)
19 (api:call-loc (root current-location) (or args (list)))
20 (api:call-loc (root current-location) args)
20 (void))
21 (void))
21
22
22 ;;; 2var
23 ;;; 2var
23
24
24 ;;; 3expr
25 ;;; 3expr
25
26
26 ;;; 4code
27 ;;; 4code
27
28
28 (defun rand (a &optional (b 1))
29 (defun rand (a &optional (b 1))
29 (let ((min (min a b))
30 (let ((min (min a b))
30 (max (max a b)))
31 (max (max a b)))
31 (+ min (chain *math (random (- max min))))))
32 (+ min (chain *math (random (- max min))))))
32
33
33 ;;; 5arrays
34 ;;; 5arrays
34
35
35 (defun copyarr (to from start count)
36 (defun copyarr (to from start count)
36 (multiple-value-bind (to-name to-slot)
37 (multiple-value-bind (to-name to-slot)
37 (api:var-real-name to)
38 (api:var-real-name to)
38 (multiple-value-bind (from-name from-slot)
39 (multiple-value-bind (from-name from-slot)
39 (api:var-real-name from)
40 (api:var-real-name from)
40 (for ((i start))
41 (for ((i start))
41 ((< i (min (api:array-size from-name)
42 ((< i (min (api:array-size from-name)
42 (+ start count))))
43 (+ start count))))
43 ((incf i))
44 ((incf i))
44 (api:set-var to-name (+ start i) to-slot
45 (api:set-var to-name (+ start i) to-slot
45 (api:get-var from-name (+ start i) from-slot))))))
46 (api:get-var from-name (+ start i) from-slot))))))
46
47
47 (defun arrpos (name value &optional (start 0))
48 (defun arrpos (name value &optional (start 0))
48 (multiple-value-bind (real-name slot)
49 (multiple-value-bind (real-name slot)
49 (api:var-real-name name)
50 (api:var-real-name name)
50 (for ((i start)) ((< i (api:array-size name))) ((incf i))
51 (for ((i start)) ((< i (api:array-size name))) ((incf i))
51 (when (eq (api:get-var real-name i slot) value)
52 (when (eq (api:get-var real-name i slot) value)
52 (return-from arrpos i))))
53 (return-from arrpos i))))
53 -1)
54 -1)
54
55
55 (defun arrcomp (name pattern &optional (start 0))
56 (defun arrcomp (name pattern &optional (start 0))
56 (multiple-value-bind (real-name slot)
57 (multiple-value-bind (real-name slot)
57 (api:var-real-name name)
58 (api:var-real-name name)
58 (for ((i start)) ((< i (api:array-size name))) ((incf i))
59 (for ((i start)) ((< i (api:array-size name))) ((incf i))
59 (when (funcall (getprop (api:get-var real-name i slot) 'match) pattern)
60 (when (funcall (getprop (api:get-var real-name i slot) 'match) pattern)
60 (return-from arrcomp i))))
61 (return-from arrcomp i))))
61 -1)
62 -1)
62
63
63 ;;; 6str
64 ;;; 6str
64
65
65 (defun instr (s subs &optional (start 1))
66 (defun instr (s subs &optional (start 1))
66 (+ start (chain s (substring (- start 1)) (search subs))))
67 (+ start (chain s (substring (- start 1)) (search subs))))
67
68
68 (defun isnum (s)
69 (defun isnum (s)
69 (if (is-na-n s)
70 (if (is-na-n s)
70 0
71 0
71 -1))
72 -1))
72
73
73 (defun strcomp (s pattern)
74 (defun strcomp (s pattern)
74 (if (chain s (match pattern))
75 (if (chain s (match pattern))
75 -1
76 -1
76 0))
77 0))
77
78
78 (defun strfind (s pattern group)
79 (defun strfind (s pattern group)
79 (let* ((re (new (*reg-exp pattern)))
80 (let* ((re (new (*reg-exp pattern)))
80 (match (chain re (exec s))))
81 (match (chain re (exec s))))
81 (chain match (group group))))
82 (chain match (group group))))
82
83
83 (defun strpos (s pattern &optional (group 0))
84 (defun strpos (s pattern &optional (group 0))
84 (let* ((re (new (*reg-exp pattern)))
85 (let* ((re (new (*reg-exp pattern)))
85 (match (chain re (exec s)))
86 (match (chain re (exec s)))
86 (found (chain match (group group))))
87 (found (chain match (group group))))
87 (if found
88 (if found
88 (chain s (search found))
89 (chain s (search found))
89 0)))
90 0)))
90
91
91 ;;; 7if
92 ;;; 7if
92
93
93 ;; Has to be a function because it always evaluates all three of its
94 ;; Has to be a function because it always evaluates all three of its
94 ;; arguments
95 ;; arguments
95 (defun iif (cond-expr then-expr else-expr)
96 (defun iif (cond-expr then-expr else-expr)
96 (if cond-expr then-expr else-expr))
97 (if cond-expr then-expr else-expr))
97
98
98 ;;; 8sub
99 ;;; 8sub
99
100
100 (defun gosub (target &rest args)
101 (defun gosub (target &rest args)
101 (api:call-loc target args)
102 (api:call-loc target args)
102 (void))
103 (void))
103
104
104 (defun func (target &rest args)
105 (defun func (target &rest args)
105 (api:call-loc target args))
106 (api:call-loc target args))
106
107
107 ;;; 9loops
108 ;;; 9loops
108
109
109 ;;; 10dynamic
110 ;;; 10dynamic
110
111
111 (defun dynamic (block &rest args)
112 (defun dynamic (block &rest args)
112 (when (stringp block)
113 (when (stringp block)
113 (api:report-error "DYNAMIC can't evaluate arbitrary strings.\\nUse {braces} to create blocks for DYNAMIC."))
114 (api:report-error "DYNAMIC can't evaluate arbitrary strings.\\nUse {braces} to create blocks for DYNAMIC."))
114 (api:with-call-args args
115 (api:with-call-args args
115 (funcall block args))
116 (funcall block args))
116 (void))
117 (void))
117
118
118 (defun dyneval (block &rest args)
119 (defun dyneval (block &rest args)
119 (when (stringp block)
120 (when (stringp block)
120 (api:report-error "DYNEVAL can't evaluate arbitrary strings.\\nUse {braces} to create blocks for DYNEVAL."))
121 (api:report-error "DYNEVAL can't evaluate arbitrary strings.\\nUse {braces} to create blocks for DYNEVAL."))
121 (api:with-call-args args
122 (api:with-call-args args
122 (funcall block args)))
123 (funcall block args)))
123
124
124 ;;; 11main
125 ;;; 11main
125
126
126 (defun main-p (s)
127 (defun main-p (s)
127 (api:add-text :main s)
128 (api:add-text :main s)
128 (void))
129 (void))
129
130
130 (defun main-pl (s)
131 (defun main-pl (s)
131 (api:add-text :main s)
132 (api:add-text :main s)
132 (api:newline :main)
133 (api:newline :main)
133 (void))
134 (void))
134
135
135 (defun main-nl (s)
136 (defun main-nl (s)
136 (api:newline :main)
137 (api:newline :main)
137 (api:add-text :main s)
138 (api:add-text :main s)
138 (void))
139 (void))
139
140
140 (defun maintxt (s)
141 (defun maintxt (s)
141 (api:get-text :main)
142 (api:get-text :main)
142 (void))
143 (void))
143
144
144 ;; For clarity (it leaves a lib.desc() call in JS)
145 ;; For clarity (it leaves a lib.desc() call in JS)
145 (defun desc (s)
146 (defun desc (s)
146 "")
147 "")
147
148
148 (defun main-clear ()
149 (defun main-clear ()
149 (api:clear-text :main)
150 (api:clear-text :main)
150 (void))
151 (void))
151
152
152 ;;; 12stat
153 ;;; 12stat
153
154
154 (defun stat-p (s)
155 (defun stat-p (s)
155 (api:add-text :stat s)
156 (api:add-text :stat s)
156 (void))
157 (void))
157
158
158 (defun stat-pl (s)
159 (defun stat-pl (s)
159 (api:add-text :stat s)
160 (api:add-text :stat s)
160 (api:newline :stat)
161 (api:newline :stat)
161 (void))
162 (void))
162
163
163 (defun stat-nl (s)
164 (defun stat-nl (s)
164 (api:newline :stat)
165 (api:newline :stat)
165 (api:add-text :stat s)
166 (api:add-text :stat s)
166 (void))
167 (void))
167
168
168 (defun stattxt (s)
169 (defun stattxt (s)
169 (api:get-text :stat)
170 (api:get-text :stat)
170 (void))
171 (void))
171
172
172 (defun stat-clear ()
173 (defun stat-clear ()
173 (api:clear-text :stat)
174 (api:clear-text :stat)
174 (void))
175 (void))
175
176
176 (defun cls ()
177 (defun cls ()
177 (stat-clear)
178 (stat-clear)
178 (main-clear)
179 (main-clear)
179 (cla)
180 (cla)
180 (cmdclear)
181 (cmdclear)
181 (void))
182 (void))
182
183
183 ;;; 13diag
184 ;;; 13diag
184
185
185 ;;; 14act
186 ;;; 14act
186
187
187 (defun curacts ()
188 (defun curacts ()
188 (let ((acts (root acts)))
189 (let ((acts (root acts)))
189 (lambda ()
190 (lambda ()
190 (setf (root acts) acts)
191 (setf (root acts) acts)
191 (void))))
192 (void))))
192
193
193 ;;; 15objs
194 ;;; 15objs
194
195
195 (defun addobj (name)
196 (defun addobj (name)
196 (chain (root objs) (push name))
197 (chain (root objs) (push name))
197 (api:update-objs)
198 (api:update-objs)
198 (void))
199 (void))
199
200
200 (defun delobj (name)
201 (defun delobj (name)
201 (let ((index (chain (root objs) (index-of name))))
202 (let ((index (chain (root objs) (index-of name))))
202 (when (> index -1)
203 (when (> index -1)
203 (killobj (1+ index))))
204 (killobj (1+ index))))
204 (void))
205 (void))
205
206
206 (defun killobj (&optional (num nil))
207 (defun killobj (&optional (num nil))
207 (if (eq nil num)
208 (if (eq nil num)
208 (setf (root objs) (list))
209 (setf (root objs) (list))
209 (chain (root objs) (splice (1- num) 1)))
210 (chain (root objs) (splice (1- num) 1)))
210 (api:update-objs)
211 (api:update-objs)
211 (void))
212 (void))
212
213
213 ;;; 16menu
214 ;;; 16menu
214
215
215 (defun menu (menu-name)
216 (defun menu (menu-name)
216 (let ((menu-data (list)))
217 (let ((menu-data (list)))
217 (loop :for item-obj :in (@ (api:get-array (api:var-real-name menu-name)) values)
218 (loop :for item-obj :in (@ (api:get-array (api:var-real-name menu-name)) values)
218 :for item := (@ item-obj :str)
219 :for item := (@ item-obj :str)
219 :do (cond ((string= item "")
220 :do (cond ((string= item "")
220 (break))
221 (break))
221 ((string= item "-:-")
222 ((string= item "-:-")
222 (chain menu-data (push :delimiter)))
223 (chain menu-data (push :delimiter)))
223 (t
224 (t
224 (let* ((tokens (chain item (split ":"))))
225 (let* ((tokens (chain item (split ":"))))
225 (when (= (length tokens) 2)
226 (when (= (length tokens) 2)
226 (chain tokens (push "")))
227 (chain tokens (push "")))
227 (let* ((text (chain tokens (splice 0 (- (length tokens) 2)) (join ":")))
228 (let* ((text (chain tokens (splice 0 (- (length tokens) 2)) (join ":")))
228 (loc (getprop tokens (- (length tokens) 2)))
229 (loc (getprop tokens (- (length tokens) 2)))
229 (icon (getprop tokens (- (length tokens) 1))))
230 (icon (getprop tokens (- (length tokens) 1))))
230 (chain menu-data
231 (chain menu-data
231 (push (create :text text
232 (push (create :text text
232 :loc loc
233 :loc loc
233 :icon icon))))))))
234 :icon icon))))))))
234 (api:menu menu-data)
235 (api:menu menu-data)
235 (void)))
236 (void)))
236
237
237 ;;; 17sound
238 ;;; 17sound
238
239
239 (defun play (filename &optional (volume 100))
240 (defun play (filename &optional (volume 100))
240 (let ((audio (new (*audio filename))))
241 (let ((audio (new (*audio filename))))
241 (setf (getprop (root playing) filename) audio)
242 (setf (getprop (root playing) filename) audio)
242 (setf (@ audio volume) (* volume 0.01))
243 (setf (@ audio volume) (* volume 0.01))
243 (chain audio (play))))
244 (chain audio (play))))
244
245
245 (defun close (filename)
246 (defun close (filename)
246 (funcall (root playing filename) stop)
247 (funcall (root playing filename) stop)
247 (delete (root playing filename))
248 (delete (root playing filename))
248 (void))
249 (void))
249
250
250 (defun closeall ()
251 (defun closeall ()
251 (loop :for k :in (chain *object (keys (root playing)))
252 (loop :for k :in (chain *object (keys (root playing)))
252 :for v := (getprop (root playing) k)
253 :for v := (getprop (root playing) k)
253 :do (funcall v stop))
254 :do (funcall v stop))
254 (setf (root playing) (create)))
255 (setf (root playing) (create)))
255
256
256 ;;; 18img
257 ;;; 18img
257
258
258 (defun refint ()
259 (defun refint ()
259 ;; "Force interface update" Uh... what exactly do we do here?
260 ;; "Force interface update" Uh... what exactly do we do here?
260 (api:report-error "REFINT is not supported")
261 (api:report-error "REFINT is not supported")
261 )
262 )
262
263
263 ;;; 19input
264 ;;; 19input
264
265
265 (defun usertxt ()
266 (defun usertxt ()
266 (let ((input (by-id "qsp-input")))
267 (let ((input (by-id "qsp-input")))
267 (@ input value)))
268 (@ input value)))
268
269
269 (defun cmdclear ()
270 (defun cmdclear ()
270 (let ((input (by-id "qsp-input")))
271 (let ((input (by-id "qsp-input")))
271 (setf (@ input value) "")))
272 (setf (@ input value) "")))
272
273
273 (defun input (text)
274 (defun input (text)
274 (chain window (prompt text)))
275 (chain window (prompt text)))
275
276
276 ;;; 20time
277 ;;; 20time
277
278
278 (defun msecscount ()
279 (defun msecscount ()
279 (- (chain *date (now)) (root started-at)))
280 (- (chain *date (now)) (root started-at)))
280
281
281 ;;; 21local
282 ;;; 21local
282
283
283 ;;; 22for
284 ;;; 22for
284
285
285 ;;; misc
286 ;;; misc
286
287
287 (defun rgb (red green blue)
288 (defun rgb (red green blue)
288 (flet ((rgb-to-hex (comp)
289 (flet ((rgb-to-hex (comp)
289 (let ((hex (chain (*number comp) (to-string 16))))
290 (let ((hex (chain (*number comp) (to-string 16))))
290 (if (< (length hex) 2)
291 (if (< (length hex) 2)
291 (+ "0" hex)
292 (+ "0" hex)
292 hex))))
293 hex))))
293 (+ "#" (rgb-to-hex red) (rgb-to-hex green) (rgb-to-hex red))))
294 (+ "#" (rgb-to-hex red) (rgb-to-hex green) (rgb-to-hex red))))
294
295
295 (defun openqst ()
296 (defun openqst (name)
296 (api:report-error "OPENQST is not supported."))
297 (api-call run-game name))
297
298
298 (defun addqst ()
299 (defun addqst (name)
299 (api:report-error "ADDQST is not supported. Bundle the library with the main game."))
300 (let ((game (api-call filename-game name)))
301 ;; Add the game's locations
302 (chain *object (assign (root locs)
303 (getprop (root games) name)))))
300
304
301 (defun killqst ()
305 (defun killqst ()
302 (api:report-error "KILLQST is not supported."))
306 ;; Delete all locations not from the current main game
307 (loop :for (k v) :in (root games)
308 :do (unless (string= k (root main-game))
309 (delete (getprop (root locs) k)))))
310
@@ -1,41 +1,41 b''
1
1
2 (in-package sugar-qsp.js)
2 (in-package sugar-qsp.js)
3
3
4 ;;; Contains symbols from standard JS library to avoid obfuscating
4 ;;; Contains symbols from standard JS library to avoid obfuscating
5 ;;; and/or namespacing them
5 ;;; and/or namespacing them
6
6
7 (cl:defmacro syms (cl:&rest syms)
7 (cl:defmacro syms (cl:&rest syms)
8 `(cl:progn
8 `(cl:progn
9 ,@(cl:loop :for sym :in syms
9 ,@(cl:loop :for sym :in syms
10 :collect `(cl:export ',sym))))
10 :collect `(cl:export ',sym))))
11
11
12 (syms
12 (syms
13 ;; main
13 ;; main
14 window
14 window
15 *object
15 *object
16 now
16 now
17 onload
17 onload
18 keys includes
18 keys includes
19 has-own-property
19 has-own-property
20 ;; api
20 ;; api
21 document get-element-by-id
21 document get-element-by-id
22 onclick onchange
22 onclick onchange
23 atob btoa split
23 atob btoa split
24 alert prompt
24 alert prompt
25 set-timeout set-interval clear-interval
25 set-timeout set-interval clear-interval
26 *promise *j-s-o-n
26 *promise *j-s-o-n
27 href parse
27 href parse match
28 set-prototype-of
28 set-prototype-of
29 body append-child remove-child
29 body append-child remove-child
30 add ; remove (is already in COMMON-LISP)
30 add ; remove (is already in COMMON-LISP)
31 create-element set-attribute class-list
31 create-element set-attribute class-list
32 *file-reader read-as-text
32 *file-reader read-as-text
33 style display src
33 style display src
34 page-x page-y
34 page-x page-y
35 top left
35 top left
36 ;; lib
36 ;; lib
37 *number parse-int
37 *number parse-int
38 to-string to-upper-case concat
38 to-string to-upper-case concat
39 click target current-target files index-of result
39 click target current-target files index-of result
40 decode-u-r-i-component splice
40 decode-u-r-i-component splice
41 )
41 )
@@ -1,135 +1,148 b''
1
1
2 (in-package sugar-qsp)
2 (in-package sugar-qsp)
3
3
4 (defun entry-point-no-args ()
4 (defun entry-point-no-args ()
5 (entry-point uiop:*command-line-arguments*))
5 (entry-point uiop:*command-line-arguments*))
6
6
7 (defun entry-point (args)
7 (defun entry-point (args)
8 (catch :terminate
8 (catch :terminate
9 (let ((compiler (apply #'make-instance 'compiler (parse-opts args))))
9 (let ((compiler (apply #'make-instance 'compiler (parse-opts args))))
10 (write-compiled-file compiler)))
10 (write-compiled-file compiler)))
11 (values))
11 (values))
12
12
13 (defun parse-opts (args)
13 (defun parse-opts (args)
14 (let ((mode :source)
14 (let ((mode :sources)
15 (data (list :source nil :target nil :js nil :css nil :body nil :compile nil :beautify nil)))
15 (data (list :sources nil :target nil :js nil :css nil :body nil :compile nil :beautify nil)))
16 (loop :for arg :in args
16 (loop :for arg :in args
17 :do (alexandria:switch (arg :test #'string=)
17 :do (alexandria:switch (arg :test #'string=)
18 ("-o" (setf mode :target))
18 ("-o" (setf mode :target))
19 ("--js" (setf mode :js))
19 ("--js" (setf mode :js))
20 ("--css" (setf mode :css))
20 ("--css" (setf mode :css))
21 ("--body" (setf mode :body))
21 ("--body" (setf mode :body))
22 ("-c" (setf (getf data :compile) t))
22 ("-c" (setf (getf data :compile) t))
23 ("--beautify" (setf (getf data :beautify) t))
23 ("--beautify" (setf (getf data :beautify) t))
24 (t (push arg (getf data mode)))))
24 (t (push arg (getf data mode)))))
25 (unless (= 1 (length (getf data :source)))
25 (unless (< 0 (length (getf data :sources)))
26 (print-usage)
26 (print-usage)
27 (report-error "There should be exactly one source"))
27 (report-error "There should be at least one source"))
28 (unless (> 1 (length (getf data :target)))
28 (unless (> 1 (length (getf data :target)))
29 (print-usage)
29 (print-usage)
30 (report-error "There should be no more than one target"))
30 (report-error "There should be no more than one target"))
31 (unless (> 1 (length (getf data :body)))
31 (unless (> 1 (length (getf data :body)))
32 (print-usage)
32 (print-usage)
33 (report-error "There should be no more than one body"))
33 (report-error "There should be no more than one body"))
34 (unless (getf data :target)
34 (unless (getf data :target)
35 (setf (getf data :target)
35 (setf (getf data :target)
36 (let* ((source (first (getf data :source)))
36 (let* ((sources (first (getf data :sources)))
37 (tokens (uiop:split-string source :separator "."))
37 (tokens (uiop:split-string sources :separator "."))
38 (target (format nil "~{~A~^.~}.html"
38 (target (format nil "~{~A~^.~}.html"
39 (butlast tokens))))
39 (butlast tokens))))
40 (list target))))
40 (list target))))
41 (list :source (first (getf data :source))
41 (list :sources (getf data :sources)
42 :target (first (getf data :target))
42 :target (first (getf data :target))
43 :js (getf data :js)
43 :js (getf data :js)
44 :css (getf data :css)
44 :css (getf data :css)
45 :body (first (getf data :body))
45 :body (first (getf data :body))
46 :compile (getf data :compile)
46 :compile (getf data :compile)
47 :beautify (getf data :beautify))))
47 :beautify (getf data :beautify))))
48
48
49 (defun print-usage ()
49 (defun print-usage ()
50 (format t "USAGE: "))
50 (format t "USAGE: "))
51
51
52 (defun parse-file (filename)
52 (defun parse-file (filename)
53 (p:parse 'sugar-qsp-grammar
53 (p:parse 'sugar-qsp-grammar
54 (alexandria:read-file-into-string filename)))
54 (alexandria:read-file-into-string filename)))
55
55
56 (defun report-error (fmt &rest args)
56 (defun report-error (fmt &rest args)
57 (apply #'format t fmt args)
57 (apply #'format t fmt args)
58 (throw :terminate nil))
58 (throw :terminate nil))
59
59
60 ;;; JS
60 ;;; JS
61
61
62 (defun minify-package (package-designator minify prefix)
62 (defun minify-package (package-designator minify prefix)
63 (setf (ps:ps-package-prefix package-designator) prefix)
63 (setf (ps:ps-package-prefix package-designator) prefix)
64 (if minify
64 (if minify
65 (ps:obfuscate-package package-designator)
65 (ps:obfuscate-package package-designator)
66 (ps:unobfuscate-package package-designator)))
66 (ps:unobfuscate-package package-designator)))
67
67
68 (defmethod js-sources ((compiler compiler))
68 (defmethod js-sources ((compiler compiler))
69 (let ((ps:*ps-print-pretty* (beautify compiler)))
69 (let ((ps:*ps-print-pretty* (beautify compiler)))
70 (cond ((beautify compiler)
70 (cond ((beautify compiler)
71 (minify-package "SUGAR-QSP.MAIN" nil "qsp_")
71 (minify-package "SUGAR-QSP.MAIN" nil "qsp_")
72 (minify-package "SUGAR-QSP.API" nil "qsp_api_")
72 (minify-package "SUGAR-QSP.API" nil "qsp_api_")
73 (minify-package "SUGAR-QSP.LIB" nil "qsp_lib_"))
73 (minify-package "SUGAR-QSP.LIB" nil "qsp_lib_"))
74 (t
74 (t
75 (minify-package "SUGAR-QSP.MAIN" t "_")
75 (minify-package "SUGAR-QSP.MAIN" t "_")
76 (minify-package "SUGAR-QSP.API" t "a_")
76 (minify-package "SUGAR-QSP.API" t "a_")
77 (minify-package "SUGAR-QSP.LIB" t "l_")))
77 (minify-package "SUGAR-QSP.LIB" t "l_")))
78 (format nil "~{~A~^~%~%~}" (mapcar #'ps:ps* (reverse (js compiler))))))
78 (format nil "~{~A~^~%~%~}" (mapcar #'ps:ps* (reverse (js compiler))))))
79
79
80 ;;; CSS
80 ;;; CSS
81
81
82 (defmethod css-sources ((compiler compiler))
82 (defmethod css-sources ((compiler compiler))
83 (format nil "~{~A~^~%~%~}" (css compiler)))
83 (format nil "~{~A~^~%~%~}" (css compiler)))
84
84
85 ;;; HTML
85 ;;; HTML
86
86
87 (defmethod html-sources ((compiler compiler))
87 (defmethod html-sources ((compiler compiler))
88 (let ((flute:*escape-html* nil)
88 (let ((flute:*escape-html* nil)
89 (body-template (body compiler))
89 (body-template (body compiler))
90 (js (js-sources compiler))
90 (js (js-sources compiler))
91 (css (css-sources compiler)))
91 (css (css-sources compiler)))
92 (with-output-to-string (out)
92 (with-output-to-string (out)
93 (write
93 (write
94 (flute:h
94 (flute:h
95 (html
95 (html
96 (head
96 (head
97 (title "SugarQSP"))
97 (title "SugarQSP"))
98 (body
98 (body
99 body-template
99 body-template
100 (style css)
100 (style css)
101 (script js))))
101 (script js))))
102 :stream out
102 :stream out
103 :pretty nil))))
103 :pretty nil))))
104
104
105 (defmethod initialize-instance ((compiler compiler) &key source ((:js js-files)) ((:css css-files)) ((:body body-file)) compile &allow-other-keys)
105 (defun filename-game (filename)
106 (let ((filename (alexandria:lastcar (uiop:split-string filename :separator "/"))))
107 (format nil "~{~A~^.~}" (butlast (uiop:split-string filename :separator ".")))))
108
109 (defmethod initialize-instance ((compiler compiler) &key sources ((:js js-files)) ((:css css-files)) ((:body body-file)) compile &allow-other-keys)
106 (call-next-method)
110 (call-next-method)
107 (with-slots (body css js)
111 (with-slots (body css js)
108 compiler
112 compiler
109 ;; Compile the game's JS
113 ;; Compile the game's JS
110 (push (list* 'progn (parse-file source)) js)
114 (dolist (source sources)
115 (let ((ps (parse-file source))
116 (game-name (filename-game source)))
117 (destructuring-bind (kw &rest locations)
118 ps
119 (unless (eq kw 'lib:game)
120 (report-error "Internal error!"))
121 (push
122 `(lib:game (,game-name) ,@locations)
123 js))))
111 ;; Does the user need us to do anything else
124 ;; Does the user need us to do anything else
112 (unless compile
125 (unless compile
113 ;; Read in body
126 ;; Read in body
114 (when body-file
127 (when body-file
115 (setf body
128 (setf body
116 (alexandria:read-file-into-string body-file)))
129 (alexandria:read-file-into-string body-file)))
117 ;; Include js files
130 ;; Include js files
118 (dolist (js-file js-files)
131 (dolist (js-file js-files)
119 (push (format nil "////// Included file ~A~%~A" js-file
132 (push (format nil "////// Included file ~A~%~A" js-file
120 (alexandria:read-file-into-string js-file))
133 (alexandria:read-file-into-string js-file))
121 js))
134 js))
122 ;; Include css files
135 ;; Include css files
123 (dolist (css-file css-files)
136 (dolist (css-file css-files)
124 (push (format nil "////// Included file ~A~%~A" css-file
137 (push (format nil "////// Included file ~A~%~A" css-file
125 (alexandria:read-file-into-string css-file))
138 (alexandria:read-file-into-string css-file))
126 css)))))
139 css)))))
127
140
128 (defmethod write-compiled-file ((compiler compiler))
141 (defmethod write-compiled-file ((compiler compiler))
129 (alexandria:write-string-into-file
142 (alexandria:write-string-into-file
130 (if (compile-only compiler)
143 (if (compile-only compiler)
131 ;; Just the JS
144 ;; Just the JS
132 (preprocess-js (js-sources compiler) (beautify compiler))
145 (js-sources compiler)
133 ;; All of it
146 ;; All of it
134 (html-sources compiler))
147 (html-sources compiler))
135 (target compiler) :if-exists :supersede))
148 (target compiler) :if-exists :supersede))
@@ -1,44 +1,51 b''
1
1
2 (in-package sugar-qsp.main)
2 (in-package sugar-qsp.main)
3
3
4 (setf (root)
4 (setf (root)
5 (create
5 (create
6 ;;; Game session state
6 ;;; Game session state (saved in savegames)
7 ;; Variables
7 ;; Variables
8 vars (create)
8 vars (create)
9 ;; Inventory (objects)
9 ;; Inventory (objects)
10 objs (list)
10 objs (list)
11 current-location nil
11 current-location nil
12 ;; Game time
12 ;; Game time
13 started-at (chain *date (now))
13 started-at (chain *date (now))
14 ;; Timers
14 ;; Timers
15 timer-interval 500
15 timer-interval 500
16 timer-obj nil
16 timer-obj nil
17 ;; Games
18 loaded-games (list)
19
17 ;;; Transient state
20 ;;; Transient state
21 ;; ACTions
22 acts (create)
18 ;; Savegame data
23 ;; Savegame data
19 state-stash (create)
24 state-stash (create)
20 ;; List of audio files being played
25 ;; List of audio files being played
21 playing (create)
26 playing (create)
22 ;; Local variables stack (starts with an empty frame)
27 ;; Local variables stack (starts with an empty frame)
23 locals (list)
28 locals (list)
29
24 ;;; Game data
30 ;;; Game data
25 ;; ACTions
31 ;; Games (filename -> [locations])
26 acts (create)
32 games (list)
27 ;; Locations
33 ;; The main (non library) game. Updated by openqst
34 main-game nil
35 ;; Active locations
28 locs (create)))
36 locs (create)))
29
37
30 ;; Launch the game from the first location
38 ;; Launch the game from the first location
31 (setf (@ window onload)
39 (setf (@ window onload)
32 (lambda ()
40 (lambda ()
33 (#.(intern "INIT-DOM" "SUGAR-QSP.API"))
41 (#.(intern "INIT-DOM" "SUGAR-QSP.API"))
34 ;; For MSECCOUNT
42 ;; For MSECCOUNT
35 (setf (root started-at) (chain *date (now)))
43 (setf (root started-at) (chain *date (now)))
36 ;; For $COUNTER and SETTIMER
44 ;; For $COUNTER and SETTIMER
37 (#.(intern "SET-TIMER" "SUGAR-QSP.API")
45 (#.(intern "SET-TIMER" "SUGAR-QSP.API")
38 (root timer-interval))
46 (root timer-interval))
39 ;; Start the first location
47 ;; Start the first game
40 (funcall (getprop (root locs)
48 (#.(intern "RUN-GAME" "SUGAR-QSP.API")
41 (chain *object (keys (root locs)) 0))
49 (chain *object (keys (root games)) 0))
42 (list))
43 (values)))
50 (values)))
44
51
@@ -1,93 +1,93 b''
1
1
2 (in-package cl-user)
2 (in-package cl-user)
3
3
4 (defpackage :sugar-qsp.js)
4 (defpackage :sugar-qsp.js)
5
5
6 (defpackage :sugar-qsp.main
6 (defpackage :sugar-qsp.main
7 (:use :cl :ps :sugar-qsp.js)
7 (:use :cl :ps :sugar-qsp.js)
8 (:export #:api-call #:by-id
8 (:export #:api-call #:by-id
9 #:root #:in
9 #:root #:in
10 #:vars #:objs #:current-location
10 #:vars #:objs #:current-location
11 #:started-at #:timer-interval #:timer-obj
11 #:started-at #:timer-interval #:timer-obj
12 #:state-stash #:playing #:locals
12 #:state-stash #:playing #:locals
13 #:acts #:locs))
13 #:acts #:locs #:games))
14
14
15 ;;; API functions
15 ;;; API functions
16 (defpackage :sugar-qsp.api
16 (defpackage :sugar-qsp.api
17 (:use :cl :ps :sugar-qsp.main :sugar-qsp.js)
17 (:use :cl :ps :sugar-qsp.main :sugar-qsp.js)
18 (:export #:with-frame #:with-call-args
18 (:export #:with-frame #:with-call-args
19 #:stash-state
19 #:stash-state
20
20
21 #:report-error #:sleep #:init-dom #:call-serv-loc
21 #:report-error #:sleep #:init-dom #:call-serv-loc
22 #:newline #:clear-id #:prepare-contents #:get-id #:set-id #:append-id
22 #:newline #:clear-id #:prepare-contents #:get-id #:set-id #:append-id
23 #:init-args #:get-result #:call-loc #:call-act
23 #:init-args #:get-result #:call-loc #:call-act
24 #:get-frame #:add-text #:get-text #:clear-text #:enable-frame
24 #:get-frame #:add-text #:get-text #:clear-text #:enable-frame
25 #:add-act #:del-act #:clear-act #:update-acts
25 #:add-act #:del-act #:clear-act #:update-acts
26 #:qspfor
26 #:qspfor
27 #:*var #:new-value #:index-num #:get #:set #:kill
27 #:*var #:new-value #:index-num #:get #:set #:kill
28 #:var-real-name #:ensure-var #:var-ref #:get-var #:set-var
28 #:var-real-name #:ensure-var #:var-ref #:get-var #:set-var
29 #:get-array #:set-array #:kill-var #:array-size
29 #:get-array #:set-array #:kill-var #:array-size
30 #:push-local-frame #:pop-local-frame #:current-local-frame #:new-local
30 #:push-local-frame #:pop-local-frame #:current-local-frame #:new-local
31 #:update-objs
31 #:update-objs
32 #:menu
32 #:menu
33 #:clean-audio
33 #:clean-audio
34 #:show-image
34 #:show-image
35 #:opengame #:savegame
35 #:opengame #:savegame
36 ))
36 ))
37
37
38 ;;; QSP library functions and macros
38 ;;; QSP library functions and macros
39 (defpackage :sugar-qsp.lib
39 (defpackage :sugar-qsp.lib
40 (:use :cl :ps :sugar-qsp.main :sugar-qsp.js)
40 (:use :cl :ps :sugar-qsp.main :sugar-qsp.js)
41 (:local-nicknames (#:api :sugar-qsp.api))
41 (:local-nicknames (#:api :sugar-qsp.api))
42 (:export #:str #:exec #:qspblock #:qspfor #:location
42 (:export #:str #:exec #:qspblock #:qspfor #:game #:location
43 #:qspcond #:qspvar #:set #:local #:jump
43 #:qspcond #:qspvar #:set #:local #:jump
44
44
45 #:killvar #:killall
45 #:killvar #:killall
46 #:obj #:loc #:no
46 #:obj #:loc #:no
47 #:qspver #:curloc
47 #:qspver #:curloc
48 #:rnd #:qspmax #:qspmin
48 #:rnd #:qspmax #:qspmin
49 #:arrsize #:len
49 #:arrsize #:len
50 #:mid #:ucase #:lcase #:trim #:replace #:val #:qspstr
50 #:mid #:ucase #:lcase #:trim #:replace #:val #:qspstr
51 #:exit #:desc
51 #:exit #:desc
52 #:showstat #:msg
52 #:showstat #:msg
53 #:showacts #:delact #:cla
53 #:showacts #:delact #:cla
54 #:showobjs #:countobj #:getobj
54 #:showobjs #:countobj #:getobj
55 #:isplay
55 #:isplay
56 #:view
56 #:view
57 #:showinput
57 #:showinput
58 #:wait #:settimer
58 #:wait #:settimer
59 #:local
59 #:local
60 #:opengame #:savegame
60 #:opengame #:savegame
61
61
62 #:goto #:xgoto
62 #:goto #:xgoto
63 #:rand
63 #:rand
64 #:copyarr #:arrpos #:arrcomp
64 #:copyarr #:arrpos #:arrcomp
65 #:instr #:isnum #:strcomp #:strfind #:strpos
65 #:instr #:isnum #:strcomp #:strfind #:strpos
66 #:iif
66 #:iif
67 #:gosub #:func
67 #:gosub #:func
68 #:dynamic #:dyneval
68 #:dynamic #:dyneval
69 #:main-p #:main-pl #:main-nl #:maintxt #:desc #:main-clear
69 #:main-p #:main-pl #:main-nl #:maintxt #:desc #:main-clear
70 #:stat-p #:stat-pl #:stat-nl #:stattxt #:stat-clear #:cls
70 #:stat-p #:stat-pl #:stat-nl #:stattxt #:stat-clear #:cls
71 #:curacts
71 #:curacts
72 #:addobj #:delobj #:killobj
72 #:addobj #:delobj #:killobj
73 #:menu
73 #:menu
74 #:play #:close #:closeall
74 #:play #:close #:closeall
75 #:refint
75 #:refint
76 #:usertxt #:cmdclear #:input
76 #:usertxt #:cmdclear #:input
77 #:msecscount
77 #:msecscount
78 #:rgb
78 #:rgb
79 #:openqst #:addqst #:killqst
79 #:openqst #:addqst #:killqst
80 ))
80 ))
81
81
82 ;;; The compiler
82 ;;; The compiler
83 (defpackage :sugar-qsp
83 (defpackage :sugar-qsp
84 (:use :cl)
84 (:use :cl)
85 (:local-nicknames (#:p #:esrap)
85 (:local-nicknames (#:p #:esrap)
86 (#:lib :sugar-qsp.lib)
86 (#:lib :sugar-qsp.lib)
87 (#:api :sugar-qsp.api)
87 (#:api :sugar-qsp.api)
88 (#:main :sugar-qsp.main))
88 (#:main :sugar-qsp.main))
89 (:export #:parse-file #:entry-point))
89 (:export #:parse-file #:entry-point))
90
90
91 (setf (ps:ps-package-prefix "SUGAR-QSP.MAIN") "qsp_")
91 (setf (ps:ps-package-prefix "SUGAR-QSP.MAIN") "qsp_")
92 (setf (ps:ps-package-prefix "SUGAR-QSP.API") "qsp_api_")
92 (setf (ps:ps-package-prefix "SUGAR-QSP.API") "qsp_api_")
93 (setf (ps:ps-package-prefix "SUGAR-QSP.LIB") "qsp_lib_")
93 (setf (ps:ps-package-prefix "SUGAR-QSP.LIB") "qsp_lib_")
@@ -1,619 +1,620 b''
1
1
2 (in-package sugar-qsp)
2 (in-package sugar-qsp)
3
3
4 ;;;; Parses TXT source to an intermediate representation
4 ;;;; Parses TXT source to an intermediate representation
5
5
6 ;;; Utility
6 ;;; Utility
7
7
8 (defun remove-nth (list nth)
8 (defun remove-nth (list nth)
9 (append (subseq list 0 nth)
9 (append (subseq list 0 nth)
10 (subseq list (1+ nth))))
10 (subseq list (1+ nth))))
11
11
12 (defun not-quote (char)
12 (defun not-quote (char)
13 (not (eql #\' char)))
13 (not (eql #\' char)))
14
14
15
15
16 (defun not-doublequote (char)
16 (defun not-doublequote (char)
17 (not (eql #\" char)))
17 (not (eql #\" char)))
18
18
19 (defun not-brace (char)
19 (defun not-brace (char)
20 (not (eql #\} char)))
20 (not (eql #\} char)))
21
21
22 (defun not-integer (string)
22 (defun not-integer (string)
23 (when (find-if-not #'digit-char-p string)
23 (when (find-if-not #'digit-char-p string)
24 t))
24 t))
25
25
26 (defun not-newline (char)
26 (defun not-newline (char)
27 (not (eql #\newline char)))
27 (not (eql #\newline char)))
28
28
29 (defun id-any-char (char)
29 (defun id-any-char (char)
30 (and
30 (and
31 (not (digit-char-p char))
31 (not (digit-char-p char))
32 (not (eql #\newline char))
32 (not (eql #\newline char))
33 (not (find char " !:&=<>+-*/,'\"()[]{}"))))
33 (not (find char " !:&=<>+-*/,'\"()[]{}"))))
34
34
35 (defun intern-first (list)
35 (defun intern-first (list)
36 (list* (intern (string-upcase (first list)) :lib)
36 (list* (intern (string-upcase (first list)) :lib)
37 (rest list)))
37 (rest list)))
38
38
39 (eval-when (:compile-toplevel :load-toplevel :execute)
39 (eval-when (:compile-toplevel :load-toplevel :execute)
40 (defun remove-nil (list)
40 (defun remove-nil (list)
41 (remove nil list)))
41 (remove nil list)))
42
42
43 (defun binop-rest (list)
43 (defun binop-rest (list)
44 (destructuring-bind (ws1 operator ws2 operand2)
44 (destructuring-bind (ws1 operator ws2 operand2)
45 list
45 list
46 (declare (ignore ws1 ws2))
46 (declare (ignore ws1 ws2))
47 (list (intern (string-upcase operator) :lib) operand2)))
47 (list (intern (string-upcase operator) :lib) operand2)))
48
48
49 (defun do-binop% (left-op other-ops)
49 (defun do-binop% (left-op other-ops)
50 (if (null other-ops)
50 (if (null other-ops)
51 left-op
51 left-op
52 (destructuring-bind ((operator right-op) &rest rest-ops)
52 (destructuring-bind ((operator right-op) &rest rest-ops)
53 other-ops
53 other-ops
54 (if (and (listp left-op)
54 (if (and (listp left-op)
55 (eq (first left-op)
55 (eq (first left-op)
56 operator))
56 operator))
57 (do-binop% (append left-op (list right-op)) rest-ops)
57 (do-binop% (append left-op (list right-op)) rest-ops)
58 (do-binop% (list operator left-op right-op) rest-ops)))))
58 (do-binop% (list operator left-op right-op) rest-ops)))))
59
59
60 (defun do-binop (list)
60 (defun do-binop (list)
61 (destructuring-bind (left-op rest-ops)
61 (destructuring-bind (left-op rest-ops)
62 list
62 list
63 (do-binop% left-op
63 (do-binop% left-op
64 (mapcar #'binop-rest rest-ops))))
64 (mapcar #'binop-rest rest-ops))))
65
65
66 (p:defrule line-continuation (and #\_ #\newline)
66 (p:defrule line-continuation (and #\_ #\newline)
67 (:constant nil))
67 (:constant nil))
68
68
69 (p:defrule text-spaces (+ (or #\space #\tab line-continuation))
69 (p:defrule text-spaces (+ (or #\space #\tab line-continuation))
70 (:text t))
70 (:text t))
71
71
72 (p:defrule spaces (+ (or #\space #\tab line-continuation))
72 (p:defrule spaces (+ (or #\space #\tab line-continuation))
73 (:constant nil)
73 (:constant nil)
74 (:error-report nil))
74 (:error-report nil))
75
75
76 (p:defrule spaces? (* (or #\space #\tab line-continuation))
76 (p:defrule spaces? (* (or #\space #\tab line-continuation))
77 (:constant nil)
77 (:constant nil)
78 (:error-report nil))
78 (:error-report nil))
79
79
80 (p:defrule colon #\:
80 (p:defrule colon #\:
81 (:constant nil))
81 (:constant nil))
82
82
83 (p:defrule equal #\=
83 (p:defrule equal #\=
84 (:constant nil))
84 (:constant nil))
85
85
86 (p:defrule alphanumeric (alphanumericp character))
86 (p:defrule alphanumeric (alphanumericp character))
87
87
88 (p:defrule not-newline (not-newline character))
88 (p:defrule not-newline (not-newline character))
89
89
90 (p:defrule squote-esc "''"
90 (p:defrule squote-esc "''"
91 (:lambda (list)
91 (:lambda (list)
92 (p:text (elt list 0))))
92 (p:text (elt list 0))))
93
93
94 (p:defrule dquote-esc "\"\""
94 (p:defrule dquote-esc "\"\""
95 (:lambda (list)
95 (:lambda (list)
96 (p:text (elt list 0))))
96 (p:text (elt list 0))))
97
97
98 (p:defrule sstring-chars (+ (and (and (p:! "<<") (p:! (p:~ "\"exec:")))
98 (p:defrule sstring-chars (+ (and (and (p:! "<<") (p:! (p:~ "\"exec:")))
99 (or squote-esc (not-quote character))))
99 (or squote-esc (not-quote character))))
100 (:lambda (list)
100 (:lambda (list)
101 (p:text (mapcar #'second list))))
101 (p:text (mapcar #'second list))))
102
102
103 (p:defrule dstring-chars (+ (and (and (p:! "<<") (p:! (p:~ "'exec:")))
103 (p:defrule dstring-chars (+ (and (and (p:! "<<") (p:! (p:~ "'exec:")))
104 (or dquote-esc (not-doublequote character))))
104 (or dquote-esc (not-doublequote character))))
105 (:lambda (list)
105 (:lambda (list)
106 (p:text (mapcar #'second list))))
106 (p:text (mapcar #'second list))))
107
107
108 ;;; Identifiers
108 ;;; Identifiers
109
109
110 (defparameter *keywords* '(act addlib addobj addqst and arrcomp arrpos arrsize cla clear *clear close clr *clr cls cmdclear cmdclr copyarr counter countobj 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 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))
110 (defparameter *keywords* '(act addlib addobj addqst and arrcomp arrpos arrsize cla clear *clear close clr *clr cls cmdclear cmdclr copyarr counter countobj 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 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))
111
111
112 (defun trim-$ (str)
112 (defun trim-$ (str)
113 (if (char= #\$ (elt str 0))
113 (if (char= #\$ (elt str 0))
114 (subseq str 1)
114 (subseq str 1)
115 str))
115 str))
116
116
117 (defun qsp-keyword-p (id)
117 (defun qsp-keyword-p (id)
118 (member (intern (trim-$ (string-upcase id))) *keywords*))
118 (member (intern (trim-$ (string-upcase id))) *keywords*))
119
119
120 (defun not-qsp-keyword-p (id)
120 (defun not-qsp-keyword-p (id)
121 (not (member (intern (trim-$ (string-upcase id))) *keywords*)))
121 (not (member (intern (trim-$ (string-upcase id))) *keywords*)))
122
122
123 (p:defrule qsp-keyword (qsp-keyword-p identifier-raw))
123 (p:defrule qsp-keyword (qsp-keyword-p identifier-raw))
124
124
125 (p:defrule id-first (id-any-char character))
125 (p:defrule id-first (id-any-char character))
126 (p:defrule id-next (or (id-any-char character)
126 (p:defrule id-next (or (id-any-char character)
127 (digit-char-p character)))
127 (digit-char-p character)))
128 (p:defrule identifier-raw (and id-first (* id-next))
128 (p:defrule identifier-raw (and id-first (* id-next))
129 (:lambda (list)
129 (:lambda (list)
130 (intern (string-upcase (p:text list)) :lib)))
130 (intern (string-upcase (p:text list)) :lib)))
131
131
132 (p:defrule identifier (not-qsp-keyword-p identifier-raw))
132 (p:defrule identifier (not-qsp-keyword-p identifier-raw))
133
133
134 ;;; Strings
134 ;;; Strings
135
135
136 (p:defrule qsp-string (or normal-string brace-string))
136 (p:defrule qsp-string (or normal-string brace-string))
137
137
138 (p:defrule normal-string (or sstring dstring)
138 (p:defrule normal-string (or sstring dstring)
139 (:lambda (str)
139 (:lambda (str)
140 (list* 'lib:str (or str (list "")))))
140 (list* 'lib:str (or str (list "")))))
141
141
142 (p:defrule sstring (and #\' (* (or string-interpol
142 (p:defrule sstring (and #\' (* (or string-interpol
143 sstring-exec
143 sstring-exec
144 sstring-chars))
144 sstring-chars))
145 #\')
145 #\')
146 (:function second))
146 (:function second))
147
147
148 (p:defrule dstring (and #\" (* (or string-interpol
148 (p:defrule dstring (and #\" (* (or string-interpol
149 dstring-exec
149 dstring-exec
150 dstring-chars))
150 dstring-chars))
151 #\")
151 #\")
152 (:function second))
152 (:function second))
153
153
154 (p:defrule string-interpol (and "<<" expression ">>")
154 (p:defrule string-interpol (and "<<" expression ">>")
155 (:function second))
155 (:function second))
156
156
157 (p:defrule sstring-exec-body (+ (or squote-esc (not-doublequote character)))
157 (p:defrule sstring-exec-body (+ (or squote-esc (not-doublequote character)))
158 (:text t))
158 (:text t))
159
159
160 (p:defrule dstring-exec-body (+ (or dquote-esc (not-quote character)))
160 (p:defrule dstring-exec-body (+ (or dquote-esc (not-quote character)))
161 (:text t))
161 (:text t))
162
162
163 (p:defrule sstring-exec (and (p:~ "\"exec:") sstring-exec-body #\")
163 (p:defrule sstring-exec (and (p:~ "\"exec:") sstring-exec-body #\")
164 (:lambda (list)
164 (:lambda (list)
165 (list* 'lib:exec (p:parse 'exec-body (second list)))))
165 (list* 'lib:exec (p:parse 'exec-body (second list)))))
166
166
167 (p:defrule dstring-exec (and (p:~ "'exec:") dstring-exec-body #\')
167 (p:defrule dstring-exec (and (p:~ "'exec:") dstring-exec-body #\')
168 (:lambda (list)
168 (:lambda (list)
169 (list* 'lib:exec (p:parse 'exec-body (second list)))))
169 (list* 'lib:exec (p:parse 'exec-body (second list)))))
170
170
171 (p:defrule brace-string (and #\{ before-statement block-body #\})
171 (p:defrule brace-string (and #\{ before-statement block-body #\})
172 (:lambda (list)
172 (:lambda (list)
173 (list* 'lib:qspblock (third list))))
173 (list* 'lib:qspblock (third list))))
174
174
175 ;;; Location
175 ;;; Location
176
176
177 (p:defrule sugar-qsp-grammar (and (* (or spaces #\newline))
177 (p:defrule sugar-qsp-grammar (and (* (or spaces #\newline))
178 (* location))
178 (* location))
179 (:function second))
179 (:lambda (list)
180 `(lib:game ,@(second list))))
180
181
181 (p:defrule location (and location-header block-body location-end)
182 (p:defrule location (and location-header block-body location-end)
182 (:destructure (header body end)
183 (:destructure (header body end)
183 (declare (ignore end))
184 (declare (ignore end))
184 `(lib:location (,header) ,@body)))
185 `(lib:location (,header) ,@body)))
185
186
186 (p:defrule location-header (and #\#
187 (p:defrule location-header (and #\#
187 (+ not-newline)
188 (+ not-newline)
188 (and #\newline spaces? before-statement))
189 (and #\newline spaces? before-statement))
189 (:destructure (spaces1 name spaces2)
190 (:destructure (spaces1 name spaces2)
190 (declare (ignore spaces1 spaces2))
191 (declare (ignore spaces1 spaces2))
191 (string-upcase (string-trim " " (p:text name)))))
192 (string-upcase (string-trim " " (p:text name)))))
192
193
193 (p:defrule location-end (and #\- (* not-newline) #\newline before-statement)
194 (p:defrule location-end (and #\- (* not-newline) #\newline before-statement)
194 (:constant nil))
195 (:constant nil))
195
196
196 ;;; Block body
197 ;;; Block body
197
198
198 (p:defrule newline-block-body (and #\newline spaces? block-body)
199 (p:defrule newline-block-body (and #\newline spaces? block-body)
199 (:function third))
200 (:function third))
200
201
201 (p:defrule block-body (* statement)
202 (p:defrule block-body (* statement)
202 (:function remove-nil))
203 (:function remove-nil))
203
204
204 ;; Just for <a href="exec:...'>
205 ;; Just for <a href="exec:...'>
205 ;; Explicitly called from that rule's production
206 ;; Explicitly called from that rule's production
206 (p:defrule exec-body (and before-statement line-body)
207 (p:defrule exec-body (and before-statement line-body)
207 (:function second))
208 (:function second))
208
209
209 (p:defrule line-body (and inline-statement (* next-inline-statement))
210 (p:defrule line-body (and inline-statement (* next-inline-statement))
210 (:lambda (list)
211 (:lambda (list)
211 (list* (first list) (second list))))
212 (list* (first list) (second list))))
212
213
213 (p:defrule before-statement (* (or #\newline spaces))
214 (p:defrule before-statement (* (or #\newline spaces))
214 (:constant nil))
215 (:constant nil))
215
216
216 (p:defrule statement-end (or statement-end-real statement-end-block-close))
217 (p:defrule statement-end (or statement-end-real statement-end-block-close))
217
218
218 (p:defrule statement-end-real (and (or #\newline
219 (p:defrule statement-end-real (and (or #\newline
219 (and #\& spaces? (p:& statement%)))
220 (and #\& spaces? (p:& statement%)))
220 before-statement)
221 before-statement)
221 (:constant nil))
222 (:constant nil))
222
223
223 (p:defrule statement-end-block-close (or (p:& #\}))
224 (p:defrule statement-end-block-close (or (p:& #\}))
224 (:constant nil))
225 (:constant nil))
225
226
226 (p:defrule inline-statement (and statement% spaces?)
227 (p:defrule inline-statement (and statement% spaces?)
227 (:function first))
228 (:function first))
228
229
229 (p:defrule next-inline-statement (and #\& spaces? inline-statement)
230 (p:defrule next-inline-statement (and #\& spaces? inline-statement)
230 (:function third))
231 (:function third))
231
232
232 (p:defrule not-a-non-statement (and (p:! (p:~ "elseif"))
233 (p:defrule not-a-non-statement (and (p:! (p:~ "elseif"))
233 (p:! (p:~ "else"))
234 (p:! (p:~ "else"))
234 (p:! (p:~ "end"))))
235 (p:! (p:~ "end"))))
235
236
236 (p:defrule statement (and inline-statement statement-end)
237 (p:defrule statement (and inline-statement statement-end)
237 (:function first))
238 (:function first))
238
239
239 (p:defrule statement% (and not-a-non-statement
240 (p:defrule statement% (and not-a-non-statement
240 (or label comment string-output
241 (or label comment string-output
241 block non-returning-intrinsic local
242 block non-returning-intrinsic local
242 assignment expression-output))
243 assignment expression-output))
243 (:function second))
244 (:function second))
244
245
245 (p:defrule expr-stopper (or comment block non-returning-intrinsic))
246 (p:defrule expr-stopper (or comment block non-returning-intrinsic))
246
247
247 (p:defrule string-output qsp-string
248 (p:defrule string-output qsp-string
248 (:lambda (string)
249 (:lambda (string)
249 (list 'lib:main-pl string)))
250 (list 'lib:main-pl string)))
250
251
251 (p:defrule expression-output expression
252 (p:defrule expression-output expression
252 (:lambda (list)
253 (:lambda (list)
253 (list 'lib:main-pl list)))
254 (list 'lib:main-pl list)))
254
255
255 (p:defrule label (and colon identifier)
256 (p:defrule label (and colon identifier)
256 (:lambda (list)
257 (:lambda (list)
257 (intern (string (second list)) :keyword)))
258 (intern (string (second list)) :keyword)))
258
259
259 (p:defrule comment (and #\! (* (or qsp-string brace-comment text-spaces not-newline)))
260 (p:defrule comment (and #\! (* (or qsp-string brace-comment text-spaces not-newline)))
260 (:constant nil))
261 (:constant nil))
261
262
262 (p:defrule brace-comment (and #\{ (* (not-brace character)) #\})
263 (p:defrule brace-comment (and #\{ (* (not-brace character)) #\})
263 (:constant nil))
264 (:constant nil))
264
265
265 (p:defrule local (and (p:~ "local") spaces variable (p:? (and spaces? #\= spaces? expression)))
266 (p:defrule local (and (p:~ "local") spaces variable (p:? (and spaces? #\= spaces? expression)))
266 (:lambda (list)
267 (:lambda (list)
267 (list* 'lib:local (third list)
268 (list* 'lib:local (third list)
268 (when (fourth list)
269 (when (fourth list)
269 (list (fourth (fourth list)))))))
270 (list (fourth (fourth list)))))))
270
271
271 ;;; Blocks
272 ;;; Blocks
272
273
273 (p:defrule block (or block-act block-if block-for))
274 (p:defrule block (or block-act block-if block-for))
274
275
275 (p:defrule block-if (and block-if-head block-if-body)
276 (p:defrule block-if (and block-if-head block-if-body)
276 (:destructure (head body)
277 (:destructure (head body)
277 `(lib:qspcond (,@head ,@(first body))
278 `(lib:qspcond (,@head ,@(first body))
278 ,@(rest body))))
279 ,@(rest body))))
279
280
280 (p:defrule block-if-head (and (p:~ "if") spaces expression spaces? colon spaces?)
281 (p:defrule block-if-head (and (p:~ "if") spaces expression spaces? colon spaces?)
281 (:function remove-nil)
282 (:function remove-nil)
282 (:function cdr))
283 (:function cdr))
283
284
284 (p:defrule block-if-body (or block-if-ml block-if-sl)
285 (p:defrule block-if-body (or block-if-ml block-if-sl)
285 (:destructure (if-body elseifs else &rest ws)
286 (:destructure (if-body elseifs else &rest ws)
286 (declare (ignore ws))
287 (declare (ignore ws))
287 `(,(remove-nil if-body) ,@elseifs ,@(when else `((else ,@else))))))
288 `(,(remove-nil if-body) ,@elseifs ,@(when else `((else ,@else))))))
288
289
289 (p:defrule block-if-sl (and line-body
290 (p:defrule block-if-sl (and line-body
290 (p:? block-if-elseif-inline)
291 (p:? block-if-elseif-inline)
291 (p:? block-if-else-inline)
292 (p:? block-if-else-inline)
292 spaces?))
293 spaces?))
293
294
294 (p:defrule block-if-ml (and (and #\newline spaces?)
295 (p:defrule block-if-ml (and (and #\newline spaces?)
295 block-body
296 block-body
296 (p:? block-if-elseif)
297 (p:? block-if-elseif)
297 (p:? block-if-else)
298 (p:? block-if-else)
298 block-if-end)
299 block-if-end)
299 (:lambda (list)
300 (:lambda (list)
300 (cdr list)))
301 (cdr list)))
301
302
302 (p:defrule block-if-elseif-inline (and block-if-elseif-head line-body (p:? block-if-elseif-inline))
303 (p:defrule block-if-elseif-inline (and block-if-elseif-head line-body (p:? block-if-elseif-inline))
303 (:destructure (head statements elseif)
304 (:destructure (head statements elseif)
304 `((,@(rest head) ,@(remove-nil statements)) ,@elseif)))
305 `((,@(rest head) ,@(remove-nil statements)) ,@elseif)))
305
306
306 (p:defrule block-if-elseif (and block-if-elseif-head statement-end block-body (p:? block-if-elseif))
307 (p:defrule block-if-elseif (and block-if-elseif-head statement-end block-body (p:? block-if-elseif))
307 (:destructure (head ws statements elseif)
308 (:destructure (head ws statements elseif)
308 (declare (ignore ws))
309 (declare (ignore ws))
309 `((,@(rest head) ,@(remove-nil statements)) ,@elseif)))
310 `((,@(rest head) ,@(remove-nil statements)) ,@elseif)))
310
311
311 (p:defrule block-if-elseif-head (and (p:~ "elseif") spaces expression spaces? colon spaces?)
312 (p:defrule block-if-elseif-head (and (p:~ "elseif") spaces expression spaces? colon spaces?)
312 (:function remove-nil)
313 (:function remove-nil)
313 (:function intern-first))
314 (:function intern-first))
314
315
315 (p:defrule block-if-else-inline (and block-if-else-head line-body)
316 (p:defrule block-if-else-inline (and block-if-else-head line-body)
316 (:function second))
317 (:function second))
317
318
318 (p:defrule block-if-else (and block-if-else-head #\newline spaces? block-body)
319 (p:defrule block-if-else (and block-if-else-head #\newline spaces? block-body)
319 (:function fourth))
320 (:function fourth))
320
321
321 (p:defrule block-if-else-head (and (p:~ "else") spaces?)
322 (p:defrule block-if-else-head (and (p:~ "else") spaces?)
322 (:constant nil))
323 (:constant nil))
323
324
324 (p:defrule block-if-end (and (p:~ "end")
325 (p:defrule block-if-end (and (p:~ "end")
325 (p:? (and spaces (p:~ "if"))))
326 (p:? (and spaces (p:~ "if"))))
326 (:constant nil))
327 (:constant nil))
327
328
328 (p:defrule block-act (and block-act-head (or block-ml block-sl))
329 (p:defrule block-act (and block-act-head (or block-ml block-sl))
329 (:lambda (list)
330 (:lambda (list)
330 (apply #'append list)))
331 (apply #'append list)))
331
332
332 (p:defrule block-act-head (and (p:~ "act") spaces? qsp-string spaces?
333 (p:defrule block-act-head (and (p:~ "act") spaces? qsp-string spaces?
333 (p:? block-act-head-img)
334 (p:? block-act-head-img)
334 colon spaces?)
335 colon spaces?)
335 (:lambda (list)
336 (:lambda (list)
336 (intern-first (list (first list)
337 (intern-first (list (first list)
337 (third list)
338 (third list)
338 (or (fifth list) '(lib:str ""))))))
339 (or (fifth list) '(lib:str ""))))))
339
340
340 (p:defrule block-act-head-img (and #\, spaces? qsp-string spaces?)
341 (p:defrule block-act-head-img (and #\, spaces? qsp-string spaces?)
341 (:lambda (list)
342 (:lambda (list)
342 (or (third list) "")))
343 (or (third list) "")))
343
344
344 (p:defrule block-for (and block-for-head (or block-ml block-sl))
345 (p:defrule block-for (and block-for-head (or block-ml block-sl))
345 (:lambda (list)
346 (:lambda (list)
346 (apply #'append list)))
347 (apply #'append list)))
347
348
348 (p:defrule block-for-head (and (p:~ "for") spaces variable spaces? equal spaces? expression
349 (p:defrule block-for-head (and (p:~ "for") spaces variable spaces? equal spaces? expression
349 (p:~ "to") spaces expression
350 (p:~ "to") spaces expression
350 block-for-head-step
351 block-for-head-step
351 colon spaces?)
352 colon spaces?)
352 (:lambda (list)
353 (:lambda (list)
353 (unless (eq (fourth (third list)) :num)
354 (unless (eq (fourth (third list)) :num)
354 (error "For counter variable must be numeric."))
355 (error "For counter variable must be numeric."))
355 (list 'lib:qspfor
356 (list 'lib:qspfor
356 (elt list 2)
357 (elt list 2)
357 (elt list 6)
358 (elt list 6)
358 (elt list 9)
359 (elt list 9)
359 (elt list 10))))
360 (elt list 10))))
360
361
361 (p:defrule block-for-head-step (p:? (and (p:~ "step") spaces expression spaces?))
362 (p:defrule block-for-head-step (p:? (and (p:~ "step") spaces expression spaces?))
362 (:lambda (list)
363 (:lambda (list)
363 (if list
364 (if list
364 (third list)
365 (third list)
365 1)))
366 1)))
366
367
367 (p:defrule block-sl line-body)
368 (p:defrule block-sl line-body)
368
369
369 (p:defrule block-ml (and newline-block-body block-end)
370 (p:defrule block-ml (and newline-block-body block-end)
370 (:lambda (list)
371 (:lambda (list)
371 (apply #'list* (butlast list))))
372 (apply #'list* (butlast list))))
372
373
373 (p:defrule block-end (and (p:~ "end"))
374 (p:defrule block-end (and (p:~ "end"))
374 (:constant nil))
375 (:constant nil))
375
376
376 ;;; Calls
377 ;;; Calls
377
378
378 (p:defrule first-argument (and expression spaces?)
379 (p:defrule first-argument (and expression spaces?)
379 (:function first))
380 (:function first))
380 (p:defrule next-argument (and "," spaces? expression)
381 (p:defrule next-argument (and "," spaces? expression)
381 (:function third))
382 (:function third))
382 (p:defrule arguments (or parenthesized-arguments plain-arguments no-arguments))
383 (p:defrule arguments (or parenthesized-arguments plain-arguments no-arguments))
383 (p:defrule parenthesized-arguments (and spaces? #\( base-arguments #\))
384 (p:defrule parenthesized-arguments (and spaces? #\( base-arguments #\))
384 (:function third))
385 (:function third))
385 (p:defrule plain-arguments (and spaces? base-arguments)
386 (p:defrule plain-arguments (and spaces? base-arguments)
386 (:function second))
387 (:function second))
387 (p:defrule no-arguments (or (and spaces? (p:& #\newline))
388 (p:defrule no-arguments (or (and spaces? (p:& #\newline))
388 (and spaces? (p:& #\&))
389 (and spaces? (p:& #\&))
389 spaces?)
390 spaces?)
390 (:constant nil))
391 (:constant nil))
391 (p:defrule base-arguments (or (and first-argument (* next-argument)) spaces?)
392 (p:defrule base-arguments (or (and first-argument (* next-argument)) spaces?)
392 (:lambda (list)
393 (:lambda (list)
393 (if (null list)
394 (if (null list)
394 nil
395 nil
395 (list* (first list) (second list)))))
396 (list* (first list) (second list)))))
396
397
397 ;;; Intrinsics
398 ;;; Intrinsics
398
399
399 (defmacro defintrinsics ((rule-name returning-rule-name non-returning-rule-name) &body clauses)
400 (defmacro defintrinsics ((rule-name returning-rule-name non-returning-rule-name) &body clauses)
400 `(progn
401 `(progn
401 ,@(loop :for clause :in clauses
402 ,@(loop :for clause :in clauses
402 :collect `(defintrinsic ,@clause))
403 :collect `(defintrinsic ,@clause))
403 (p:defrule ,returning-rule-name (or ,@(remove-nil
404 (p:defrule ,returning-rule-name (or ,@(remove-nil
404 (mapcar (lambda (clause)
405 (mapcar (lambda (clause)
405 (when (second clause)
406 (when (second clause)
406 (alexandria:symbolicate
407 (alexandria:symbolicate
407 'intrinsic- (first clause))))
408 'intrinsic- (first clause))))
408 clauses))))
409 clauses))))
409 (p:defrule ,non-returning-rule-name (or ,@(remove-nil
410 (p:defrule ,non-returning-rule-name (or ,@(remove-nil
410 (mapcar (lambda (clause)
411 (mapcar (lambda (clause)
411 (unless (second clause)
412 (unless (second clause)
412 (alexandria:symbolicate
413 (alexandria:symbolicate
413 'intrinsic- (first clause))))
414 'intrinsic- (first clause))))
414 clauses))))
415 clauses))))
415 (p:defrule ,rule-name (or ,returning-rule-name ,non-returning-rule-name))))
416 (p:defrule ,rule-name (or ,returning-rule-name ,non-returning-rule-name))))
416
417
417 (defmacro defintrinsic (sym returning &optional (min-arity 0) (max-arity 10) &rest names)
418 (defmacro defintrinsic (sym returning &optional (min-arity 0) (max-arity 10) &rest names)
418 (declare (ignore returning))
419 (declare (ignore returning))
419 (setf names
420 (setf names
420 (if names
421 (if names
421 (mapcar #'string-upcase names)
422 (mapcar #'string-upcase names)
422 (list (string sym))))
423 (list (string sym))))
423 `(p:defrule ,(alexandria:symbolicate 'intrinsic- sym)
424 `(p:defrule ,(alexandria:symbolicate 'intrinsic- sym)
424 (and (p:? #\$) (or ,@(loop :for name :in names :collect `(p:~ ,name)))
425 (and (p:? #\$) (or ,@(loop :for name :in names :collect `(p:~ ,name)))
425 arguments)
426 arguments)
426 (:destructure (dollar name arguments)
427 (:destructure (dollar name arguments)
427 (declare (ignore dollar))
428 (declare (ignore dollar))
428 (unless (<= ,min-arity (length arguments) ,max-arity)
429 (unless (<= ,min-arity (length arguments) ,max-arity)
429 (error "Intrinsic ~A expects between ~A and ~A arguments but ~A were provided:~%~S"
430 (error "Intrinsic ~A expects between ~A and ~A arguments but ~A were provided:~%~S"
430 name ,min-arity ,max-arity (length arguments) arguments))
431 name ,min-arity ,max-arity (length arguments) arguments))
431 (list* ',(intern (string sym) :lib) arguments))))
432 (list* ',(intern (string sym) :lib) arguments))))
432
433
433 (defintrinsics (intrinsic returning-intrinsic non-returning-intrinsic)
434 (defintrinsics (intrinsic returning-intrinsic non-returning-intrinsic)
434 ;; Transitions
435 ;; Transitions
435 (goto% nil 0 10 "gt" "goto")
436 (goto% nil 0 10 "gt" "goto")
436 (xgoto% nil 0 10 "xgt" "xgoto")
437 (xgoto% nil 0 10 "xgt" "xgoto")
437 ;; Variables
438 ;; Variables
438 (killvar nil 0 2)
439 (killvar nil 0 2)
439 ;; Expressions
440 ;; Expressions
440 (obj t 1 1)
441 (obj t 1 1)
441 (loc t 1 1)
442 (loc t 1 1)
442 (no t 1 1)
443 (no t 1 1)
443 ;; Basic
444 ;; Basic
444 (qspver t 0 0)
445 (qspver t 0 0)
445 (curloc t 0 0)
446 (curloc t 0 0)
446 (rand t 1 2)
447 (rand t 1 2)
447 (rnd t 0 0)
448 (rnd t 0 0)
448 (qspmax t 1 10 "max")
449 (qspmax t 1 10 "max")
449 (qspmin t 1 10 "min")
450 (qspmin t 1 10 "min")
450 ;; Arrays
451 ;; Arrays
451 (killall nil 0 0)
452 (killall nil 0 0)
452 (copyarr nil 2 4)
453 (copyarr nil 2 4)
453 (arrsize t 1 1)
454 (arrsize t 1 1)
454 (arrpos t 2 3)
455 (arrpos t 2 3)
455 (arrcomp t 2 3)
456 (arrcomp t 2 3)
456 ;; Strings
457 ;; Strings
457 (len t 1 1)
458 (len t 1 1)
458 (mid t 2 3)
459 (mid t 2 3)
459 (ucase t 1 1)
460 (ucase t 1 1)
460 (lcase t 1 1)
461 (lcase t 1 1)
461 (trim t 1 1)
462 (trim t 1 1)
462 (replace t 2 3)
463 (replace t 2 3)
463 (instr t 2 3)
464 (instr t 2 3)
464 (isnum t 1 1)
465 (isnum t 1 1)
465 (val t 1 1)
466 (val t 1 1)
466 (qspstr t 1 1 "str")
467 (qspstr t 1 1 "str")
467 (strcomp t 2 2)
468 (strcomp t 2 2)
468 (strfind t 2 3)
469 (strfind t 2 3)
469 (strpos t 2 3)
470 (strpos t 2 3)
470 ;; IF
471 ;; IF
471 (iif t 2 3)
472 (iif t 2 3)
472 ;; Subs
473 ;; Subs
473 (gosub nil 1 10 "gosub" "gs")
474 (gosub nil 1 10 "gosub" "gs")
474 (func t 1 10)
475 (func t 1 10)
475 (exit nil 0 0)
476 (exit nil 0 0)
476 ;; Jump
477 ;; Jump
477 (jump nil 1 1)
478 (jump nil 1 1)
478 ;; Dynamic
479 ;; Dynamic
479 (dynamic nil 1 10)
480 (dynamic nil 1 10)
480 (dyneval t 1 10)
481 (dyneval t 1 10)
481 ;; Sound
482 ;; Sound
482 (play nil 1 2)
483 (play nil 1 2)
483 (isplay t 1 1)
484 (isplay t 1 1)
484 (close nil 1 1)
485 (close nil 1 1)
485 (closeall nil 0 0 "close all")
486 (closeall nil 0 0 "close all")
486 ;; Main window
487 ;; Main window
487 (main-pl nil 1 1 "*pl")
488 (main-pl nil 1 1 "*pl")
488 (main-nl nil 0 1 "*nl")
489 (main-nl nil 0 1 "*nl")
489 (main-p nil 1 1 "*p")
490 (main-p nil 1 1 "*p")
490 (maintxt t 0 0)
491 (maintxt t 0 0)
491 (desc t 1 1)
492 (desc t 1 1)
492 (main-clear nil 0 0 "*clear" "*clr")
493 (main-clear nil 0 0 "*clear" "*clr")
493 ;; Aux window
494 ;; Aux window
494 (showstat nil 1 1)
495 (showstat nil 1 1)
495 (stat-pl nil 1 1 "pl")
496 (stat-pl nil 1 1 "pl")
496 (stat-nl nil 0 1 "nl")
497 (stat-nl nil 0 1 "nl")
497 (stat-p nil 1 1 "p")
498 (stat-p nil 1 1 "p")
498 (stattxt t 0 0)
499 (stattxt t 0 0)
499 (stat-clear nil 0 0 "clear" "clr")
500 (stat-clear nil 0 0 "clear" "clr")
500 (cls nil 0 0)
501 (cls nil 0 0)
501 ;; Dialog
502 ;; Dialog
502 (msg nil 1 1)
503 (msg nil 1 1)
503 ;; Acts
504 ;; Acts
504 (showacts nil 1 1)
505 (showacts nil 1 1)
505 (delact nil 1 1 "delact" "del act")
506 (delact nil 1 1 "delact" "del act")
506 (curacts t 0 0)
507 (curacts t 0 0)
507 (cla nil 0 0)
508 (cla nil 0 0)
508 ;; Objects
509 ;; Objects
509 (showobjs nil 1 1)
510 (showobjs nil 1 1)
510 (addobj nil 1 3 "addobj" "add obj")
511 (addobj nil 1 3 "addobj" "add obj")
511 (delobj nil 1 1 "delobj" "del obj")
512 (delobj nil 1 1 "delobj" "del obj")
512 (killobj nil 0 1)
513 (killobj nil 0 1)
513 (countobj t 0 0)
514 (countobj t 0 0)
514 (getobj t 1 1)
515 (getobj t 1 1)
515 ;; Menu
516 ;; Menu
516 (menu nil 1 1)
517 (menu nil 1 1)
517 ;; Images
518 ;; Images
518 (refint nil 0 0)
519 (refint nil 0 0)
519 (view nil 0 1)
520 (view nil 0 1)
520 ;; Fonts
521 ;; Fonts
521 (rgb t 3 3)
522 (rgb t 3 3)
522 ;; Input
523 ;; Input
523 (showinput nil 1 1)
524 (showinput nil 1 1)
524 (usertxt t 0 0 "user_text" "usrtxt")
525 (usertxt t 0 0 "user_text" "usrtxt")
525 (cmdclear nil 0 0 "cmdclear" "cmdclr")
526 (cmdclear nil 0 0 "cmdclear" "cmdclr")
526 (input t 1 1)
527 (input t 1 1)
527 ;; Files
528 ;; Files
528 (openqst nil 1 1)
529 (openqst nil 1 1)
529 (addqst nil 1 1 "addqst" "addlib" "inclib")
530 (addqst nil 1 1 "addqst" "addlib" "inclib")
530 (killqst nil 1 1 "killqst" "dellib" "freelib")
531 (killqst nil 1 1 "killqst" "dellib" "freelib")
531 (opengame nil 0 0)
532 (opengame nil 0 0)
532 (savegame nil 0 0)
533 (savegame nil 0 0)
533 ;; Real time
534 ;; Real time
534 (wait nil 1 1)
535 (wait nil 1 1)
535 (msecscount t 0 0)
536 (msecscount t 0 0)
536 (settimer nil 1 1))
537 (settimer nil 1 1))
537
538
538 ;;; Expression
539 ;;; Expression
539
540
540 (p:defrule expression or-expr)
541 (p:defrule expression or-expr)
541
542
542 (p:defrule or-expr (and and-expr (* (and spaces? or-op spaces? and-expr)))
543 (p:defrule or-expr (and and-expr (* (and spaces? or-op spaces? and-expr)))
543 (:function do-binop))
544 (:function do-binop))
544
545
545 (p:defrule and-expr (and eq-expr (* (and spaces? and-op spaces? eq-expr)))
546 (p:defrule and-expr (and eq-expr (* (and spaces? and-op spaces? eq-expr)))
546 (:function do-binop))
547 (:function do-binop))
547
548
548 (p:defrule eq-expr (and sum-expr (* (and spaces? (or "<=" ">=" "=<" "=>" "<>"
549 (p:defrule eq-expr (and sum-expr (* (and spaces? (or "<=" ">=" "=<" "=>" "<>"
549 "=" "<" ">" "!")
550 "=" "<" ">" "!")
550 spaces? sum-expr)))
551 spaces? sum-expr)))
551 (:function do-binop))
552 (:function do-binop))
552
553
553 (p:defrule sum-expr (and mod-expr (* (and spaces? (or #\+ #\-) spaces? mod-expr)))
554 (p:defrule sum-expr (and mod-expr (* (and spaces? (or #\+ #\-) spaces? mod-expr)))
554 (:function do-binop))
555 (:function do-binop))
555
556
556 (p:defrule mod-expr (and mul-expr (* (and spaces? (p:~ "mod") spaces? mul-expr)))
557 (p:defrule mod-expr (and mul-expr (* (and spaces? (p:~ "mod") spaces? mul-expr)))
557 (:function do-binop))
558 (:function do-binop))
558
559
559 (p:defrule mul-expr (and unary-expr (* (and spaces? (or #\* #\/) spaces? unary-expr)))
560 (p:defrule mul-expr (and unary-expr (* (and spaces? (or #\* #\/) spaces? unary-expr)))
560 (:function do-binop))
561 (:function do-binop))
561
562
562 (p:defrule unary-expr (and (p:? (or #\+ #\-)) atom-expr)
563 (p:defrule unary-expr (and (p:? (or #\+ #\-)) atom-expr)
563 (:lambda (list)
564 (:lambda (list)
564 (let ((expr (remove-nil list)))
565 (let ((expr (remove-nil list)))
565 (if (= 1 (length expr))
566 (if (= 1 (length expr))
566 (first expr)
567 (first expr)
567 (intern-first expr)))))
568 (intern-first expr)))))
568
569
569 (p:defrule atom-expr (and (or variable literal returning-intrinsic paren-expr) spaces?)
570 (p:defrule atom-expr (and (or variable literal returning-intrinsic paren-expr) spaces?)
570 (:function first))
571 (:function first))
571
572
572 (p:defrule paren-expr (and #\( spaces? expression spaces? #\))
573 (p:defrule paren-expr (and #\( spaces? expression spaces? #\))
573 (:function third))
574 (:function third))
574
575
575 (p:defrule or-op (p:~ "or")
576 (p:defrule or-op (p:~ "or")
576 (:constant "or"))
577 (:constant "or"))
577
578
578 (p:defrule and-op (p:~ "and")
579 (p:defrule and-op (p:~ "and")
579 (:constant "and"))
580 (:constant "and"))
580
581
581 ;;; Variables
582 ;;; Variables
582
583
583 (p:defrule variable (and identifier (p:? array-index))
584 (p:defrule variable (and identifier (p:? array-index))
584 (:destructure (id idx)
585 (:destructure (id idx)
585 (let ((idx (case idx
586 (let ((idx (case idx
586 (nil 0)
587 (nil 0)
587 (:last nil)
588 (:last nil)
588 (t idx))))
589 (t idx))))
589 (if (char= #\$ (elt (string id) 0))
590 (if (char= #\$ (elt (string id) 0))
590 (list 'lib:qspvar (intern (subseq (string-upcase id) 1) :lib) idx :str)
591 (list 'lib:qspvar (intern (subseq (string-upcase id) 1) :lib) idx :str)
591 (list 'lib:qspvar id idx :num)))))
592 (list 'lib:qspvar id idx :num)))))
592
593
593 (p:defrule array-index (and #\[ spaces? (p:? expression) spaces? #\])
594 (p:defrule array-index (and #\[ spaces? (p:? expression) spaces? #\])
594 (:lambda (list)
595 (:lambda (list)
595 (or (third list) :last)))
596 (or (third list) :last)))
596
597
597 (p:defrule assignment (or kw-assignment plain-assignment op-assignment)
598 (p:defrule assignment (or kw-assignment plain-assignment op-assignment)
598 (:destructure (qspvar eq expr)
599 (:destructure (qspvar eq expr)
599 (declare (ignore eq))
600 (declare (ignore eq))
600 (list 'lib:set qspvar expr)))
601 (list 'lib:set qspvar expr)))
601
602
602 (p:defrule kw-assignment (and (or (p:~ "let") (p:~ "set")) spaces? (or op-assignment plain-assignment))
603 (p:defrule kw-assignment (and (or (p:~ "let") (p:~ "set")) spaces? (or op-assignment plain-assignment))
603 (:function third))
604 (:function third))
604
605
605 (p:defrule op-assignment (and variable spaces? (or "+" "-" "*" "/") #\= spaces? expression)
606 (p:defrule op-assignment (and variable spaces? (or "+" "-" "*" "/") #\= spaces? expression)
606 (:destructure (qspvar ws1 op eq ws2 expr)
607 (:destructure (qspvar ws1 op eq ws2 expr)
607 (declare (ignore ws1 ws2))
608 (declare (ignore ws1 ws2))
608 (list qspvar eq (intern-first (list op qspvar expr)))))
609 (list qspvar eq (intern-first (list op qspvar expr)))))
609
610
610 (p:defrule plain-assignment (and variable spaces? #\= spaces? expression)
611 (p:defrule plain-assignment (and variable spaces? #\= spaces? expression)
611 (:function remove-nil))
612 (:function remove-nil))
612
613
613 ;;; Non-string literals
614 ;;; Non-string literals
614
615
615 (p:defrule literal (or qsp-string brace-string number))
616 (p:defrule literal (or qsp-string brace-string number))
616
617
617 (p:defrule number (+ (or #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))
618 (p:defrule number (+ (or #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))
618 (:lambda (list)
619 (:lambda (list)
619 (parse-integer (p:text list))))
620 (parse-integer (p:text list))))
@@ -1,163 +1,172 b''
1
1
2 (in-package sugar-qsp.lib)
2 (in-package sugar-qsp.lib)
3
3
4 ;;;; Parenscript macros which make the parser's intermediate
4 ;;;; Parenscript macros which make the parser's intermediate
5 ;;;; representation directly compilable by Parenscript
5 ;;;; representation directly compilable by Parenscript
6 ;;;; Some utility macros for other .ps sources too.
6 ;;;; Some utility macros for other .ps sources too.
7
7
8 ;;; Utils
8 ;;; Utils
9
9
10 ;;; Common
10 ;;; Common
11
11
12 (defpsmacro label-block (() &body body)
12 (defpsmacro label-block (() &body body)
13 (let ((has-labels (some #'keywordp body)))
13 (let ((has-labels (some #'keywordp body)))
14 `(block nil
14 `(block nil
15 ,@(when has-labels
15 ,@(when has-labels
16 '((defvar _labels)))
16 '((defvar _labels)))
17 (tagbody
17 (tagbody
18 ,@body
18 ,@body
19 (void)))))
19 (void)))))
20
20
21 (defpsmacro str (&rest forms)
21 (defpsmacro str (&rest forms)
22 (cond ((zerop (length forms))
22 (cond ((zerop (length forms))
23 "")
23 "")
24 ((and (= 1 (length forms))
24 ((and (= 1 (length forms))
25 (stringp (first forms)))
25 (stringp (first forms)))
26 (first forms))
26 (first forms))
27 (t
27 (t
28 `(& ,@forms))))
28 `(& ,@forms))))
29
29
30 ;;; 1loc
30 ;;; 1loc
31
31
32 (defpsmacro game ((name) &body body)
33 `(progn
34 (setf (root games ,name)
35 (create))
36 ,@(loop :for location :in body
37 :collect `(setf (root games ,name ,(caadr location))
38 ,location))))
39
32 (defpsmacro location ((name) &body body)
40 (defpsmacro location ((name) &body body)
33 `(setf (root locs ,name)
41 (declare (ignore name))
34 (async-lambda (args)
42 "Name is used by the game macro above"
35 (label-block ()
43 `(async-lambda (args)
36 ,@body))))
44 (label-block ()
45 ,@body)))
37
46
38 (defpsmacro goto% (target &rest args)
47 (defpsmacro goto% (target &rest args)
39 `(progn
48 `(progn
40 (goto ,target ,args)
49 (goto ,target ,args)
41 (exit)))
50 (exit)))
42
51
43 (defpsmacro xgoto% (target &rest args)
52 (defpsmacro xgoto% (target &rest args)
44 `(progn
53 `(progn
45 (xgoto ,target ,args)
54 (xgoto ,target ,args)
46 (exit)))
55 (exit)))
47
56
48 ;;; 2var
57 ;;; 2var
49
58
50 (defpsmacro qspvar (name index slot)
59 (defpsmacro qspvar (name index slot)
51 `(api-call get-var ,(string name) ,index ,slot))
60 `(api-call get-var ,(string name) ,index ,slot))
52
61
53 (defpsmacro set ((var vname vindex vslot) value)
62 (defpsmacro set ((var vname vindex vslot) value)
54 (assert (eq var 'qspvar))
63 (assert (eq var 'qspvar))
55 `(api-call set-var ,(string vname) ,vindex ,vslot ,value))
64 `(api-call set-var ,(string vname) ,vindex ,vslot ,value))
56
65
57 ;;; 3expr
66 ;;; 3expr
58
67
59 (defpsmacro <> (op1 op2)
68 (defpsmacro <> (op1 op2)
60 `(not (equal ,op1 ,op2)))
69 `(not (equal ,op1 ,op2)))
61
70
62 (defpsmacro ! (op1 op2)
71 (defpsmacro ! (op1 op2)
63 `(not (equal ,op1 ,op2)))
72 `(not (equal ,op1 ,op2)))
64
73
65 ;;; 4code
74 ;;; 4code
66
75
67 (defpsmacro exec (&body body)
76 (defpsmacro exec (&body body)
68 (format nil "javascript: ~{~A~^~%~}" (mapcar #'ps* body)))
77 (format nil "javascript: ~{~A~^~%~}" (mapcar #'ps* body)))
69
78
70 ;;; 5arrays
79 ;;; 5arrays
71
80
72 ;;; 6str
81 ;;; 6str
73
82
74 (defpsmacro & (&rest args)
83 (defpsmacro & (&rest args)
75 `(chain "" (concat ,@args)))
84 `(chain "" (concat ,@args)))
76
85
77 ;;; 7if
86 ;;; 7if
78
87
79 (defpsmacro qspcond (&rest clauses)
88 (defpsmacro qspcond (&rest clauses)
80 `(cond ,@(loop :for clause :in clauses
89 `(cond ,@(loop :for clause :in clauses
81 :collect (list (first clause)
90 :collect (list (first clause)
82 `(tagbody
91 `(tagbody
83 ,@(rest clause))))))
92 ,@(rest clause))))))
84
93
85 ;;; 8sub
94 ;;; 8sub
86
95
87 ;;; 9loops
96 ;;; 9loops
88 ;;; Yep, that's a huge kludge since Javascript doesn't support arbitrary labels
97 ;;; Yep, that's a huge kludge since Javascript doesn't support arbitrary labels
89
98
90 (defpsmacro jump (target)
99 (defpsmacro jump (target)
91 `(return-from label-body
100 `(return-from label-body
92 (funcall (getprop _labels ,(string-upcase (second target))))))
101 (funcall (getprop _labels ,(string-upcase (second target))))))
93
102
94 (defpsmacro tagbody (&body body)
103 (defpsmacro tagbody (&body body)
95 (let ((funcs (list nil "_nil")))
104 (let ((funcs (list nil "_nil")))
96 (dolist (form body)
105 (dolist (form body)
97 (cond ((keywordp form)
106 (cond ((keywordp form)
98 (setf (first funcs) (reverse (first funcs)))
107 (setf (first funcs) (reverse (first funcs)))
99 (push (string-upcase form) funcs)
108 (push (string-upcase form) funcs)
100 (push nil funcs))
109 (push nil funcs))
101 (t
110 (t
102 (push form (first funcs)))))
111 (push form (first funcs)))))
103 (setf (first funcs) (reverse (first funcs)))
112 (setf (first funcs) (reverse (first funcs)))
104 (setf funcs (reverse funcs))
113 (setf funcs (reverse funcs))
105 (if (= 2 (length funcs))
114 (if (= 2 (length funcs))
106 `(progn
115 `(progn
107 ,@body)
116 ,@body)
108 `(progn
117 `(progn
109 (setf ,@(loop :for (label code . rest-labels) :on funcs :by #'cddr
118 (setf ,@(loop :for (label code . rest-labels) :on funcs :by #'cddr
110 :append `((@ _labels ,label)
119 :append `((@ _labels ,label)
111 (block label-body
120 (block label-body
112 (block ,(intern label)
121 (block ,(intern label)
113 ,@code
122 ,@code
114 ,@(when rest-labels
123 ,@(when rest-labels
115 `((funcall
124 `((funcall
116 (getprop _labels ,(first rest-labels))))))))))
125 (getprop _labels ,(first rest-labels))))))))))
117 (funcall (getprop _labels "_nil"))))))
126 (funcall (getprop _labels "_nil"))))))
118
127
119 ;;; 10dynamic
128 ;;; 10dynamic
120
129
121 (defpsmacro qspblock (&body body)
130 (defpsmacro qspblock (&body body)
122 `(async-lambda (args)
131 `(async-lambda (args)
123 (label-block ()
132 (label-block ()
124 ,@body)))
133 ,@body)))
125
134
126 ;;; 11main
135 ;;; 11main
127
136
128 (defpsmacro act (name img &body body)
137 (defpsmacro act (name img &body body)
129 `(api-call add-act ,name ,img
138 `(api-call add-act ,name ,img
130 (async-lambda ()
139 (async-lambda ()
131 (label-block ()
140 (label-block ()
132 ,@body))))
141 ,@body))))
133
142
134 ;;; 12aux
143 ;;; 12aux
135
144
136 ;;; 13diag
145 ;;; 13diag
137
146
138 ;;; 14act
147 ;;; 14act
139
148
140 ;;; 15objs
149 ;;; 15objs
141
150
142 ;;; 16menu
151 ;;; 16menu
143
152
144 ;;; 17sound
153 ;;; 17sound
145
154
146 ;;; 18img
155 ;;; 18img
147
156
148 ;;; 19input
157 ;;; 19input
149
158
150 ;;; 20time
159 ;;; 20time
151
160
152 ;;; 21local
161 ;;; 21local
153
162
154 ;;; 22for
163 ;;; 22for
155
164
156 (defpsmacro qspfor (var from to step &body body)
165 (defpsmacro qspfor (var from to step &body body)
157 `((intern "QSPFOR" "API")
166 `((intern "QSPFOR" "API")
158 ,(string (second var)) ,(third var) ;; name and index
167 ,(string (second var)) ,(third var) ;; name and index
159 ,from ,to ,step
168 ,from ,to ,step
160 (lambda ()
169 (lambda ()
161 (block nil
170 (block nil
162 ,@body
171 ,@body
163 t))))
172 t))))
General Comments 0
You need to be logged in to leave comments. Login now