meval.lisp (9944B)
1 (require 'match "match") 2 3 (defun env-size (env) 4 (if (or (equalp env #()) (eq env nil)) 5 0 6 (+ 1 (env-size (aref env 0))))) 7 8 (defun get-env-num-r (num env counter) 9 (cond ((or (equalp env #()) (eq env nil)) 10 env) 11 ((= num counter) 12 env) 13 (T 14 (get-env-num-r num (aref env 0) (- counter 1))))) 15 16 (defun get-env-num (num env) 17 "Récupère l’environnement correspondant à celui souhaité." 18 (get-env-num-r num env (- (env-size env) 1))) 19 20 (defun current-env (env) 21 (let ((env-size (- (env-size env) 1))) 22 (defun current-env-r (env counter) 23 (if (= counter env-size) 24 env 25 (current-env-r (aref env 0) (+ counter 1)))) 26 (current-env-r env 0))) 27 28 (defun get-lower-env (env) 29 "Récupère l’environnement le plus bas" 30 (if (or (= (array-total-size env) 0) 31 (eq (aref env 0) nil)) 32 env 33 (get-lower-env (aref env 0)))) 34 35 (defun make-rest-lower-env (lower-env pos values pos-rest) 36 (cond ((= pos pos-rest) 37 (setf (aref lower-env pos) values)) 38 (T 39 (setf (aref lower-env pos) (car values)) 40 (make-rest-lower-env lower-env 41 (+ pos 1) 42 (cdr values) 43 pos-rest)))) 44 45 (defun make-rest (env values &optional (pos-rest 1)) 46 "Construit l'environnement en rajoutant tous les valeurs 47 du &rest dans une cellule de l'env sous forme d'une liste" 48 (let ((size (- (array-total-size env) 1))) 49 (make-rest-lower-env env 1 values pos-rest)) 50 env) 51 52 (defun make-env (size list-values env &optional pos-rest) 53 "Construis l’environnement en appariant les paramètres aux valeurs 54 correspondantes et signale une exception si paramètres et arguments 55 ne concordent pas. Si l’environnement passe en paramètre n’est pas vide, 56 le nouvel environnement y est inclus." 57 (let ((new-env (copy-all env))) 58 (cond ((and (not pos-rest) 59 (< size (length list-values))) 60 (error "Too arguments")) 61 ((> size (length list-values)) 62 (error "Too few arguments")) 63 (T 64 (if (= (array-total-size new-env) 0) 65 (setf new-env (make-array (+ 1 size) :initial-element nil)) 66 (setf (aref (get-lower-env new-env) 0) (make-array (+ 1 size) :initial-element nil))) 67 (let ((lower-env (get-lower-env new-env))) 68 (if pos-rest 69 (make-rest lower-env 70 list-values 71 pos-rest) 72 (loop 73 for value in list-values 74 for rank = 1 then (+ rank 1) 75 do (setf (aref lower-env rank) value) 76 ))) 77 new-env)))) 78 79 (declaim (ftype function meval)) ;; Récursion mutuelle meval / map-meval + meval-body + meval-args + meval-lambda + msetf 80 81 (defun map-meval (list env) 82 (mapcar (lambda (x) (meval x env)) list)) 83 84 (defun meval-body (list-expr env) 85 "Évalue en séquence la liste des expressions et 86 retourne la valeur retournée par la dernière" 87 (if (endp list-expr) 88 nil 89 (if (endp (cdr list-expr)) 90 (meval (car list-expr) env) 91 (progn 92 (meval (car list-expr) env) 93 (meval-body (cdr list-expr) env))))) 94 95 (defun meval-args (list-expr env) 96 "Évalue en séquence la liste des expressions et 97 retourne la liste de leurs valeurs" 98 (if (endp list-expr) 99 nil 100 (if (endp (cdr list-expr)) 101 `(,(meval (car list-expr) env)) 102 `(,(meval (car list-expr) env) 103 ,@(meval-args (cdr list-expr) env))))) 104 105 (defun meval-lambda (lclosure args env) 106 "Applique une λ-fonction quelconque à des valeurs 107 d’arguments dans un certain environnement." 108 (match (:nil :lclosure :size (? integerp) :rest (? integerp)? :body _*) lclosure 109 (meval lclosure 110 (make-env size args env (car rest))))) 111 112 (defun msetf (place val env) 113 (let ((sub-env (get-env-num (first place) env))) 114 (if sub-env 115 (setf (aref sub-env (second place)) 116 (meval val env))))) 117 118 (defun make-empty-list (size) 119 (if (= size 0) 120 nil 121 (cons nil (make-empty-list (- size 1))))) 122 123 (defun meval (expr &optional (env #())) 124 "Interprète le langage intermédiaire passé en paramètre." 125 (cond-match expr 126 ((:nil :const :val . _) expr val) 127 ((:nil :cvar :num-env (? integerp) :index (? integerp)) 128 (if (= num-env 0) 129 (aref (current-env env) index) 130 (let ((sub-env (get-env-num num-env env))) 131 (if sub-env 132 (aref sub-env index) 133 (error "The variable unbound : ~w" expr))))) 134 ((:nil :if :predicat @. :expr1 @. :expr2 @.) 135 (if (meval predicat env) 136 (meval expr1 env) 137 (meval expr2 env))) 138 ((:nil :mcall set-defun :func-name @. :closure _*) 139 (let ((name (meval func-name env))) 140 (setf (get name :defun) closure) 141 name)) 142 ((:nil :mcall set-defmacro :macro-name @. :closure _*) 143 (let ((name (meval macro-name env))) 144 (setf (get name :defmacro) closure) 145 name)) 146 ((:nil :mcall :func-name (? $$ (get x :defun)) :params _*) 147 (let ((values (meval-args params env))) 148 (meval-lambda (car (get func-name :defun)) 149 values 150 (make-env (length values) values env)))) 151 ((:nil :mcall :macro-name (? $$ (get x :defmacro)) :params _*) 152 (let ((values (meval-args params env))) 153 (meval (lisp2li (meval-lambda (car (get macro-name :defmacro)) 154 params 155 (make-env (length values) values env)) 156 env) 157 env))) 158 ((:nil :mcall :lambda (:nil :lclosure (? integerp) (? integerp)? _*) :args _*) 159 (meval-lambda lambda (meval-args args env) env)) 160 ((:nil :call :func-name _ :body _*) 161 (apply (symbol-function func-name) (meval-args body env))) 162 ((:nil :progn :body _*) 163 (meval-body body env)) 164 ((:nil :lclosure :size (? integerp) :rest (? integerp)? :body _*) 165 (meval-body `(,body) env)) 166 ((:nil :set-var :place @. :value _) 167 (msetf place value env)) 168 ((:nil :let :size (? integerp) :affectations (:nil :set-var :places @ :values _)* :body _*) 169 (meval-body body (make-env size (meval-args values env) env))) 170 ((:nil :unknown :call (:name $ :params _*) :environ _*) 171 (lisp2li call environ)) 172 (_* 173 (error "form special ~S not yet implemented" expr)))) 174 175 ;; Test unitaire 176 (require 'test-unitaire "test-unitaire") 177 (require 'lisp2li "lisp2li") 178 (erase-tests meval) 179 (deftest (meval :const) 180 (meval (lisp2li 3 ())) 181 3) 182 183 (deftest (meval quote) 184 (meval (lisp2li '3 ())) 185 3) 186 187 (deftest (meval quote) 188 (meval (lisp2li ''3 ())) 189 3) 190 191 (deftest (meval quote) 192 (meval (lisp2li '''3 ())) 193 ''3) 194 195 (deftest (meval :cvar) 196 (meval (lisp2li 'x '((x 0 2))) #(() 4 5 6)) 197 5) 198 199 (deftest (meval :cvar) 200 (meval '(:cvar 1 2) #(#(() 7 8) 4 5 6)) 201 5) 202 203 (deftest (meval :call) 204 (meval '(:call + (:const . 3) (:cvar 0 1)) #(() 4 5 6)) 205 7) 206 207 (deftest (meval :call) 208 (meval '(:call list (:const . 3) (:const . 2))) 209 '(3 2)) 210 211 (deftest (meval :if) 212 (meval '(:if (:const . T) 213 (:const . T) 214 (:const . nil))) 215 T) 216 217 (deftest (meval :if) 218 (meval '(:if (:call eq (:const . 1) 219 (:cvar 0 1)) 220 (:const . T) 221 (:const . nil)) #(() 1 2 3)) 222 T) 223 224 (deftestvar (meval make-env) empty-env #()) 225 (deftest (meval make-env) 226 (make-env 2 '(1 2) empty-env) 227 #(() 1 2) 228 #'equalp) 229 230 (deftestvar (meval make-env) env #(() 1 2)) 231 (deftest (meval make-env) 232 (make-env 2 '(7 8) env) 233 #(#(() 7 8) 1 2) 234 #'equalp) 235 236 (deftestvar (meval make-env make-rest) env #(() nil nil)) 237 (deftest (meval make-env make-rest) 238 (make-rest env '(1 2 3 4) 2) 239 #(() 1 (2 3 4)) 240 #'equalp) 241 242 (deftestvar (meval make-env &rest) env #(() 1 2)) 243 (deftest (meval make-env &rest) 244 (make-env 2 '(7 8 9) env 2) 245 #(#(() 7 (8 9)) 1 2) 246 #'equalp) 247 248 (deftest (meval make-env &rest) 249 (make-env 1 '(nil) env 1) 250 #(#(() (nil)) 1 2) 251 #'equalp) 252 253 (deftest (meval meval-body) 254 (meval-body '((:const . 3)) #()) 255 '3) 256 257 (deftest (meval meval-body) 258 (meval-body '((:const . 3) (:call cons (:const . 1) (:const . 2))) #()) 259 '(1 . 2)) 260 261 (deftest (meval meval-args) 262 (meval-args '((:const . 3)) #()) 263 '(3)) 264 265 (deftest (meval meval-args) 266 (meval-args '((:const . 3) (:const 1 2 3)) #()) 267 '(3 (1 2 3))) 268 269 (deftest (meval meval-args) 270 (meval-args '((:cvar 0 1) (:call cons (:cvar 0 3) 271 (:cvar 0 2))) #(() 1 2 3)) 272 '(1 (3 . 2))) 273 274 (deftest (meval meval-lambda) 275 (meval-lambda '(:lclosure 2 :call cons 276 (:cvar 0 1) 277 (:cvar 0 2)) 278 '(1 2) #()) 279 '(1 . 2)) 280 281 (deftest (meval :mcall :lclosure) 282 (meval (lisp2li '((lambda (x y) (cons x y)) 1 2) ())) 283 '(1 . 2)) 284 285 (deftest (meval :mcall :lclosure) 286 (meval (lisp2li '((lambda (x &rest y) (cons x y)) 1 2 3 4) ())) 287 '(1 2 3 4)) 288 289 (deftestvar (meval :set-var) env #(() 2)) 290 (deftest (meval :set-var) 291 (progn 292 (meval (lisp2li '(setf x 42) '((x 0 1))) env) 293 env) 294 #(() 42) 295 ;; Pour une raison totalement inexplicable, ce test fail avec #'equalp sous sbcl 296 ;; alors que les deux objets sont equalp en dehors du test (si on les met dans deux 297 ;; variable globale pour tester après). Pour l'instant, cette fonction suffira. 298 (lambda (x y) 299 (every #'identity (map 'list (lambda (x y) (or (eq x y) (and (numberp x) (numberp y) (= x y)))) x y)))) 300 301 (provide 'meval)