##// END OF EJS Templates
Change string handling, some debug stuff
naryl -
r58:2f85fb42 default
parent child Browse files
Show More
@@ -1,157 +1,157 b''
1
1
2 (in-package txt2web)
2 (in-package txt2web)
3
3
4 (defvar *app-name* "txt2web")
4 (defvar *app-name* "txt2web")
5
5
6 (defun entry-point-no-args ()
6 (defun entry-point-no-args ()
7 (setf *delivered* t)
7 (setf *delivered* t)
8 (entry-point uiop:*command-line-arguments*))
8 (entry-point uiop:*command-line-arguments*))
9
9
10 (defun entry-point (args)
10 (defun entry-point (args)
11 (let ((*package* (find-package :txt2web)))
11 (let ((*package* (find-package :txt2web)))
12 (catch :terminate
12 (catch :terminate
13 (let ((compiler (apply #'make-instance 'compiler (parse-opts args))))
13 (let ((compiler (apply #'make-instance 'compiler (parse-opts args))))
14 (write-compiled-file compiler))))
14 (write-compiled-file compiler))))
15 (values))
15 (values))
16
16
17 (defun parse-opts (args)
17 (defun parse-opts (args)
18 (let ((mode :sources)
18 (let ((mode :sources)
19 (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)))
20 (loop :for arg :in args
20 (loop :for arg :in args
21 :do (alexandria:switch (arg :test #'string=)
21 :do (alexandria:switch (arg :test #'string=)
22 ("-o" (setf mode :target))
22 ("-o" (setf mode :target))
23 ("--js" (setf mode :js))
23 ("--js" (setf mode :js))
24 ("--css" (setf mode :css))
24 ("--css" (setf mode :css))
25 ("--body" (setf mode :body))
25 ("--body" (setf mode :body))
26 ("-c" (setf (getf data :compile) t))
26 ("-c" (setf (getf data :compile) t))
27 ("--beautify" (setf (getf data :beautify) t))
27 ("--beautify" (setf (getf data :beautify) t))
28 (t (push arg (getf data mode)))))
28 (t (push arg (getf data mode)))))
29 (unless (< 0 (length (getf data :sources)))
29 (unless (< 0 (length (getf data :sources)))
30 (report-error "There should be at least one source"))
30 (report-error "There should be at least one source"))
31 (unless (> 1 (length (getf data :target)))
31 (unless (> 1 (length (getf data :target)))
32 (report-error "There should be no more than one target"))
32 (report-error "There should be no more than one target"))
33 (unless (> 1 (length (getf data :body)))
33 (unless (> 1 (length (getf data :body)))
34 (report-error "There should be no more than one body"))
34 (report-error "There should be no more than one body"))
35 (unless (getf data :target)
35 (unless (getf data :target)
36 (setf (getf data :target)
36 (setf (getf data :target)
37 (let* ((sources (first (getf data :sources)))
37 (let* ((sources (first (getf data :sources)))
38 (tokens (uiop:split-string sources :separator "."))
38 (tokens (uiop:split-string sources :separator "."))
39 (target (format nil "~{~A~^.~}.html"
39 (target (format nil "~{~A~^.~}.html"
40 (butlast tokens))))
40 (butlast tokens))))
41 (list target))))
41 (list target))))
42 (list :sources (getf data :sources)
42 (list :sources (getf data :sources)
43 :target (first (getf data :target))
43 :target (first (getf data :target))
44 :js (getf data :js)
44 :js (getf data :js)
45 :css (getf data :css)
45 :css (getf data :css)
46 :body (first (getf data :body))
46 :body (first (getf data :body))
47 :compile (getf data :compile)
47 :compile (getf data :compile)
48 :beautify (getf data :beautify))))
48 :beautify (getf data :beautify))))
49
49
50 (defun print-usage ()
50 (defun print-usage ()
51 (lformat t :usage *app-name*))
51 (lformat t :usage *app-name*))
52
52
53 (defun parse-file (filename)
53 (defun parse-file (filename)
54 (handler-case
54 (handler-case
55 (p:parse 'txt2web-grammar
55 (p:parse 'txt2web-grammar
56 (alexandria:read-file-into-string filename))
56 (alexandria:read-file-into-string filename :external-format :utf-8))
57 (p:esrap-parse-error (e)
57 (p:esrap-parse-error (e)
58 (format t "~A~%" e)
58 (format t "~A~%" e)
59 (throw :terminate nil))))
59 (throw :terminate nil))))
60
60
61 (defun report-error (fmt &rest args)
61 (defun report-error (fmt &rest args)
62 (format t "ERROR: ~A~%" (apply #'format nil fmt args))
62 (format t "ERROR: ~A~%" (apply #'format nil fmt args))
63 (print-usage)
63 (print-usage)
64 (throw :terminate nil))
64 (throw :terminate nil))
65
65
66 ;;; JS
66 ;;; JS
67
67
68 (defun minify-package (package-designator minify prefix)
68 (defun minify-package (package-designator minify prefix)
69 (setf (ps:ps-package-prefix package-designator) prefix)
69 (setf (ps:ps-package-prefix package-designator) prefix)
70 (if minify
70 (if minify
71 (ps:obfuscate-package package-designator)
71 (ps:obfuscate-package package-designator)
72 (ps:unobfuscate-package package-designator)))
72 (ps:unobfuscate-package package-designator)))
73
73
74 (defmethod js-sources ((compiler compiler))
74 (defmethod js-sources ((compiler compiler))
75 (let ((ps:*ps-print-pretty* (beautify compiler)))
75 (let ((ps:*ps-print-pretty* (beautify compiler)))
76 (cond ((beautify compiler)
76 (cond ((beautify compiler)
77 (minify-package "TXT2WEB.MAIN" nil "qsp_")
77 (minify-package "TXT2WEB.MAIN" nil "qsp_")
78 (minify-package "TXT2WEB.API" nil "qsp_api_")
78 (minify-package "TXT2WEB.API" nil "qsp_api_")
79 (minify-package "TXT2WEB.LIB" nil "qsp_lib_"))
79 (minify-package "TXT2WEB.LIB" nil "qsp_lib_"))
80 (t
80 (t
81 (minify-package "TXT2WEB.MAIN" t "_")
81 (minify-package "TXT2WEB.MAIN" t "_")
82 (minify-package "TXT2WEB.API" t "a_")
82 (minify-package "TXT2WEB.API" t "a_")
83 (minify-package "TXT2WEB.LIB" t "l_")))
83 (minify-package "TXT2WEB.LIB" t "l_")))
84 (format nil "~{~A~^~%~%~}" (mapcar #'ps:ps* (reverse (js compiler))))))
84 (format nil "~{~A~^~%~%~}" (mapcar #'ps:ps* (reverse (js compiler))))))
85
85
86 ;;; CSS
86 ;;; CSS
87
87
88 (defmethod css-sources ((compiler compiler))
88 (defmethod css-sources ((compiler compiler))
89 (format nil "~{~A~^~%~%~}" (css compiler)))
89 (format nil "~{~A~^~%~%~}" (css compiler)))
90
90
91 ;;; HTML
91 ;;; HTML
92
92
93 (defmethod html-sources ((compiler compiler))
93 (defmethod html-sources ((compiler compiler))
94 (let ((flute:*escape-html* nil)
94 (let ((flute:*escape-html* nil)
95 (body-template (body compiler))
95 (body-template (body compiler))
96 (js (js-sources compiler))
96 (js (js-sources compiler))
97 (css (css-sources compiler)))
97 (css (css-sources compiler)))
98 (with-output-to-string (out)
98 (with-output-to-string (out)
99 (write
99 (write
100 (flute:h
100 (flute:h
101 (html
101 (html
102 (head
102 (head
103 (title "txt2web"))
103 (title "txt2web"))
104 (body
104 (body
105 body-template
105 body-template
106 (style css)
106 (style css)
107 (script js))))
107 (script js))))
108 :stream out
108 :stream out
109 :pretty nil))))
109 :pretty nil))))
110
110
111 (defun filename-game (filename)
111 (defun filename-game (filename)
112 (let ((filename (alexandria:lastcar (uiop:split-string filename :separator "/"))))
112 (let ((filename (alexandria:lastcar (uiop:split-string filename :separator "/"))))
113 (format nil "~{~A~^.~}" (butlast (uiop:split-string filename :separator ".")))))
113 (format nil "~{~A~^.~}" (butlast (uiop:split-string filename :separator ".")))))
114
114
115 (defmethod initialize-instance ((compiler compiler) &key sources ((:js js-files)) ((:css css-files)) ((:body body-file)) compile &allow-other-keys)
115 (defmethod initialize-instance ((compiler compiler) &key sources ((:js js-files)) ((:css css-files)) ((:body body-file)) compile &allow-other-keys)
116 (call-next-method)
116 (call-next-method)
117 (with-slots (body css js)
117 (with-slots (body css js)
118 compiler
118 compiler
119 ;; Compile the game's JS
119 ;; Compile the game's JS
120 (dolist (source sources)
120 (dolist (source sources)
121 (let ((ps (parse-file source))
121 (let ((ps (parse-file source))
122 (game-name (filename-game source)))
122 (game-name (filename-game source)))
123 (destructuring-bind (kw &rest locations)
123 (destructuring-bind (kw &rest locations)
124 ps
124 ps
125 (unless (eq kw 'lib:game)
125 (unless (eq kw 'lib:game)
126 (report-error "Internal error!"))
126 (report-error "Internal error!"))
127 (push
127 (push
128 `(lib:game (,game-name) ,@locations)
128 `(lib:game (,game-name) ,@locations)
129 js))))
129 js))))
130 ;; Does the user need us to do anything else
130 ;; Does the user need us to do anything else
131 (unless compile
131 (unless compile
132 ;; Read in body
132 ;; Read in body
133 (when body-file
133 (when body-file
134 (setf body
134 (setf body
135 (alexandria:read-file-into-string body-file)))
135 (alexandria:read-file-into-string body-file :external-format :utf-8)))
136 ;; Include js files
136 ;; Include js files
137 (dolist (js-file js-files)
137 (dolist (js-file js-files)
138 (push (format nil "////// Included file ~A~%~A" js-file
138 (push (format nil "////// Included file ~A~%~A" js-file
139 (alexandria:read-file-into-string js-file))
139 (alexandria:read-file-into-string js-file :external-format :utf-8))
140 js))
140 js))
141 ;; Include css files
141 ;; Include css files
142 (when css-files
142 (when css-files
143 ;; User option overrides the default css
143 ;; User option overrides the default css
144 (setf css nil)
144 (setf css nil)
145 (dolist (css-file css-files)
145 (dolist (css-file css-files)
146 (push (format nil "////// Included file ~A~%~A" css-file
146 (push (format nil "////// Included file ~A~%~A" css-file
147 (alexandria:read-file-into-string css-file))
147 (alexandria:read-file-into-string css-file :external-format :utf-8))
148 css))))))
148 css))))))
149
149
150 (defmethod write-compiled-file ((compiler compiler))
150 (defmethod write-compiled-file ((compiler compiler))
151 (alexandria:write-string-into-file
151 (alexandria:write-string-into-file
152 (if (compile-only compiler)
152 (if (compile-only compiler)
153 ;; Just the JS
153 ;; Just the JS
154 (js-sources compiler)
154 (js-sources compiler)
155 ;; All of it
155 ;; All of it
156 (html-sources compiler))
156 (html-sources compiler))
157 (target compiler) :if-exists :supersede))
157 (target compiler) :if-exists :supersede))
@@ -1,629 +1,660 b''
1
1
2 (in-package txt2web)
2 (in-package txt2web)
3
3
4 ;;;; Parses TXT source to an intermediate representation
4 ;;;; Parses TXT source to an intermediate representation
5
5
6 (eval-when (:compile-toplevel :load-toplevel :execute)
6 (eval-when (:compile-toplevel :load-toplevel :execute)
7 (defparameter *max-args* 10))
7 (defparameter *max-args* 10))
8
8
9 ;;; Utility
9 ;;; Utility
10
10
11 (defun remove-nth (list nth)
11 (defun remove-nth (list nth)
12 (append (subseq list 0 nth)
12 (append (subseq list 0 nth)
13 (subseq list (1+ nth))))
13 (subseq list (1+ nth))))
14
14
15 (defun not-quote (char)
15 (defun not-quote (char)
16 (not (eql #\' char)))
16 (not (eql #\' char)))
17
17
18 (defun not-doublequote (char)
18 (defun not-doublequote (char)
19 (not (eql #\" char)))
19 (not (eql #\" char)))
20
20
21 (defun not-brace (char)
21 (defun not-brace (char)
22 (not (eql #\} char)))
22 (not (eql #\} char)))
23
23
24 (defun not-integer (string)
24 (defun not-integer (string)
25 (when (find-if-not #'digit-char-p string)
25 (when (find-if-not #'digit-char-p string)
26 t))
26 t))
27
27
28 (defun not-newline (char)
28 (defun not-newline (char)
29 (not (eql #\newline char)))
29 (not (eql #\newline char)))
30
30
31 (defun id-any-char (char)
31 (defun id-any-char (char)
32 (and
32 (and
33 (not (digit-char-p char))
33 (not (digit-char-p char))
34 (not (eql #\newline char))
34 (not (eql #\newline char))
35 (not (find char " !:&=<>+-*/,'\"()[]{}"))))
35 (not (find char " !:&=<>+-*/,'\"()[]{}"))))
36
36
37 (defun intern-first (list)
37 (defun intern-first (list)
38 (list* (intern (string-upcase (first list)) "TXT2WEB.LIB")
38 (list* (intern (string-upcase (first list)) "TXT2WEB.LIB")
39 (rest list)))
39 (rest list)))
40
40
41 (eval-when (:compile-toplevel :load-toplevel :execute)
41 (eval-when (:compile-toplevel :load-toplevel :execute)
42 (defun remove-nil (list)
42 (defun remove-nil (list)
43 (remove nil list)))
43 (remove nil list)))
44
44
45 (defun binop-rest (list)
45 (defun binop-rest (list)
46 (destructuring-bind (ws1 operator ws2 operand2)
46 (destructuring-bind (ws1 operator ws2 operand2)
47 list
47 list
48 (declare (ignore ws1 ws2))
48 (declare (ignore ws1 ws2))
49 (list (intern (string-upcase operator) "TXT2WEB.LIB") operand2)))
49 (list (intern (string-upcase operator) "TXT2WEB.LIB") operand2)))
50
50
51 (defun do-binop% (left-op other-ops)
51 (defun do-binop% (left-op other-ops)
52 (if (null other-ops)
52 (if (null other-ops)
53 left-op
53 left-op
54 (destructuring-bind ((operator right-op) &rest rest-ops)
54 (destructuring-bind ((operator right-op) &rest rest-ops)
55 other-ops
55 other-ops
56 (if (and (listp left-op)
56 (if (and (listp left-op)
57 (eq (first left-op)
57 (eq (first left-op)
58 operator))
58 operator))
59 (do-binop% (append left-op (list right-op)) rest-ops)
59 (do-binop% (append left-op (list right-op)) rest-ops)
60 (do-binop% (list operator left-op right-op) rest-ops)))))
60 (do-binop% (list operator left-op right-op) rest-ops)))))
61
61
62 (walker:deftransform parser-qspmod mod (&rest args)
62 (walker:deftransform parser-qspmod mod (&rest args)
63 (list* 'qspmod (mapcar #'walker:walk-continue args)))
63 (list* 'qspmod (mapcar #'walker:walk-continue args)))
64
64
65 (defun do-binop (list)
65 (defun do-binop (list)
66 (walker:walk 'parser-qspmod
66 (walker:walk 'parser-qspmod
67 (destructuring-bind (left-op rest-ops)
67 (destructuring-bind (left-op rest-ops)
68 list
68 list
69 (do-binop% left-op
69 (do-binop% left-op
70 (mapcar #'binop-rest rest-ops)))))
70 (mapcar #'binop-rest rest-ops)))))
71
71
72 (defun maybe-text (list)
73 "Leaves lists in place and applies esrap:text to everything else"
74 (let ((parts nil)
75 (part (list 'text)))
76 (loop :for token :in list
77 :do (cond ((listp token)
78 (push (nreverse part) parts)
79 (setf part (list 'text))
80 (push token parts))
81 (t (push token part))))
82 (push (nreverse part) parts)
83 (remove ""
84 (loop :for part :in (nreverse parts)
85 :collect (case (first part)
86 ('text (p:text (rest part)))
87 (t part)))
88 :test #'equal)))
89
72 (p:defrule line-continuation (and #\_ #\newline)
90 (p:defrule line-continuation (and #\_ #\newline)
73 (:constant nil))
91 (:constant nil))
74
92
75 (p:defrule text-spaces (+ (or #\space #\tab line-continuation))
93 (p:defrule text-spaces (+ (or #\space #\tab line-continuation))
76 (:text t))
94 (:text t))
77
95
78 (p:defrule spaces (+ (or #\space #\tab line-continuation))
96 (p:defrule spaces (+ (or #\space #\tab line-continuation))
79 (:constant nil)
97 (:constant nil)
80 (:error-report nil))
98 (:error-report nil))
81
99
82 (p:defrule spaces? (* (or #\space #\tab line-continuation))
100 (p:defrule spaces? (* (or #\space #\tab line-continuation))
83 (:constant nil)
101 (:constant nil)
84 (:error-report nil))
102 (:error-report nil))
85
103
86 (p:defrule colon #\:
104 (p:defrule colon #\:
87 (:constant nil))
105 (:constant nil))
88
106
89 (p:defrule equal #\=
107 (p:defrule equal #\=
90 (:constant nil))
108 (:constant nil))
91
109
92 (p:defrule alphanumeric (alphanumericp character))
110 (p:defrule alphanumeric (alphanumericp character))
93
111
94 (p:defrule not-newline (not-newline character))
112 (p:defrule not-newline (not-newline character))
95
113
96 (p:defrule squote-esc "''"
114 (p:defrule squote-esc "''"
97 (:lambda (list)
115 (:lambda (list)
98 (p:text (elt list 0))))
116 (p:text (elt list 0))))
99
117
100 (p:defrule dquote-esc "\"\""
118 (p:defrule dquote-esc "\"\""
101 (:lambda (list)
119 (:lambda (list)
102 (p:text (elt list 0))))
120 (p:text (elt list 0))))
103
121
104 (p:defrule sstring-chars (+ (and (and (p:! "<<") (p:! (p:~ "\"exec:")))
122 (p:defrule sstring-char (or squote-esc (not-quote character))
105 (or squote-esc (not-quote character))))
123 (:text t))
106 (:lambda (list)
107 (p:text (mapcar #'second list))))
108
124
109 (p:defrule dstring-chars (+ (and (and (p:! "<<") (p:! (p:~ "'exec:")))
125 (p:defrule dstring-char (or dquote-esc (not-doublequote character))
110 (or dquote-esc (not-doublequote character))))
126 (:text t))
111 (:lambda (list)
112 (p:text (mapcar #'second list))))
113
127
114 ;;; Identifiers
128 ;;; Identifiers
115
129
116 (defparameter *keywords* '(act addlib addobj addqst and arrcomp arrpos arrsize cla clear *clear close clr *clr cls cmdclear cmdclr copyarr countobj curact curacts curloc debug delact dellib delobj desc disablescroll 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 len let loc local maintxt max menu mid min mod msecscount msg nl *nl no nosave obj opengame openqst or p *p pl *pl play qspver rand refint replace rgb rnd savegame selact selobj set settimer showacts showinput showobjs showstat stattxt step str strcomp strfind strpos to trim ucase unsel unselect user_text usrtxt val view wait xgoto xgt))
130 (defparameter *keywords* '(act addlib addobj addqst and arrcomp arrpos arrsize cla clear *clear close clr *clr cls cmdclear cmdclr copyarr countobj curact curacts curloc debug delact dellib delobj desc disablescroll 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 len let loc local maintxt max menu mid min mod msecscount msg nl *nl no nosave obj opengame openqst or p *p pl *pl play qspver rand refint replace rgb rnd savegame selact selobj set settimer showacts showinput showobjs showstat stattxt step str strcomp strfind strpos to trim ucase unsel unselect user_text usrtxt val view wait xgoto xgt))
117
131
118 (defun trim-$ (str)
132 (defun trim-$ (str)
119 (if (char= #\$ (elt str 0))
133 (if (char= #\$ (elt str 0))
120 (subseq str 1)
134 (subseq str 1)
121 str))
135 str))
122
136
123 (defun qsp-keyword-p (id)
137 (defun qsp-keyword-p (id)
124 (member (intern (trim-$ (string-upcase id))) *keywords*))
138 (member (intern (trim-$ (string-upcase id))) *keywords*))
125
139
126 (defun not-qsp-keyword-p (id)
140 (defun not-qsp-keyword-p (id)
127 (not (member (intern (trim-$ (string-upcase id))) *keywords*)))
141 (not (member (intern (trim-$ (string-upcase id))) *keywords*)))
128
142
129 (p:defrule qsp-keyword (qsp-keyword-p identifier-raw))
143 (p:defrule qsp-keyword (qsp-keyword-p identifier-raw))
130
144
131 (p:defrule id-first (id-any-char character))
145 (p:defrule id-first (id-any-char character))
132 (p:defrule id-next (or (id-any-char character)
146 (p:defrule id-next (or (id-any-char character)
133 (digit-char-p character)))
147 (digit-char-p character)))
134 (p:defrule identifier-raw (and id-first (* id-next))
148 (p:defrule identifier-raw (and id-first (* id-next))
135 (:lambda (list)
149 (:lambda (list)
136 (intern (string-upcase (p:text list)) "TXT2WEB.LIB")))
150 (intern (string-upcase (p:text list)) "TXT2WEB.LIB")))
137
151
138 (p:defrule identifier (not-qsp-keyword-p identifier-raw))
152 (p:defrule identifier (not-qsp-keyword-p identifier-raw))
139
153
140 ;;; Strings
154 ;;; Strings
141
155
142 (p:defrule qsp-string (or normal-string brace-string))
156 (p:defrule qsp-string (or normal-string brace-string))
143
157
158 (p:defrule brace-string (and #\{ before-statement block-body #\})
159 (:lambda (list)
160 (list* 'lib:qspblock (third list))))
161
144 (p:defrule normal-string (or sstring dstring)
162 (p:defrule normal-string (or sstring dstring)
145 (:lambda (str)
163 (:lambda (str)
146 (list* 'lib:str (or str (list "")))))
164 (list* 'lib:str (or str (list "")))))
147
165
148 (p:defrule sstring (and #\' (* (or string-interpol
166 (p:defrule sstring (and #\' (* (or sstring-interpol
149 sstring-exec
167 sstring-exec
150 sstring-chars))
168 sstring-char))
151 #\')
169 #\')
152 (:function second))
170 (:lambda (list)
171 (maybe-text (second list))))
153
172
154 (p:defrule dstring (and #\" (* (or string-interpol
173 (p:defrule dstring (and #\" (* (or dstring-interpol
155 dstring-exec
174 dstring-exec
156 dstring-chars))
175 dstring-char))
157 #\")
176 #\")
158 (:function second))
177 (:lambda (list)
178 (maybe-text (second list))))
159
179
160 (p:defrule string-interpol (and "<<" expression ">>")
180 (defun parse-interpol (list)
161 (:function second))
181 (p:parse 'expression (p:text (mapcar 'second (second list)))))
182
183 (defun parse-exec (list)
184 (list* 'lib:exec (p:parse 'exec-body (p:text (second list)))))
162
185
163 (p:defrule sstring-exec-body (+ (or squote-esc (not-doublequote character)))
186 (p:defrule sstring-interpol (and "<<" (+ (and (p:! ">>")
164 (:text t))
187 sstring-char))
188 ">>")
189 (:function parse-interpol))
165
190
166 (p:defrule dstring-exec-body (+ (or dquote-esc (not-quote character)))
191 (p:defrule dstring-interpol (and "<<" (+ (and (p:! ">>")
167 (:text t))
192 dstring-char))
193 ">>")
194 (:function parse-interpol))
168
195
169 (p:defrule sstring-exec (and (p:~ "\"exec:") sstring-exec-body #\")
196 (p:defrule sstring-exec (or (and (p:~ "\"exec:")
170 (:lambda (list)
197 (+ (and (p:& (not-doublequote character)) sstring-char))
171 (list* 'lib:exec (p:parse 'exec-body (second list)))))
198 #\")
199 (and (p:~ "''exec:")
200 (+ (not-quote character))
201 "''"))
202 (:function parse-exec))
172
203
173 (p:defrule dstring-exec (and (p:~ "'exec:") dstring-exec-body #\')
204 (p:defrule dstring-exec (or (and (p:~ "'exec:")
174 (:lambda (list)
205 (+ (and (p:& (not-quote character)) dstring-char))
175 (list* 'lib:exec (p:parse 'exec-body (second list)))))
206 #\')
176
207 (and (p:~ "\"\"exec")
177 (p:defrule brace-string (and #\{ before-statement block-body #\})
208 (+ (not-doublequote character))
178 (:lambda (list)
209 "\"\""))
179 (list* 'lib:qspblock (third list))))
210 (:function parse-exec))
180
211
181 ;;; Location
212 ;;; Location
182
213
183 (p:defrule txt2web-grammar (and (* (or spaces #\newline))
214 (p:defrule txt2web-grammar (and (* (or spaces #\newline))
184 (* location))
215 (* location))
185 (:lambda (list)
216 (:lambda (list)
186 `(lib:game ,@(second list))))
217 `(lib:game ,@(second list))))
187
218
188 (p:defrule location (and location-header block-body location-end)
219 (p:defrule location (and location-header block-body location-end)
189 (:destructure (header body end)
220 (:destructure (header body end)
190 (declare (ignore end))
221 (declare (ignore end))
191 `(lib:location (,header) ,@body)))
222 `(lib:location (,header) ,@body)))
192
223
193 (p:defrule location-header (and #\#
224 (p:defrule location-header (and #\#
194 (+ not-newline)
225 (+ not-newline)
195 (and #\newline spaces? before-statement))
226 (and #\newline spaces? before-statement))
196 (:destructure (spaces1 name spaces2)
227 (:destructure (spaces1 name spaces2)
197 (declare (ignore spaces1 spaces2))
228 (declare (ignore spaces1 spaces2))
198 (string-upcase (string-trim " " (p:text name)))))
229 (string-upcase (string-trim " " (p:text name)))))
199
230
200 (p:defrule location-end (and #\- (* not-newline) #\newline before-statement)
231 (p:defrule location-end (and #\- (* not-newline) #\newline before-statement)
201 (:constant nil))
232 (:constant nil))
202
233
203 ;;; Block body
234 ;;; Block body
204
235
205 (p:defrule newline-block-body (and #\newline spaces? block-body)
236 (p:defrule newline-block-body (and #\newline spaces? block-body)
206 (:function third))
237 (:function third))
207
238
208 (p:defrule block-body (* statement)
239 (p:defrule block-body (* statement)
209 (:function remove-nil))
240 (:function remove-nil))
210
241
211 ;; Just for <a href="exec:...'>
242 ;; Just for <a href="exec:...'>
212 ;; Explicitly called from that rule's production
243 ;; Explicitly called from that rule's production
213 (p:defrule exec-body (and before-statement line-body)
244 (p:defrule exec-body (and before-statement line-body)
214 (:function second))
245 (:function second))
215
246
216 (p:defrule line-body (and inline-statement (* next-inline-statement))
247 (p:defrule line-body (and inline-statement (* next-inline-statement))
217 (:lambda (list)
248 (:lambda (list)
218 (list* (first list) (second list))))
249 (list* (first list) (second list))))
219
250
220 (p:defrule before-statement (* (or #\newline spaces))
251 (p:defrule before-statement (* (or #\newline spaces))
221 (:constant nil))
252 (:constant nil))
222
253
223 (p:defrule statement-end (or statement-end-real statement-end-block-close))
254 (p:defrule statement-end (or statement-end-real statement-end-block-close))
224
255
225 (p:defrule statement-end-real (and (or #\newline
256 (p:defrule statement-end-real (and (or #\newline
226 (and #\& spaces? (p:& statement%)))
257 (and #\& spaces? (p:& statement%)))
227 before-statement)
258 before-statement)
228 (:constant nil))
259 (:constant nil))
229
260
230 (p:defrule statement-end-block-close (or (p:& #\}))
261 (p:defrule statement-end-block-close (or (p:& #\}))
231 (:constant nil))
262 (:constant nil))
232
263
233 (p:defrule inline-statement (and statement% spaces?)
264 (p:defrule inline-statement (and statement% spaces?)
234 (:function first))
265 (:function first))
235
266
236 (p:defrule next-inline-statement (and #\& spaces? inline-statement)
267 (p:defrule next-inline-statement (and #\& spaces? inline-statement)
237 (:function third))
268 (:function third))
238
269
239 (p:defrule not-a-non-statement (and (p:! (p:~ "elseif"))
270 (p:defrule not-a-non-statement (and (p:! (p:~ "elseif"))
240 (p:! (p:~ "else"))
271 (p:! (p:~ "else"))
241 (p:! (p:~ "end"))))
272 (p:! (p:~ "end"))))
242
273
243 (p:defrule statement (and inline-statement statement-end)
274 (p:defrule statement (and inline-statement statement-end)
244 (:function first))
275 (:function first))
245
276
246 (p:defrule statement% (and not-a-non-statement
277 (p:defrule statement% (and not-a-non-statement
247 (or label comment string-output
278 (or label comment string-output
248 block non-returning-intrinsic local
279 block non-returning-intrinsic local
249 assignment expression-output))
280 assignment expression-output))
250 (:function second))
281 (:function second))
251
282
252 (p:defrule expr-stopper (or comment block non-returning-intrinsic))
283 (p:defrule expr-stopper (or comment block non-returning-intrinsic))
253
284
254 (p:defrule string-output qsp-string
285 (p:defrule string-output qsp-string
255 (:lambda (string)
286 (:lambda (string)
256 (list 'lib:main-pl string)))
287 (list 'lib:main-pl string)))
257
288
258 (p:defrule expression-output expression
289 (p:defrule expression-output expression
259 (:lambda (list)
290 (:lambda (list)
260 (list 'lib:main-pl list)))
291 (list 'lib:main-pl list)))
261
292
262 (p:defrule label (and colon identifier)
293 (p:defrule label (and colon identifier)
263 (:lambda (list)
294 (:lambda (list)
264 (intern (string (second list)) :keyword)))
295 (intern (string (second list)) :keyword)))
265
296
266 (p:defrule comment (and #\! (* (or qsp-string brace-comment text-spaces not-newline)))
297 (p:defrule comment (and #\! (* (or qsp-string brace-comment text-spaces not-newline)))
267 (:constant nil))
298 (:constant nil))
268
299
269 (p:defrule brace-comment (and #\{ (* (not-brace character)) #\})
300 (p:defrule brace-comment (and #\{ (* (not-brace character)) #\})
270 (:constant nil))
301 (:constant nil))
271
302
272 (p:defrule local (and (p:~ "local") spaces variable (p:? (and spaces? #\= spaces? expression)))
303 (p:defrule local (and (p:~ "local") spaces variable (p:? (and spaces? #\= spaces? expression)))
273 (:lambda (list)
304 (:lambda (list)
274 (list* 'lib:local (third list)
305 (list* 'lib:local (third list)
275 (when (fourth list)
306 (when (fourth list)
276 (list (fourth (fourth list)))))))
307 (list (fourth (fourth list)))))))
277
308
278 ;;; Blocks
309 ;;; Blocks
279
310
280 (p:defrule block (or block-act block-if block-for))
311 (p:defrule block (or block-act block-if block-for))
281
312
282 (p:defrule block-if (and block-if-head block-if-body)
313 (p:defrule block-if (and block-if-head block-if-body)
283 (:destructure (head body)
314 (:destructure (head body)
284 `(lib:qspcond (,@head ,@(first body))
315 `(lib:qspcond (,@head ,@(first body))
285 ,@(rest body))))
316 ,@(rest body))))
286
317
287 (p:defrule block-if-head (and (p:~ "if") spaces expression spaces? colon spaces?)
318 (p:defrule block-if-head (and (p:~ "if") spaces expression spaces? colon spaces?)
288 (:function remove-nil)
319 (:function remove-nil)
289 (:function cdr))
320 (:function cdr))
290
321
291 (p:defrule block-if-body (or block-if-ml block-if-sl)
322 (p:defrule block-if-body (or block-if-ml block-if-sl)
292 (:destructure (if-body elseifs else &rest ws)
323 (:destructure (if-body elseifs else &rest ws)
293 (declare (ignore ws))
324 (declare (ignore ws))
294 `(,(remove-nil if-body) ,@elseifs ,@(when else `((else ,@else))))))
325 `(,(remove-nil if-body) ,@elseifs ,@(when else `((else ,@else))))))
295
326
296 (p:defrule block-if-sl (and line-body
327 (p:defrule block-if-sl (and line-body
297 (p:? block-if-elseif-inline)
328 (p:? block-if-elseif-inline)
298 (p:? block-if-else-inline)
329 (p:? block-if-else-inline)
299 spaces?))
330 spaces?))
300
331
301 (p:defrule block-if-ml (and (and #\newline spaces?)
332 (p:defrule block-if-ml (and (and #\newline spaces?)
302 block-body
333 block-body
303 (p:? block-if-elseif)
334 (p:? block-if-elseif)
304 (p:? block-if-else)
335 (p:? block-if-else)
305 block-if-end)
336 block-if-end)
306 (:lambda (list)
337 (:lambda (list)
307 (cdr list)))
338 (cdr list)))
308
339
309 (p:defrule block-if-elseif-inline (and block-if-elseif-head line-body (p:? block-if-elseif-inline))
340 (p:defrule block-if-elseif-inline (and block-if-elseif-head line-body (p:? block-if-elseif-inline))
310 (:destructure (head statements elseif)
341 (:destructure (head statements elseif)
311 `((,@(rest head) ,@(remove-nil statements)) ,@elseif)))
342 `((,@(rest head) ,@(remove-nil statements)) ,@elseif)))
312
343
313 (p:defrule block-if-elseif (and block-if-elseif-head statement-end block-body (p:? block-if-elseif))
344 (p:defrule block-if-elseif (and block-if-elseif-head statement-end block-body (p:? block-if-elseif))
314 (:destructure (head ws statements elseif)
345 (:destructure (head ws statements elseif)
315 (declare (ignore ws))
346 (declare (ignore ws))
316 `((,@(rest head) ,@(remove-nil statements)) ,@elseif)))
347 `((,@(rest head) ,@(remove-nil statements)) ,@elseif)))
317
348
318 (p:defrule block-if-elseif-head (and (p:~ "elseif") spaces expression spaces? colon spaces?)
349 (p:defrule block-if-elseif-head (and (p:~ "elseif") spaces expression spaces? colon spaces?)
319 (:function remove-nil)
350 (:function remove-nil)
320 (:function intern-first))
351 (:function intern-first))
321
352
322 (p:defrule block-if-else-inline (and block-if-else-head line-body)
353 (p:defrule block-if-else-inline (and block-if-else-head line-body)
323 (:function second))
354 (:function second))
324
355
325 (p:defrule block-if-else (and block-if-else-head #\newline spaces? block-body)
356 (p:defrule block-if-else (and block-if-else-head #\newline spaces? block-body)
326 (:function fourth))
357 (:function fourth))
327
358
328 (p:defrule block-if-else-head (and (p:~ "else") spaces?)
359 (p:defrule block-if-else-head (and (p:~ "else") spaces?)
329 (:constant nil))
360 (:constant nil))
330
361
331 (p:defrule block-if-end (and (p:~ "end")
362 (p:defrule block-if-end (and (p:~ "end")
332 (p:? (and spaces (p:~ "if"))))
363 (p:? (and spaces (p:~ "if"))))
333 (:constant nil))
364 (:constant nil))
334
365
335 (p:defrule block-act (and block-act-head (or block-ml block-sl))
366 (p:defrule block-act (and block-act-head (or block-ml block-sl))
336 (:lambda (list)
367 (:lambda (list)
337 (apply #'append list)))
368 (apply #'append list)))
338
369
339 (p:defrule block-act-head (and (p:~ "act") spaces? qsp-string spaces?
370 (p:defrule block-act-head (and (p:~ "act") spaces? qsp-string spaces?
340 (p:? block-act-head-img)
371 (p:? block-act-head-img)
341 colon spaces?)
372 colon spaces?)
342 (:lambda (list)
373 (:lambda (list)
343 (intern-first (list (first list)
374 (intern-first (list (first list)
344 (third list)
375 (third list)
345 (or (fifth list) '(lib:str ""))))))
376 (or (fifth list) '(lib:str ""))))))
346
377
347 (p:defrule block-act-head-img (and #\, spaces? qsp-string spaces?)
378 (p:defrule block-act-head-img (and #\, spaces? qsp-string spaces?)
348 (:lambda (list)
379 (:lambda (list)
349 (or (third list) "")))
380 (or (third list) "")))
350
381
351 (p:defrule block-for (and block-for-head (or block-ml block-sl))
382 (p:defrule block-for (and block-for-head (or block-ml block-sl))
352 (:lambda (list)
383 (:lambda (list)
353 (apply #'append list)))
384 (apply #'append list)))
354
385
355 (p:defrule block-for-head (and (p:~ "for") spaces variable spaces? equal spaces? expression
386 (p:defrule block-for-head (and (p:~ "for") spaces variable spaces? equal spaces? expression
356 (p:~ "to") spaces expression
387 (p:~ "to") spaces expression
357 block-for-head-step
388 block-for-head-step
358 colon spaces?)
389 colon spaces?)
359 (:lambda (list)
390 (:lambda (list)
360 (list 'lib:qspfor
391 (list 'lib:qspfor
361 (elt list 2)
392 (elt list 2)
362 (elt list 6)
393 (elt list 6)
363 (elt list 9)
394 (elt list 9)
364 (elt list 10))))
395 (elt list 10))))
365
396
366 (p:defrule block-for-head-step (p:? (and (p:~ "step") spaces expression spaces?))
397 (p:defrule block-for-head-step (p:? (and (p:~ "step") spaces expression spaces?))
367 (:lambda (list)
398 (:lambda (list)
368 (if list
399 (if list
369 (third list)
400 (third list)
370 1)))
401 1)))
371
402
372 (p:defrule block-sl line-body)
403 (p:defrule block-sl line-body)
373
404
374 (p:defrule block-ml (and newline-block-body block-end)
405 (p:defrule block-ml (and newline-block-body block-end)
375 (:lambda (list)
406 (:lambda (list)
376 (apply #'list* (butlast list))))
407 (apply #'list* (butlast list))))
377
408
378 (p:defrule block-end (and (p:~ "end"))
409 (p:defrule block-end (and (p:~ "end"))
379 (:constant nil))
410 (:constant nil))
380
411
381 ;;; Calls
412 ;;; Calls
382
413
383 (p:defrule first-argument (and expression spaces?)
414 (p:defrule first-argument (and expression spaces?)
384 (:function first))
415 (:function first))
385 (p:defrule next-argument (and "," spaces? expression)
416 (p:defrule next-argument (and "," spaces? expression)
386 (:function third))
417 (:function third))
387 (p:defrule arguments (or parenthesized-arguments plain-arguments no-arguments))
418 (p:defrule arguments (or parenthesized-arguments plain-arguments no-arguments))
388 (p:defrule parenthesized-arguments (and spaces? #\( base-arguments #\))
419 (p:defrule parenthesized-arguments (and spaces? #\( base-arguments #\))
389 (:function third))
420 (:function third))
390 (p:defrule plain-arguments (and spaces? base-arguments)
421 (p:defrule plain-arguments (and spaces? base-arguments)
391 (:function second))
422 (:function second))
392 (p:defrule no-arguments (or (and spaces? (p:& #\newline))
423 (p:defrule no-arguments (or (and spaces? (p:& #\newline))
393 (and spaces? (p:& #\&))
424 (and spaces? (p:& #\&))
394 spaces?)
425 spaces?)
395 (:constant nil))
426 (:constant nil))
396 (p:defrule base-arguments (or (and first-argument (* next-argument)) spaces?)
427 (p:defrule base-arguments (or (and first-argument (* next-argument)) spaces?)
397 (:lambda (list)
428 (:lambda (list)
398 (if (null list)
429 (if (null list)
399 nil
430 nil
400 (list* (first list) (second list)))))
431 (list* (first list) (second list)))))
401
432
402 ;;; Intrinsics
433 ;;; Intrinsics
403
434
404 (defmacro defintrinsics ((rule-name returning-rule-name non-returning-rule-name) &body clauses)
435 (defmacro defintrinsics ((rule-name returning-rule-name non-returning-rule-name) &body clauses)
405 `(progn
436 `(progn
406 ,@(loop :for clause :in clauses
437 ,@(loop :for clause :in clauses
407 :collect `(defintrinsic ,@clause))
438 :collect `(defintrinsic ,@clause))
408 (p:defrule ,returning-rule-name (or ,@(remove-nil
439 (p:defrule ,returning-rule-name (or ,@(remove-nil
409 (mapcar (lambda (clause)
440 (mapcar (lambda (clause)
410 (when (second clause)
441 (when (second clause)
411 (alexandria:symbolicate
442 (alexandria:symbolicate
412 'intrinsic- (first clause))))
443 'intrinsic- (first clause))))
413 clauses))))
444 clauses))))
414 (p:defrule ,non-returning-rule-name (or ,@(remove-nil
445 (p:defrule ,non-returning-rule-name (or ,@(remove-nil
415 (mapcar (lambda (clause)
446 (mapcar (lambda (clause)
416 (unless (second clause)
447 (unless (second clause)
417 (alexandria:symbolicate
448 (alexandria:symbolicate
418 'intrinsic- (first clause))))
449 'intrinsic- (first clause))))
419 clauses))))
450 clauses))))
420 (p:defrule ,rule-name (or ,returning-rule-name ,non-returning-rule-name))))
451 (p:defrule ,rule-name (or ,returning-rule-name ,non-returning-rule-name))))
421
452
422 (defmacro defintrinsic (sym returning &optional (min-arity 0) max-arity &rest names)
453 (defmacro defintrinsic (sym returning &optional (min-arity 0) max-arity &rest names)
423 (declare (ignore returning))
454 (declare (ignore returning))
424 (unless max-arity
455 (unless max-arity
425 (setf max-arity *max-args*))
456 (setf max-arity *max-args*))
426 (setf names
457 (setf names
427 (if names
458 (if names
428 (mapcar #'string-upcase names)
459 (mapcar #'string-upcase names)
429 (list (string sym))))
460 (list (string sym))))
430 `(p:defrule ,(alexandria:symbolicate 'intrinsic- sym)
461 `(p:defrule ,(alexandria:symbolicate 'intrinsic- sym)
431 (and (p:? #\$) (or ,@(loop :for name :in names :collect `(p:~ ,name)))
462 (and (p:? #\$) (or ,@(loop :for name :in names :collect `(p:~ ,name)))
432 arguments)
463 arguments)
433 (:destructure (dollar name arguments)
464 (:destructure (dollar name arguments)
434 (declare (ignore dollar))
465 (declare (ignore dollar))
435 (unless (<= ,min-arity (length arguments) ,max-arity)
466 (unless (<= ,min-arity (length arguments) ,max-arity)
436 (error "Intrinsic ~A expects between ~A and ~A arguments but ~A were provided:~%~S"
467 (error "Intrinsic ~A expects between ~A and ~A arguments but ~A were provided:~%~S"
437 name ,min-arity ,max-arity (length arguments) arguments))
468 name ,min-arity ,max-arity (length arguments) arguments))
438 (list* ',(intern (string sym) "TXT2WEB.LIB") arguments))))
469 (list* ',(intern (string sym) "TXT2WEB.LIB") arguments))))
439
470
440 (defintrinsics (intrinsic returning-intrinsic non-returning-intrinsic)
471 (defintrinsics (intrinsic returning-intrinsic non-returning-intrinsic)
441 ;; Transitions
472 ;; Transitions
442 (goto% nil 0 nil "gt" "goto")
473 (goto% nil 0 nil "gt" "goto")
443 (xgoto% nil 0 nil "xgt" "xgoto")
474 (xgoto% nil 0 nil "xgt" "xgoto")
444 ;; Variables
475 ;; Variables
445 (killvar nil 0 2)
476 (killvar nil 0 2)
446 ;; Expressions
477 ;; Expressions
447 (obj t 1 1)
478 (obj t 1 1)
448 (loc t 1 1)
479 (loc t 1 1)
449 (no t 1 1)
480 (no t 1 1)
450 ;; Basic
481 ;; Basic
451 (qspver t 0 0)
482 (qspver t 0 0)
452 (curloc t 0 0)
483 (curloc t 0 0)
453 (rand t 1 2)
484 (rand t 1 2)
454 (rnd t 0 0)
485 (rnd t 0 0)
455 (qspmax t 1 nil "max")
486 (qspmax t 1 nil "max")
456 (qspmin t 1 nil "min")
487 (qspmin t 1 nil "min")
457 ;; Arrays
488 ;; Arrays
458 (killall nil 0 0)
489 (killall nil 0 0)
459 (copyarr nil 2 4)
490 (copyarr nil 2 4)
460 (arrsize t 1 1)
491 (arrsize t 1 1)
461 (arrpos t 2 3)
492 (arrpos t 2 3)
462 (arrcomp t 2 3)
493 (arrcomp t 2 3)
463 ;; Strings
494 ;; Strings
464 (len t 1 1)
495 (len t 1 1)
465 (mid t 2 3)
496 (mid t 2 3)
466 (ucase t 1 1)
497 (ucase t 1 1)
467 (lcase t 1 1)
498 (lcase t 1 1)
468 (trim t 1 1)
499 (trim t 1 1)
469 (qspreplace t 2 3 "replace")
500 (qspreplace t 2 3 "replace")
470 (instr t 2 3)
501 (instr t 2 3)
471 (isnum t 1 1)
502 (isnum t 1 1)
472 (val t 1 1)
503 (val t 1 1)
473 (qspstr t 1 1 "str")
504 (qspstr t 1 1 "str")
474 (strcomp t 2 2)
505 (strcomp t 2 2)
475 (strfind t 2 3)
506 (strfind t 2 3)
476 (strpos t 2 3)
507 (strpos t 2 3)
477 ;; IF
508 ;; IF
478 (iif t 2 3)
509 (iif t 2 3)
479 ;; Subs
510 ;; Subs
480 (gosub nil 1 nil "gosub" "gs")
511 (gosub nil 1 nil "gosub" "gs")
481 (func t 1 nil)
512 (func t 1 nil)
482 (exit nil 0 0)
513 (exit nil 0 0)
483 ;; Jump
514 ;; Jump
484 (jump nil 1 1)
515 (jump nil 1 1)
485 ;; Dynamic
516 ;; Dynamic
486 (dynamic nil 1 nil)
517 (dynamic nil 1 nil)
487 (dyneval t 1 nil)
518 (dyneval t 1 nil)
488 ;; Sound
519 ;; Sound
489 (play nil 1 2)
520 (play nil 1 2)
490 (isplay t 1 1)
521 (isplay t 1 1)
491 (close nil 1 1)
522 (close nil 1 1)
492 (closeall nil 0 0 "close all")
523 (closeall nil 0 0 "close all")
493 ;; Main window
524 ;; Main window
494 (main-pl nil 1 1 "*pl")
525 (main-pl nil 1 1 "*pl")
495 (main-nl nil 0 1 "*nl")
526 (main-nl nil 0 1 "*nl")
496 (main-p nil 1 1 "*p")
527 (main-p nil 1 1 "*p")
497 (maintxt t 0 0)
528 (maintxt t 0 0)
498 (desc t 1 1)
529 (desc t 1 1)
499 (main-clear nil 0 0 "*clear" "*clr")
530 (main-clear nil 0 0 "*clear" "*clr")
500 ;; Aux window
531 ;; Aux window
501 (showstat nil 1 1)
532 (showstat nil 1 1)
502 (stat-pl nil 1 1 "pl")
533 (stat-pl nil 1 1 "pl")
503 (stat-nl nil 0 1 "nl")
534 (stat-nl nil 0 1 "nl")
504 (stat-p nil 1 1 "p")
535 (stat-p nil 1 1 "p")
505 (stattxt t 0 0)
536 (stattxt t 0 0)
506 (stat-clear nil 0 0 "clear" "clr")
537 (stat-clear nil 0 0 "clear" "clr")
507 (cls nil 0 0)
538 (cls nil 0 0)
508 ;; Dialog
539 ;; Dialog
509 (msg nil 1 1)
540 (msg nil 1 1)
510 ;; Acts
541 ;; Acts
511 (showacts nil 1 1)
542 (showacts nil 1 1)
512 (delact nil 1 1 "delact" "del act")
543 (delact nil 1 1 "delact" "del act")
513 (curacts t 0 0)
544 (curacts t 0 0)
514 (selact t 0 0)
545 (selact t 0 0)
515 (cla nil 0 0)
546 (cla nil 0 0)
516 ;; Objects
547 ;; Objects
517 (showobjs nil 1 1)
548 (showobjs nil 1 1)
518 (addobj nil 1 3 "addobj" "add obj")
549 (addobj nil 1 3 "addobj" "add obj")
519 (delobj nil 1 1 "delobj" "del obj")
550 (delobj nil 1 1 "delobj" "del obj")
520 (killobj nil 0 1)
551 (killobj nil 0 1)
521 (countobj t 0 0)
552 (countobj t 0 0)
522 (getobj t 1 1)
553 (getobj t 1 1)
523 (selobj t 0 0)
554 (selobj t 0 0)
524 (unsel nil 0 0 "unsel" "unselect")
555 (unsel nil 0 0 "unsel" "unselect")
525 ;; Menu
556 ;; Menu
526 (menu nil 1 1)
557 (menu nil 1 1)
527 ;; Images
558 ;; Images
528 (refint nil 0 0)
559 (refint nil 0 0)
529 (view nil 0 1)
560 (view nil 0 1)
530 (img nil 1)
561 (img nil 1)
531 (*img nil 1)
562 (*img nil 1)
532 ;; Fonts
563 ;; Fonts
533 (rgb t 3 3)
564 (rgb t 3 3)
534 ;; Input
565 ;; Input
535 (showinput nil 1 1)
566 (showinput nil 1 1)
536 (usertxt t 0 0 "user_text" "usrtxt")
567 (usertxt t 0 0 "user_text" "usrtxt")
537 (cmdclear nil 0 0 "cmdclear" "cmdclr")
568 (cmdclear nil 0 0 "cmdclear" "cmdclr")
538 (input t 1 1)
569 (input t 1 1)
539 ;; Files
570 ;; Files
540 (openqst nil 1 1)
571 (openqst nil 1 1)
541 (addqst nil 1 1 "addqst" "addlib" "inclib")
572 (addqst nil 1 1 "addqst" "addlib" "inclib")
542 (killqst nil 1 1 "killqst" "dellib" "freelib")
573 (killqst nil 1 1 "killqst" "dellib" "freelib")
543 (opengame nil 0 0)
574 (opengame nil 0 0)
544 (savegame nil 0 0)
575 (savegame nil 0 0)
545 ;; Real time
576 ;; Real time
546 (wait nil 1 1)
577 (wait nil 1 1)
547 (msecscount t 0 0)
578 (msecscount t 0 0)
548 (settimer nil 1 1))
579 (settimer nil 1 1))
549
580
550 ;;; Expression
581 ;;; Expression
551
582
552 (p:defrule expression or-expr)
583 (p:defrule expression or-expr)
553
584
554 (p:defrule or-expr (and and-expr (* (and spaces? or-op spaces? and-expr)))
585 (p:defrule or-expr (and and-expr (* (and spaces? or-op spaces? and-expr)))
555 (:function do-binop))
586 (:function do-binop))
556
587
557 (p:defrule and-expr (and eq-expr (* (and spaces? and-op spaces? eq-expr)))
588 (p:defrule and-expr (and eq-expr (* (and spaces? and-op spaces? eq-expr)))
558 (:function do-binop))
589 (:function do-binop))
559
590
560 (p:defrule eq-expr (and sum-expr (* (and spaces? (or "<=" ">=" "=<" "=>" "<>"
591 (p:defrule eq-expr (and sum-expr (* (and spaces? (or "<=" ">=" "=<" "=>" "<>"
561 "=" "<" ">" "!")
592 "=" "<" ">" "!")
562 spaces? sum-expr)))
593 spaces? sum-expr)))
563 (:function do-binop))
594 (:function do-binop))
564
595
565 (p:defrule sum-expr (and mod-expr (* (and spaces? (or #\+ #\-) spaces? mod-expr)))
596 (p:defrule sum-expr (and mod-expr (* (and spaces? (or #\+ #\-) spaces? mod-expr)))
566 (:function do-binop))
597 (:function do-binop))
567
598
568 (p:defrule mod-expr (and mul-expr (* (and spaces? (p:~ "mod") spaces? mul-expr)))
599 (p:defrule mod-expr (and mul-expr (* (and spaces? (p:~ "mod") spaces? mul-expr)))
569 (:function do-binop))
600 (:function do-binop))
570
601
571 (p:defrule mul-expr (and unary-expr (* (and spaces? (or #\* #\/) spaces? unary-expr)))
602 (p:defrule mul-expr (and unary-expr (* (and spaces? (or #\* #\/) spaces? unary-expr)))
572 (:function do-binop))
603 (:function do-binop))
573
604
574 (p:defrule unary-expr (and (p:? (or #\+ #\-)) atom-expr)
605 (p:defrule unary-expr (and (p:? (or #\+ #\-)) atom-expr)
575 (:lambda (list)
606 (:lambda (list)
576 (let ((expr (remove-nil list)))
607 (let ((expr (remove-nil list)))
577 (if (= 1 (length expr))
608 (if (= 1 (length expr))
578 (first expr)
609 (first expr)
579 (intern-first expr)))))
610 (intern-first expr)))))
580
611
581 (p:defrule atom-expr (and (or variable literal returning-intrinsic paren-expr) spaces?)
612 (p:defrule atom-expr (and (or variable literal returning-intrinsic paren-expr) spaces?)
582 (:function first))
613 (:function first))
583
614
584 (p:defrule paren-expr (and #\( spaces? expression spaces? #\))
615 (p:defrule paren-expr (and #\( spaces? expression spaces? #\))
585 (:function third))
616 (:function third))
586
617
587 (p:defrule or-op (p:~ "or")
618 (p:defrule or-op (p:~ "or")
588 (:constant "or"))
619 (:constant "or"))
589
620
590 (p:defrule and-op (p:~ "and")
621 (p:defrule and-op (p:~ "and")
591 (:constant "and"))
622 (:constant "and"))
592
623
593 ;;; Variables
624 ;;; Variables
594
625
595 (p:defrule variable (and identifier (p:? array-index))
626 (p:defrule variable (and identifier (p:? array-index))
596 (:destructure (id idx-raw)
627 (:destructure (id idx-raw)
597 (let ((idx (case idx-raw
628 (let ((idx (case idx-raw
598 ((nil) 0)
629 ((nil) 0)
599 (:last nil)
630 (:last nil)
600 (t idx-raw))))
631 (t idx-raw))))
601 (list 'lib:qspvar id idx))))
632 (list 'lib:qspvar id idx))))
602
633
603 (p:defrule array-index (and #\[ spaces? (p:? expression) spaces? #\])
634 (p:defrule array-index (and #\[ spaces? (p:? expression) spaces? #\])
604 (:lambda (list)
635 (:lambda (list)
605 (or (third list) :last)))
636 (or (third list) :last)))
606
637
607 (p:defrule assignment (or kw-assignment plain-assignment op-assignment)
638 (p:defrule assignment (or kw-assignment plain-assignment op-assignment)
608 (:destructure (qspvar eq expr)
639 (:destructure (qspvar eq expr)
609 (declare (ignore eq))
640 (declare (ignore eq))
610 (list 'lib:set qspvar expr)))
641 (list 'lib:set qspvar expr)))
611
642
612 (p:defrule kw-assignment (and (or (p:~ "let") (p:~ "set")) spaces? (or op-assignment plain-assignment))
643 (p:defrule kw-assignment (and (or (p:~ "let") (p:~ "set")) spaces? (or op-assignment plain-assignment))
613 (:function third))
644 (:function third))
614
645
615 (p:defrule op-assignment (and variable spaces? (or "+" "-" "*" "/") #\= spaces? expression)
646 (p:defrule op-assignment (and variable spaces? (or "+" "-" "*" "/") #\= spaces? expression)
616 (:destructure (qspvar ws1 op eq ws2 expr)
647 (:destructure (qspvar ws1 op eq ws2 expr)
617 (declare (ignore ws1 ws2))
648 (declare (ignore ws1 ws2))
618 (list qspvar eq (intern-first (list op qspvar expr)))))
649 (list qspvar eq (intern-first (list op qspvar expr)))))
619
650
620 (p:defrule plain-assignment (and variable spaces? #\= spaces? expression)
651 (p:defrule plain-assignment (and variable spaces? #\= spaces? expression)
621 (:function remove-nil))
652 (:function remove-nil))
622
653
623 ;;; Non-string literals
654 ;;; Non-string literals
624
655
625 (p:defrule literal (or qsp-string brace-string number))
656 (p:defrule literal (or qsp-string brace-string number))
626
657
627 (p:defrule number (+ (or #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))
658 (p:defrule number (+ (or #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))
628 (:lambda (list)
659 (:lambda (list)
629 (parse-integer (p:text list))))
660 (parse-integer (p:text list))))
@@ -1,131 +1,136 b''
1
2 ;;;; Parenscript
1
3
2 (in-package parenscript)
4 (in-package parenscript)
3
5
4 ;;; async/await
6 ;;; async/await
5
7
6 (defprinter ps-js::await (x)
8 (defprinter ps-js::await (x)
7 (psw (string-downcase "await "))
9 (psw (string-downcase "await "))
8 (print-op-argument 'ps-js::await x))
10 (print-op-argument 'ps-js::await x))
9
11
10 (define-trivial-special-ops await ps-js::await)
12 (define-trivial-special-ops await ps-js::await)
11
13
12 (define-statement-operator async-defun (name lambda-list &rest body)
14 (define-statement-operator async-defun (name lambda-list &rest body)
13 (multiple-value-bind (effective-args body-block docstring)
15 (multiple-value-bind (effective-args body-block docstring)
14 (compile-named-function-body name lambda-list body)
16 (compile-named-function-body name lambda-list body)
15 (list 'ps-js::async-defun name effective-args docstring body-block)))
17 (list 'ps-js::async-defun name effective-args docstring body-block)))
16
18
17 (defprinter ps-js::async-defun (name args docstring body-block)
19 (defprinter ps-js::async-defun (name args docstring body-block)
18 (when docstring (print-comment docstring))
20 (when docstring (print-comment docstring))
19 (psw "async ")
21 (psw "async ")
20 (print-fun-def name args body-block))
22 (print-fun-def name args body-block))
21
23
22 (define-expression-operator async-lambda (lambda-list &rest body)
24 (define-expression-operator async-lambda (lambda-list &rest body)
23 (multiple-value-bind (effective-args effective-body)
25 (multiple-value-bind (effective-args effective-body)
24 (parse-extended-function lambda-list body)
26 (parse-extended-function lambda-list body)
25 `(ps-js::async-lambda
27 `(ps-js::async-lambda
26 ,effective-args
28 ,effective-args
27 ,(let ((*function-block-names* ()))
29 ,(let ((*function-block-names* ()))
28 (compile-function-body effective-args effective-body)))))
30 (compile-function-body effective-args effective-body)))))
29
31
30 (defprinter ps-js::async-lambda (args body-block)
32 (defprinter ps-js::async-lambda (args body-block)
31 (psw "async ")
33 (psw "async ")
32 (print-fun-def nil args body-block))
34 (print-fun-def nil args body-block))
33
35
34 (cl:export 'await)
36 (cl:export 'await)
35 (cl:export 'async-defun)
37 (cl:export 'async-defun)
36 (cl:export 'async-lambda)
38 (cl:export 'async-lambda)
37
39
38 ;;; ES6
40 ;;; ES6
39
41
40 (define-expression-operator => (lambda-list &rest body)
42 (define-expression-operator => (lambda-list &rest body)
41 (unless (listp lambda-list)
43 (unless (listp lambda-list)
42 (setf lambda-list (list lambda-list)))
44 (setf lambda-list (list lambda-list)))
43 (multiple-value-bind (effective-args effective-body)
45 (multiple-value-bind (effective-args effective-body)
44 (parse-extended-function lambda-list body)
46 (parse-extended-function lambda-list body)
45 `(ps-js::=>
47 `(ps-js::=>
46 ,effective-args
48 ,effective-args
47 ,(let ((*function-block-names* ()))
49 ,(let ((*function-block-names* ()))
48 (compile-function-body effective-args effective-body)))))
50 (compile-function-body effective-args effective-body)))))
49
51
50 (defprinter ps-js::=> (args body)
52 (defprinter ps-js::=> (args body)
51 (unless (= 1 (length args))
53 (unless (= 1 (length args))
52 (psw "("))
54 (psw "("))
53 (loop for (arg . remaining) on args do
55 (loop for (arg . remaining) on args do
54 (psw (symbol-to-js-string arg)) (when remaining (psw ", ")))
56 (psw (symbol-to-js-string arg)) (when remaining (psw ", ")))
55 (unless (= 1 (length args))
57 (unless (= 1 (length args))
56 (psw ")"))
58 (psw ")"))
57 (psw " => ")
59 (psw " => ")
58 (ps-print body))
60 (ps-print body))
59
61
60 (cl:export '=>)
62 (cl:export '=>)
61
63
62 ;;; Actually return nothing (with no empty return)
64 ;;; Actually return nothing (with no empty return)
63 (defvar *old-return-result-of* (function return-result-of))
65 (defvar *old-return-result-of* (function return-result-of))
64
66
65 (defun return-result-of (tag form)
67 (defun return-result-of (tag form)
66 (if (equal form '(void))
68 (if (equal form '(void))
67 nil
69 nil
68 (funcall *old-return-result-of* tag form)))
70 (funcall *old-return-result-of* tag form)))
69 (cl:export 'void)
71 (cl:export 'void)
70
72
71 ;;; Bitwise stuff
73 ;;; Bitwise stuff
72 ;; No idea why these are not exported
74 ;; No idea why these are not exported
73 (export '<<)
75 (export '<<)
74 (export '>>)
76 (export '>>)
75
77
78 ;;;; Esrap
79
76 (in-package esrap)
80 (in-package esrap)
81
77 (defmethod print-object :around ((condition esrap-error) stream)
82 (defmethod print-object :around ((condition esrap-error) stream)
78 (when (not txt2web::*delivered*)
83 (when (not txt2web::*delivered*)
79 (return-from print-object
84 (return-from print-object
80 (call-next-method)))
85 (call-next-method)))
81 (when (or *print-escape*
86 (when (or *print-escape*
82 *print-readably*
87 *print-readably*
83 (and *print-lines* (<= *print-lines* 5)))
88 (and *print-lines* (<= *print-lines* 5)))
84 (return-from print-object))
89 (return-from print-object))
85
90
86 ;; FIXME: this looks like it won't do the right thing when used as
91 ;; FIXME: this looks like it won't do the right thing when used as
87 ;; part of a logical block.
92 ;; part of a logical block.
88 (if-let ((text (esrap-error-text condition))
93 (if-let ((text (esrap-error-text condition))
89 (position (esrap-error-position condition)))
94 (position (esrap-error-position condition)))
90 (labels ((safe-index (index)
95 (labels ((safe-index (index)
91 (min (max index 0) (length text)))
96 (min (max index 0) (length text)))
92 (find-newline (&key (start 0) (end (length text)) (from-end t))
97 (find-newline (&key (start 0) (end (length text)) (from-end t))
93 (let ((start (safe-index start))
98 (let ((start (safe-index start))
94 (end (safe-index end)))
99 (end (safe-index end)))
95 (cond
100 (cond
96 ((when-let ((position (position #\Newline text
101 ((when-let ((position (position #\Newline text
97 :start start :end end
102 :start start :end end
98 :from-end from-end)))
103 :from-end from-end)))
99 (1+ position)))
104 (1+ position)))
100 ((and from-end (zerop start))
105 ((and from-end (zerop start))
101 start)
106 start)
102 ((and (not from-end) (= end (length text)))
107 ((and (not from-end) (= end (length text)))
103 end)))))
108 end)))))
104 ;; FIXME: magic numbers
109 ;; FIXME: magic numbers
105 (let* ((line (count #\Newline text :end position))
110 (let* ((line (count #\Newline text :end position))
106 (column (- position (or (find-newline :end position) 0) 1))
111 (column (- position (or (find-newline :end position) 0) 1))
107 (min-start (- position 160))
112 (min-start (- position 160))
108 (max-end (+ position 24))
113 (max-end (+ position 24))
109 (line-start (or (find-newline :start min-start
114 (line-start (or (find-newline :start min-start
110 :end position)
115 :end position)
111 (safe-index min-start)))
116 (safe-index min-start)))
112 (start (cond
117 (start (cond
113 ((= (safe-index min-start) line-start)
118 ((= (safe-index min-start) line-start)
114 line-start)
119 line-start)
115 ((find-newline :start min-start
120 ((find-newline :start min-start
116 :end (1- line-start)))
121 :end (1- line-start)))
117 (t
122 (t
118
123
119 line-start)))
124 line-start)))
120 (end (or (find-newline :start position
125 (end (or (find-newline :start position
121 :end max-end
126 :end max-end
122 :from-end nil)
127 :from-end nil)
123 (safe-index max-end)))
128 (safe-index max-end)))
124 (*print-circle* nil))
129 (*print-circle* nil))
125 (txt2web::lformat stream :error
130 (txt2web::lformat stream :error
126 (= position (length text))
131 (= position (length text))
127 (list (subseq text start end))
132 (list (subseq text start end))
128 (- position line-start)
133 (- position line-start)
129 (1+ line) (1+ column) position)))
134 (1+ line) (1+ column) position)))
130
135
131 (format stream "~2&<text and position not available>~2%")))
136 (format stream "~2&<text and position not available>~2%")))
@@ -1,26 +1,51 b''
1
1
2 (in-package txt2web)
2 (in-package txt2web)
3
3
4 (defvar *delivered* nil)
4 (defvar *delivered* nil)
5
5
6 (defun src-file (filename)
6 (defun src-file (filename)
7 (uiop/pathname:merge-pathnames*
7 (uiop/pathname:merge-pathnames*
8 filename
8 filename
9 (asdf:system-source-directory :txt2web)))
9 (asdf:system-source-directory :txt2web)))
10
10
11 (defun read-progn-from-string (string)
11 (defun read-progn-from-string (string)
12 `(progn
12 `(progn
13 ,@(read-code-from-string string)))
13 ,@(read-code-from-string string)))
14
14
15 (defun read-code-from-string (string)
15 (defun read-code-from-string (string)
16 (with-input-from-string (in string)
16 (with-input-from-string (in string)
17 (let ((*package* *package*))
17 (let ((*package* *package*))
18 (loop :for form := (read in nil :eof)
18 (loop :for form := (read in nil :eof)
19 :until (eq form :eof)
19 :until (eq form :eof)
20 :when (eq (first form) 'cl:in-package)
20 :when (eq (first form) 'cl:in-package)
21 :do (setf *package* (find-package (second form)))
21 :do (setf *package* (find-package (second form)))
22 :else
22 :else
23 :collect form))))
23 :collect form))))
24
24
25 (defun load-src (filename)
25 (defun load-src (filename)
26 (alexandria:read-file-into-string (src-file filename)))
26 (alexandria:read-file-into-string (src-file filename) :external-format :utf-8))
27
28 ;;;; For testing
29
30 (defvar *dont-expand* '(setf))
31
32 (defun should-expand (form)
33 (cond ((not (listp form))
34 nil)
35 ((listp (car form))
36 t)
37 ((member (car form) *dont-expand*)
38 nil)
39 ((not (symbolp (car form)))
40 nil)
41 ((not (eq (symbol-package (car form))
42 (find-package :parenscript)))
43 t)))
44
45 (defun ps-macroexpand-all (form)
46 (if (should-expand form)
47 (let ((form (ps::ps-macroexpand form)))
48 (if (listp form)
49 (mapcar #'ps-macroexpand-all form)
50 form))
51 form))
General Comments 0
You need to be logged in to leave comments. Login now