altos/lisp: working on lexical scoping
[fw/altos] / src / lisp / ao_lisp_frame.c
1 /*
2  * Copyright © 2016 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  */
14
15 #include "ao_lisp.h"
16
17 #if 0
18 #define DBG(...)        printf(__VA_ARGS__)
19 #else
20 #define DBG(...)
21 #endif
22
23 static inline int
24 frame_num_size(int num)
25 {
26         return sizeof (struct ao_lisp_frame) + num * sizeof (struct ao_lisp_val);
27 }
28
29 static int
30 frame_size(void *addr)
31 {
32         struct ao_lisp_frame    *frame = addr;
33         return frame_num_size(frame->num);
34 }
35
36 #define OFFSET(a)       ((int) ((uint8_t *) (ao_lisp_ref(a)) - ao_lisp_const))
37
38 static void
39 frame_mark(void *addr)
40 {
41         struct ao_lisp_frame    *frame = addr;
42         int                     f;
43
44         for (;;) {
45                 DBG("frame mark %p\n", frame);
46                 if (!AO_LISP_IS_POOL(frame))
47                         break;
48                 for (f = 0; f < frame->num; f++) {
49                         struct ao_lisp_val      *v = &frame->vals[f];
50
51                         ao_lisp_poly_mark(v->val, 0);
52                         DBG ("\tframe mark atom %s %d val %d at %d\n",
53                              ao_lisp_poly_atom(v->atom)->name,
54                              OFFSET(v->atom), OFFSET(v->val), f);
55                 }
56                 frame = ao_lisp_poly_frame(frame->next);
57                 DBG("frame next %p\n", frame);
58                 if (!frame)
59                         break;
60                 if (ao_lisp_mark_memory(frame, frame_size(frame)))
61                         break;
62         }
63 }
64
65 static void
66 frame_move(void *addr)
67 {
68         struct ao_lisp_frame    *frame = addr;
69         int                     f;
70
71         for (;;) {
72                 struct ao_lisp_frame    *next;
73                 int                     ret;
74
75                 DBG("frame move %p\n", frame);
76                 if (!AO_LISP_IS_POOL(frame))
77                         break;
78                 for (f = 0; f < frame->num; f++) {
79                         struct ao_lisp_val      *v = &frame->vals[f];
80
81                         ao_lisp_poly_move(&v->atom, 0);
82                         DBG("moved atom %s\n", ao_lisp_poly_atom(v->atom)->name);
83                         ao_lisp_poly_move(&v->val, 0);
84                 }
85                 next = ao_lisp_poly_frame(frame->next);
86                 ret = 1;
87                 if (next)
88                         ret = ao_lisp_move_memory((void **) &next, frame_size(next));
89                 if (next != ao_lisp_poly_frame(frame->next))
90                         frame->next = ao_lisp_frame_poly(next);
91                 if (ret)
92                         break;
93                 frame = next;
94         }
95 }
96
97 const struct ao_lisp_type ao_lisp_frame_type = {
98         .mark = frame_mark,
99         .size = frame_size,
100         .move = frame_move
101 };
102
103 void
104 ao_lisp_frame_print(ao_poly p)
105 {
106         struct ao_lisp_frame    *frame = ao_lisp_poly_frame(p);
107         int                     f;
108
109         printf ("{");
110         if (frame) {
111                 for (f = 0; f < frame->num; f++) {
112                         if (f != 0)
113                                 printf(", ");
114                         ao_lisp_poly_print(frame->vals[f].atom);
115                         printf(" = ");
116                         ao_lisp_poly_print(frame->vals[f].val);
117                 }
118                 if (frame->next)
119                         ao_lisp_poly_print(frame->next);
120         }
121         printf("}");
122 }
123
124 ao_poly *
125 ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom)
126 {
127         int f;
128         for (f = 0; f < frame->num; f++)
129                 if (frame->vals[f].atom == atom)
130                         return &frame->vals[f].val;
131         return NULL;
132 }
133
134 int
135 ao_lisp_frame_set(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val)
136 {
137         while (frame) {
138                 if (!AO_LISP_IS_CONST(frame)) {
139                         ao_poly *ref = ao_lisp_frame_ref(frame, atom);
140                         if (ref) {
141                                 *ref = val;
142                                 return 1;
143                         }
144                 }
145                 frame = ao_lisp_poly_frame(frame->next);
146         }
147         return 0;
148 }
149
150 ao_poly
151 ao_lisp_frame_get(struct ao_lisp_frame *frame, ao_poly atom)
152 {
153         while (frame) {
154                 ao_poly *ref = ao_lisp_frame_ref(frame, atom);
155                 if (ref)
156                         return *ref;
157                 frame = ao_lisp_poly_frame(frame->next);
158         }
159         return AO_LISP_NIL;
160 }
161
162 struct ao_lisp_frame *
163 ao_lisp_frame_new(int num)
164 {
165         struct ao_lisp_frame *frame = ao_lisp_alloc(frame_num_size(num));
166
167         if (!frame)
168                 return NULL;
169         frame->type = AO_LISP_FRAME;
170         frame->num = num;
171         frame->next = AO_LISP_NIL;
172         memset(frame->vals, '\0', num * sizeof (struct ao_lisp_val));
173         return frame;
174 }
175
176 static struct ao_lisp_frame *
177 ao_lisp_frame_realloc(struct ao_lisp_frame *frame, int new_num)
178 {
179         struct ao_lisp_frame    *new;
180         int                     copy;
181
182         if (new_num == frame->num)
183                 return frame;
184         new = ao_lisp_frame_new(new_num);
185         if (!new)
186                 return NULL;
187         copy = new_num;
188         if (copy > frame->num)
189                 copy = frame->num;
190         memcpy(new->vals, frame->vals, copy * sizeof (struct ao_lisp_val));
191         if (frame)
192                 new->next = frame->next;
193         return new;
194 }
195
196 struct ao_lisp_frame *
197 ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val)
198 {
199         ao_poly *ref = frame ? ao_lisp_frame_ref(frame, atom) : NULL;
200         if (!ref) {
201                 int f;
202                 if (frame) {
203                         f = frame->num;
204                         frame = ao_lisp_frame_realloc(frame, f + 1);
205                 } else {
206                         f = 0;
207                         frame = ao_lisp_frame_new(1);
208                 }
209                 if (!frame)
210                         return NULL;
211                 DBG ("add atom %s %d, val %d at %d\n", ao_lisp_poly_atom(atom)->name, OFFSET(atom), OFFSET(val), f);
212                 frame->vals[f].atom = atom;
213                 ref = &frame->vals[f].val;
214         }
215         *ref = val;
216         return frame;
217 }