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