diff --git a/lisp2li.lisp b/lisp2li.lisp index 0a3a821..6822aec 100644 --- a/lisp2li.lisp +++ b/lisp2li.lisp @@ -95,7 +95,7 @@ par le compilateur et par l’interpréteur" (if (member '&rest (second expr)) `(:lclosure . (,(get-nb-params (second expr)) ,(+ 1 (mposition '&rest (second expr))) - ,(lisp2li (implicit-progn (cddr expr)) + ,@(lisp2li (implicit-progn (cddr expr)) (make-stat-env (second expr) env)))) `(:lclosure . ,(cons (get-nb-params (second expr)) (lisp2li (implicit-progn (cddr expr)) @@ -266,9 +266,9 @@ par le compilateur et par l’interpréteur" (deftest (lisp2li rest) (lisp2li `(lambda (x &rest y) (cons x y)) ()) - '(:lclosure 2 2 (:call cons + '(:lclosure 2 2 :call cons (:cvar 0 1) - (:cvar 0 2)))) + (:cvar 0 2))) (deftest (lisp2li unknown) (lisp2li '(bar 3) ()) diff --git a/meval.lisp b/meval.lisp index 314beeb..b7c32d5 100644 --- a/meval.lisp +++ b/meval.lisp @@ -1,10 +1,8 @@ -(setq *debug* nil) (load "match") (defun get-env-num (num env) - (format *debug* "~&get-env-num ~&~T=> num = ~a ~&~T=> env = ~a" num env) +"Récupère l’environnement correspondant à celui souhaité." (defun get-env-num-t (num env counter) - (format *debug* "~&get-env-num-t ~&~T=> num = ~a ~&~T=> env = ~a ~&~T=> counter = ~a" num env counter) (cond ((= counter num) env) ((eq (aref env 0) nil) nil) (T @@ -13,37 +11,59 @@ (get-env-num-t num env 0)) (defun get-lower-env (env) - (format *debug* "~&get-lower-env ~&~T=> env = ~a" env) + "Récupère l’environnement le plus bas" (if (or (= (array-total-size env) 0) (eq (aref env 0) nil)) env (get-lower-env (aref env 0)))) -(defun make-env (size list-values env) - "Construit un nouvel environnement de taille dans -et remplie ce nouvelle environnement avec les valeurs contenu dans -" - (format *debug* "~&make-env ~&~T=> size = ~a ~&~T=> list-value = ~a ~&~T=> env = ~a" size list-values env) - (if (= (array-total-size env) 0) - (setf env (make-array (+ 1 size))) - (setf (aref (get-lower-env env) 0) (make-array (+ 1 size)))) - (let ((lower-env (get-lower-env env))) - (format *debug* "~&(make-env let) ~&~T=> lower-env = ~a" lower-env) - (loop - for value in list-values - for rank = 1 then (+ rank 1) - do (setf (aref lower-env rank) value) - )) +(defun make-rest (env values &optional (pos-rest 1)) + "Construit l'environnement en rajoutant tous les valeurs +du &rest dans une cellule de l'env sous forme d'une liste" + (let ((size (- (array-total-size env) 1))) + (defun make-rest-lower-env (lower-env pos values) + (cond ((= pos pos-rest) + (setf (aref lower-env pos) values)) + (T + (setf (aref lower-env pos) (car values)) + (make-rest-lower-env lower-env + (+ pos 1) + (cdr values))))) + (make-rest-lower-env env 1 values)) env) +(defun make-env (size list-values env &optional pos-rest) + "Construis l’environnement en appariant les paramètres aux valeurs + correspondantes et signale une exception si paramètres et arguments + ne concordent pas. Si l’environnement passe en paramètre n’est pas vide, + le nouvel environnement y est inclus." + (cond ((and (not pos-rest) + (< size (length list-values))) + (error "Too arguments")) + ((> size (length list-values)) + (error "Too few arguments")) + (T + (if (= (array-total-size env) 0) + (setf env (make-array (+ 1 size))) + (setf (aref (get-lower-env env) 0) (make-array (+ 1 size)))) + (let ((lower-env (get-lower-env env))) + (if pos-rest + (make-rest lower-env + list-values + pos-rest) + (loop + for value in list-values + for rank = 1 then (+ rank 1) + do (setf (aref lower-env rank) value) + ))) + env))) + (defun map-meval (list env) - (format *debug* "~&map-meval ~&~T=> list = ~a ~&~T=> env = ~a" list env) (mapcar (lambda (x) (meval x env)) list)) (defun meval-progn (list env) "Mevalue toutes les sous expressions et renvoie la valeur de la dernier" - (format *debug* "~&meval-progn ~&~T=> list = ~a ~&~T env = ~a" list env) (if (endp list) nil (if (endp (cdr list)) @@ -52,99 +72,65 @@ la valeur de la dernier" (meval (car list) env) (meval-progn (cdr list) env))))) -(defun modify-lower-env (lower-env value pos) - (format *debug* "~&modify-lower-env ~&~T=> lower-env = ~a ~&~T=> value = ~a ~&~T=> pos = ~a" lower-env value pos) - (let ((env-bis (make-array (+ pos 1)))) - (defun construct-new-lower-env (new-env old-env) - (format *debug* "~&construct-new-lower-env ~&~T=> new-env = ~a ~&~T=> old-env = ~a" new-env old-env) - (loop - for i = 0 then (+ i 1) - do (setf (aref new-env i) (aref old-env i)) - while (<= i (- pos 1)) - )) - (setf (aref lower-env pos) value) - (construct-new-lower-env env-bis lower-env) - (format *debug* "~&modify-lower-env ~&~T env-bis = ~a" env-bis) - (setf lower-env env-bis) - )) +(defun meval-body (list-expr env) + "Évalue en séquence la liste des expressions et +retourne la valeur retournée par la dernière" + (if (endp list-expr) + nil + (if (endp (cdr list-expr)) + (meval (car list-expr) env) + (progn + (meval (car list-expr) env) + (meval-body (cdr list-expr) env))))) -(defun make-rest (env &optional (pos-rest 1)) - (format *debug* "~&make-rest ~&~T=> env = ~a ~&~T=> pos-rest = ~a" env pos-rest) - (let* ((lower-env (get-lower-env env)) - (size (- (if (= 0 (array-total-size lower-env)) - 1 - (array-total-size lower-env)) - 1))) - (defun make-rest-lower-env (lower-env pos) - (format *debug* "~&make-rest-lower-env ~&~T=> lower-env = ~a ~&~T=> pos = ~a ~&~T=> size = ~a" lower-env pos size) - (cond ((>= pos size) - (cons (aref lower-env pos) nil)) - ((< pos pos-rest) - (make-rest-lower-env lower-env (+ pos 1))) - (T - (cons (aref lower-env pos) - (make-rest-lower-env lower-env (+ pos 1)))))) - (modify-lower-env (get-lower-env env) (make-rest-lower-env (get-lower-env env) pos-rest) pos-rest) - (format *debug* "~&make-rest ~&~T=> lower-env = ~a" (get-lower-env env))) - env) +(defun meval-args (list-expr env) + "Évalue en séquence la liste des expressions et +retourne la liste de leurs valeurs" + (if (endp list-expr) + nil + (if (endp (cdr list-expr)) + `(,(meval (car list-expr) env)) + `(,(meval (car list-expr) env) + ,@(meval-args (cdr list-expr) env))))) + +(defun meval-lambda (lclosure args env) + "Applique une λ-fonction quelconque à des valeurs +d’arguments dans un certain environnement." + (match (:nil :lclosure :size (? integerp) :rest (? integerp)? :body _*) lclosure + (meval lclosure + (make-env size args env rest)))) (defun meval (expr &optional (env #())) "Interprète le langage intermédiaire passé en paramètre." - (format *debug* "~&meval ~&~T=> expr = ~a ~&~T=> env = ~a" expr env) - (cond ((match :const (first expr)) - (format *debug* "~&(meval :const) ~&~T=> expr = ~a ~&~T=> env = ~a" expr env) - (cdr expr)) - ((match :cvar (first expr)) - (format *debug* "~&(meval :cvar) ~&~T=> expr = ~a ~&~T=> env = ~a" expr env) - (let ((sub-env (get-env-num (second expr) env))) - (if sub-env - (aref sub-env (third expr)) - (error "The variable ~S is unbound" expr)))) - ((match :if (first expr)) - (format *debug* "~&(meval :if) ~&~T=> expr = ~a ~&~T=> env = ~a" expr env) - (if (meval (second expr) env) - (meval (third expr) env) - (meval (fourth expr) env))) - ((match :call (first expr)) - (format *debug* "~&(meval :call) ~&~T=> expr = ~a ~&~T=> env = ~a" expr env) - (apply (symbol-function (cadr expr)) (map-meval (cddr expr) env))) - ((match :mcall (first expr)) - (format *debug* "~&(meval :mcall) ~&~T=> expr = ~a ~&~T=> env = ~a" expr env) - (if (consp (second expr)) - (let ((closure (second expr))) - (format *debug* "~&~T=> closure = ~a" closure) - (cond ((and (atom (third closure)) - (constantp (third closure)) - (integerp (third closure))) - (meval closure - (make-rest (make-env (length (cddr expr)) - (map-meval (cddr expr) env) - env) - (caddr closure)))) - (T - (cond ((< (second closure) (length (cddr expr))) - (error "Too arguments")) - ((> (second closure) (length (cddr expr))) - (error "Too few arguments")) - (T - (meval closure - (make-env (second closure) - (map-meval (cddr expr)env) - env))))))) - (error "form not yet implemented"))) - ((match :progn (first expr)) - (format *debug* "~&(meval :progn) ~&~T=> expr = ~a ~&~T=> env = ~a" expr env) - (meval-progn (cdr expr) env)) - ((match :lclosure (first expr)) - (format *debug* "~&(meval :lclosure) ~&~T=> expr = ~a~&~T=> env = ~a" expr env) - (if (and (atom (caddr expr)) - (constantp (caddr expr)) - (integerp (caddr expr))) - (meval-progn (cdddr expr) env) - (meval-progn `(,(cddr expr)) env))) + (cond ((eq ':const (first expr)) + (match (:nil :const :val . _) expr val)) + ((eq ':cvar (first expr)) + (match (:nil :cvar :num-env (? integerp) :index (? integerp)) expr + (let ((sub-env (get-env-num num-env env))) + (if sub-env + (aref sub-env index) + (error "The variable unbound" expr))))) + ((eq ':if (first expr)) + (match (:nil :if :predicat @. :expr1 @. :expr2 @.) expr + (if (meval predicat env) + (meval expr1 env) + (meval expr2 env)))) + ((eq ':call (first expr)) + (match (:nil :call :func-name _ :body _*) expr + (apply (symbol-function func-name) (map-meval body env)))) + ((eq ':mcall (first expr)) + (match (:nil :mcall :lambda (:nil :lclosure (? integerp) (? integerp)? _*) :args _*) expr + (meval-lambda lambda (meval-args args env) env))) + ((eq ':progn (first expr)) + (match (:nil :progn :body @.+) expr + (meval-body body env))) + ((eq ':lclosure (first expr)) + (match (:nil :lclosure (? integerp) (? integerp)? :body _*) expr + (meval-body `(,body) env))) (T (error "form special ~S not yet implemented" (car expr))))) + ;; Test unitaire (load "test-unitaire") (load "lisp2li") @@ -194,6 +180,63 @@ la valeur de la dernier" (:const . nil)) #(() 1 2 3)) T) +(deftestvar (meval make-env) empty-env #()) +(deftest (meval make-env) + (make-env 2 '(1 2) empty-env) + #(() 1 2) + #'equalp) + +(deftestvar (meval make-env) env #(() 1 2)) +(deftest (meval make-env) + (make-env 2 '(7 8) env) + #(#(() 7 8) 1 2) + #'equalp) + +(deftestvar (meval make-env make-rest) env #(() nil nil)) +(deftest (meval make-env make-rest) + (make-rest env '(1 2 3 4) 2) + #(() 1 (2 3 4)) + #'equalp) + +(deftestvar (meval make-env &rest) env #(() 1 2)) +(deftest (meval make-env &rest) + (make-env 2 '(7 8 9) env 2) + #(#(() 7 (8 9)) 1 2) + #'equalp) + +(deftest (meval make-env &rest) + (make-env 1 '(nil) env 1) + #(#(() (nil)) 1 2) + #'equalp) + +(deftest (meval meval-body) + (meval-body '((:const . 3)) #()) + '3) + +(deftest (meval meval-body) + (meval-body '((:const . 3) (:call cons (:const . 1) (:const . 2))) #()) + '(1 . 2)) + +(deftest (meval meval-args) + (meval-args '((:const . 3)) #()) + '(3)) + +(deftest (meval meval-args) + (meval-args '((:const . 3) (:const 1 2 3)) #()) + '(3 (1 2 3))) + +(deftest (meval meval-args) + (meval-args '((:cvar 0 1) (:call cons (:cvar 0 3) + (:cvar 0 2))) #(() 1 2 3)) + '(1 (3 . 2))) + +(deftest (meval meval-lambda) + (meval-lambda '(:lclosure 2 :call cons + (:cvar 0 1) + (:cvar 0 2)) + '(1 2) #()) + '(1 . 2)) + (deftest (meval :mcall :lclosure) (meval (lisp2li '((lambda (x y) (cons x y)) 1 2) ())) '(1 . 2)) @@ -201,12 +244,3 @@ la valeur de la dernier" (deftest (meval :mcall :lclosure) (meval (lisp2li '((lambda (x &rest y) (cons x y)) 1 2 3 4) ())) '(1 2 3 4)) - -(deftest (meval defun) - (meval '(defun foo (x) x)) - foo) - -(deftest (meval defun) - (meval '(defun foo (x y z) (list x y z))) - foo) - diff --git a/test-unitaire.lisp b/test-unitaire.lisp index eb96786..8549460 100644 --- a/test-unitaire.lisp +++ b/test-unitaire.lisp @@ -77,8 +77,11 @@ nil)))))) (defmacro deftestvar (module name value) - `(test-add-variable ',module - (list ',name (list 'copy-tree ',value)))) + (if (arrayp value) + `(test-add-variable ',module + (list ',name (list 'copy-seq ',value))) + `(test-add-variable ',module + (list ',name (list 'copy-tree ',value))))) (defvar run-tests-counter 0)