1 (in-package #:avm2-compiler
)
3 ;;; pieces of sicl/iteration.lisp that work so far
5 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
9 (define-condition expected-symbol
(program-error)
10 ((%found
:initarg
:found
:reader found
))
12 (lambda (condition stream
)
13 (princ "Expected a symbol but found: " stream
)
14 (print (found condition
) stream
))))
16 (define-condition malformed-body
(program-error)
17 ((%body
:initarg
:body
:reader body
))
19 (lambda (condition stream
)
20 (princ "Expected a body in the form of" stream
)
22 (princ "a proper list, but found: ")
23 (print (body condition
) stream
))))
25 (define-condition malformed-variable-clauses
(program-error)
26 ((%found
:initarg
:found
:reader found
))
28 (lambda (condition stream
)
29 (princ "Expected a proper list of variable clauses," stream
)
31 (princ "but found: " stream
)
32 (print (found condition
) stream
))))
34 (define-condition malformed-variable-clause
(program-error)
35 ((%found
:initarg
:found
:reader found
))
37 (lambda (condition stream
)
38 (princ "Expected a variable clause of the form" stream
)
40 (princ "var, (var), (var init-form), or (var init-form step-form),"
43 (princ "but found: " stream
)
44 (print (found condition
) stream
))))
46 (define-condition malformed-end-test
(program-error)
47 ((%found
:initarg
:found
:reader found
))
49 (lambda (condition stream
)
50 (princ "Expected an end test clause of the form" stream
)
52 (princ "(end-test result-form*)," stream
)
54 (princ "but found: " stream
)
55 (print (found condition
) stream
))))
57 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
61 ;;; Split a body into declarations and forms.
62 (defun split-body (body &optional declarations
)
64 (not (consp (car body
)))
65 (not (eq (caar body
) 'declare
)))
66 (values (nreverse declarations
) body
)
67 (split-body (cdr body
) (cons (car body
) declarations
))))
69 ;;; Check that an object is a proper list
70 (defun proper-list-p (object)
73 (proper-list-p (cdr object
)))))
75 ;;; For do and do* we need to map over the variable binding clauses.
76 ;;; We therefore need mapcar or something similar. But in order to
77 ;;; avoid introducing a dependency on sequence operations, we define
78 ;;; our own mapcar using only recursion.
80 (defun local-mapcar (function list
)
83 (cons (funcall function
(car list
))
84 (local-mapcar function
(cdr list
)))))
86 (let ((*symbol-table
* *cl-symbol-table
*))
88 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
90 ;;; Macros dolist and dotimes
92 ;;; The spec says that the variable is bound to nil when the
93 ;;; result-form is evaluated. But we don't want the declarations to
94 ;;; have to include nil as one of the values of var. For that reason,
95 ;;; there needs to be a different binding of the variable when the
96 ;;; forms of the body are evaluated and when the result-form is
99 ;;; The spec says we have a choice between binding or assigning the
100 ;;; variable in each iteration. For dolist, choosing assignment gets
101 ;;; complicated in the first iteration though, because we would have
102 ;;; to come up with an initial value of the variable that is
103 ;;; compatible with the declarations. For that reason, we choose to
106 (swf-defmacro dolist
((var list-form
&optional result-form
) &body body
)
107 (progn;; do some syntax checking
108 (unless (symbolp var
)
109 (error 'expected-symbol
:found var
))
110 (unless (proper-list-p body
)
111 (error 'malformed-body
:body body
))
112 (multiple-value-bind (declarations forms
)
114 (let ((start-tag (gensym "START"))
115 (end-tag (gensym "END"))
116 (list-var (gensym "LIST-VAR")))
117 `(let ((,list-var
,list-form
))
121 (when (endp ,list-var
)
123 (let ((,var
(car ,list-var
)))
130 #+nil
(declare (ignorable ,var
))
133 ;;; For dotimes, we don't have the problem of initial value which is
134 ;;; always 0, so we can bind the variable once for the entire loop
137 (swf-defmacro dotimes
((var count-form
&optional result-form
) &body body
)
138 ;; do some syntax checking
139 (unless (symbolp var
)
140 (error 'expected-symbol
:found var
))
141 (unless (proper-list-p body
)
142 (error 'malformed-body
:body body
))
143 (multiple-value-bind (declarations forms
)
145 (let ((start-tag (gensym))
147 (count-var (gensym)))
148 `(let ((,count-var
,count-form
)
150 #+nil
(declare (type integer
,var
))
155 (when (= ,var
,count-var
)
162 #+nil
(declare (ignorable ,var
))
165 (defun check-variable-clauses (variable-clauses)
166 (unless (proper-list-p variable-clauses
)
167 (error 'malformed-variable-clauses
:found variable-clauses
))
170 (unless (or (symbolp clause
)
172 (symbolp (car clause
))
173 (or (null (cdr clause
))
175 (null (cdddr clause
)))))
176 (error 'malformed-variable-clause
180 (defun extract-bindings (variable-clauses)
183 (cond ((symbolp clause
) clause
)
184 ((null (cdr clause
)) (car clause
))
185 (t (list (car clause
) (cadr clause
)))))
188 (defun extract-updates (variable-clauses)
189 (if (null variable-clauses
) '()
190 (let ((clause (car variable-clauses
)))
191 (if (and (consp clause
)
192 (not (null (cddr clause
))))
195 (extract-updates (cdr variable-clauses
)))
196 (extract-updates (cdr variable-clauses
))))))
198 #+nil
(swf-defmacro do
(variable-clauses end-test
&body body
)
199 ;; do some syntax checking
200 (check-variable-clauses variable-clauses
)
201 (unless (proper-list-p body
)
202 (error 'malformed-body
:body body
))
203 (unless (and (proper-list-p end-test
)
204 (not (null end-test
)))
205 (error 'malformed-end-test
:found end-test
))
206 (multiple-value-bind (declarations forms
)
208 (let ((start-tag (gensym)))
210 (let ,(extract-bindings variable-clauses
)
214 (when ,(car end-test
)
216 (progn ,@(cdr end-test
))))
218 (psetq ,@(extract-updates variable-clauses
))
219 (go ,start-tag
)))))))
221 #+nil
(defmacro do
* (variable-clauses end-test
&body body
)
222 ;; do some syntax checking
223 (check-variable-clauses variable-clauses
)
224 (unless (proper-list-p body
)
225 (error 'malformed-body
:body body
))
226 (unless (and (proper-list-p end-test
)
227 (not (null end-test
)))
228 (error 'malformed-end-test
:found end-test
))
229 (multiple-value-bind (declarations forms
)
231 (let ((start-tag (gensym)))
233 (let* ,(extract-bindings variable-clauses
)
237 (when ,(car end-test
)
239 (progn ,@(cdr end-test
))))
241 (setq ,@(extract-updates variable-clauses
))
242 (go ,start-tag
))))))))
245 #+nil
(dump-defun-asm ()
247 (dolist (a (cons "a" (cons "b" (cons "c" nil
)))
249 (%set-local temp
(+ temp
(:to-string a
))))))