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