commit 138946826221f54504339f580c5906354eb9e5ac
parent beab137d542a381b02130287d932ff5b555b9809
Author: Georges Dupéron <jahvascriptmaniac+github@free.fr>
Date: Fri, 19 Nov 2010 17:21:13 +0100
Import des modifications de compilation-georges.
À partir de maintenant, je bosse dans master.
Diffstat:
3 files changed, 388 insertions(+), 66 deletions(-)
diff --git a/implementation/compilation.lisp b/implementation/compilation.lisp
@@ -135,4 +135,4 @@
;; pop r1
;; pop r0
;; add r1 r0
-;; retn
-\ No newline at end of file
+;; retn
diff --git a/implementation/mini-meval.lisp b/implementation/mini-meval.lisp
@@ -1,6 +1,34 @@
(load "match")
(load "util")
+;; TODO (dans mini-meval et/ou compilateur) :
+;; - match-automaton(tagbody+block)
+;; - declaim
+;; - format
+;; - ` (quasiquote)
+;; - setf (écrire la macro)
+;; - fdefinition, funcctionp, …
+;; - symbolp, keywordp, keywords non mutables + nil et t, intern, make-symbol
+;; - car / cdr, replaca replacad, cons, list (fonction), listp, consp, atom, null (ou eq nil), …
+;; - and / or (macros => if)
+;; - &rest
+;; - eq (vérifier qu'on préserve bien l'égalité de pointeurs là où il faut) / = / eql / equal / equalp
+;; - load / open / read / close
+;; - defvar (gestion correcte des variables spéciales)
+;; - loop
+;; - dolist / dotimes
+;; - array support (array-total-size, row-major-aref, copy-seq)
+;; - string support (char=, map, string (symbol => string), format, print)
+;; - warn
+;; - coder un reverse rapide.
+;; - transformation de la récursion terminale.
+
+;; - vérifier qu'on a pas transformé certaines fonctions en formes spéciales (il faut qu'on puisse toujours les récupérer avec #').
+
+;; cell (un seul pointeur, transparent (y compris pour le type),
+;; avec trois fonctions spéciales pour le get / set / tester le type),
+;; sera utilisé pour les closures et les variables spéciales.
+
(defun slice-up-lambda-list (lambda-list)
(match-automaton lambda-list fixed
(fixed accept)
@@ -42,7 +70,7 @@
(reject (error "slice-up-lambda-list : ~w ne peut être ici." last-element))))
;; Exemples :
-;; (slice-up-lambda-list '(a b &optional u &rest c &key ((:foo bar)) :quux (:baz 'glop) &aux x))
+;; (slice-up-lambda-list '(a b &optional u &rest c &key ((:foo bar)) :quux (:baz 'glop) &aux (x 1) (y (+ x 2))))
;; (slice-up-lambda-list '(a b &rest))
;; (slice-up-lambda-list '(a b))
@@ -51,21 +79,21 @@
(if fixed
(if (endp params)
(error "mini-meval-params : not enough parameters !")
- (mini-meval-params (cdr params) global (acons (car fixed) (car params) local) (cdr fixed) optional rest key other aux))
+ (mini-meval-params (cdr params) global (acons `(,(car fixed) . variable) (car params) local) (cdr fixed) optional rest key other aux))
(if optional
(let* ((var (caar optional))
(value (if (endp params)
(mini-meval (cadar optional) global local)
(car params)))
(svar (caddar optional))
- (new-local (acons var value local))
+ (new-local (acons `(,var . variable) value local))
(new-local-2 (if svar
- (acons svar (endp params) new-local)
+ (acons `(,svar . variable) (endp params) new-local)
new-local)))
(mini-meval-params (cdr params) global new-local-2 nil (cdr optional) rest key other aux))
(if rest
- (mini-meval-params params global (acons (car rest) params local) nil nil nil key other aux)
- ;; TODO : finir d'implémenter &key &allow-other-keys &aux (et relire CLTL).
+ (mini-meval-params params global (acons `(,(car rest) . variable) params local) nil nil nil key other aux)
+ ;; TODO : finir d'implémenter &key &allow-other-keys &aux &rest (et relire CLTL).
local))))
; (if key
; (let* ((keyword (first (car key)))
@@ -76,24 +104,45 @@
; maybe-val
; (error "mini-meval-params : Nombre de paramètres impair alors qu'il y a &key."))))
; (svar (fourth (car key)))
-; (new-local (acons var (if maybe-val-2
+; (new-local (acons `(,var . variable) (if maybe-val-2
; (cadr maybe-val-2)
; (mini-meval (third (car key)) global local))
; local))
; (new-local-2 (if svar
-; (acons svar (not (not (maybe-val-2))) new-local)
+; (acons `(,svar . variable) (not (not (maybe-val-2))) new-local)
; new-local)))
-; (mini-meval-params params global new-local-2 nil nil nil (cdr key) aux)
+; (mini-meval-params params global new-local-2 nil nil nil (cdr key) other aux)
(defun mini-meval-get-params-from-real (etat-global etat-local lambda-list effective-parameters)
"Lambda-list doit être déjà sliced."
- (apply #'mini-meval-params effective-parameters etat-global etat-local
- (cdr (assoc 'fixed lambda-list))
- (cdr (assoc 'optional lambda-list))
- (cdr (assoc 'rest lambda-list))
- (cdr (assoc 'key lambda-list))
- (cdr (assoc 'other lambda-list))
- (cdr (assoc 'aux lambda-list))))
+ (funcall #'mini-meval-params effective-parameters etat-global etat-local
+ (cdr (assoc 'fixed lambda-list))
+ (cdr (assoc 'optional lambda-list))
+ (cdr (assoc 'rest lambda-list))
+ (cdr (assoc 'key lambda-list))
+ (cdr (assoc 'other lambda-list))
+ (cdr (assoc 'aux lambda-list))))
+
+(defun splice-up-tagbody-1 (todo-body body result)
+ (if (endp todo-body)
+ (acons nil body result)
+ (if (symbolp (car todo-body))
+ (splice-up-tagbody-1 (cdr todo-body)
+ body
+ (acons (car todo-body) body result))
+ (splice-up-tagbody-1 (cdr todo-body)
+ (cons (car todo-body) body)
+ result))))
+
+(defun splice-up-tagbody (body)
+ (splice-up-tagbody-1 (reverse body) nil nil))
+
+(defun mini-meval-error (expr etat-global etat-local &rest message)
+ (error "~w~&expression = ~w~&etat-global = ~w~&etat-local = ~w"
+ (apply #'format nil message)
+ expr
+ etat-global
+ etat-local))
#|
Mini-meval est un meval très simple destiné à évaluer les macros et les autres directives avec eval-when :compile-toplevel.
@@ -101,7 +150,7 @@ Mini-meval est un meval très simple destiné à évaluer les macros et les autr
;; Fonctionnement de mini-meval
Mini-meval sera appellé sur des morceaux spécifiques du fichier source. Il faut donc qu'il puisse maintenir son état entre les appels.
|#
-(defun mini-meval (expr &optional etat-global etat-local)
+(defun mini-meval (expr &optional (etat-global (cons nil nil)) etat-local)
#|
L'algorithme d'évaluation est très simple et suit le schéma donné dans CLTL 5.1.3 :
1) Si l'expression est une forme spéciale, on la traite de manière particulière
@@ -113,12 +162,14 @@ Mini-meval sera appellé sur des morceaux spécifiques du fichier source. Il fau
(cond-match
expr
+ ((debug :id _?)
+ (format t "~&debug :~& id = ~w~& global = ~w~& local = ~w" id etat-global etat-local))
#| 2) Cas des macros |#
- ((:name $ :params _*)
- (let ((definition (assoc* `(,name macro) #'equal etat-local etat-global)))
+ ((:name $$ :params _*)
+ (let ((definition (assoc* `(,name . macro) #'equal etat-local (cdr etat-global))))
(if definition
#| - Si on a une fonction de ce nom dans l'état-local ou dans l'etat-global, on l'exécute. |#
- (apply (cdr definition) (mapcar (lambda (x) (mini-meval x etat-global etat-local)) params))
+ (mini-meval (apply (cdr definition) params) etat-global etat-local)
(else))))
#| 1) Cas des formes spéciales |#
((eval-when :situations ($*) :body _*)
@@ -126,49 +177,47 @@ Mini-meval sera appellé sur des morceaux spécifiques du fichier source. Il fau
(mini-meval body etat-global etat-local)
nil))
((flet ((:name $ :lambda-list @ :fbody _*)*) :body _*)
- (mini-meval `(progn ,body)
+ (mini-meval `(progn ,@body)
etat-global
(reduce* etat-local (lambda (new-etat-local name lambda-list fbody)
- (acons (cons name 'function)
- (mini-meval `(lamdba ,lambda-list ,@fbody) etat-global etat-local)
+ (acons `(,name . function)
+ (mini-meval `(lambda ,lambda-list ,@fbody) etat-global etat-local)
new-etat-local))
name lambda-list fbody)))
((labels ((:name $ :lambda-list @ :fbody _*)*) :body _*)
- (let* ((new-bindings (reduce* nil (lambda (new-bindings name) `(((,name . 'function) . nil) . ,new-bindings))
+ (let* ((new-bindings (reduce* nil (lambda (new-bindings name) `(((,name . function) . nil) . ,new-bindings))
name))
(new-etat-local (append new-bindings etat-local)))
(mapcar (lambda (name lambda-list fbody)
;; On fait un assoc / setf dans new-bindings, qui ne contient que les fonctions qu'on vient juste d'ajouter, pour éviter
;; le risque inexistant de faire une mutation dans etat-local.
;; TODO : vérifier que ça marche.
- (assoc-set `(,name 'function)
- (mini-meval `(lambda ,lambda-list ,@fbody) new-etat-local)
- new-bindings
- #'equal))
+ (setf (cdr (assoc `(,name . function) new-bindings :test #'equal))
+ (mini-meval `(lambda ,lambda-list ,@fbody) etat-global new-etat-local)))
name lambda-list fbody)
- (mini-meval `(progn ,body) etat-global new-etat-local)))
+ (mini-meval `(progn ,@body) etat-global new-etat-local)))
((let ((:name $ :value _)*) :body _*)
- (mini-meval `(progn ,body)
+ (mini-meval `(progn ,@body)
etat-global
(reduce* etat-local (lambda (new-etat-local name value)
- (acons (cons name 'variable)
+ (acons `(,name . variable)
(mini-meval value etat-global etat-local)
new-etat-local))
name value)))
- ((let* ((:name $ :value _)*) :body _*)
- (mini-meval `(progn ,body)
+ (((? (eq x 'let*)) ((:name $ :value _)*) :body _*)
+ (mini-meval `(progn ,@body)
etat-global
(reduce* etat-local (lambda (new-etat-local name value)
- (acons (cons name 'variable)
+ (acons `(,name . variable)
;; Comme let sauf new-etat-local au lieu de etat-local ici.
(mini-meval value etat-global new-etat-local)
new-etat-local))
name value)))
((macrolet ((:name $ :lambda-list @ :mbody _*)*) :body _*)
- (mini-meval `(progn ,body)
+ (mini-meval `(progn ,@body)
etat-global
(reduce* etat-local (lambda (new-etat-local name lambda-list mbody)
- (acons (cons name 'macro)
+ (acons `(,name . macro)
;; comme le flet sauf nil au lieu de new-etat-local
;; CLTL 7.5 :
;; The precise rule is that the macro-expansion functions defined
@@ -179,7 +228,7 @@ Mini-meval sera appellé sur des morceaux spécifiques du fichier source. Il fau
new-etat-local))
name lambda-list mbody)))
((progn :body _*)
- (cdr (last (mapcar (lambda (expr) (mini-meval expr etat-global etat-local))
+ (car (last (mapcar (lambda (expr) (mini-meval expr etat-global etat-local))
body))))
((if :condition _ :si-vrai _ :si-faux _?)
(if (mini-meval condition etat-global etat-local)
@@ -190,49 +239,318 @@ Mini-meval sera appellé sur des morceaux spécifiques du fichier source. Il fau
((lambda :lambda-list @ :body _*)
(let ((sliced-lambda-list (slice-up-lambda-list lambda-list)))
(lambda (&rest effective-parameters)
- (mini-meval body
+ (mini-meval `(progn ,@body)
etat-global
(mini-meval-get-params-from-real etat-global etat-local sliced-lambda-list effective-parameters)))))
((defun :name $ :lambda-list @ :body _*)
- (assoc-set `(,name 'function)
+ (assoc-set `(,name . function)
(mini-meval `(lambda ,lambda-list ,@body) etat-global etat-local)
- etat-global
+ (cdr etat-global)
#'equal)
name)
((defmacro :name $ :lambda-list @ :body _*)
- (assoc-set `(,name 'macro)
+ (assoc-set `(,name . macro)
(mini-meval `(lambda ,lambda-list ,@body) etat-global etat-local)
- etat-global
+ (cdr etat-global)
#'equal)
name)
((defvar :name $ :value _)
- (assoc-set `(,name 'variable)
+ (assoc-set `(,name . variable)
(mini-meval value etat-global etat-local)
- etat-global
+ (cdr etat-global)
#'equal)
name)
- ((setf/setq)
- )
+ ((setq :name $ :value _)
+ (let ((definition (assoc* `(,name . variable) #'equal etat-local (cdr etat-global))))
+ (if definition
+ (let ((real-value (mini-meval value etat-global etat-local)))
+ (setf (cdr definition) real-value)
+ real-value)
+ (mini-meval `(defvar ,name ,value) etat-global etat-local))))
+ ((function :name $$)
+ (let ((definition (assoc* `(,name . function) #'equal etat-local (cdr etat-global))))
+ (if definition
+ (cdr definition)
+ (mini-meval-error expr etat-global etat-local "mini-meval : undefined function : ~w." name))))
+ ((funcall :name _ :params _*)
+ (apply (mini-meval name etat-global etat-local)
+ (mapcar (lambda (x) (mini-meval x etat-global etat-local)) params)))
+ ((apply :name _ :p1 _ :params _*)
+ (let ((fun (mini-meval name etat-global etat-local))
+ (args (mapcar (lambda (x) (mini-meval x etat-global etat-local)) (cons p1 params))))
+ (apply fun (append (butlast args) (car (last args))))))
+ ((declaim _*)
+ nil)
+ ((error :format _ :args _*)
+ (error "mini-meval : fonction error appellée par le code, le message est :~&~w" (apply #'format nil format args)))
+ ((go :target $$)
+ (when (null target)
+ (min-meval-error expr etat-global etat-local "mini-meval : nil ne peut pas être une étiquette pour un return-from."))
+ (let ((association (assoc* `(,target . tagbody-tag) #'equal etat-local etat-global)))
+ (if association
+ (funcall (cdr association))
+ (mini-meval-error expr etat-global etat-local "mini-meval : tentative de faire un go sur une étiquette qui n'existe pas ou plus : ~w.~&~w" target))))
+ ((tagbody :body _*)
+ (let ((spliced-body (splice-up-tagbody body))
+ (next-tag nil)
+ (new-etat-local nil))
+ (tagbody
+ init
+ (setq new-etat-local
+ (reduce* etat-local
+ (lambda (new-etat-local tag)
+ (acons `(,(car tag) . tagbody-tag)
+ (lambda () (setq next-tag (car tag)) (go go-to-tag))
+ new-etat-local))
+ spliced-body))
+ go-to-tag
+ (mini-meval `(progn ,@(cdr (assoc next-tag spliced-body)))
+ etat-global
+ new-etat-local))))
+ ((return-from :block-name $$ :value _)
+ (let ((association (assoc* `(,block-name . block-name) #'equal etat-local etat-global)))
+ (if association
+ (funcall (cdr association) value)
+ (mini-meval-error expr etat-global etat-local "mini-meval : tentative de faire un return-from pour un bloc qui n'existe pas ou plus : ~w." block-name))))
+ ((block :block-name $$ :body _*)
+ (block block-catcher
+ (mini-meval `(progn ,@body) etat-global (acons `(,block-name . block-name)
+ (lambda (x) (return-from block-catcher x))
+ etat-local))))
+ ((quote :val _)
+ val)
#| Traitement des appels de fonction |#
((:lambda (lambda @ _*) :params _*)
#| - Si c'est une fonction anonyme, on l'exécute. |#
(apply (mini-meval lambda etat-global etat-local) params))
((:name $ :params _*)
- (let ((definition (assoc* `(,name function) #'equal etat-local etat-global)))
+ (let ((definition (assoc* `(,name . function) #'equal etat-local (cdr etat-global))))
(if definition
#| - Si on a une fonction de ce nom dans l'état-local ou dans l'etat-global, on l'exécute. |#
(apply (cdr definition) (mapcar (lambda (x) (mini-meval x etat-global etat-local)) params))
- (error "mini-meval : undefined function : ~w" name))))
- ((:name . $$)
- (let ((definition (assoc* `(,name variable) #'equal etat-local etat-global)))
- (if definition
- (cdr definition)
- (error "mini-meval : undefined variable : ~w" name))))
+ (mini-meval-error expr etat-global etat-local "mini-meval : undefined function : ~w." name))))
((:num . (? numberp))
num)
((:str . (? stringp))
str)
- ((quote :val _)
- val)
(()
- nil)))
+ nil)
+ ((:name . $$)
+ (let ((definition (assoc* `(,name . variable) #'equal etat-local (cdr etat-global))))
+ (if definition
+ (cdr definition)
+ (mini-meval-error expr etat-global etat-local "mini-meval : undefined variable : ~w." name))))))
+
+(defun push-functions (etat-global functions)
+ (cons nil (mapcar-append (cdr etat-global) (lambda (x) `((,x . function) . ,(fdefinition x))) functions)))
+
+(defmacro etat-global-fn (&rest functions)
+ `(push-functions '(nil) ',functions))
+
+(load "test-unitaire")
+(erase-tests mini-meval)
+
+(deftestvar mini-meval e-global (etat-global-fn list + - cons car cdr < > <= >= =))
+
+(deftest (mini-meval constante)
+ (mini-meval 42 e-global nil)
+ 42)
+
+(deftest (mini-meval appel-fonction)
+ (mini-meval '(+ 2 3) e-global nil)
+ 5)
+
+(deftest (mini-meval appel-fonction)
+ (mini-meval '(+ 2 (+ 3 4)) e-global nil)
+ 9)
+
+(deftest (mini-meval variable)
+ (mini-meval 'x e-global (acons '(x . variable) 42 nil))
+ 42)
+
+(deftest (mini-meval appel-fonction-et-variable)
+ (mini-meval '(+ x x 3) e-global (acons '(x . variable) 42 nil))
+ 87)
+
+(deftest (mini-meval appel-fonction-et-variable)
+ (mini-meval '(+ x (+ 3 x)) e-global (acons '(x . variable) 42 nil))
+ 87)
+
+(deftest (mini-meval lambda extérieur)
+ (funcall (mini-meval '(lambda (x) x) e-global nil) 3)
+ 3)
+
+(deftest (mini-meval lambda extérieur)
+ (funcall (mini-meval '(lambda (x) (+ x 3)) e-global nil) 4)
+ 7)
+
+(deftest (mini-meval lambda immédiat)
+ (mini-meval '((lambda (x) (+ x 3)) 4) e-global nil)
+ 7)
+
+(deftest (mini-meval let)
+ (mini-meval '(let ((x 3) (y 4)) (+ x y)) e-global nil)
+ 7)
+
+(deftest (mini-meval let)
+ (mini-meval '(let ((x 3) (y 4) (z 5)) (let ((z (+ x y)) (w z)) (list x y z w))) e-global nil)
+ '(3 4 7 5))
+
+(deftest (mini-meval let*)
+ (mini-meval '(let ((x 3) (y 4) (z 5)) (let* ((z (+ x y)) (w z)) (list x y z w))) e-global nil)
+ '(3 4 7 7))
+
+(deftest (mini-meval progn)
+ (mini-meval '(progn 1 2 3 4) e-global nil)
+ 4)
+
+(deftest (mini-meval defvar)
+ (mini-meval '(progn (defvar x 42) x) e-global nil)
+ 42)
+
+(deftest (mini-meval defun)
+ (mini-meval '(progn (defun double (x) (+ x x)) (double 3)) e-global nil)
+ 6)
+
+(deftest (mini-meval quote)
+ (mini-meval ''x e-global nil)
+ 'x)
+
+(deftest (mini-meval defmacro)
+ (mini-meval '(progn (defmacro qlist (x y) (list 'list (list 'quote x) (list 'quote y))) (qlist a b)) e-global nil)
+ '(a b))
+
+(deftest (mini-meval macrolet)
+ (mini-meval '(progn
+ (defun qlist (a b) (list a b))
+ (list
+ (qlist 'a 'b)
+ (macrolet ((qlist (x y) (list 'list (list 'quote x) (list 'quote y))))
+ (qlist 'a 'b))
+ (qlist 'a 'b)))
+ e-global nil)
+ '((a b) ('a 'b) (a b)))
+
+(deftest (mini-meval setf setq)
+ (mini-meval '(list (defvar x 42) x (setq x 123) x) e-global nil)
+ '(x 42 123 123))
+
+(deftest (mini-meval funcall)
+ (mini-meval '(funcall #'+ 1 2 3) e-global nil)
+ '6)
+
+(deftest (mini-meval apply)
+ (mini-meval '(apply #'+ 1 2 (list (+ 1 2) 4)) e-global nil)
+ '10)
+
+(deftest (mini-meval function external)
+ (mini-meval '#'+ e-global nil)
+ #'+)
+
+(deftest (mini-meval function external)
+ (mini-meval '(funcall #'+ 1 2 3) e-global nil)
+ '6)
+
+(deftest (mini-meval function internal)
+ (funcall (mini-meval '(progn (defun foo (x) (+ x 40)) #'foo) e-global nil) 2)
+ '42)
+
+(deftest (mini-meval function internal)
+ (mini-meval '(progn (defun foo (x) (+ x 40)) (funcall #'foo 2)) e-global nil)
+ '42)
+
+(deftest (mini-meval function internal)
+ (mini-meval '(progn (defvar bar (list (lambda (x) (+ x 40)) 1 2 3)) (funcall (car bar) 2)) e-global nil)
+ '42)
+
+(deftest (mini-meval lambda optional)
+ (mini-meval '((lambda (x &optional (y 2)) (list x y)) 1) e-global nil)
+ '(1 2))
+
+(deftest (mini-meval lambda closure single-instance)
+ (mini-meval '(progn
+ (defvar foo (let ((y 1)) (cons (lambda (x) (list x y)) (lambda (z) (setq y (+ y z)) nil))))
+ (list (funcall (car foo) 4) (funcall (cdr foo) 5) (funcall (car foo) 4))) e-global nil)
+ '((4 1) nil (4 6)))
+
+(deftest (mini-meval lambda closure multiple-instances)
+ (mini-meval '(progn
+ (defun counter (&optional (ctr 0)) (cons (lambda () ctr) (lambda (&optional (x 1)) (setq ctr (+ ctr x)) nil)))
+ (defvar foo0 (counter))
+ (defvar foo42 (counter 42))
+ (list
+ (funcall (car foo0)) ;; show 0
+ (funcall (car foo42)) ;; show 42
+ (funcall (cdr foo0)) ;; add 0
+ (funcall (car foo0)) ;; show 0
+ (funcall (cdr foo42)) ;; add 42
+ (funcall (car foo42)) ;; show 42
+ (funcall (car foo0)) ;; shwo 0
+ (funcall (car foo42)) ;; show 42
+ (funcall (cdr foo42) 6) ;; add 42 (+ 6)
+ (funcall (cdr foo0) 5) ;; add 0 (+ 5)
+ (funcall (car foo42)) ;; show 42
+ (funcall (car foo0)))) ;; show 0
+ e-global nil)
+ '(0 42 nil 1 nil 43 1 43 nil nil 49 6))
+
+(deftest (mini-meval labels)
+ (mini-meval '(list
+ (defun foo (x) (+ x 1))
+ (foo 3)
+ (labels ((foo (x) (+ x 3)))
+ (foo 3)))
+ e-global nil)
+ '(foo 4 6))
+
+(deftest (mini-meval flet)
+ (mini-meval '(list
+ (defun foo (x) (+ x 1))
+ (foo 3)
+ (flet ((foo (x) (+ x 3)))
+ (foo 3)))
+ e-global nil)
+ '(foo 4 6))
+
+(deftest (mini-meval labels)
+ (mini-meval '(< 2 3) e-global nil)
+ t)
+
+(deftest (mini-meval labels)
+ (mini-meval '(list
+ (defun fibo (n) (if (< n 2) 1 (+ (fibo (- n 1)) (fibo (- n 2))))) ;; fibo 0 -> 1; 1 -> 1; 2 -> 2 ...
+ (fibo 5)
+ (labels ((fibo (n) (if (< n 3) 1 (+ (fibo (- n 1)) (fibo (- n 2)))))) ;; fibo 1 -> 1; 2 -> 1; 3 -> 2 ...
+ (fibo 5)))
+ e-global nil)
+ '(fibo 8 5))
+
+(deftest (mini-meval flet)
+ (mini-meval '(list
+ (defun fibo (n) (if (< n 2) 1 (+ (fibo (- n 1)) (fibo (- n 2))))) ;; fibo 0 -> 1; 1 -> 1; 2 -> 2 ...
+ (fibo 5)
+ (flet ((fibo (n) (if (< n 3) 1 (+ (fibo (- n 1)) (fibo (- n 2)))))) ;; fibo 1 -> 1; 2 -> 1; 3 -> 2 ...
+ (fibo 5)))
+ e-global nil)
+ ;; Le flet ne permet pas les définitions récursives, donc le fibo
+ ;; de l'extérieur est appellé après le 1er niveau de récursion.
+ '(fibo 8 8))
+
+(deftest-error (mini-meval error)
+ (mini-meval '(error "Some user error message.") (cons nil nil) nil))
+
+(deftest (mini-meval tagbody)
+ (mini-meval '(let ((x 0)) (tagbody foo (setq x 1) (go baz) bar (setq x 2) baz) x))
+ 1)
+
+(deftest (mini-meval tagbody)
+ (mini-meval '(tagbody foo 1 bar 2 baz 3))
+ nil)
+
+(deftest (mini-meval block)
+ (mini-meval '(block foo 1 (return-from foo 4) 2))
+ 4)
+
+(deftest (mini-meval block)
+ (mini-meval '(block foo 1 2))
+ 2)
+\ No newline at end of file
diff --git a/util.lisp b/util.lisp
@@ -13,7 +13,7 @@
(defmacro assoc-set (k v alist &optional (compare #'eq))
`(let ((my-k ,k)
(my-v ,v))
- (let ((association (assoc my-k ,alist :key ,compare)))
+ (let ((association (assoc my-k ,alist :test ,compare)))
(if association
(setf (cdr association) my-v)
(push (cons my-k my-v) ,alist)))))
@@ -109,13 +109,7 @@
res))
((stringp data)
(copy-seq data))
- ((null data)
- nil)
- ((symbolp data)
- data)
- ((numberp data)
- data)
- ((characterp data)
+ ((or (null data) (symbolp data) (numberp data) (characterp data) (functionp data))
data)
(t
(warn "copy-all : Je ne sais pas copier ~w" data)
@@ -170,3 +164,13 @@
(defun group (lst)
(reverse-alist (group-1 lst)))
+
+(defun find-what-is-used-1 (expr)
+ (if (propper-list-p expr)
+ (apply #'append (if (symbolp (car expr))
+ (list (car expr))
+ nil)
+ (mapcar #'find-what-is-used (cdr expr)))))
+
+(defun find-what-is-used (expr)
+ (remove-duplicates (find-what-is-used-1 expr)))