Correction de bugs sur l'initialisation parallèle du for, remise en route du with, ajour du collect et du append.

This commit is contained in:
Georges Dupéron 2010-11-21 08:11:35 +01:00
parent d17bbb8990
commit bea5dc4765

View File

@ -1,15 +1,18 @@
(defmacro dbg (x) `(print ,x))
(defmacro dbg (x) nil)
;; TODO : remplacer les deux my-loop-finish par loop-finish à la fin.
(defun transform-loop (expr)
(let* ((name nil)
(acc (make-symbol "acc"))
(acc (make-symbol "ACC"))
(acc-tail (make-symbol "ACC-TAIL"))
(first-sym (make-symbol "FIRST"))
(variables nil)
(all-variables nil)
(result nil)
(initialization nil)
(loopbody nil)
(loopbody-sym (make-symbol "LOOPBODY"))
(finally nil)
(finally-sym (make-symbol "FINALLY"))
(loop-keywords '(named
with for as repeat
initially finally
@ -21,23 +24,28 @@
if when unless else end
and))
(stack nil)
; (group-with nil)
(repeat-sym nil)
(destination nil)
(with-initial-values nil)
(for-clause-type nil)
(for-getter-fun nil)
(for-initial-value nil)
(for-step-fun nil)
(for-end-predicate nil)
(for-numeric-direction nil)
(for-numeric-start nil)
(for-numeric-end nil)
(for-numeric-step nil)
(for-numeric-limit nil)
(for-initially-psetq nil)
(for-initially-affect nil)
(storage-sym nil)
(vars-names nil)
(get-vars-and-types-end-keywords nil)
(destr-psetq nil)
(left-destr nil)
(right-destr nil)
(destr-whole-sym (make-symbol "whole"))
(top-variables `((,acc nil)
(,destr-whole-sym nil))))
(destr-whole-sym (make-symbol "WHOLE")))
(macrolet ((advance (x) `(setq ,x (cdr ,x))))
(tagbody
start
@ -65,6 +73,13 @@
(when (endp expr) (go end-parse))
(case (car expr)
(do (go do))
(collect (go collect))
(append (go append))
(nconc (go nconc))
(sum (go sum))
(count (go count))
(minimize (go minimize))
(maximize (go maximize))
(initially (push 'prologue stack) (go initially))
(finally (push 'prologue stack) (go finally))
(otherwise
@ -72,32 +87,78 @@
(error "bootstrap : invalid syntax in loop form : ~w." expr)))
(go main)
collect
(advance expr)
(if (endp expr) (error "bootstrap : loop : expected expression after collect but found the end of the loop form."))
(if (member expr loop-keywords) (error "bootstrap : loop : loop keyword ~w can't appear here." (car expr)))
(push `(if ,acc
(setq ,acc-tail (cdr (rplacd ,acc-tail (cons ,(car expr) nil))))
(setq ,acc-tail (setq ,acc (cons ,(car expr) nil))))
loopbody)
(advance expr)
(go main)
append
(advance expr)
(if (endp expr) (error "bootstrap : loop : expected expression after append but found the end of the loop form."))
(if (member expr loop-keywords) (error "bootstrap : loop : loop keyword ~w can't appear here." (car expr)))
(push `(if ,acc
(setq ,acc-tail (last (rplacd ,acc-tail (copy-list ,(car expr)))))
(setq ,acc-tail (last (setq ,acc (copy-list ,(car expr))))))
loopbody)
(advance expr)
(go main)
nconc
(error "niy")
(go main)
sum
(error "niy")
(go main)
count
(error "niy")
(go main)
minimize
(error "niy")
(go main)
maximize
(error "niy")
(go main)
with
(dbg 'with)
(error "broken for now")
;; (advance expr)
;; with-loop
;; (dbg 'with-loop)
;; (setq group-with nil)
;; (push 'with stack)
;; (setq affect-destr-keywords '(=)) ;; '(= in) pour le for.
;; (go destructuring)
;; (when (eq 'and (car expr))
;; (go with-loop))
;; (push variables all-variables)
;; (setq variables nil)
;; (go prologue)
(advance expr)
(setq get-vars-and-types-end-keywords '(=))
(push 'with-got-vars stack)
(go get-vars-and-types)
with-got-vars
(setq with-initial-values nil)
(when (eq '= (car expr))
(advance expr)
(setq with-initial-values (car expr))
(advance expr))
with-make-let
(dbg 'with-make-let)
(setq left-destr vars-names)
(setq right-destr with-initial-values)
(push 'end-with stack)
(go destructuring-let)
end-with
(push variables all-variables)
(push nil all-variables)
(setq variables nil)
(when (eq 'and (car expr))
(go with))
(go prologue)
for
(dbg 'for)
(advance expr)
(advance expr) ;; gobble for / and
;; (for vars in values)
;; (for vars on values)
;; (for vars = values [then expr])
;; (for vars across vector) ;; non implémenté
;; being : hash et package non supportés.
;; (for var [from/downfrom/upfrom expr1] [to/downto/upto/below/above expr2] [by expr3])
(setq storage-sym (make-symbol "storage-for"))
(setq storage-sym (make-symbol "STORAGE-FOR"))
(setq get-vars-and-types-end-keywords '(in on = across being from downfrom upfrom to downto upto below above by))
(push 'for-got-vars stack)
(go get-vars-and-types)
@ -148,11 +209,11 @@
(go for-make-let)
numeric-for
(setq for-initial-value 0)
(setq for-getter-fun storage-sym)
(setq for-step-fun `(+ ,storage-sym 1))
(setq for-numeric-direction 0)
(setq for-end-predicate t)
(setq for-numeric-start 0)
(setq for-numeric-step 1)
(setq for-numeric-direction 0)
(setq for-numeric-end 0)
(when (member (car expr) '(from upfrom downfrom))
(when (eq 'downfrom (car expr)) (setq for-numeric-direction -1))
(when (eq 'upfrom (car expr)) (setq for-numeric-direction 1))
@ -172,66 +233,87 @@
(setq for-numeric-direction 1))
(advance expr)
(when (endp expr) (error "bootstrap : loop : expected expression after ~w but found the end of the loop form." for-numeric-limit))
(setq for-numeric-end (car expr))
(case for-numeric-limit
(to (if (= for-numeric-direction -1)
(setq for-end-predicate `(< ,storage-sym ,(car expr)))
(setq for-end-predicate `(> ,storage-sym ,(car expr)))))
(downto (setq for-end-predicate `(< ,storage-sym ,(car expr))))
(upto (setq for-end-predicate `(> ,storage-sym ,(car expr))))
(below (setq for-end-predicate `(>= ,storage-sym ,(car expr))))
(above (setq for-end-predicate `(<= ,storage-sym ,(car expr)))))
(setq for-end-predicate `(< (car ,storage-sym) (third ,storage-sym)))
(setq for-end-predicate `(> (car ,storage-sym) (third ,storage-sym)))))
(downto (setq for-end-predicate `(< (car ,storage-sym) (third ,storage-sym))))
(upto (setq for-end-predicate `(> (car ,storage-sym) (third ,storage-sym))))
(below (setq for-end-predicate `(>= (car ,storage-sym) (third ,storage-sym))))
(above (setq for-end-predicate `(<= (car ,storage-sym) (third ,storage-sym)))))
(advance expr))
(when (eq 'by (car expr))
(advance expr)
(when (endp expr) (error "bootstrap : loop : expected expression after by but found the end of the loop form."))
(setq for-step-fun `(+ ,storage-sym ,(* (if (= for-numeric-direction -1) -1 1)
(car expr))))
(setq for-numeric-step (car expr))
(advance expr))
(setq for-initial-value `(list ,for-numeric-start ,for-numeric-step ,for-numeric-end))
(if (= -1 for-numeric-direction)
(setq for-step-fun `(cons (- (car ,storage-sym) (second ,storage-sym)) (cdr ,storage-sym)))
(setq for-step-fun `(cons (+ (car ,storage-sym) (second ,storage-sym)) (cdr ,storage-sym))))
(setq for-getter-fun `(car ,storage-sym))
(go for-make-let)
vector-for
(error "bootstrap : loop : syntax (loop for var across vector) not implemented yet !")
(go end-for)
(go for-end)
hash-package-for
(error "bootstrap : loop : looping across hashes and packages is not implemented yet !")
(go end-for)
(go for-end)
for-make-let
(push `(,storage-sym ,for-initial-value) variables)
(push `(,storage-sym nil) variables)
(setq left-destr vars-names)
(push 'for-make-psetq stack)
(push 'for-make-initially-psetq stack)
(go destructuring-empty-let)
;; (setq left-destr vars-names)
;; (setq right-destr `(funcall ,for-getter-fun (setq ,storage-sym ,for-initial-value)))
;; (push 'for-make-psetq stack)
;; (go destructuring-let)
for-make-psetq
(unless (eq t for-end-predicate)
(push `(when ,for-end-predicate (go finally)) loopbody))
for-make-initially-psetq
(push storage-sym for-initially-psetq)
(push for-initial-value for-initially-psetq)
(setq left-destr vars-names)
(setq right-destr for-getter-fun)
(push 'for-push-psetq stack)
(psetq for-initially-affect destr-psetq destr-psetq for-initially-affect) ;; exchange
(push 'for-make-body-psetq stack)
(go destructuring-psetq)
for-push-psetq
(push destr-psetq loopbody)
(push `(setq ,storage-sym ,for-step-fun) loopbody)
;; (go end-for)
end-for
for-make-body-psetq
(psetq destr-psetq for-initially-affect for-initially-affect destr-psetq) ;; re-exchange
(unless (eq storage-sym for-step-fun)
(push `(unless ,first-sym (setq ,storage-sym ,for-step-fun)) loopbody))
(unless (eq t for-end-predicate)
(push `(when ,for-end-predicate (go ,finally-sym)) loopbody))
(setq left-destr vars-names)
(setq right-destr for-getter-fun)
(push 'for-end stack)
(go destructuring-psetq)
for-end
(when (eq 'and (car expr)) (go for))
(push variables all-variables)
(push `((setq ,@(reverse for-initially-psetq))
(setq ,@(reverse for-initially-affect)))
all-variables)
(setq variables nil)
(setq for-initially-psetq nil)
(setq for-initially-affect nil)
(push `(setq ,@(reverse destr-psetq)) loopbody)
(setq destr-psetq nil)
(go prologue)
repeat
(dbg 'repeat)
(advance expr)
(let ((repeat-sym (make-symbol "repeat-counter")))
(push `((,repeat-sym ,(car expr))) all-variables)
(push `(setq ,repeat-sym (- ,repeat-sym 1)) loopbody)
(push `(when (< ,repeat-sym 0) (go finally)) loopbody))
(setq repeat-sym (make-symbol "REPEAT-COUNTER"))
(push `((,repeat-sym ,(car expr))) all-variables)
(push nil all-variables)
(push `(setq ,repeat-sym (- ,repeat-sym 1)) loopbody)
(push `(when (< ,repeat-sym 0) (go ,finally-sym)) loopbody)
(advance expr)
(go prologue)
do
(dbg 'do)
(advance expr)
@ -312,26 +394,25 @@
;; Cas sans destructuring
(unless (consp left-destr)
(setq destr-psetq `(setq ,left-destr ,right-destr))
(push left-destr destr-psetq)
(push right-destr destr-psetq)
(go destr-psetq-end))
(setq destr-psetq `((car (setq ,destr-whole-sym ,right-destr)) ,(car left-destr) psetq)) ;; in reverse order
(push (car left-destr) destr-psetq)
(push `(car (setq ,destr-whole-sym ,right-destr)) destr-psetq)
(advance left-destr)
destr-psetq-loop
(dbg 'destr-psetq-loop)
(when (endp left-destr)
(go destr-psetq-reverse-end))
(go destr-psetq-end))
(when (atom left-destr)
(push left-destr destr-psetq)
(push destr-whole-sym destr-psetq)
(go destr-psetq-reverse-end))
(go destr-psetq-end))
(push (car left-destr) destr-psetq)
(push `(car (setq ,destr-whole-sym (cdr ,destr-whole-sym))) destr-psetq)
(advance left-destr)
(go destr-psetq-loop)
destr-psetq-reverse-end
(dbg 'destr-psetq-reverse-end)
(setq destr-psetq (reverse destr-psetq))
destr-psetq-end
(dbg 'destr-psetq-end)
(go return)
@ -406,57 +487,73 @@
finally-end
(dbg 'finally-end)
(go return)
return
(dbg 'return)
(when (endp stack) (error "bootstrap : loop : internal error : call stack is empty !"))
(let ((destination (car stack)))
(setq stack (cdr stack))
(case destination
(prologue (go prologue))
(with (go with))
(main (go main))
(for-got-vars (go for-got-vars))
(for-make-psetq (go for-make-psetq))
(for-push-psetq (go for-push-psetq))
(otherwise (error "bootstrap : loop : internal error : invalid return point on call stack : ~w" destination))))
(setq destination (car stack))
(setq stack (cdr stack))
(case destination
(prologue (go prologue))
(main (go main))
(with-got-vars (go with-got-vars))
(end-with (go end-with))
(for-got-vars (go for-got-vars))
(for-make-initially-psetq (go for-make-initially-psetq))
(for-make-body-psetq (go for-make-body-psetq))
(for-end (go for-end))
(otherwise (error "bootstrap : loop : internal error : invalid return point on call stack : ~w" destination)))
end-parse
(dbg 'end-parse)
make-body
(dbg 'make-body)
(setq finally `(progn ,@(reverse (cons `(return-from ,name ,acc) finally))))
(setq initialization (reverse initialization))
(setq loopbody (reverse loopbody))
(setq result
`(tagbody
initialization
(progn ,@(reverse initialization))
loopbody
(progn ,@(reverse loopbody))
(go loopbody)
finally
(progn ,@(reverse finally))
implicit-return
(return-from ,name ,acc)))
`(macrolet ((my-loop-finish () '(go ,finally-sym)))
(tagbody
(progn ,@initialization)
,loopbody-sym
(progn ,@loopbody)
(setq ,first-sym nil)
(go ,loopbody-sym)
,finally-sym
,finally)))
build-lets-loop
(dbg 'build-lets-loop)
(when (endp all-variables)
(go build-block-and-let))
(setq result `(let ,(reverse (car all-variables)) ,result))
(setq result `(let ,(reverse (cadr all-variables)) ,@(car all-variables) ,result))
(advance all-variables)
(advance all-variables)
(go build-lets-loop)
build-block-and-let
(dbg 'build-block-and-lets)
(setq result
`(block ,name (let ,top-variables
,acc
,destr-whole-sym
,result)))
`(block ,name
(let ((,acc nil)
(,acc-tail nil)
(,destr-whole-sym nil)
(,first-sym t))
,acc
,acc-tail
,destr-whole-sym
,first-sym
;; If you call loop-finish during variable declarations, and you use variables that haven't been initialized,
;; then it will fail / use variables from the surrounding environment. But it's you freakin' problem if you do
;; such bizarre things.
(macrolet ((my-loop-finish () ',finally))
,result))))
the-end
(dbg 'the-end)
))
;; music
rideau))
result))
;; (eval (transform-loop '(for (i j) in '((1 1) (2 4) (3 9)) do (print i))))
;; (eval (transform-loop '(for (i j) in '((1 1) (2 4) (3 9)) for k from 0 to 5 do (format t "~&~a ~a ~a" i j k) initially (print 'i) finally (print 'f) (print i))))
;; (eval (transform-loop '(for i = 42 and j in (list 1 i 3) for k = i then (cons i j) collect (list i j k))))
#|
(loop (print 5))