; .EnTete "Le-Lisp (c) version 15.2" " " "Les Macros du Compilateur" ; .EnPied " " "%" " " ; .sp 2 ; .SuperTitre "Les Macros du Compilateur" ; ; .Centre "*****************************************************************" ; .Centre " Ce fichier est en lecture seule hors du projet ALE de l'INRIA. " ; .Centre " Il est maintenu par ILOG SA, 2 Avenue Gallie'ni, 94250 Gentilly " ; .Centre " (c) Le-Lisp est une marque de'pose'e de l'INRIA " ; .Centre "*****************************************************************" ; .Centre "$Header: cpmac.ll,v 4.6 88/12/27 01:42:49 nuyens Exp $" (unless (>= (version) 15.2) (error 'load 'erricf 'cpmac)) ; Les macros de l'interpre`te (DM et DMD) sont une tre`s bonne chose ; pour le compilateur qui ne va compiler que le re'sultat des ; expansions. Cette technique est si bonne qu'on va rede'finir ; des fonctions standard sous forme de macros spe'ciales, les ; \fImacros du compilateur\fR. Il en existe de 2 sortes\ : ; .br ; - les macros ferme'es (:macro-close) qui sont toujours exe'cute'es ; .br ; - les macros ouvertes (:macro-open) qui ne sont exe'cute'es que si ; l'indicateur global :OPEN-P est vrai. ; .Section "Les Variables Globales" ; Tous les symboles pre'fixe's par : seront cre'e's dans le ; package COMPILER. (defvar #:sys-package:colon 'compiler) ; #:compiler:open-p : indique que les compilations open ; (voir la section suivante) sont autorise'es. ; Une compilation open peut donner des re'sultats ; diffe'ents de ceux de l'interpre`te en cas de mauvais type d'arguments. (defvar :open-p t) ; .Section "De'finitions des Macros" (df defmacro-open (name . fval) (setfn (symbol name 'macro-open) 'expr fval) name) (de make-macro-open (nom fval) (setfn (symbol nom 'macro-open) 'expr fval) nom) (de macro-openp (nom) (getfn1 nom 'macro-open)) (de remove-macro-open (nom) (when (getsymb1 nom 'macro-open) (remob (getsymb1 nom 'macro-open)))) ; .Section "Les Fonctions Exporte'es" (de :macro-expand-error (l) ; peut (et doit) e^tre rede'finie (error ':macro-expand-error "erreur durant la macroexpansion" l)) (de :macroexpand (l) ; expanse la forme . (if (and (consp l) (symbolp (car l))) (let ((x ()) (cl (car l)) (cd (cdr l))) (setq x (catcherror () (cond ((and :open-p (setq x (getfn1 cl 'macro-open))) ; Macros ouvertes du compilateur. ; Si elle retourne (), la macro est surcharge'e ; et n'est plus effective. (or (apply x (cdr l)) l)) ; Les macros internes pre'de'finies ((:macroexpand-internal cl (cdr l))) ((eq (typefn cl) 'macro) ; Macros utilisateurs. (apply (cons 'lambda (valfn cl)) l) ) ((eq (typefn cl) 'dmacro) ; Displace macros utilisateurs. (apply (cons 'lambda (valfn cl)) (cdr l)) ) ((eq (typefn cl) 'msubr) ; Macros syste`mes ou utilisateurs compile'es. (call (valfn cl) l () ()) ) ((eq (typefn cl) 'dmsubr) ; Displace macros syste`mes ou utilisateurs compile'es. (call (valfn cl) (cdr l) () ()) ) (t l) ))) (cond ; Une macro a produit une erreur (catcherror) ((atom x) (:macro-expand-error cl)) ; Test si la macro expansion a fait quelquechose ; et me^me pour les vicieux qui travaillent directement ; sur la forme a` expanser. ((and (consp (car x)) (or (neq l (car x)) (neq cl (caar x)) (neq cd (cdar x)))) (:macroexpand (car x))) ; Sinon on retourne le me^me objet. (t (car x)))) l)) ; .Section "Les Expansions internes" (de :macroexpand-internal (fnt l) (or (and :open-p (:macroexpand-internal-open fnt l)) (:macroexpand-internal-close fnt l) )) (de :macroexpand-internal-close (fnt l) (selectq fnt (COND (:mc:cond l)) (UNLESS `(if (not ,(car l)) (progn ,@(cdr l)))) (WHEN `(if ,(car l) (progn ,@(cdr l)))) (IFN `(if (not ,(car l)) ,@(cdr l))) (NEQ `(not (eq ,@l))) (NEQUAL `(not (equal ,@l))) (NULL `(not ,@l)) (ATOMP `(atom ,@l)) (DECR `(setq ,(car l) (,(if (cdr l) '- '1-) ,@l))) (INCR `(setq ,(car l) (,(if (cdr l) '+ '1+) ,@l))) (NEWL `(setq ,(car l) (cons ,(cadr l) ,(car l)))) (NEXTL `(prog1 ,(if (cdr l) `(setq ,(cadr l) (car ,(car l))) `(car ,(car l))) (setq ,(car l) (cdr ,(car l))) )) (NEWR `(setq ,(car l) (let ((:newr ,(cadr l))) (nconc ,(car l) (ncons :newr))))) (DYNAMIC-LET (:mc:dynamic-let l)) (DYNAMIC (:mc:dynamic l)) (RETURN `(return-from () ,@l)) (MAP (:map l 'map 'null)) (MAPL (:map l 'map 'null)) (MAPLIST (:map l 'map 'cons)) (MAPCON (:map l 'map 'nreconc)) (MAPC (:map l 'mapc 'null)) (MAPCAR (:map l 'mapc 'cons)) (MAPCAN (:map l 'mapc 'nreconc)) (EVERY (:map l 'mapc 'every)) (ANY (:map l 'mapc 'any)) (MAPVECTOR (:mapvector l)) (UNTILEXIT `(tag ,(car l) (while t ,@(cdr l)))) (LOOP `(while t ,@l)) (CATCHERROR (:mc:catcherror l)) (ERRSET (:mc:errset l)) (ERR `(exit #:system:error-tag ,@l)) (EVAL-WHEN (:mc:eval-when l)) (DESETQ `(deset ',(car l) ,(cadr l))) (DEFPROP `(putprop ',(car l) ',(cadr l) ',(caddr l))) (PSETQ (if (cddr l) `(setq ,(car l) (prog1 ,(cadr l) (psetq ,.(cddr l))) ) `(setq ,(car l) ,(cadr l))) ) (SETQQ (if (cddr l) `(progn (setq ,(car l) ',(cadr l)) (setqq ,.(cddr l)) ) `(setq ,(car l) ',(cadr l)) )) (LETVQ `((lambda (,(car l)) ,@(cddr l)) ,(cadr l))) (PROG2 `(progn ,(car l) (prog1 ,@(cdr l)))) (LOGNOT `(logxor ,(car l) -1)) (ADD1 `(add ,(car l) 1)) (SUB1 `(sub ,(car l) 1)) (TIME (:mc:time (car l))) (t ()) )) (de :macroexpand-internal-open (fnt l) (selectq fnt (CAAR `(car (car ,.l))) (CADR `(car (cdr ,.l))) (CDAR `(cdr (car ,.l))) (CDDR `(cdr (cdr ,.l))) (CAAAR `(car (car (car ,.l)))) (CAADR `(car (car (cdr ,.l)))) (CADAR `(car (cdr (car ,.l)))) (CADDR `(car (cdr (cdr ,.l)))) (CDAAR `(cdr (car (car ,.l)))) (CDADR `(cdr (car (cdr ,.l)))) (CDDAR `(cdr (cdr (car ,.l)))) (CDDDR `(cdr (cdr (cdr ,.l)))) (CAAAAR `(car (car (car (car ,.l))))) (CAAADR `(car (car (car (cdr ,.l))))) (CAADAR `(car (car (cdr (car ,.l))))) (CAADDR `(car (car (cdr (cdr ,.l))))) (CADAAR `(car (cdr (car (car ,.l))))) (CADADR `(car (cdr (car (cdr ,.l))))) (CADDAR `(car (cdr (cdr (car ,.l))))) (CADDDR `(car (cdr (cdr (cdr ,.l))))) (CDAAAR `(cdr (car (car (car ,.l))))) (CDAADR `(cdr (car (car (cdr ,.l))))) (CDADAR `(cdr (car (cdr (car ,.l))))) (CDADDR `(cdr (car (cdr (cdr ,.l))))) (CDDAAR `(cdr (cdr (car (car ,.l))))) (CDDADR `(cdr (cdr (car (cdr ,.l))))) (CDDDAR `(cdr (cdr (cdr (car ,.l))))) (CDDDDR `(cdr (cdr (cdr (cdr ,.l))))) (t ()) )) ; Ceci enleve' (dans la passe' une erreur des plus vicieuses. ; A vous de la trouver!! ; (:macroexpand '(trouver l erreur)) ; .Section "Fonctions Spe'cialis'es (ordre alpha)" (de :mc:catcherror ((s . l)) (cond ((eq s t) `(let ((#:system:error-flag t)) (tag #:system:error-tag (ncons (progn ,@l))) )) ((null s) `(let ((#:system:error-flag ()) (#:system:print-msgs 0) (#:system:debug ())) (tag #:system:error-tag (ncons (progn ,@l))) )) (t `(let ((#:system:error-flag (eval ,s))) (let ((#:system:print-msgs (if #:system:error-flag #:system:print-msgs 0)) (#:system:debug (if #:system:error-flag #:system:debug ()) )) (tag #:system:error-tag (ncons (progn ,@l))) ))))) (de :mc:cond (l) (if (null (cdr l)) (if (cdar l) (if (eq (caar l) t) `(progn ,@(cdar l)) `(if ,(caar l) (progn ,@(cdar l))) ) (or (caar l) 'nil) ) (if (cdar l) `(if ,(caar l) (progn ,@(cdar l)) (cond ,@(cdr l))) `(or ,(caar l) (cond ,@(cdr l))) ))) (de :mc:dynamic (l) ;; un reference variable dynamique. (when (featurep 'complice) (putprop (car l) t dynamic-flag)) (car l)) (de :mc:dynamic-let (l) ;; produire une liaison dynamique. ;; llcp le fait par de'faut, mais on doit l'indiquer a` complice. (when (featurep 'complice) (mapc (lambda ((var val))(putprop var t dynamic-flag)) (car l))) `(let ,(car l) ,@(cdr l))) ;;; Par compatibilite', complice regard loaded-from-file pour de'cider ;;; s'il faut lier dynamiquement. (defvar dynamic-flag '#:system:loaded-from-file) (defvar :exported-env ()) (de :mc:eval-when ((S* . E*)) (let ( (ret 'nil) ) (cond ((memq 'load S*) (setq ret `(progn ,@E*))) ((memq 'local-compile S*) (eprogn E*)) ((memq 'compile S*) (eprogn E*) (unless (member E* :exported-env) (newl :exported-env E*)) )) ret )) (de :mc:errset ((l s)) `(let ((#:system:error-flag ,s)) (tag #:system:error-tag (ncons ,l)) )) ; .Section "Les spe'cialistes de l'expansion des fonctionnelles" (de :map ((fnt . larg) targ tret) (let ((n (length larg)) (glarg ()) (res '#:system:map:r)) (repeat n (newl glarg (symbol '#:system:map (concat "arg" (decr n))))) `((lambda ,glarg ,(:map-result (:map-while (:map-next-res (:map-funcall (:map-next-arg glarg targ) fnt) tret res) tret (mapcar (lambda (m) `(consp ,m)) glarg)) tret res )) ,@larg ))) (de :mapvector ((fnt v)) `(let* ((#:system:map:r 0) (#:system:map:v ,v) (#:system:map:n (vlength #:system:map:v))) (while (lt #:system:map:r #:system:map:n) ,(:map-funcall '((vref #:system:map:v #:system:map:r)) fnt) (setq #:system:map:r (add1 #:system:map:r))))) (de :map-next-arg (larg type-arg) (mapcar (lambda (m) `(prog1 ,(if (eq type-arg 'map) m `(car ,m)) (setq ,m (cdr ,m))) ) larg )) (de :map-funcall (corps fnt) (cond ((not (consp fnt)) (mcons 'funcall fnt corps)) ((memq (car fnt) '(function quote)) (if (and (symbolp (cadr fnt)) (memq (typefn (cadr fnt)) '(() fexpr fsubr)) ) (mcons 'funcall fnt corps) (cons (cadr fnt) corps) )) ((eq (car fnt) 'lambda) (cons fnt corps)) ((eq (car fnt) 'flambda) (cons (cons 'lambda (cdr fnt)) corps)) ; Ge'ne're une erreur a` l'interpre'tation. ((eq (car fnt) 'mlambda) (mcons 'funcall fnt corps)) (t (mcons 'funcall fnt corps)) )) (de :map-next-res (exp type-result res) (selectq type-result (null exp) (cons `(setq ,res (cons ,exp ,res))) (nreconc `(setq ,res (nreconc ,exp ,res))) (t `(setq ,res ,exp)) )) (de :map-while (exp type-result glarg) (selectq type-result ((null cons nreconc) `(while (and ,@glarg) ,exp)) (every `(while (and ,@glarg ,exp))) (any `(while (and ,@glarg (not ,exp)))) )) (de :map-result (exp type-result res) (selectq type-result (null exp) ((cons nreconc) `((lambda (,res) ,exp (nreverse ,res)) ())) (every `((lambda (,res) ,exp ,res) t)) (any `((lambda (,res) ,exp ,res) ())) )) (defun :mc:time (e) (if (and (consp e) (eq (car e) 'quote)) `(let ( (:time (runtime)) ) ,(cadr e) (fsub (runtime) :time)) `(let ( (:time (runtime)) ) (eval ,e) (fsub (runtime) :time))))