www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 05222c00c4cad591bfc23cd9206edd33dafae2c1
parent c49cecb1abf93a9e37a8be5de1534981468ff724
Author: Georges Dupéron <jahvascriptmaniac+github@free.fr>
Date:   Sat,  8 Jan 2011 22:51:53 +0100

squash-lisp-1 : 90% (il manque les tests unitaires).

Diffstat:
Alisp/notes/lambda-parameters.txt | 7+++++++
Mlisp/squash-lisp-1.lisp | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mlisp/squash-lisp-2.lisp | 11+++++------
3 files changed, 92 insertions(+), 36 deletions(-)

diff --git a/lisp/notes/lambda-parameters.txt b/lisp/notes/lambda-parameters.txt @@ -0,0 +1,7 @@ +implémentation de sbcl : + +; in: LAMBDA (#:WHOLE2122 #:ENVIRONMENT2123) +; (LET* ((OBJECT (CAR (CDR #:WHOLE2122))) +; (BODY (CAR (CDR #))) +; (CATCH-CODE (CAR (CDR #)))) +; (BLOCK TAGBODY-UNWIND-CATCH CATCH-CODE `(TAGBODY ,@(CDR BODY)))) diff --git a/lisp/squash-lisp-1.lisp b/lisp/squash-lisp-1.lisp @@ -131,22 +131,22 @@ (setf (car zone) unique-label-sym)) (squash-lisp-1 `(let ((,tagbody-id-sym (cons nil nil))) - (unwind-catch ,tagbody-id-sym - (progn - ,@(progn (dolist (zone spliced-body) - (push `(jump-label ,(car zone)) res) - (push `(progn ,@(cdr zone)) res)) - ;; (cdr (reverse …)) pour zapper le tout premier (jump-label …) - (cdr (reverse res)))) - nil) + (tagbody-unwind-catch ,tagbody-id-sym + (progn + ,@(progn (dolist (zone spliced-body) + (push `(jump-label ,(car zone)) res) + (push `(progn ,@(cdr zone)) res)) + ;; (cdr (reverse …)) pour zapper le tout premier (jump-label …) + (cdr (reverse res)))) + nil) nil) nil new-etat))) - ((go :target $$) + ((go :target (? or symbolp numberp)) (let ((association (assoc-etat target 'squash-tagbody-catch etat))) (unless association (error "Squash-Lisp-1 : Can't go to label ~w, it is inexistant or not lexically apparent." target)) - (squash-lisp-1 `(progn (half-unwind ,(cadr association) + (squash-lisp-1 `(progn (unwind-for-tagbody ,(cadr association) (jump ,(cddr association)))) nil etat))) @@ -171,21 +171,21 @@ `(unwind-protect ,(squash-lisp-1 body nil etat) ,(squash-lisp-1 a-cleanup nil etat))) - ((unwind-catch :object _ :body _ :catch-code _) - `(unwind-catch ,(squash-lisp-1 object nil etat) - ,(squash-lisp-1 body nil etat) - ,(squash-lisp-1 catch-code nil etat))) + ((:type (? (member x '(unwind-catch tagbody-unwind-catch))) :object _ :body _ :catch-code _) + `(,type ,(squash-lisp-1 object nil etat) + ,(squash-lisp-1 body nil etat) + ,(squash-lisp-1 catch-code nil etat))) ((unwind :object _) `(unwind ,(squash-lisp-1 object nil etat))) - ((half-unwind :object _ :post-unwind-code _) - `(half-unwind ,(squash-lisp-1 object nil etat) ,(squash-lisp-1 post-unwind-code nil etat))) + ((unwind-for-tagbody :object _ :post-unwind-code _) + `(unwind-for-tagbody ,(squash-lisp-1 object nil etat) ,(squash-lisp-1 post-unwind-code nil etat))) - ((jump-label :name _) + ((jump-label :name $$) expr) - ((jump :dest _) + ((jump :dest $$) expr) ;; Transformation des (let[*] (var1 var2 var3) …) en (let[*] ((var1 nil) (var2 nil) (var3 nil)) …) @@ -201,15 +201,15 @@ ,(squash-lisp-1 `(progn ,@body) nil etat))) ((flet ((:name $$ :params @ :fbody _*)*) :body _*) - `(simple-flet ,@(mapcar (lambda (name params fbody) - (cons name (squash-lisp-1 `(lambda ,params (progn ,@fbody)) nil etat))) - name params fbody) + `(simple-flet ,(mapcar (lambda (name params fbody) + (list name (squash-lisp-1 `(lambda ,params (progn ,@fbody)) nil etat))) + name params fbody) ,(squash-lisp-1 `(progn ,@body) nil etat))) ((labels ((:name $$ :params @ :fbody _*)*) :body _*) - `(simple-labels ,@(mapcar (lambda (name params fbody) - (cons name (squash-lisp-1 `(lambda ,params (progn ,@fbody)) nil etat))) - name params fbody) + `(simple-labels ,(mapcar (lambda (name params fbody) + (list name (squash-lisp-1 `(lambda ,params (progn ,@fbody)) nil etat))) + name params fbody) ,(squash-lisp-1 `(progn ,@body) nil etat))) ;; TODO : defun @@ -272,6 +272,54 @@ (_ (error "squash-lisp-1: Not implemented yet : ~a" expr)))) +(defun squash-lisp-1-wrap (expr) + `(macrolet ((unwind-catch (object body catch-code) + (let ((bname (make-symbol "block"))) + `(block ,bname + (catch ,object (return-from ,bname ,body)) + ,catch-code + nil))) + (tagbody-unwind-catch (object body catch-code) + catch-code ;; unused variable + ;; les (progn object) et (progn x) sert à permettre l'expansion des macros sur x + ;; (il est possible qu'elles ne soient pas expansées à la racine du tagbody) + `(tagbody (progn ,object) ,@(mapcar (lambda (x) (if (eq (car x) 'jump-label) (cadr x) (progn x))) (cdr body)))) + (unwind (object) + `(throw ,object nil)) + (unwind-for-tagbody (object post-unwind-code) + object ;; unused variable + post-unwind-code) + ;;Les macros ne sont pas expansées à la racine d'un tagbody, donc on expanse à la main + ;; les jump-label lorsqu'on rencontre un tagbody-unwind-catch. + ;;(jump-label (name) + ;; name) + (jump (dest) + `(go ,dest)) + (simple-flet (spec &rest body) + `(flet ,(mapcar (lambda (x) (list (car x) (second (second x)) (third (second x)))) spec) ;; nom, lambda-list, fbody + ,@body)) + (simple-labels (spec &rest body) + `(labels ,(mapcar (lambda (x) (list (car x) (second (second x)) (third (second x)))) spec) ;; nom, lambda-list, fbody + ,@body)) + (get-var (x) + x)) + ,expr)) + +(eval (squash-lisp-1-wrap + '(unwind-catch 'foo + (progn (print 1) + (unwind 'foo) + (print 2)) + (print 3)))) + +(eval (squash-lisp-1-wrap (squash-lisp-1 '(flet ((foo (x) (+ x 1)) (bar (y z) (cons y z))) (list (foo 3) (bar 4 5)))))) + +(eval (squash-lisp-1-wrap (squash-lisp-1 '(tagbody a 1 (print 'x) b (print 'y) (go 3) d (print 'z) 3 (print 'f))))) + +;; +;; (squash-lisp-1 '(flet ((foo (x) (+ x 1)) (bar (y z) (cons y z))) (list (foo 3) (bar 4 5)))) + + (defun squash-lisp-1-check (expr) "Vérifie si expr est bien un résultat valable de squash-lisp-1. Permet aussi d'avoir une «grammaire» du simple-lisp niveau 1. @@ -283,18 +331,19 @@ Attention : il y a quelques invariants qui ne sont pas présents dans cette vér ((unwind-protect :body _ :cleanup _) (and (squash-lisp-1-check body) (squash-lisp-1-check cleanup))) - ((unwind-catch :object _ :body _ :catch-code _) + ;; tagbody-unwind-catch est équivalent à unwind-catch, mais nécessaire pour les macrolet. + (((? (member x '(unwind-catch tagbody-unwind-catch))) :object _ :body _ :catch-code _) (and (squash-lisp-1-check object) (squash-lisp-1-check body) (squash-lisp-1-check catch-code))) ((unwind :object _) (squash-lisp-1-check object)) - ((half-unwind :object _ :post-unwind-code _) + ((unwind-for-tagbody :object _ :post-unwind-code _) (and (squash-lisp-1-check object) (squash-lisp-1-check post-unwind-code))) - ((jump-label :name _) ;; TODO : être plus précis que "_" + ((jump-label :name $$) t) - ((jump :dest _) ;; TODO : être plus précis que "_" + ((jump :dest $$) t) (((? (member x '(let let* simple-flet simple-labels))) ((:name $$ :value _)*) :body _) (every #'squash-lisp-1-check (cons body value))) @@ -311,7 +360,8 @@ Attention : il y a quelques invariants qui ne sont pas présents dans cette vér ((setq :name $$ :value _) (squash-lisp-1-check value)) (_ - (error "squash-lisp-1-check: Assertion failed ! This should not be here : ~a" expr)))) + (warn "squash-lisp-1-check: Assertion failed ! This should not be here : ~a" expr) + nil))) #| Notes sur l'implémentation d'unwind. @@ -352,7 +402,7 @@ jmp @after-protect-code jmp @start-unwind @after-protect-code -(half-unwind object post-unwind-code) est compilé ainsi : +(unwind-for-tagbody object post-unwind-code) est compilé ainsi : jsr @find-unwind-destination mov [immediate]@post-unwind-code @singleton-post-unwind-code add 3 sp ;; On "re-push" l'adresse de la cible, l'objet et le marqueur, mettre 2 au lieu de 3 si on n'a pas de marqueur. diff --git a/lisp/squash-lisp-2.lisp b/lisp/squash-lisp-2.lisp @@ -9,6 +9,9 @@ expr ((progn :body _*) `(progn ,@(mapcar (lambda (x) (squash-lisp-2 x env-var env-fun globals)) body))) + ;; simple-tagbody est équivalent à un progn, mais nécessaire pour les macrolet. + ((simple-tagbody :body _*) + `(simple-tagbody ,@(mapcar (lambda (x) (squash-lisp-2 x env-var env-fun globals)) body))) ((unwind-protect :body _ :cleanup _) `(unwind-protect ,(squash-lisp-2 body env-var env-fun globals) ,(squash-lisp-2 cleanup env-var env-fun globals))) @@ -21,11 +24,9 @@ ((half-unwind :object _ :post-unwind-code _) `(half-unwind ,(squash-lisp-2 object env-var env-fun globals) ,(squash-lisp-2 post-unwind-code env-var env-fun globals))) - ;; TODO : symbole ? - ((jump-label :name _) ;; TODO : être plus précis que "_" + ((jump-label :name $$) expr) - ;; TODO : symbole ? - ((jump :dest _) ;; TODO : être plus précis que "_" + ((jump :dest $$) expr) ((let ((:name $$ :value _)*) :body _) (setq name (mapcar (lambda (x) (cons x (derived-symbol x))) name)) @@ -73,11 +74,9 @@ ,@(mapcar (lambda (x) (squash-lisp-2 x env-var env-fun globals)) params))) ((quote _) expr) - ;; TODO ((get-var :var $$) (assoc-or var env-var (assoc-or-push var (derived-symbol var) (car globals)))) - ;; TODO ((setq :name $$ :value _) `(setq ,(assoc-or name env-var (assoc-or-push name (derived-symbol name) (car globals)))