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