-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathenvironnement.lisp
152 lines (135 loc) · 5.31 KB
/
environnement.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
;; Gestion de l'environnement
;; Attention :
;; - Lorsqu'on fait un setf, ça renvoie la valeur affectée, pas
;; l'objet modifié. Si on veut le renvoyer, il faut explicitement
;; le mettre après le setf.
;; - Les environnements sont partagés entre toutes les clôtures et
;; autres qui les utilisent. Par ex. :
;; (let ((x 0))
;; (lambda () (setf (x) (+ x 1)))
;; (lambda () x))
;; Dans ce cas, les deux lambdas ont accès au même x, dans le même
;; environnement. La modification par l'une des fonctions se
;; répercute sur la valeur accédée par l'autre.
;; - Lorsqu'on définit une fonction, il faut mettre juste après la
;; liste des paramètres une chaîne de caractères qui documente la
;; fonction (une docstring).
;; - L'environnement top-level est partage par tous le monde
;; Exemple de la structure env-stack après création de deux
;; environnements en plus du top-level et ajout de plusieurs laisons.
(require 'test-unitaire "test-unitaire")
(erase-tests environnement)
(deftestvar environnement exemple-env-stack
'(;; Environnement le plus bas (dernières définitions par ordre
;; chronologique).
("DEFUN"
(x . plop))
;; Un autre environnement (définitions "plus vieilles").
("LET"
(y . "#lambda")
(x . "bijour")
(z . 123))
;; Top-level. Environnement le plus haut (définitions "globales"
;; faites avec defun, defvar etc.).
("TOP-LEVEL"
(y . 56)
(x . 42)
(foo . "#lambda"))))
;; '((...) (...) (...)) => 3 environnement dans env-stack
(defun empty-env-stack ()
"Constructeur de la pile d'environnements."
(list (list (copy-seq "TOP-LEVEL"))))
(defun push-new-env (env-stack name)
"Crée un nouvel environnement, l'ajoute à ENV-STACK et renvoie la
version modifiée (sans altérer l'original).
Le paramètre ENV-STACK est toute la pile d'environnements."
(cons (list name) env-stack))
(defun add-binding (env-stack name value)
"Ajoute une liaison au dernier environnement (le plus bas)."
(setf (cdar env-stack)
(cons (cons name value)
(cdar env-stack)))
env-stack)
(defun get-binding (env-stack name)
"Récupère la liaison correspondant à NAME ."
(if (atom env-stack)
nil ; TODO : Penser à peut-être mettre un warn ou error.
(let ((ass (assoc name (cdar env-stack))))
(if ass ass
(get-binding (cdr env-stack) name)))))
(defun set-binding (env-stack name new-value)
"Modifie la valeur associée à une liaison."
(setf (cdr (get-binding env-stack name))
new-value)
env-stack)
(defun get-binding-value (env-stack name)
"Récupère la valeur associée a NAME ."
(cdr (get-binding env-stack name)))
(defun top-level-env-stack (env-stack)
"Recupere la pile d'environnement contenant uniquement
l'environnement top-level"
(if (atom (cdr env-stack))
env-stack
(top-level-env-stack (cdr env-stack))))
(defun get-top-level-binding (env-stack name)
"Récupère la liaison au top-level correspondant à NAME ."
(get-binding (top-level-env-stack env-stack) name))
(defun add-top-level-binding (env-stack name value)
"Ajoute une liaison \"globale\" à l'environnement top-level."
(add-binding (top-level-env-stack env-stack) name value)
env-stack)
(defun set-top-level-binding (env-stack name new-value) ;; modifie une definition
"Modifie la valeur associée à une liaison \"globale\" de
l'environnement top-level."
(set-binding (top-level-env-stack env-stack) name new-value)
env-stack)
(defun print-env-stack (env-stack)
(let ((*print-circle* t))
(if (atom env-stack)
nil
(progn (format t "~&~a: " (caar env-stack))
(mapcar (lambda (b) (format t "~& ~w = ~w" (car b) (cdr b)))
(cdar env-stack))
(print-env-stack (cdr env-stack))))))
;;Test Unitaire
(deftest environnement
(push-new-env (env-var (empty-env-stack)) "TEST")
'(("TEST") "TOP-LEVEL"))
(deftest environnement
(push-new-env exemple-env-stack "TEST")
(cons '("TEST") exemple-env-stack))
(deftest environnement
(add-binding (empty-env-stack) 'x 42)
'(("TOP-LEVEL" (x . 42))))
(deftest environnement
(add-binding (push-new-env (empty-env-stack) "FOO-BAR") 'x 42)
'(("FOO-BAR" (x . 42)) ("TOP-LEVEL")))
(deftest environnement
(add-binding (add-binding (empty-env-stack) 'x 42) 'y 56)
'(("TOP-LEVEL" (y . 56) (x . 42))))
;; TODO : Rajouter un test d'erreur => Georges!!!!!!
;(deftest environnement (set-binding (empty-env-stack) 'x 42) nil)
(deftest environnement
(set-binding (add-binding (empty-env-stack) 'x 42) 'x .42)
'(("TOP-LEVEL" (x . .42))))
(deftest environnement
(get-binding '(("TOP-LEVEL" (X . 42)))
'x)
'(x . 42))
(deftest environnement
(get-binding-value '(("FOO" (Z . 42)) ("TOP-LEVEL" (x . 42)))
'x)
42)
(deftest environnement
(top-level-env-stack '(("BAR" (X . 42))
("TOP-LEVEL" (X . 24) (Z . 73))))
'(("TOP-LEVEL" (X . 24) (Z . 73))))
(deftest environnement
(add-top-level-binding (copy-tree '(("TEST" (X . 42)) ("TOP-LEVEL" (Y . 56))))
'Z 78)
'(("TEST" (X . 42)) ("TOP-LEVEL" (Z . 78) (Y . 56))))
(deftest environnement
(set-top-level-binding (copy-tree '(("LEVEL2" (X . 42)) ("TOP-LEVEL" (Y . 56))))
'Y "42")
'(("LEVEL2" (X . 42)) ("TOP-LEVEL" (Y . "42"))))
(provide 'environnement)