##// END OF EJS Templates
Rename system to txt2web
naryl -
r49:cd6f7adb default
parent child Browse files
Show More
@@ -0,0 +1,24 b''
1
2 (defsystem txt2web
3 :description "QSP compiler to monolithic HTML page"
4 :depends-on (:alexandria :system-locale ;; General
5 :esrap ;; Parsing
6 :parenscript :flute ;; Codegening
7 )
8 :pathname "src/"
9 :serial t
10 :components ((:file "package")
11 (:file "utils")
12 (:file "l10n")
13 (:file "walker")
14
15 (:file "patches")
16 (:file "js-syms")
17 (:file "main-macros")
18 (:file "ps-macros")
19 (:file "api-macros")
20 (:file "intrinsic-macros")
21
22 (:file "class")
23 (:file "main")
24 (:file "parser")))
@@ -1,46 +1,47 b''
1 1
2 2 BIN = txt2web
3 3 PKG = $(BIN)
4 SYSTEM = $(BIN)
4 5 DIST = txt2web.tar.xz
5 6
6 7 LISP = sbcl
7 8
8 9 all: $(BIN)
9 10
10 11 dist: $(DIST)
11 12
12 13 graphs: diagrams.png
13 14
14 15 $(BIN): *.asd src/*.lisp src/*.ps strings/*.sexp
15 16 buildapp.$(LISP) --asdf-path .\
16 17 --asdf-tree .qlot/dists\
17 --load-system $(PKG)\
18 --load-system $(SYSTEM)\
18 19 --entry $(PKG):entry-point\
19 20 --output $(BIN)
20 21
21 22 install-deps:
22 23 sbcl --load install-deps.lisp
23 24
24 25 update-deps:
25 26 sbcl --load update-deps.lisp
26 27
27 28 %.png: %.dot
28 29 dot $< -T png -o $@
29 30
30 31 $(DIST): $(BIN) extras/*
31 32 tar cfvJ $@ $< extras
32 33
33 34 upload: $(DIST)
34 35 curl --upload-file $(DIST) https://transfer.sh/$(DIST)
35 36 @echo
36 37
37 38 distclean: clean clean-deps
38 39
39 40 clean:
40 41 rm -f $(BIN) $(DIST)
41 42
42 43 clean-deps:
43 rm qlfile.lock
44 rm -rf .qlot
44 -rm qlfile.lock
45 -rm -rf .qlot
45 46
46 47 .PHONY: all graphs install-deps update-deps clean upload
@@ -1,52 +1,52 b''
1 1 ("quicklisp" .
2 2 (:class qlot/source/dist:source-dist
3 3 :initargs (:distribution "http://beta.quicklisp.org/dist/quicklisp.txt" :%version :latest)
4 :version "2020-04-27"))
4 :version "2020-06-10"))
5 5 ("alexandria" .
6 6 (:class qlot/source/ql:source-ql
7 7 :initargs (:%version :latest)
8 :version "ql-2020-04-27"))
8 :version "ql-2020-06-10"))
9 9 ("system-locale" .
10 10 (:class qlot/source/ql:source-ql
11 11 :initargs (:%version :latest)
12 :version "ql-2020-04-27"))
12 :version "ql-2020-06-10"))
13 13 ("esrap" .
14 14 (:class qlot/source/ql:source-ql
15 15 :initargs (:%version :latest)
16 :version "ql-2020-04-27"))
16 :version "ql-2020-06-10"))
17 17 ("parenscript" .
18 18 (:class qlot/source/ql:source-ql
19 19 :initargs (:%version :latest)
20 :version "ql-2020-04-27"))
20 :version "ql-2020-06-10"))
21 21 ("flute" .
22 22 (:class qlot/source/ql:source-ql
23 23 :initargs (:%version :latest)
24 :version "ql-2020-04-27"))
24 :version "ql-2020-06-10"))
25 25 ("cl-ppcre" .
26 26 (:class qlot/source/ql:source-ql
27 27 :initargs (:%version :latest)
28 :version "ql-2020-04-27"))
28 :version "ql-2020-06-10"))
29 29 ("anaphora" .
30 30 (:class qlot/source/ql:source-ql
31 31 :initargs (:%version :latest)
32 :version "ql-2020-04-27"))
32 :version "ql-2020-06-10"))
33 33 ("named-readtables" .
34 34 (:class qlot/source/ql:source-ql
35 35 :initargs (:%version :latest)
36 :version "ql-2020-04-27"))
36 :version "ql-2020-06-10"))
37 37 ("assoc-utils" .
38 38 (:class qlot/source/ql:source-ql
39 39 :initargs (:%version :latest)
40 :version "ql-2020-04-27"))
40 :version "ql-2020-06-10"))
41 41 ("let-over-lambda" .
42 42 (:class qlot/source/ql:source-ql
43 43 :initargs (:%version :latest)
44 :version "ql-2020-04-27"))
44 :version "ql-2020-06-10"))
45 45 ("documentation-utils" .
46 46 (:class qlot/source/ql:source-ql
47 47 :initargs (:%version :latest)
48 :version "ql-2020-04-27"))
48 :version "ql-2020-06-10"))
49 49 ("trivial-indent" .
50 50 (:class qlot/source/ql:source-ql
51 51 :initargs (:%version :latest)
52 :version "ql-2020-04-27"))
52 :version "ql-2020-06-10"))
@@ -1,46 +1,46 b''
1 1
2 (in-package sugar-qsp.api)
2 (in-package txt2web.api)
3 3
4 4 (defpsmacro with-call-args (args &body body)
5 5 `(progn
6 6 (init-args ,args)
7 7 ,@body
8 8 (get-result)))
9 9
10 10 (defpsmacro with-frame (&body body)
11 11 `(progn
12 12 (push-local-frame)
13 13 (unwind-protect
14 14 ,@body
15 15 (pop-local-frame))))
16 16
17 17 (defpsmacro href-call (func &rest args)
18 18 `(+ "javascript:" (inline-call ,func ,@args)))
19 19
20 20 (defpsmacro inline-call (func &rest args)
21 21 `(+ ',func
22 22 "(\""
23 23 ,(first args)
24 24 ,@(loop :for arg :in (cdr args)
25 25 :collect "\", \""
26 26 :collect arg)
27 27 "\");"))
28 28
29 29 (defpsmacro with-sleep ((resume-func) &body body)
30 30 `(new (*promise
31 31 (lambda (resolve)
32 32 (start-sleeping)
33 33 (let ((,resume-func (lambda ()
34 34 (finish-sleeping)
35 35 (resolve)))))
36 36 ,@body))))
37 37
38 38 (defvar *serv-vars* nil)
39 39
40 40 (defpsmacro define-serv-var (name (value &optional index) &body body)
41 41 (setf name (string-upcase (symbol-name name)))
42 42 (pushnew name *serv-vars* :test #'equal)
43 43 `(setf (getprop serv-vars ,name)
44 44 (create :name ,name
45 45 :body (lambda (,value ,@(when index (list index)))
46 46 ,@body))))
@@ -1,531 +1,531 b''
1 1
2 (in-package sugar-qsp.api)
2 (in-package txt2web)
3 3
4 4 ;;; API deals with DOM manipulation and some bookkeeping for the
5 5 ;;; intrinsics, namely variables
6 6 ;;; API is an implementation detail and has no QSP documentation. It
7 7 ;;; doesn't call intrinsics
8 8
9 9 ;;; Utils
10 10
11 11 (defun make-act-html (title img)
12 12 (+ "<a class='qsp-act' href='" (href-call call-act title) "' onmouseover='" (inline-call select-act title) "'>"
13 13 (if img (+ "<img src='" img "'>") "")
14 14 title
15 15 "</a>"))
16 16
17 17 (defun make-menu-item-html (num title img loc)
18 18 (+ "<a href='" (href-call finish-menu loc) "'>"
19 19 (if img (+ "<img src='" img "'>") "")
20 20 title
21 21 "</a>"))
22 22
23 23 (defun make-obj (title img selected)
24 24 (+ "<li onclick='" (inline-call select-obj title img) "'>"
25 25 "<a class='qsp-obj" (if selected " qsp-obj-selected" "") "'>"
26 26 (if img (+ "<img src='" img "'>") "")
27 27 title
28 28 "</a>"))
29 29
30 30 (defun make-menu-delimiter ()
31 31 "<hr>")
32 32
33 33 (defun copy-obj (obj)
34 34 (chain *j-s-o-n (parse (chain *j-s-o-n (stringify obj)))))
35 35
36 36 (defun report-error (text)
37 37 (alert text))
38 38
39 39 (defun start-sleeping ()
40 40 (chain (by-id "qsp") class-list (add "disable")))
41 41
42 42 (defun finish-sleeping ()
43 43 (chain (by-id "qsp") class-list (remove "disable")))
44 44
45 45 (defun sleep (msec)
46 46 (with-sleep (resume)
47 47 (set-timeout resume msec)))
48 48
49 49 (defun init-dom ()
50 50 ;; Save/load buttons
51 51 (let ((btn (by-id "qsp-btn-save")))
52 52 (setf (@ btn onclick) savegame)
53 53 (setf (@ btn href) "#"))
54 54 (let ((btn (by-id "qsp-btn-open")))
55 55 (setf (@ btn onclick) opengame)
56 56 (setf (@ btn href) "#"))
57 57 ;; Close image on click
58 58 (setf (@ (by-id "qsp-image-container") onclick)
59 59 show-image)
60 60 ;; Enter in input field
61 61 (setf (@ (get-frame :input) onkeyup)
62 62 on-input-key)
63 63 ;; Close the dropdown on any click
64 64 (setf (@ window onclick)
65 65 (lambda (event)
66 66 (setf (@ window mouse)
67 67 (list (@ event page-x)
68 68 (@ event page-y)))
69 69 (finish-menu nil))))
70 70
71 71 (defun call-serv-loc (var-name &rest args)
72 72 (let ((loc-name (get-global var-name 0)))
73 73 (when loc-name
74 74 (let ((loc (getprop *locs loc-name)))
75 75 (when loc
76 76 (call-loc loc-name args))))))
77 77
78 78 (defun filename-game (filename)
79 79 (let ((game-name (chain filename (match "(.*/)?([^.]+)(\\.[a-zA-Z]+)?") 2))))
80 80 (getprop *games game-name))
81 81
82 82 (defun run-game (name)
83 83 (let ((game (filename-game name)))
84 84 (setf *main-game name)
85 85 ;; Replace locations with the new game's
86 86 (setf *locs game)
87 87 (funcall (getprop game
88 88 (chain *object (keys game) 0))
89 89 (list))))
90 90
91 91 ;;; Misc
92 92
93 93 (defun newline (key)
94 94 (append-id (key-to-id key) "<br>" t))
95 95
96 96 (defun clear-id (id)
97 97 (setf (inner-html (by-id id)) ""))
98 98
99 99 (defun escape-html (text)
100 100 (chain text
101 101 (replace (regex "/&/g") "&amp;")
102 102 (replace (regex "/</g") "&lt;")
103 103 (replace (regex "/>/g") "&gt;")
104 104 (replace (regex "/\"/g") "&quot;")
105 105 (replace (regex "/'/g") "&apos;")))
106 106
107 107 (defun prepare-contents (s &optional force-html)
108 108 (setf s (chain s (to-string)))
109 109 (if (or force-html (get-global "USEHTML" 0))
110 110 s
111 111 (escape-html s)))
112 112
113 113 (defun get-id (id &optional force-html)
114 114 (inner-html (by-id id)))
115 115
116 116 (defun set-id (id contents &optional force-html)
117 117 (setf (inner-html (by-id id)) (prepare-contents contents force-html)))
118 118
119 119 (defun append-id (id contents &optional force-html)
120 120 (when contents
121 121 (incf (inner-html (by-id id)) (prepare-contents contents force-html))))
122 122
123 123 (defun on-input-key (ev)
124 124 (when (= 13 (@ ev key-code))
125 125 (chain ev (prevent-default))
126 126 (call-serv-loc "$USERCOM")))
127 127
128 128 ;;; Function calls
129 129
130 130 (defun init-args (args)
131 131 (dotimes (i (length args))
132 132 (let ((arg (elt args i)))
133 133 (if (numberp arg)
134 134 (set-var args i :num arg)
135 135 (set-var args i :str arg)))))
136 136
137 137 (defun get-result ()
138 138 (or (get-global "$RESULT" 0)
139 139 (get-global "RESULT" 0)))
140 140
141 141 (defun call-loc (name args)
142 142 (setf name (chain name (to-upper-case)))
143 143 (with-frame
144 144 (with-call-args args
145 145 (funcall (getprop *locs name))))
146 146 (void))
147 147
148 148 (defun call-act (title)
149 149 (with-frame
150 150 (funcall (getprop *acts title :act)))
151 151 (void))
152 152
153 153 ;;; Text windows
154 154
155 155 (defun key-to-id (key)
156 156 (case key
157 157 (:all "qsp")
158 158 (:main "qsp-main")
159 159 (:stat "qsp-stat")
160 160 (:objs "qsp-objs")
161 161 (:acts "qsp-acts")
162 162 (:input "qsp-input")
163 163 (:image "qsp-image")
164 164 (:dropdown "qsp-dropdown")
165 165 (t (report-error "Internal error!"))))
166 166
167 167 (defun get-frame (key)
168 168 (by-id (key-to-id key)))
169 169
170 170 (defun add-text (key text)
171 171 (append-id (key-to-id key) text))
172 172
173 173 (defun get-text (key)
174 174 (get-id (key-to-id key)))
175 175
176 176 (defun clear-text (key)
177 177 (clear-id (key-to-id key)))
178 178
179 179 (defun enable-frame (key enable)
180 180 (let ((obj (get-frame key)))
181 181 (setf (@ obj style display) (if enable "block" "none"))
182 182 (void)))
183 183
184 184 ;;; Actions
185 185
186 186 (defun add-act (title img act)
187 187 (setf (getprop *acts title)
188 188 (create :title title :img img :act act :selected nil))
189 189 (update-acts))
190 190
191 191 (defun del-act (title)
192 192 (delete (getprop *acts title))
193 193 (update-acts))
194 194
195 195 (defun clear-act ()
196 196 (setf *acts (create))
197 197 (update-acts))
198 198
199 199 (defun update-acts ()
200 200 (clear-id "qsp-acts")
201 201 (let ((elt (by-id "qsp-acts")))
202 202 (for-in (title *acts)
203 203 (let ((obj (getprop *acts title)))
204 204 (incf (inner-html elt) (make-act-html title (getprop obj :img)))))))
205 205
206 206 (defun select-act (title)
207 207 (loop :for (k v) :of *acts
208 208 :do (setf (getprop v :selected) nil))
209 209 (setf (getprop *acts title :selected) t)
210 210 (call-serv-loc "$ONACTSEL"))
211 211
212 212 ;;; "Syntax"
213 213
214 214 (defun qspfor (name index from to step body)
215 215 (for ((i from))
216 216 ((< i to))
217 217 ((incf i step))
218 218 (set-var name index :num i)
219 219 (unless (await (funcall body))
220 220 (return-from qspfor))))
221 221
222 222 ;;; Variables
223 223
224 224 (defun new-var (slot &rest indexes)
225 225 (let ((v (list)))
226 226 (dolist (index indexes)
227 227 (setf (elt v index) (if (eq #\$ (elt slot 0)) "" 0)))
228 228 (setf (@ v :indexes) (create))
229 229 v))
230 230
231 231 (defun set-str-element (slot index value)
232 232 (if (has index (getprop slot :indexes))
233 233 (setf (elt (getprop slot)
234 234 (getprop slot :indexes index))
235 235 value)
236 236 (progn
237 237 (chain slot (push value))
238 238 (setf (elt slot index)
239 239 (length slot))))
240 240 (void))
241 241
242 242 (defun set-any-element (slot index value)
243 243 (cond ((null index)
244 244 (chain (elt slot) (push value)))
245 245 ((numberp index)
246 246 (setf (elt slot index) value))
247 247 ((stringp index)
248 248 (set-str-element slot index value))
249 249 (t (report-error "INTERNAL ERROR")))
250 250 (void))
251 251
252 252 (defun set-serv-var (name index value)
253 253 (let ((slot (getprop *globals name)))
254 254 (set-any-element slot index value))
255 255 (funcall (getprop serv-vars name :body) value index)
256 256 (void))
257 257
258 258 (defun get-element (slot index)
259 259 (if (numberp index)
260 260 (elt slot index)
261 261 (elt slot (getprop slot :indexes index))))
262 262
263 263 (defun get-global (name index)
264 264 (elt (getprop *globals name) index))
265 265
266 266 (defun kill-var (store name &optional index)
267 267 (setf name (chain name (to-upper-case)))
268 268 (if (and index (not (= 0 index)))
269 269 (chain (getprop *globals name) (kill index))
270 270 (delete (getprop *globals name)))
271 271 (void))
272 272
273 273 (defun array-size (name)
274 274 (@ (var-ref name) :values length))
275 275
276 276 ;;; Locals
277 277
278 278 (defun push-local-frame ()
279 279 (chain *locals (push (create)))
280 280 (void))
281 281
282 282 (defun pop-local-frame ()
283 283 (chain *locals (pop))
284 284 (void))
285 285
286 286 (defun current-local-frame ()
287 287 (elt *locals (1- (length *locals))))
288 288
289 289 ;;; Objects
290 290
291 291 (defun select-obj (title img)
292 292 (loop :for (k v) :of *objs
293 293 :do (setf (getprop v :selected) nil))
294 294 (setf (getprop *objs title :selected) t)
295 295 (call-serv-loc "$ONOBJSEL" title img))
296 296
297 297 (defun update-objs ()
298 298 (let ((elt (by-id "qsp-objs")))
299 299 (setf (inner-html elt) "<ul>")
300 300 (loop :for (name obj) :of *objs
301 301 :do (incf (inner-html elt)
302 302 (make-obj name (@ obj :img) (@ obj :selected))))
303 303 (incf (inner-html elt) "</ul>")))
304 304
305 305 ;;; Menu
306 306
307 307 (defun open-menu (menu-data)
308 308 (let ((elt (get-frame :dropdown))
309 309 (i 0))
310 310 (loop :for item :in menu-data
311 311 :do (incf i)
312 312 :do (incf (inner-html elt)
313 313 (if (eq item :delimiter)
314 314 (make-menu-delimiter i)
315 315 (make-menu-item-html i
316 316 (@ item :text)
317 317 (@ item :icon)
318 318 (@ item :loc)))))
319 319 (let ((mouse (@ window mouse)))
320 320 (setf (@ elt style left) (+ (elt mouse 0) "px"))
321 321 (setf (@ elt style top) (+ (elt mouse 1) "px"))
322 322 ;; Make sure it's inside the viewport
323 323 (when (> (@ document body inner-width)
324 324 (+ (elt mouse 0) (@ elt inner-width)))
325 325 (incf (@ elt style left) (@ elt inner-width)))
326 326 (when (> (@ document body inner-height)
327 327 (+ (elt mouse 0) (@ elt inner-height)))
328 328 (incf (@ elt style top) (@ elt inner-height))))
329 329 (setf (@ elt style display) "block")))
330 330
331 331 (defun finish-menu (loc)
332 332 (when *menu-resume
333 333 (let ((elt (get-frame :dropdown)))
334 334 (setf (inner-html elt) "")
335 335 (setf (@ elt style display) "none")
336 336 (funcall *menu-resume)
337 337 (setf *menu-resume nil))
338 338 (when loc
339 339 (call-loc loc)))
340 340 (void))
341 341
342 342 (defun menu (menu-data)
343 343 (with-sleep (resume)
344 344 (open-menu menu-data)
345 345 (setf *menu-resume resume))
346 346 (void))
347 347
348 348 ;;; Content
349 349
350 350 (defun clean-audio ()
351 351 (loop :for k :in (chain *object (keys *playing))
352 352 :for v := (getprop *playing k)
353 353 :do (when (@ v ended)
354 354 (delete (@ *playing k)))))
355 355
356 356 (defun show-image (path)
357 357 (let ((img (get-frame :image)))
358 358 (cond (path
359 359 (setf (@ img src) path)
360 360 (setf (@ img style display) "flex"))
361 361 (t
362 362 (setf (@ img src) "")
363 363 (setf (@ img style display) "hidden")))))
364 364
365 365 (defun show-inline-images (frame-name images)
366 366 (let ((frame (get-frame frame-name))
367 367 (text ""))
368 368 (incf text "<div style='position:relative; display: inline-block'>")
369 369 (incf text (+ "<img src='" (@ images 0) "'>"))
370 370 (loop :for image :in (chain images (slice 1))
371 371 :do (incf text
372 372 (+ "<img style='position:absolute' src='" image "'>")))
373 373 (incf text "</div>")
374 374 (incf (inner-html frame) text)))
375 375
376 376 (defun rgb-string (rgb)
377 377 (let ((red (ps::>> rgb 16))
378 378 (green (logand (ps::>> rgb 8) 255))
379 379 (blue (logand rgb 255)))
380 380 (flet ((rgb-to-hex (comp)
381 381 (let ((hex (chain (*number comp) (to-string 16))))
382 382 (if (< (length hex) 2)
383 383 (+ "0" hex)
384 384 hex))))
385 385 (+ "#" (rgb-to-hex red) (rgb-to-hex green) (rgb-to-hex blue)))))
386 386
387 387 (defun store-obj (key obj)
388 388 (store-str key (btoa (encode-u-r-i-component (chain *j-s-o-n (stringify obj)))))
389 389 (void))
390 390 (defun store-str (key str)
391 391 (chain local-storage (set-item (+ "qsp_" key) str))
392 392 (void))
393 393
394 394 (defun load-obj (key)
395 395 (chain *j-s-o-n (parse (encode-u-r-i-component (atob (load-str key))))))
396 396 (defun load-str (key)
397 397 (chain local-storage (get-item (+ "qsp_" key))))
398 398
399 399 ;;; Saves
400 400
401 401 (defun slot-savegame (slot comment)
402 402 (let ((saves (load-obj "saves")))
403 403 (setf (@ saves slot) comment)
404 404 (store-obj saves))
405 405 (store-str slot (state-to-base64))
406 406 (void))
407 407
408 408 (defun slot-loadgame (slot)
409 409 (base64-to-state (load-str slot))
410 410 (void))
411 411
412 412 (defun slot-deletegame (slot)
413 413 (let ((saves (load-obj "saves")))
414 414 (setf (@ saves slot) undefined)
415 415 (store-obj saves))
416 416 (store-str slot undefined)
417 417 (void))
418 418
419 419 (defun slot-listgames ()
420 420 (load-obj "saves"))
421 421
422 422 (defun opengame ()
423 423 (let ((element (chain document (create-element :input))))
424 424 (chain element (set-attribute :type :file))
425 425 (chain element (set-attribute :id :qsp-opengame))
426 426 (chain element (set-attribute :tabindex -1))
427 427 (chain element (set-attribute "aria-hidden" t))
428 428 (setf (@ element style display) :block)
429 429 (setf (@ element style visibility) :hidden)
430 430 (setf (@ element style position) :fixed)
431 431 (setf (@ element onchange)
432 432 (lambda (event)
433 433 (let* ((file (@ event target files 0))
434 434 (reader (new (*file-reader))))
435 435 (setf (@ reader onload)
436 436 (lambda (ev)
437 437 (block nil
438 438 (let ((target (@ ev current-target)))
439 439 (unless (@ target result)
440 440 (return))
441 441 (base64-to-state (@ target result))
442 442 (unstash-state)))))
443 443 (chain reader (read-as-text file)))))
444 444 (chain document body (append-child element))
445 445 (chain element (click))
446 446 (chain document body (remove-child element))))
447 447
448 448 (defun savegame ()
449 449 (let ((element (chain document (create-element :a))))
450 450 (chain element (set-attribute :href (+ "data:text/plain;charset=utf-8," (state-to-base64))))
451 451 (chain element (set-attribute :download "savegame.sav"))
452 452 (setf (@ element style display) :none)
453 453 (chain document body (append-child element))
454 454 (chain element (click))
455 455 (chain document body (remove-child element))))
456 456
457 457 (defun stash-state (args)
458 458 (call-serv-loc "$ONGSAVE")
459 459 (setf *state-stash
460 460 (chain *j-s-o-n (stringify
461 461 (create :vars *globals
462 462 :objs *objs
463 463 :loc-args args
464 464 :msecs (- (chain *date (now)) *started-at)
465 465 :timer-interval *timer-interval
466 466 :main-html (inner-html
467 467 (get-frame :main))
468 468 :stat-html (inner-html
469 469 (get-frame :stat))
470 470 :next-location *current-location))))
471 471 (void))
472 472
473 473 (defun unstash-state ()
474 474 (let ((data (chain *j-s-o-n (parse *state-stash))))
475 475 (clear-act)
476 476 (setf *globals (@ data :vars))
477 477 (loop :for k :in (chain *object (keys *globals))
478 478 :do (chain *object (set-prototype-of (getprop *globals k)
479 479 (@ *var prototype))))
480 480 (setf *started-at (- (chain *date (now)) (@ data :msecs)))
481 481 (setf *objs (@ data :objs))
482 482 (setf *current-location (@ data :next-location))
483 483 (setf (inner-html (get-frame :main))
484 484 (@ data :main-html))
485 485 (setf (inner-html (get-frame :stat))
486 486 (@ data :stat-html))
487 487 (update-objs)
488 488 (set-timer (@ data :timer-interval))
489 489 (call-serv-loc "$ONGLOAD")
490 490 (call-loc *current-location (@ data :loc-args))
491 491 (void)))
492 492
493 493 (defun state-to-base64 ()
494 494 (btoa (encode-u-r-i-component *state-stash)))
495 495
496 496 (defun base64-to-state (data)
497 497 (setf *state-stash (decode-u-r-i-component (atob data))))
498 498
499 499 ;;; Timers
500 500
501 501 (defun set-timer (interval)
502 502 (setf *timer-interval interval)
503 503 (clear-interval *timer-obj)
504 504 (setf *timer-obj
505 505 (set-interval
506 506 (lambda ()
507 507 (call-serv-loc "$COUNTER"))
508 508 interval)))
509 509
510 510 ;;; Special variables
511 511
512 512 (defvar serv-vars (create))
513 513
514 514 (define-serv-var $backimage (path)
515 515 (setf (@ (get-frame :main) style background-image) path))
516 516
517 517 (define-serv-var bcolor (color)
518 518 (setf (@ (get-frame :all) style background-color) (rgb-string color)))
519 519
520 520 (define-serv-var fcolor (color)
521 521 (setf (@ (get-frame :all) style color) (rgb-string color)))
522 522
523 523 (define-serv-var lcolor (color)
524 524 (setf (@ (get-frame :style) inner-text)
525 525 (+ "a { color: " (rgb-string color) ";}")))
526 526
527 527 (define-serv-var fsize (size)
528 528 (setf (@ (get-frame :all) style font-size) size))
529 529
530 530 (define-serv-var $fname (font-name)
531 531 (setf (@ (get-frame :all) style font-family) (+ font-name ",serif")))
@@ -1,14 +1,14 b''
1 1
2 (in-package sugar-qsp)
2 (in-package txt2web)
3 3
4 4 (defclass compiler ()
5 5 ((body :accessor body :initform #.(load-src "extras/body.html"))
6 6 (css :accessor css :initform (list #.(load-src "extras/default.css")))
7 7 (js :accessor js :initform (reverse
8 8 (list
9 9 '#.(read-progn-from-string (load-src "src/main.ps"))
10 10 '#.(read-progn-from-string (load-src "src/api.ps"))
11 11 '#.(read-progn-from-string (load-src "src/intrinsics.ps")))))
12 12 (compile :accessor compile-only :initarg :compile)
13 13 (target :accessor target :initarg :target)
14 14 (beautify :accessor beautify :initarg :beautify)))
@@ -1,170 +1,170 b''
1 1
2 (in-package sugar-qsp.lib)
2 (in-package txt2web.lib)
3 3
4 4 ;;;; Macros implementing some intrinsics where it makes sense
5 5 ;;;; E.g. an equivalent JS function exists, or it's a direct API call
6 6
7 7 ;;; 1loc
8 8
9 9 ;;; 2var
10 10
11 11 (defpsmacro killvar (varname &optional index)
12 12 `(api-call kill-var ,varname ,index))
13 13
14 14 (defpsmacro killall ()
15 15 `(api-call kill-all))
16 16
17 17 ;;; 3expr
18 18
19 19 (defpsmacro no (arg)
20 20 `(- -1 ,arg))
21 21
22 22 ;;; 4code
23 23
24 24 (defpsmacro qspver ()
25 25 "0.0.1")
26 26
27 27 (defpsmacro curloc ()
28 28 `*current-location)
29 29
30 30 (defpsmacro rnd ()
31 31 `(funcall rand 1 1000))
32 32
33 33 (defpsmacro qspmax (&rest args)
34 34 (if (= 1 (length args))
35 35 `(*math.max.apply nil ,@args)
36 36 `(*math.max ,@args)))
37 37
38 38 (defpsmacro qspmin (&rest args)
39 39 (if (= 1 (length args))
40 40 `(*math.min.apply nil ,@args)
41 41 `(*math.min ,@args)))
42 42
43 43 ;;; 5arrays
44 44
45 45 (defpsmacro arrsize (name)
46 46 `(api-call array-size ,name))
47 47
48 48 ;;; 6str
49 49
50 50 (defpsmacro len (s)
51 51 `(length ,s))
52 52
53 53 (defpsmacro mid (s from &optional count)
54 54 `(chain ,s (substring ,from ,count)))
55 55
56 56 (defpsmacro ucase (s)
57 57 `(chain ,s (to-upper-case)))
58 58
59 59 (defpsmacro lcase (s)
60 60 `(chain ,s (to-lower-case)))
61 61
62 62 (defpsmacro trim (s)
63 63 `(chain ,s (trim)))
64 64
65 65 (defpsmacro replace (s from to)
66 66 `(chain ,s (replace ,from ,to)))
67 67
68 68 (defpsmacro val (s)
69 69 `(parse-int ,s 10))
70 70
71 71 (defpsmacro qspstr (n)
72 72 `(chain ,n (to-string)))
73 73
74 74 ;;; 7if
75 75
76 76 ;;; 8sub
77 77
78 78 ;;; 9loops
79 79
80 80 ;; JUMP is in ps-macros.lisp (because it's a part of a huge kludge)
81 81
82 82 (defpsmacro exit ()
83 83 `(return-from nil (values)))
84 84
85 85 ;;; 10dynamic
86 86
87 87 ;;; 11main
88 88
89 89 (defpsmacro desc (s)
90 90 (declare (ignore s))
91 91 "")
92 92
93 93 ;;; 12stat
94 94
95 95 (defpsmacro showstat (enable)
96 96 `(api-call enable-frame :stat ,enable))
97 97
98 98 ;;; 13diag
99 99
100 100 (defpsmacro msg (text)
101 101 `(alert ,text))
102 102
103 103 ;;; 14act
104 104
105 105 (defpsmacro showacts (enable)
106 106 `(api-call enable-frame :acts ,enable))
107 107
108 108 (defpsmacro delact (&optional name)
109 109 (if name
110 110 `(api-call del-act ,name)
111 111 `(api-call del-act)))
112 112
113 113 (defpsmacro cla ()
114 114 `(api-call clear-act))
115 115
116 116 ;;; 15objs
117 117
118 118 (defpsmacro showobjs (enable)
119 119 `(api-call enable-frame :objs ,enable))
120 120
121 121 (defpsmacro countobj ()
122 122 `(length *objs))
123 123
124 124 (defpsmacro getobj (index)
125 125 `(or (elt *objs ,index) ""))
126 126
127 127 ;;; 16menu
128 128
129 129 ;;; 17sound
130 130
131 131 (defpsmacro isplay (filename)
132 132 `(funcall (@ playing includes) ,filename))
133 133
134 134 ;;; 18img
135 135
136 136 (defpsmacro view (&optional path)
137 137 `(api-call show-image ,path))
138 138
139 139 (defpsmacro img (&rest images)
140 140 `(api-call show-inline-images :stat (list ,@images)))
141 141
142 142 (defpsmacro *img (&rest images)
143 143 `(api-call show-inline-images :main (list ,@images)))
144 144
145 145 ;;; 19input
146 146
147 147 (defpsmacro showinput (enable)
148 148 `(api-call enable-frame :input ,enable))
149 149
150 150 ;;; 20time
151 151
152 152 (defpsmacro wait (msec)
153 153 `(await (api-call sleep ,msec)))
154 154
155 155 (defpsmacro settimer (interval)
156 156 `(api-call set-timer ,interval))
157 157
158 158 ;;; 21local
159 159
160 160 ;;; 22for
161 161
162 162 ;;; misc
163 163
164 164 (defpsmacro opengame (&optional filename)
165 165 (declare (ignore filename))
166 166 `(api-call opengame))
167 167
168 168 (defpsmacro savegame (&optional filename)
169 169 (declare (ignore filename))
170 170 `(api-call savegame))
@@ -1,326 +1,326 b''
1 1
2 (in-package sugar-qsp.lib)
2 (in-package txt2web)
3 3
4 4 ;;;; Functions and procedures defined by the QSP language.
5 5 ;;;; They can call api and deal with locations and other data directly.
6 6 ;;;; Except vars. Use VAR and SET or GET-VAR and SET-VAR api calls.
7 7
8 8 ;;; 1loc
9 9
10 10 (defun goto (target args)
11 11 (api:clear-text :main)
12 12 (funcall xgoto target args)
13 13 (void))
14 14
15 15 (defun xgoto (target args)
16 16 (setf args (or args (list)))
17 17 (api:clear-act)
18 18 (setf *current-location (chain target (to-upper-case)))
19 19 (api:stash-state args)
20 20 (api:call-loc *current-location args)
21 21 (api:call-serv-loc "$ONNEWLOC")
22 22 (void))
23 23
24 24 ;;; 2var
25 25
26 26 ;;; 3expr
27 27
28 28 (defun obj (name)
29 29 (has name *objs))
30 30
31 31 (defun loc (name)
32 32 (has name *locs))
33 33
34 34 ;;; 4code
35 35
36 36 (defun rand (a &optional (b 1))
37 37 (let ((min (min a b))
38 38 (max (max a b)))
39 39 (+ min (chain *math (random (- max min))))))
40 40
41 41 ;;; 5arrays
42 42
43 43 (defun copyarr (to from start count)
44 44 (multiple-value-bind (to-name to-slot)
45 45 (api:var-real-name to)
46 46 (multiple-value-bind (from-name from-slot)
47 47 (api:var-real-name from)
48 48 (for ((i start))
49 49 ((< i (min (api:array-size from-name)
50 50 (+ start count))))
51 51 ((incf i))
52 52 (api:set-var to-name (+ start i) to-slot
53 53 (api:get-var from-name (+ start i) from-slot))))))
54 54
55 55 (defun arrpos (name value &optional (start 0))
56 56 (multiple-value-bind (real-name slot)
57 57 (api:var-real-name name)
58 58 (for ((i start)) ((< i (api:array-size name))) ((incf i))
59 59 (when (eq (api:get-var real-name i slot) value)
60 60 (return-from arrpos i))))
61 61 -1)
62 62
63 63 (defun arrcomp (name pattern &optional (start 0))
64 64 (multiple-value-bind (real-name slot)
65 65 (api:var-real-name name)
66 66 (for ((i start)) ((< i (api:array-size name))) ((incf i))
67 67 (when (funcall (getprop (api:get-var real-name i slot) 'match) pattern)
68 68 (return-from arrcomp i))))
69 69 -1)
70 70
71 71 ;;; 6str
72 72
73 73 (defun instr (s subs &optional (start 1))
74 74 (+ start (chain s (substring (- start 1)) (search subs))))
75 75
76 76 (defun isnum (s)
77 77 (if (is-na-n s)
78 78 0
79 79 -1))
80 80
81 81 (defun strcomp (s pattern)
82 82 (if (chain s (match pattern))
83 83 -1
84 84 0))
85 85
86 86 (defun strfind (s pattern group)
87 87 (let* ((re (new (*reg-exp pattern)))
88 88 (match (chain re (exec s))))
89 89 (chain match (group group))))
90 90
91 91 (defun strpos (s pattern &optional (group 0))
92 92 (let* ((re (new (*reg-exp pattern)))
93 93 (match (chain re (exec s)))
94 94 (found (chain match (group group))))
95 95 (if found
96 96 (chain s (search found))
97 97 0)))
98 98
99 99 ;;; 7if
100 100
101 101 ;; Has to be a function because it always evaluates all three of its
102 102 ;; arguments
103 103 (defun iif (cond-expr then-expr else-expr)
104 104 (if cond-expr then-expr else-expr))
105 105
106 106 ;;; 8sub
107 107
108 108 (defun gosub (target &rest args)
109 109 (api:call-loc target args)
110 110 (void))
111 111
112 112 (defun func (target &rest args)
113 113 (api:call-loc target args))
114 114
115 115 ;;; 9loops
116 116
117 117 ;;; 10dynamic
118 118
119 119 (defun dynamic (block &rest args)
120 120 (when (stringp block)
121 121 (api:report-error "DYNAMIC can't evaluate arbitrary strings.\\nUse {braces} to create blocks for DYNAMIC."))
122 122 (api:with-call-args args
123 123 (funcall block args))
124 124 (void))
125 125
126 126 (defun dyneval (block &rest args)
127 127 (when (stringp block)
128 128 (api:report-error "DYNEVAL can't evaluate arbitrary strings.\\nUse {braces} to create blocks for DYNEVAL."))
129 129 (api:with-call-args args
130 130 (funcall block args)))
131 131
132 132 ;;; 11main
133 133
134 134 (defun main-p (s)
135 135 (api:add-text :main s)
136 136 (void))
137 137
138 138 (defun main-pl (s)
139 139 (api:add-text :main s)
140 140 (api:newline :main)
141 141 (void))
142 142
143 143 (defun main-nl (s)
144 144 (api:newline :main)
145 145 (api:add-text :main s)
146 146 (void))
147 147
148 148 (defun maintxt (s)
149 149 (api:get-text :main)
150 150 (void))
151 151
152 152 (defun desc (s)
153 153 "")
154 154
155 155 (defun main-clear ()
156 156 (api:clear-text :main)
157 157 (void))
158 158
159 159 ;;; 12stat
160 160
161 161 (defun stat-p (s)
162 162 (api:add-text :stat s)
163 163 (void))
164 164
165 165 (defun stat-pl (s)
166 166 (api:add-text :stat s)
167 167 (api:newline :stat)
168 168 (void))
169 169
170 170 (defun stat-nl (s)
171 171 (api:newline :stat)
172 172 (api:add-text :stat s)
173 173 (void))
174 174
175 175 (defun stattxt (s)
176 176 (api:get-text :stat)
177 177 (void))
178 178
179 179 (defun stat-clear ()
180 180 (api:clear-text :stat)
181 181 (void))
182 182
183 183 (defun cls ()
184 184 (stat-clear)
185 185 (main-clear)
186 186 (cla)
187 187 (cmdclear)
188 188 (void))
189 189
190 190 ;;; 13diag
191 191
192 192 ;;; 14act
193 193
194 194 (defun selact ()
195 195 (loop :for (k v) :of *acts
196 196 :do (when (@ v :selected)
197 197 (return-from selact (@ v :name)))))
198 198
199 199 (defun curacts ()
200 200 (let ((acts (api-call copy-obj *acts)))
201 201 (lambda ()
202 202 (setf *acts acts)
203 203 (void))))
204 204
205 205 ;;; 15objs
206 206
207 207 (defun addobj (name img)
208 208 (setf img (or img ""))
209 209 (setf (getprop *objs name)
210 210 (create :name name :img img :selected nil))
211 211 (api:update-objs)
212 212 (api-call call-serv-loc "$ONOBJADD" name img)
213 213 (void))
214 214
215 215 (defun delobj (name)
216 216 (delete (getprop *objs name))
217 217 (api:update-objs)
218 218 (api-call call-serv-loc "$ONOBJDEL" name)
219 219 (void))
220 220
221 221 (defun killobj (&optional (num nil))
222 222 (if (eq nil num)
223 223 (setf *objs (create))
224 224 (delobj (elt (chain *object (keys *objs)) num)))
225 225 (api:update-objs)
226 226 (void))
227 227
228 228 (defun selobj ()
229 229 (loop :for (k v) :of *objs
230 230 :do (when (@ v :selected)
231 231 (return-from selobj (@ v :name)))))
232 232
233 233 ;;; 16menu
234 234
235 235 (defun menu (menu-name)
236 236 (let ((menu-data (list)))
237 237 (loop :for item-obj :in (@ (api:get-array (api:var-real-name menu-name)) values)
238 238 :for item := (@ item-obj :str)
239 239 :do (cond ((string= item "")
240 240 (break))
241 241 ((string= item "-:-")
242 242 (chain menu-data (push :delimiter)))
243 243 (t
244 244 (let* ((tokens (chain item (split ":"))))
245 245 (when (= (length tokens) 2)
246 246 (chain tokens (push "")))
247 247 (let* ((text (chain tokens (splice 0 (- (length tokens) 2)) (join ":")))
248 248 (loc (getprop tokens (- (length tokens) 2)))
249 249 (icon (getprop tokens (- (length tokens) 1))))
250 250 (chain menu-data
251 251 (push (create :text text
252 252 :loc loc
253 253 :icon icon))))))))
254 254 (api:menu menu-data)
255 255 (void)))
256 256
257 257 ;;; 17sound
258 258
259 259 (defun play (filename &optional (volume 100))
260 260 (let ((audio (new (*audio filename))))
261 261 (setf (getprop *playing filename) audio)
262 262 (setf (@ audio volume) (* volume 0.01))
263 263 (chain audio (play))))
264 264
265 265 (defun close (filename)
266 266 (funcall (getprop *playing filename) stop)
267 267 (delete (getprop *playing filename))
268 268 (void))
269 269
270 270 (defun closeall ()
271 271 (loop :for k :in (chain *object (keys *playing))
272 272 :for v := (getprop *playing k)
273 273 :do (funcall v stop))
274 274 (setf *playing (create)))
275 275
276 276 ;;; 18img
277 277
278 278 (defun refint ()
279 279 ;; "Force interface update" Uh... what exactly do we do here?
280 280 ;(api:report-error "REFINT is not supported")
281 281 )
282 282
283 283 ;;; 19input
284 284
285 285 (defun usertxt ()
286 286 (let ((input (by-id "qsp-input")))
287 287 (@ input value)))
288 288
289 289 (defun cmdclear ()
290 290 (let ((input (by-id "qsp-input")))
291 291 (setf (@ input value) "")))
292 292
293 293 (defun input (text)
294 294 (chain window (prompt text)))
295 295
296 296 ;;; 20time
297 297
298 298 (defun msecscount ()
299 299 (- (chain *date (now)) *started-at))
300 300
301 301 ;;; 21local
302 302
303 303 ;;; 22for
304 304
305 305 ;;; misc
306 306
307 307 (defun rgb (red green blue)
308 308 (+ (<< red 16)
309 309 (<< green 8)
310 310 blue))
311 311
312 312 (defun openqst (name)
313 313 (api-call run-game name))
314 314
315 315 (defun addqst (name)
316 316 (let ((game (api-call filename-game name)))
317 317 ;; Add the game's locations
318 318 (chain *object (assign *locs
319 319 (getprop *games name)))))
320 320
321 321 (defun killqst ()
322 322 ;; Delete all locations not from the current main game
323 323 (loop :for (k v) :in *games
324 324 :do (unless (string= k *main-game)
325 325 (delete (getprop *locs k)))))
326 326
@@ -1,44 +1,44 b''
1 1
2 (in-package sugar-qsp.js)
2 (in-package txt2web.js)
3 3
4 4 ;;; Contains symbols from standard JS library to avoid obfuscating
5 5 ;;; and/or namespacing them
6 6
7 7 (cl:defmacro syms (cl:&rest syms)
8 8 `(cl:progn
9 9 ,@(cl:loop :for sym :in syms
10 10 :collect `(cl:export ',sym))))
11 11
12 12 (syms
13 13 ;; main
14 14 window
15 15 *object assign
16 16 now
17 17 onload
18 18 keys includes
19 19 has-own-property
20 20 ;; api
21 21 document get-element-by-id get-elements-by-tag-name
22 22 onclick onchange
23 23 atob btoa split
24 24 alert prompt
25 25 set-timeout set-interval clear-interval
26 26 *promise *j-s-o-n
27 27 href parse match
28 28 set-prototype-of
29 29 body append-child remove-child
30 30 add ; remove (is already in COMMON-LISP)
31 31 create-element set-attribute class-list
32 32 *file-reader read-as-text
33 33 style display src
34 34 page-x page-y
35 35 top left
36 36 background-image background-color
37 37 color inner-text font-size font-family font-name
38 38 local-storage set-item get-item
39 39 ;; lib
40 40 *number parse-int
41 41 to-string to-upper-case concat
42 42 click target current-target files index-of result
43 43 decode-u-r-i-component splice
44 44 )
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now