##// END OF EJS Templates
API call for FOR loop to make the main code less cluttered
naryl -
r19:c40f6d7d default
parent child Browse files
Show More
@@ -1,348 +1,359 b''
1
1
2 (in-package sugar-qsp)
2 (in-package sugar-qsp)
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 (setf (root api) (ps:create))
9 (setf (root api) (ps:create))
10
10
11 ;;; Utils
11 ;;; Utils
12
12
13 (defm (root api make-act-html) (title img)
13 (defm (root api make-act-html) (title img)
14 (+ "<a class='qsp-act' href='#' onclick='SugarQSP.acts[\"" title "\"].act();'>"
14 (+ "<a class='qsp-act' href='#' onclick='SugarQSP.acts[\"" title "\"].act();'>"
15 title
15 title
16 "</a>"))
16 "</a>"))
17
17
18 (defm (root api make-menu-item-html) (num title img loc)
18 (defm (root api make-menu-item-html) (num title img loc)
19 (+ "<a href='#' onclick='SugarQSP.api.runMenu(" num ", \"" loc "\")();'>"
19 (+ "<a href='#' onclick='SugarQSP.api.runMenu(" num ", \"" loc "\")();'>"
20 "<img src='" img "'>"
20 "<img src='" img "'>"
21 title
21 title
22 "</a>"))
22 "</a>"))
23
23
24 (defm (root api init-dom) ()
24 (defm (root api init-dom) ()
25 ;; Save/load buttons
25 ;; Save/load buttons
26 (let ((btn (document.get-element-by-id "qsp-btn-save")))
26 (let ((btn (document.get-element-by-id "qsp-btn-save")))
27 (setf (ps:@ btn onclick) this.savegame)
27 (setf (ps:@ btn onclick) this.savegame)
28 (setf (ps:@ btn href) "#"))
28 (setf (ps:@ btn href) "#"))
29 (let ((btn (document.get-element-by-id "qsp-btn-open")))
29 (let ((btn (document.get-element-by-id "qsp-btn-open")))
30 (setf (ps:@ btn onclick) this.opengame)
30 (setf (ps:@ btn onclick) this.opengame)
31 (setf (ps:@ btn href) "#"))
31 (setf (ps:@ btn href) "#"))
32 ;; Close image on click
32 ;; Close image on click
33 (setf (ps:@ (document.get-element-by-id "qsp-image-container") onclick)
33 (setf (ps:@ (document.get-element-by-id "qsp-image-container") onclick)
34 (this.show-image nil))
34 (this.show-image nil))
35 ;; Close the dropdown on any click
35 ;; Close the dropdown on any click
36 (setf window.onclick
36 (setf window.onclick
37 (lambda (event)
37 (lambda (event)
38 (setf (ps:@ (api-call get-frame :dropdown) style display) "none"))))
38 (setf (ps:@ (api-call get-frame :dropdown) style display) "none"))))
39
39
40 ;; To be used in saving game
40 ;; To be used in saving game
41 (defm (root api stash-state) (args)
41 (defm (root api stash-state) (args)
42 (setf (root state-stash)
42 (setf (root state-stash)
43 (*j-s-o-n.stringify
43 (*j-s-o-n.stringify
44 (ps:create vars (root vars)
44 (ps:create vars (root vars)
45 objs (root objs)
45 objs (root objs)
46 loc-args args
46 loc-args args
47 main-html (ps:@
47 main-html (ps:@
48 (document.get-element-by-id :qsp-main)
48 (document.get-element-by-id :qsp-main)
49 inner-h-t-m-l)
49 inner-h-t-m-l)
50 stat-html (ps:@
50 stat-html (ps:@
51 (document.get-element-by-id :qsp-stat)
51 (document.get-element-by-id :qsp-stat)
52 inner-h-t-m-l)
52 inner-h-t-m-l)
53 next-location (root current-location))))
53 next-location (root current-location))))
54 (values))
54 (values))
55
55
56 (defm (root api unstash-state) ()
56 (defm (root api unstash-state) ()
57 (let ((data (*j-s-o-n.parse (root state-stash))))
57 (let ((data (*j-s-o-n.parse (root state-stash))))
58 (this.clear-act)
58 (this.clear-act)
59 (setf (root vars) (ps:@ data vars))
59 (setf (root vars) (ps:@ data vars))
60 (loop :for k :in (*object.keys (root vars))
60 (loop :for k :in (*object.keys (root vars))
61 :do (*object.set-prototype-of (ps:getprop (root vars) k)
61 :do (*object.set-prototype-of (ps:getprop (root vars) k)
62 (root api *var prototype)))
62 (root api *var prototype)))
63 (setf (root objs) (ps:@ data objs))
63 (setf (root objs) (ps:@ data objs))
64 (setf (root current-location) (ps:@ data next-location))
64 (setf (root current-location) (ps:@ data next-location))
65 (setf (ps:@ (document.get-element-by-id :qsp-main) inner-h-t-m-l)
65 (setf (ps:@ (document.get-element-by-id :qsp-main) inner-h-t-m-l)
66 (ps:@ data main-html))
66 (ps:@ data main-html))
67 (setf (ps:@ (document.get-element-by-id :qsp-stat) inner-h-t-m-l)
67 (setf (ps:@ (document.get-element-by-id :qsp-stat) inner-h-t-m-l)
68 (ps:@ data stat-html))
68 (ps:@ data stat-html))
69 (funcall (root locs (root current-location)) (ps:@ data loc-args))
69 (funcall (root locs (root current-location)) (ps:@ data loc-args))
70 (this.update-objs)
70 (this.update-objs)
71 (values)))
71 (values)))
72
72
73 (defm (root api state-to-base64) ()
73 (defm (root api state-to-base64) ()
74 (btoa (encode-u-r-i-component (root state-stash))))
74 (btoa (encode-u-r-i-component (root state-stash))))
75
75
76 (defm (root api base64-to-state) (data)
76 (defm (root api base64-to-state) (data)
77 (setf (root state-stash) (decode-u-r-i-component (atob data))))
77 (setf (root state-stash) (decode-u-r-i-component (atob data))))
78
78
79 ;;; Misc
79 ;;; Misc
80
80
81 (defm (root api clear-id) (id)
81 (defm (root api clear-id) (id)
82 (setf (ps:chain document (get-element-by-id id) inner-text) ""))
82 (setf (ps:chain document (get-element-by-id id) inner-text) ""))
83
83
84 (defm (root api get-id) (id)
84 (defm (root api get-id) (id)
85 (if (var "USEHTML" 0 :num)
85 (if (var "USEHTML" 0 :num)
86 (ps:chain (document.get-element-by-id id) inner-h-t-m-l)
86 (ps:chain (document.get-element-by-id id) inner-h-t-m-l)
87 (ps:chain (document.get-element-by-id id) inner-text)))
87 (ps:chain (document.get-element-by-id id) inner-text)))
88
88
89 (defm (root api set-id) (id contents)
89 (defm (root api set-id) (id contents)
90 (if (var "USEHTML" 0 :num)
90 (if (var "USEHTML" 0 :num)
91 (setf (ps:chain (document.get-element-by-id id) inner-h-t-m-l) contents)
91 (setf (ps:chain (document.get-element-by-id id) inner-h-t-m-l) contents)
92 (setf (ps:chain (document.get-element-by-id id) inner-text) contents)))
92 (setf (ps:chain (document.get-element-by-id id) inner-text) contents)))
93
93
94 (defm (root api append-id) (id contents)
94 (defm (root api append-id) (id contents)
95 (if (var "USEHTML" 0 :num)
95 (if (var "USEHTML" 0 :num)
96 (incf (ps:chain (document.get-element-by-id id) inner-h-t-m-l) contents)
96 (incf (ps:chain (document.get-element-by-id id) inner-h-t-m-l) contents)
97 (incf (ps:chain (document.get-element-by-id id) inner-text) contents)))
97 (incf (ps:chain (document.get-element-by-id id) inner-text) contents)))
98
98
99 ;;; Function calls
99 ;;; Function calls
100
100
101 (defm (root api init-args) (args)
101 (defm (root api init-args) (args)
102 (dotimes (i (length args))
102 (dotimes (i (length args))
103 (let ((arg (elt args i)))
103 (let ((arg (elt args i)))
104 (if (numberp arg)
104 (if (numberp arg)
105 (this.set-var args i :num arg)
105 (this.set-var args i :num arg)
106 (this.set-var args i :str arg)))))
106 (this.set-var args i :str arg)))))
107
107
108 (defm (root api get-result) ()
108 (defm (root api get-result) ()
109 (if (not (equal "" (var result 0 :str)))
109 (if (not (equal "" (var result 0 :str)))
110 (var result 0 :str)
110 (var result 0 :str)
111 (var result 0 :num)))
111 (var result 0 :num)))
112
112
113 ;;; Text windows
113 ;;; Text windows
114
114
115 (defm (root api key-to-id) (key)
115 (defm (root api key-to-id) (key)
116 (case key
116 (case key
117 (:main "qsp-main")
117 (:main "qsp-main")
118 (:stat "qsp-stat")
118 (:stat "qsp-stat")
119 (:objs "qsp-objs")
119 (:objs "qsp-objs")
120 (:acts "qsp-acts")
120 (:acts "qsp-acts")
121 (:input "qsp-input")
121 (:input "qsp-input")
122 (:dropdown "qsp-dropdown")
122 (:dropdown "qsp-dropdown")
123 (t (report-error "Internal error!"))))
123 (t (report-error "Internal error!"))))
124
124
125 (defm (root api get-frame) (key)
125 (defm (root api get-frame) (key)
126 (document.get-element-by-id (this.key-to-id key)))
126 (document.get-element-by-id (this.key-to-id key)))
127
127
128 (defm (root api add-text) (key text)
128 (defm (root api add-text) (key text)
129 (this.append-id (this.key-to-id key) text))
129 (this.append-id (this.key-to-id key) text))
130
130
131 (defm (root api get-text) (key)
131 (defm (root api get-text) (key)
132 (this.get-id (this.key-to-id key)))
132 (this.get-id (this.key-to-id key)))
133
133
134 (defm (root api clear-text) (key)
134 (defm (root api clear-text) (key)
135 (this.clear-id (this.key-to-id key)))
135 (this.clear-id (this.key-to-id key)))
136
136
137 (defm (root api newline) (key)
137 (defm (root api newline) (key)
138 (let ((div (this.get-frame key)))
138 (let ((div (this.get-frame key)))
139 (ps:chain div (append-child (document.create-element "br")))))
139 (ps:chain div (append-child (document.create-element "br")))))
140
140
141 (defm (root api enable-frame) (key enable)
141 (defm (root api enable-frame) (key enable)
142 (let ((clss (ps:getprop (this.get-frame key) 'class-list)))
142 (let ((clss (ps:getprop (this.get-frame key) 'class-list)))
143 (setf clss.style.display (if enable "block" "none"))
143 (setf clss.style.display (if enable "block" "none"))
144 (values)))
144 (values)))
145
145
146 ;;; Actions
146 ;;; Actions
147
147
148 (defm (root api add-act) (title img act)
148 (defm (root api add-act) (title img act)
149 (setf (ps:getprop (root acts) title)
149 (setf (ps:getprop (root acts) title)
150 (ps:create :img img :act act))
150 (ps:create :img img :act act))
151 (this.update-acts))
151 (this.update-acts))
152
152
153 (defm (root api del-act) (title)
153 (defm (root api del-act) (title)
154 (delete (ps:getprop (root acts) title))
154 (delete (ps:getprop (root acts) title))
155 (this.update-acts))
155 (this.update-acts))
156
156
157 (defm (root api clear-act) ()
157 (defm (root api clear-act) ()
158 (setf (root acts) (ps:create))
158 (setf (root acts) (ps:create))
159 (this.clear-id "qsp-acts"))
159 (this.clear-id "qsp-acts"))
160
160
161 (defm (root api update-acts) ()
161 (defm (root api update-acts) ()
162 (this.clear-id "qsp-acts")
162 (this.clear-id "qsp-acts")
163 (ps:for-in (title (root acts))
163 (ps:for-in (title (root acts))
164 (let ((obj (ps:getprop (root acts) title)))
164 (let ((obj (ps:getprop (root acts) title)))
165 (this.append-id "qsp-acts"
165 (this.append-id "qsp-acts"
166 (this.make-act-html title (ps:getprop obj :img))))))
166 (this.make-act-html title (ps:getprop obj :img))))))
167
167
168 ;;; "Syntax"
169
170 (defm (root api qspfor) (name index from to step body)
171 (block nil
172 (ps:for ((i from))
173 ((< i to))
174 ((incf i step))
175 (this.set-var name index :num i)
176 (unless (funcall body)
177 (return)))))
178
168 ;;; Variable class
179 ;;; Variable class
169
180
170 (defm (root api *var) (name)
181 (defm (root api *var) (name)
171 ;; From strings to numbers
182 ;; From strings to numbers
172 (setf this.indexes (ps:create))
183 (setf this.indexes (ps:create))
173 ;; From numbers to {num: 0, str: ""} objects
184 ;; From numbers to {num: 0, str: ""} objects
174 (setf this.values (list))
185 (setf this.values (list))
175 (values))
186 (values))
176
187
177 (defm (root api *var prototype new-value) ()
188 (defm (root api *var prototype new-value) ()
178 (ps:create :num 0 :str ""))
189 (ps:create :num 0 :str ""))
179
190
180 (defm (root api *var prototype index-num) (index)
191 (defm (root api *var prototype index-num) (index)
181 (let ((num-index
192 (let ((num-index
182 (if (stringp index)
193 (if (stringp index)
183 (if (in index this.indexes)
194 (if (in index this.indexes)
184 (ps:getprop this.indexes index)
195 (ps:getprop this.indexes index)
185 (let ((n (length this.values)))
196 (let ((n (length this.values)))
186 (setf (ps:getprop this.indexes index) n)
197 (setf (ps:getprop this.indexes index) n)
187 n))
198 n))
188 index)))
199 index)))
189 (unless (in num-index this.values)
200 (unless (in num-index this.values)
190 (setf (elt this.values num-index) (this.new-value)))
201 (setf (elt this.values num-index) (this.new-value)))
191 num-index))
202 num-index))
192
203
193 (defm (root api *var prototype get) (index slot)
204 (defm (root api *var prototype get) (index slot)
194 (unless (or index (= 0 index))
205 (unless (or index (= 0 index))
195 (setf index (1- (length this.values))))
206 (setf index (1- (length this.values))))
196 (ps:getprop this.values (this.index-num index) slot))
207 (ps:getprop this.values (this.index-num index) slot))
197
208
198 (defm (root api *var prototype set) (index slot value)
209 (defm (root api *var prototype set) (index slot value)
199 (unless (or index (= 0 index))
210 (unless (or index (= 0 index))
200 (setf index (length store)))
211 (setf index (length store)))
201 (case slot
212 (case slot
202 (:num (setf value (ps:chain *number (parse-int value))))
213 (:num (setf value (ps:chain *number (parse-int value))))
203 (:str (setf value (ps:chain value (to-string)))))
214 (:str (setf value (ps:chain value (to-string)))))
204 (setf (ps:getprop this.values (this.index-num index) slot) value)
215 (setf (ps:getprop this.values (this.index-num index) slot) value)
205 (values))
216 (values))
206
217
207 (defm (root api *var prototype kill) (index)
218 (defm (root api *var prototype kill) (index)
208 (setf (elt this.values (this.index-num index)) (this.new-value)))
219 (setf (elt this.values (this.index-num index)) (this.new-value)))
209
220
210 ;;; Variables
221 ;;; Variables
211
222
212 (defm (root api var-real-name) (name)
223 (defm (root api var-real-name) (name)
213 (if (= (ps:@ name 0) #\$)
224 (if (= (ps:@ name 0) #\$)
214 (values (ps:chain name (substr 1)) :str)
225 (values (ps:chain name (substr 1)) :str)
215 (values name :num)))
226 (values name :num)))
216
227
217 (defm (root api ensure-var) (name)
228 (defm (root api ensure-var) (name)
218 (let ((store (this.var-ref name)))
229 (let ((store (this.var-ref name)))
219 (unless store
230 (unless store
220 (setf store (ps:new (this.-var name)))
231 (setf store (ps:new (this.-var name)))
221 (setf (ps:getprop (root vars) name) store))
232 (setf (ps:getprop (root vars) name) store))
222 store))
233 store))
223
234
224 (defm (root api var-ref) (name)
235 (defm (root api var-ref) (name)
225 (let ((local-store (this.current-local-frame)))
236 (let ((local-store (this.current-local-frame)))
226 (cond ((in name local-store)
237 (cond ((in name local-store)
227 (ps:getprop local-store name))
238 (ps:getprop local-store name))
228 ((in name (root vars))
239 ((in name (root vars))
229 (ps:getprop (root vars) name))
240 (ps:getprop (root vars) name))
230 (t nil))))
241 (t nil))))
231
242
232 (defm (root api get-var) (name index slot)
243 (defm (root api get-var) (name index slot)
233 (ps:chain (this.ensure-var name) (get index slot)))
244 (ps:chain (this.ensure-var name) (get index slot)))
234
245
235 (defm (root api set-var) (name index slot value)
246 (defm (root api set-var) (name index slot value)
236 (ps:chain (this.ensure-var name) (set index slot value))
247 (ps:chain (this.ensure-var name) (set index slot value))
237 (values))
248 (values))
238
249
239 (defm (root api get-array) (name)
250 (defm (root api get-array) (name)
240 (this.var-ref name))
251 (this.var-ref name))
241
252
242 (defm (root api set-array) (name value)
253 (defm (root api set-array) (name value)
243 (let ((store (this.var-ref name)))
254 (let ((store (this.var-ref name)))
244 (setf (ps:@ store values) (ps:@ value values))
255 (setf (ps:@ store values) (ps:@ value values))
245 (setf (ps:@ store indexes) (ps:@ value indexes)))
256 (setf (ps:@ store indexes) (ps:@ value indexes)))
246 (values))
257 (values))
247
258
248 (defm (root api kill-var) (name &optional index)
259 (defm (root api kill-var) (name &optional index)
249 (if (and index (not (= 0 index)))
260 (if (and index (not (= 0 index)))
250 (ps:chain (ps:getprop (root vars) name) (kill index))
261 (ps:chain (ps:getprop (root vars) name) (kill index))
251 (ps:delete (ps:getprop (root vars) name)))
262 (ps:delete (ps:getprop (root vars) name)))
252 (values))
263 (values))
253
264
254 (defm (root api array-size) (name)
265 (defm (root api array-size) (name)
255 (ps:getprop (this.var-ref name) 'length))
266 (ps:getprop (this.var-ref name) 'length))
256
267
257 ;;; Locals
268 ;;; Locals
258
269
259 (defm (root api push-local-frame) ()
270 (defm (root api push-local-frame) ()
260 (ps:chain (root locals) (push (ps:create)))
271 (ps:chain (root locals) (push (ps:create)))
261 (values))
272 (values))
262
273
263 (defm (root api pop-local-frame) ()
274 (defm (root api pop-local-frame) ()
264 (ps:chain (root locals) (pop))
275 (ps:chain (root locals) (pop))
265 (values))
276 (values))
266
277
267 (defm (root api current-local-frame) ()
278 (defm (root api current-local-frame) ()
268 (elt (root locals) (1- (length (root locals)))))
279 (elt (root locals) (1- (length (root locals)))))
269
280
270 (defm (root api new-local) (name)
281 (defm (root api new-local) (name)
271 (let ((frame (this.current-local-frame)))
282 (let ((frame (this.current-local-frame)))
272 (unless (in name frame)
283 (unless (in name frame)
273 (setf (ps:getprop frame name) (ps:create)))
284 (setf (ps:getprop frame name) (ps:create)))
274 (values)))
285 (values)))
275
286
276 ;;; Objects
287 ;;; Objects
277
288
278 (defm (root api update-objs) ()
289 (defm (root api update-objs) ()
279 (let ((elt (document.get-element-by-id "qsp-objs")))
290 (let ((elt (document.get-element-by-id "qsp-objs")))
280 (setf elt.inner-h-t-m-l "<ul>")
291 (setf elt.inner-h-t-m-l "<ul>")
281 (loop :for obj :in (root objs)
292 (loop :for obj :in (root objs)
282 :do (incf elt.inner-h-t-m-l (+ "<li>" obj)))
293 :do (incf elt.inner-h-t-m-l (+ "<li>" obj)))
283 (incf elt.inner-h-t-m-l "</ul>")))
294 (incf elt.inner-h-t-m-l "</ul>")))
284
295
285 ;;; Menu
296 ;;; Menu
286
297
287 (defm (root api menu) (menu-data)
298 (defm (root api menu) (menu-data)
288 (let ((elt (document.get-element-by-id "qsp-dropdown"))
299 (let ((elt (document.get-element-by-id "qsp-dropdown"))
289 (i 0))
300 (i 0))
290 (setf elt.inner-h-t-m-l "")
301 (setf elt.inner-h-t-m-l "")
291 (loop :for item :in menu-data
302 (loop :for item :in menu-data
292 :do (incf i)
303 :do (incf i)
293 :do (incf elt.inner-h-t-m-l (this.make-menu-item-html i item.text item.icon item.loc)))
304 :do (incf elt.inner-h-t-m-l (this.make-menu-item-html i item.text item.icon item.loc)))
294 (setf elt.style.display "block")))
305 (setf elt.style.display "block")))
295
306
296 ;;; Content
307 ;;; Content
297
308
298 (defm (root api clean-audio) ()
309 (defm (root api clean-audio) ()
299 (loop :for k :in (*object.keys (root playing))
310 (loop :for k :in (*object.keys (root playing))
300 :for v := (ps:getprop (root playing) k)
311 :for v := (ps:getprop (root playing) k)
301 :do (when (ps:@ v ended)
312 :do (when (ps:@ v ended)
302 (ps:delete (ps:@ (root playing) k)))))
313 (ps:delete (ps:@ (root playing) k)))))
303
314
304 (defm (root api show-image) (path)
315 (defm (root api show-image) (path)
305 (let ((img (document.get-element-by-id "qsp-image")))
316 (let ((img (document.get-element-by-id "qsp-image")))
306 (cond (path
317 (cond (path
307 (setf img.src path)
318 (setf img.src path)
308 (setf img.style.display "flex"))
319 (setf img.style.display "flex"))
309 (t
320 (t
310 (setf img.src "")
321 (setf img.src "")
311 (setf img.style.display "hidden")))))
322 (setf img.style.display "hidden")))))
312
323
313 ;;; Saves
324 ;;; Saves
314
325
315 (defm (root api opengame) ()
326 (defm (root api opengame) ()
316 (let ((element (document.create-element :input)))
327 (let ((element (document.create-element :input)))
317 (element.set-attribute :type :file)
328 (element.set-attribute :type :file)
318 (element.set-attribute :id :qsp-opengame)
329 (element.set-attribute :id :qsp-opengame)
319 (element.set-attribute :tabindex -1)
330 (element.set-attribute :tabindex -1)
320 (element.set-attribute "aria-hidden" t)
331 (element.set-attribute "aria-hidden" t)
321 (setf element.style.display :block)
332 (setf element.style.display :block)
322 (setf element.style.visibility :hidden)
333 (setf element.style.visibility :hidden)
323 (setf element.style.position :fixed)
334 (setf element.style.position :fixed)
324 (setf element.onchange
335 (setf element.onchange
325 (lambda (event)
336 (lambda (event)
326 (let* ((file (elt event.target.files 0))
337 (let* ((file (elt event.target.files 0))
327 (reader (ps:new (*file-reader))))
338 (reader (ps:new (*file-reader))))
328 (setf reader.onload
339 (setf reader.onload
329 (lambda (ev)
340 (lambda (ev)
330 (block nil
341 (block nil
331 (let ((target ev.current-target))
342 (let ((target ev.current-target))
332 (unless target.result
343 (unless target.result
333 (return))
344 (return))
334 (api-call base64-to-state target.result)
345 (api-call base64-to-state target.result)
335 (api-call unstash-state)))))
346 (api-call unstash-state)))))
336 (reader.read-as-text file))))
347 (reader.read-as-text file))))
337 (document.body.append-child element)
348 (document.body.append-child element)
338 (element.click)
349 (element.click)
339 (document.body.remove-child element)))
350 (document.body.remove-child element)))
340
351
341 (defm (root api savegame) ()
352 (defm (root api savegame) ()
342 (let ((element (document.create-element :a)))
353 (let ((element (document.create-element :a)))
343 (element.set-attribute :href (+ "data:text/plain;charset=utf-8," (api-call state-to-base64)))
354 (element.set-attribute :href (+ "data:text/plain;charset=utf-8," (api-call state-to-base64)))
344 (element.set-attribute :download "savegame.sav")
355 (element.set-attribute :download "savegame.sav")
345 (setf element.style.display :none)
356 (setf element.style.display :none)
346 (document.body.append-child element)
357 (document.body.append-child element)
347 (element.click)
358 (element.click)
348 (document.body.remove-child element)))
359 (document.body.remove-child element)))
@@ -1,203 +1,204 b''
1
1
2 (in-package sugar-qsp)
2 (in-package sugar-qsp)
3
3
4 ;;;; Parenscript macros which make the parser's intermediate
4 ;;;; Parenscript macros which make the parser's intermediate
5 ;;;; representation directly compilable by Parenscript
5 ;;;; representation directly compilable by Parenscript
6 ;;;; Some utility macros for other .ps sources too.
6 ;;;; Some utility macros for other .ps sources too.
7
7
8 ;;; Utils
8 ;;; Utils
9
9
10 (ps:defpsmacro defm (path args &body body)
10 (ps:defpsmacro defm (path args &body body)
11 `(setf ,path (lambda ,args ,@body)))
11 `(setf ,path (lambda ,args ,@body)))
12
12
13 (ps:defpsmacro root (&rest path)
13 (ps:defpsmacro root (&rest path)
14 `(ps:@ *sugar-q-s-p ,@path))
14 `(ps:@ *sugar-q-s-p ,@path))
15
15
16 (ps:defpsmacro in (key obj)
16 (ps:defpsmacro in (key obj)
17 `(ps:chain ,obj (has-own-property ,key)))
17 `(ps:chain ,obj (has-own-property ,key)))
18
18
19 (ps:defpsmacro with-frame (&body body)
19 (ps:defpsmacro with-frame (&body body)
20 `(progn
20 `(progn
21 (api-call push-local-frame)
21 (api-call push-local-frame)
22 (unwind-protect
22 (unwind-protect
23 ,@body
23 ,@body
24 (api-call pop-local-frame))))
24 (api-call pop-local-frame))))
25
25
26 ;;; Common
26 ;;; Common
27
27
28 (defmacro defpsintrinsic (name)
28 (defmacro defpsintrinsic (name)
29 `(ps:defpsmacro ,name (&rest args)
29 `(ps:defpsmacro ,name (&rest args)
30 `(funcall (root lib ,',name)
30 `(funcall (root lib ,',name)
31 ,@args)))
31 ,@args)))
32
32
33 (defmacro defpsintrinsics (() &rest names)
33 (defmacro defpsintrinsics (() &rest names)
34 `(progn ,@(loop :for name :in names
34 `(progn ,@(loop :for name :in names
35 :collect `(defpsintrinsic ,name))))
35 :collect `(defpsintrinsic ,name))))
36
36
37 (defpsintrinsics ()
37 (defpsintrinsics ()
38 rand copyarr arrpos arrcomp instr isnum strcomp strfind strpos iif gosub func dynamic dyneval main-p main-pl main-nl maintxt main-clear stat-p stat-pl stat-nl stattxt stat-clear cls curacts addobj delobj killobj menu play isplay close closeall refint view rgb showinput usertxt cmdclear input openqst addqst killqst opengame savegame wait msecscount settimer)
38 rand copyarr arrpos arrcomp instr isnum strcomp strfind strpos iif gosub func dynamic dyneval main-p main-pl main-nl maintxt main-clear stat-p stat-pl stat-nl stattxt stat-clear cls curacts addobj delobj killobj menu play isplay close closeall refint view rgb showinput usertxt cmdclear input openqst addqst killqst opengame savegame wait msecscount settimer)
39
39
40 (ps:defpsmacro api-call (func &rest args)
40 (ps:defpsmacro api-call (func &rest args)
41 `(funcall (root api ,func) ,@args))
41 `(funcall (root api ,func) ,@args))
42
42
43 (ps:defpsmacro label-block ((&key (locals t)) &body body)
43 (ps:defpsmacro label-block ((&key (locals t)) &body body)
44 (let ((has-labels (some #'keywordp body)))
44 (let ((has-labels (some #'keywordp body)))
45 `(block nil
45 `(block nil
46 ,@(when has-labels
46 ,@(when has-labels
47 '((defvar __labels)))
47 '((defvar __labels)))
48 ,@(if locals
48 ,@(if locals
49 `((with-frame
49 `((with-frame
50 (tagbody
50 (tagbody
51 ,@body)))
51 ,@body)))
52 `((tagbody
52 `((tagbody
53 ,@body))))))
53 ,@body))))))
54
54
55 (ps:defpsmacro str (&rest forms)
55 (ps:defpsmacro str (&rest forms)
56 (cond ((zerop (length forms))
56 (cond ((zerop (length forms))
57 "")
57 "")
58 ((and (= 1 (length forms))
58 ((and (= 1 (length forms))
59 (stringp (first forms)))
59 (stringp (first forms)))
60 (first forms))
60 (first forms))
61 (t
61 (t
62 `(& ,@forms))))
62 `(& ,@forms))))
63
63
64 ;;; 1loc
64 ;;; 1loc
65
65
66 (ps:defpsmacro location ((name) &body body)
66 (ps:defpsmacro location ((name) &body body)
67 `(setf (root locs ,name)
67 `(setf (root locs ,name)
68 (lambda (args)
68 (lambda (args)
69 (label-block ()
69 (label-block ()
70 (api-call init-args args)
70 (api-call init-args args)
71 ,@body
71 ,@body
72 (api-call get-result)))))
72 (api-call get-result)))))
73
73
74 (ps:defpsmacro goto (target &rest args)
74 (ps:defpsmacro goto (target &rest args)
75 `(progn
75 `(progn
76 (funcall (root lib goto) ,target ,args)
76 (funcall (root lib goto) ,target ,args)
77 (exit)))
77 (exit)))
78
78
79 (ps:defpsmacro xgoto (target &rest args)
79 (ps:defpsmacro xgoto (target &rest args)
80 `(progn
80 `(progn
81 (funcall (root lib xgoto) ,target ,args)
81 (funcall (root lib xgoto) ,target ,args)
82 (exit)))
82 (exit)))
83
83
84 (ps:defpsmacro desc (target)
84 (ps:defpsmacro desc (target)
85 (declare (ignore target))
85 (declare (ignore target))
86 (report-error "DESC is not supported"))
86 (report-error "DESC is not supported"))
87
87
88 ;;; 2var
88 ;;; 2var
89
89
90 (ps:defpsmacro var (name index slot)
90 (ps:defpsmacro var (name index slot)
91 `(api-call get-var ,(string name) ,index ,slot))
91 `(api-call get-var ,(string name) ,index ,slot))
92
92
93 (ps:defpsmacro set ((var vname vindex vslot) value)
93 (ps:defpsmacro set ((var vname vindex vslot) value)
94 (assert (eq var 'var))
94 (assert (eq var 'var))
95 `(api-call set-var ,(string vname) ,vindex ,vslot ,value))
95 `(api-call set-var ,(string vname) ,vindex ,vslot ,value))
96
96
97 ;;; 3expr
97 ;;; 3expr
98
98
99 (ps:defpsmacro <> (op1 op2)
99 (ps:defpsmacro <> (op1 op2)
100 `(not (equal ,op1 ,op2)))
100 `(not (equal ,op1 ,op2)))
101
101
102 (ps:defpsmacro ! (op1 op2)
102 (ps:defpsmacro ! (op1 op2)
103 `(not (equal ,op1 ,op2)))
103 `(not (equal ,op1 ,op2)))
104
104
105 ;;; 4code
105 ;;; 4code
106
106
107 (ps:defpsmacro exec (&body body)
107 (ps:defpsmacro exec (&body body)
108 (format nil "javascript: ~{~A~^~%~}" (mapcar #'ps:ps* body)))
108 (format nil "javascript: ~{~A~^~%~}" (mapcar #'ps:ps* body)))
109
109
110 ;;; 5arrays
110 ;;; 5arrays
111
111
112 ;;; 6str
112 ;;; 6str
113
113
114 (ps:defpsmacro & (&rest args)
114 (ps:defpsmacro & (&rest args)
115 `(ps:chain "" (concat ,@args)))
115 `(ps:chain "" (concat ,@args)))
116
116
117 ;;; 7if
117 ;;; 7if
118
118
119 (ps:defpsmacro qspcond (&rest clauses)
119 (ps:defpsmacro qspcond (&rest clauses)
120 `(cond ,@(loop :for clause :in clauses
120 `(cond ,@(loop :for clause :in clauses
121 :collect (list (first clause)
121 :collect (list (first clause)
122 `(tagbody
122 `(tagbody
123 ,@(rest clause))))))
123 ,@(rest clause))))))
124
124
125 ;;; 8sub
125 ;;; 8sub
126
126
127 ;;; 9loops
127 ;;; 9loops
128 ;;; Yep, that's a huge kludge since Javascript doesn't support arbitrary labels
128 ;;; Yep, that's a huge kludge since Javascript doesn't support arbitrary labels
129
129
130 (ps:defpsmacro jump (target)
130 (ps:defpsmacro jump (target)
131 `(return-from ,(intern (string-upcase (second target)))
131 `(return-from ,(intern (string-upcase (second target)))
132 (funcall (ps:getprop __labels ,target))))
132 (funcall (ps:getprop __labels ,target))))
133
133
134 (ps:defpsmacro tagbody (&body body)
134 (ps:defpsmacro tagbody (&body body)
135 (let ((funcs (list nil :__nil)))
135 (let ((funcs (list nil :__nil)))
136 (dolist (form body)
136 (dolist (form body)
137 (cond ((keywordp form)
137 (cond ((keywordp form)
138 (setf (first funcs) (reverse (first funcs)))
138 (setf (first funcs) (reverse (first funcs)))
139 (push form funcs)
139 (push form funcs)
140 (push nil funcs))
140 (push nil funcs))
141 (t
141 (t
142 (push form (first funcs)))))
142 (push form (first funcs)))))
143 (setf (first funcs) (reverse (first funcs)))
143 (setf (first funcs) (reverse (first funcs)))
144 (setf funcs (reverse funcs))
144 (setf funcs (reverse funcs))
145 (if (= 2 (length funcs))
145 (if (= 2 (length funcs))
146 `(progn
146 `(progn
147 ,@body)
147 ,@body)
148 `(progn
148 `(progn
149 (setf ,@(loop :for f :on funcs :by #'cddr
149 (setf ,@(loop :for f :on funcs :by #'cddr
150 :append `((ps:@ __labels ,(first f))
150 :append `((ps:@ __labels ,(first f))
151 (block ,(intern (string-upcase (string (first f))))
151 (block ,(intern (string-upcase (string (first f))))
152 ,@(second f)
152 ,@(second f)
153 ,@(when (third f)
153 ,@(when (third f)
154 `((funcall
154 `((funcall
155 (ps:getprop __labels ,(third f)))))))))
155 (ps:getprop __labels ,(third f)))))))))
156 (jump (str "__nil"))))))
156 (jump (str "__nil"))))))
157
157
158 ;;; 10dynamic
158 ;;; 10dynamic
159
159
160 (ps:defpsmacro qspblock (&body body)
160 (ps:defpsmacro qspblock (&body body)
161 `(lambda (args)
161 `(lambda (args)
162 (label-block ()
162 (label-block ()
163 (api-call init-args args)
163 (api-call init-args args)
164 ,@body
164 ,@body
165 (api-call get-result))))
165 (api-call get-result))))
166
166
167 ;;; 11main
167 ;;; 11main
168
168
169 (ps:defpsmacro act (name img &body body)
169 (ps:defpsmacro act (name img &body body)
170 `(api-call add-act ,name ,img
170 `(api-call add-act ,name ,img
171 (lambda ()
171 (lambda ()
172 (label-block ()
172 (label-block ()
173 ,@body))))
173 ,@body))))
174
174
175 ;;; 12aux
175 ;;; 12aux
176
176
177 ;;; 13diag
177 ;;; 13diag
178
178
179 ;;; 14act
179 ;;; 14act
180
180
181 ;;; 15objs
181 ;;; 15objs
182
182
183 ;;; 16menu
183 ;;; 16menu
184
184
185 ;;; 17sound
185 ;;; 17sound
186
186
187 ;;; 18img
187 ;;; 18img
188
188
189 ;;; 19input
189 ;;; 19input
190
190
191 ;;; 20time
191 ;;; 20time
192
192
193 ;;; 21local
193 ;;; 21local
194
194
195 ;;; 22for
195 ;;; 22for
196
196
197 (ps:defpsmacro qspfor (var from to step &body body)
197 (ps:defpsmacro qspfor (var from to step &body body)
198 `(block nil
198 `(api-call qspfor
199 (set ,var ,from)
199 ,(string (second var)) ,(third var) ;; name and index
200 (ps:for ()
200 ,from ,to ,step
201 ((< ,var ,to))
201 (lambda ()
202 ((set ,var (+ ,var ,step)))
202 (block nil
203 ,@body)))
203 ,@body
204 t))))
General Comments 0
You need to be logged in to leave comments. Login now