dd29e0799d742f520c633c63d955dc78eab1e596
[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 static inline int
18 frame_vals_num_size(int num)
19 {
20         return sizeof (struct ao_lisp_frame_vals) + num * sizeof (struct ao_lisp_val);
21 }
22
23 static int
24 frame_vals_size(void *addr)
25 {
26         struct ao_lisp_frame_vals       *vals = addr;
27         return frame_vals_num_size(vals->size);
28 }
29
30 static void
31 frame_vals_mark(void *addr)
32 {
33         struct ao_lisp_frame_vals       *vals = addr;
34         int                             f;
35
36         for (f = 0; f < vals->size; f++) {
37                 struct ao_lisp_val      *v = &vals->vals[f];
38
39                 ao_lisp_poly_mark(v->val, 0);
40                 MDBG_MOVE("frame mark atom %s %d val %d at %d\n",
41                           ao_lisp_poly_atom(v->atom)->name,
42                           MDBG_OFFSET(ao_lisp_ref(v->atom)),
43                           MDBG_OFFSET(ao_lisp_ref(v->val)), f);
44         }
45 }
46
47 static void
48 frame_vals_move(void *addr)
49 {
50         struct ao_lisp_frame_vals       *vals = addr;
51         int                             f;
52
53         for (f = 0; f < vals->size; f++) {
54                 struct ao_lisp_val      *v = &vals->vals[f];
55
56                 ao_lisp_poly_move(&v->atom, 0);
57                 ao_lisp_poly_move(&v->val, 0);
58                 MDBG_MOVE("frame move atom %s %d val %d at %d\n",
59                           ao_lisp_poly_atom(v->atom)->name,
60                           MDBG_OFFSET(ao_lisp_ref(v->atom)),
61                           MDBG_OFFSET(ao_lisp_ref(v->val)), f);
62         }
63 }
64
65 const struct ao_lisp_type ao_lisp_frame_vals_type = {
66         .mark = frame_vals_mark,
67         .size = frame_vals_size,
68         .move = frame_vals_move,
69         .name = "frame_vals"
70 };
71
72 static int
73 frame_size(void *addr)
74 {
75         (void) addr;
76         return sizeof (struct ao_lisp_frame);
77 }
78
79 static void
80 frame_mark(void *addr)
81 {
82         struct ao_lisp_frame    *frame = addr;
83
84         for (;;) {
85                 MDBG_MOVE("frame mark %d\n", MDBG_OFFSET(frame));
86                 if (!AO_LISP_IS_POOL(frame))
87                         break;
88                 ao_lisp_poly_mark(frame->vals, 0);
89                 frame = ao_lisp_poly_frame(frame->prev);
90                 MDBG_MOVE("frame next %d\n", MDBG_OFFSET(frame));
91                 if (!frame)
92                         break;
93                 if (ao_lisp_mark_memory(&ao_lisp_frame_type, frame))
94                         break;
95         }
96 }
97
98 static void
99 frame_move(void *addr)
100 {
101         struct ao_lisp_frame    *frame = addr;
102
103         for (;;) {
104                 struct ao_lisp_frame    *prev;
105                 int                     ret;
106
107                 MDBG_MOVE("frame move %d\n", MDBG_OFFSET(frame));
108                 if (!AO_LISP_IS_POOL(frame))
109                         break;
110                 ao_lisp_poly_move(&frame->vals, 0);
111                 prev = ao_lisp_poly_frame(frame->prev);
112                 if (!prev)
113                         break;
114                 ret = ao_lisp_move_memory(&ao_lisp_frame_type, (void **) &prev);
115                 if (prev != ao_lisp_poly_frame(frame->prev)) {
116                         MDBG_MOVE("frame prev moved from %d to %d\n",
117                                   MDBG_OFFSET(ao_lisp_poly_frame(frame->prev)),
118                                   MDBG_OFFSET(prev));
119                         frame->prev = ao_lisp_frame_poly(prev);
120                 }
121                 if (ret)
122                         break;
123                 frame = prev;
124         }
125 }
126
127 const struct ao_lisp_type ao_lisp_frame_type = {
128         .mark = frame_mark,
129         .size = frame_size,
130         .move = frame_move,
131         .name = "frame",
132 };
133
134 void
135 ao_lisp_frame_write(ao_poly p)
136 {
137         struct ao_lisp_frame            *frame = ao_lisp_poly_frame(p);
138         struct ao_lisp_frame_vals       *vals = ao_lisp_poly_frame_vals(frame->vals);
139         int                             f;
140
141         printf ("{");
142         if (frame) {
143                 if (frame->type & AO_LISP_FRAME_PRINT)
144                         printf("recurse...");
145                 else {
146                         frame->type |= AO_LISP_FRAME_PRINT;
147                         for (f = 0; f < frame->num; f++) {
148                                 if (f != 0)
149                                         printf(", ");
150                                 ao_lisp_poly_write(vals->vals[f].atom);
151                                 printf(" = ");
152                                 ao_lisp_poly_write(vals->vals[f].val);
153                         }
154                         if (frame->prev)
155                                 ao_lisp_poly_write(frame->prev);
156                         frame->type &= ~AO_LISP_FRAME_PRINT;
157                 }
158         }
159         printf("}");
160 }
161
162 static int
163 ao_lisp_frame_find(struct ao_lisp_frame *frame, int top, ao_poly atom)
164 {
165         struct ao_lisp_frame_vals       *vals = ao_lisp_poly_frame_vals(frame->vals);
166         int                             l = 0;
167         int                             r = top - 1;
168
169         while (l <= r) {
170                 int m = (l + r) >> 1;
171                 if (vals->vals[m].atom < atom)
172                         l = m + 1;
173                 else
174                         r = m - 1;
175         }
176         return l;
177 }
178
179 ao_poly *
180 ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom)
181 {
182         struct ao_lisp_frame_vals       *vals = ao_lisp_poly_frame_vals(frame->vals);
183         int                             l = ao_lisp_frame_find(frame, frame->num, atom);
184
185         if (l >= frame->num)
186                 return NULL;
187
188         if (vals->vals[l].atom != atom)
189                 return NULL;
190         return &vals->vals[l].val;
191 }
192
193 struct ao_lisp_frame    *ao_lisp_frame_free_list[AO_LISP_FRAME_FREE];
194
195 static struct ao_lisp_frame_vals *
196 ao_lisp_frame_vals_new(int num)
197 {
198         struct ao_lisp_frame_vals       *vals;
199
200         vals = ao_lisp_alloc(frame_vals_num_size(num));
201         if (!vals)
202                 return NULL;
203         vals->type = AO_LISP_FRAME_VALS;
204         vals->size = num;
205         return vals;
206 }
207
208 struct ao_lisp_frame *
209 ao_lisp_frame_new(int num)
210 {
211         struct ao_lisp_frame            *frame;
212         struct ao_lisp_frame_vals       *vals;
213
214         if (num < AO_LISP_FRAME_FREE && (frame = ao_lisp_frame_free_list[num])) {
215                 ao_lisp_frame_free_list[num] = ao_lisp_poly_frame(frame->prev);
216                 vals = ao_lisp_poly_frame_vals(frame->vals);
217         } else {
218                 frame = ao_lisp_alloc(sizeof (struct ao_lisp_frame));
219                 if (!frame)
220                         return NULL;
221                 frame->type = AO_LISP_FRAME;
222                 frame->num = 0;
223                 frame->prev = AO_LISP_NIL;
224                 frame->vals = AO_LISP_NIL;
225                 ao_lisp_poly_stash(0, ao_lisp_frame_poly(frame));
226                 vals = ao_lisp_frame_vals_new(num);
227                 frame = ao_lisp_poly_frame(ao_lisp_poly_fetch(0));
228                 frame->vals = ao_lisp_frame_vals_poly(vals);
229         }
230         frame->num = num;
231         frame->prev = AO_LISP_NIL;
232         memset(vals, '\0', vals->size * sizeof (struct ao_lisp_val));
233         return frame;
234 }
235
236 ao_poly
237 ao_lisp_frame_mark(struct ao_lisp_frame *frame)
238 {
239         if (!frame)
240                 return AO_LISP_NIL;
241         frame->type |= AO_LISP_FRAME_MARK;
242         return ao_lisp_frame_poly(frame);
243 }
244
245 void
246 ao_lisp_frame_free(struct ao_lisp_frame *frame)
247 {
248         if (!ao_lisp_frame_marked(frame)) {
249                 int     num = frame->num;
250                 if (num < AO_LISP_FRAME_FREE) {
251                         frame->prev = ao_lisp_frame_poly(ao_lisp_frame_free_list[num]);
252                         ao_lisp_frame_free_list[num] = frame;
253                 }
254         }
255 }
256
257 static struct ao_lisp_frame *
258 ao_lisp_frame_realloc(struct ao_lisp_frame *frame, int new_num)
259 {
260         struct ao_lisp_frame_vals       *vals;
261         struct ao_lisp_frame_vals       *new_vals;
262         int                             copy;
263
264         if (new_num == frame->num)
265                 return frame;
266         ao_lisp_frame_stash(0, frame);
267         new_vals = ao_lisp_frame_vals_new(new_num);
268         if (!new_vals)
269                 return NULL;
270         frame = ao_lisp_frame_fetch(0);
271         vals = ao_lisp_poly_frame_vals(frame->vals);
272         copy = new_num;
273         if (copy > frame->num)
274                 copy = frame->num;
275         memcpy(new_vals->vals, vals->vals, copy * sizeof (struct ao_lisp_val));
276         frame->vals = ao_lisp_frame_vals_poly(new_vals);
277         frame->num = new_num;
278         return frame;
279 }
280
281 void
282 ao_lisp_frame_bind(struct ao_lisp_frame *frame, int num, ao_poly atom, ao_poly val)
283 {
284         struct ao_lisp_frame_vals       *vals = ao_lisp_poly_frame_vals(frame->vals);
285         int                             l = ao_lisp_frame_find(frame, num, atom);
286
287         memmove(&vals->vals[l+1],
288                 &vals->vals[l],
289                 (num - l) * sizeof (struct ao_lisp_val));
290         vals->vals[l].atom = atom;
291         vals->vals[l].val = val;
292 }
293
294 int
295 ao_lisp_frame_add(struct ao_lisp_frame **frame_ref, ao_poly atom, ao_poly val)
296 {
297         struct ao_lisp_frame    *frame = *frame_ref;
298         ao_poly *ref = frame ? ao_lisp_frame_ref(frame, atom) : NULL;
299
300         if (!ref) {
301                 int f;
302                 ao_lisp_poly_stash(0, atom);
303                 ao_lisp_poly_stash(1, val);
304                 if (frame) {
305                         f = frame->num;
306                         frame = ao_lisp_frame_realloc(frame, f + 1);
307                 } else {
308                         f = 0;
309                         frame = ao_lisp_frame_new(1);
310                         *frame_ref = frame;
311                 }
312                 if (!frame)
313                         return 0;
314                 atom = ao_lisp_poly_fetch(0);
315                 val = ao_lisp_poly_fetch(1);
316                 ao_lisp_frame_bind(frame, frame->num - 1, atom, val);
317         } else
318                 *ref = val;
319         return 1;
320 }