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