a7e5153f5257f22d2594cdce596e94ed9bfcc62c
[fw/altos] / src / scheme / ao_scheme_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_scheme.h"
16
17 static inline int
18 frame_vals_num_size(int num)
19 {
20         return sizeof (struct ao_scheme_frame_vals) + num * sizeof (struct ao_scheme_val);
21 }
22
23 static int
24 frame_vals_size(void *addr)
25 {
26         struct ao_scheme_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_scheme_frame_vals     *vals = addr;
34         int                             f;
35
36         for (f = 0; f < vals->size; f++) {
37                 struct ao_scheme_val    *v = &vals->vals[f];
38
39                 ao_scheme_poly_mark(v->val, 0);
40                 MDBG_MOVE("frame mark atom %s %d val %d at %d    ",
41                           ao_scheme_poly_atom(v->atom)->name,
42                           MDBG_OFFSET(ao_scheme_ref(v->atom)),
43                           MDBG_OFFSET(ao_scheme_ref(v->val)), f);
44                 MDBG_DO(printf("\n"));
45         }
46 }
47
48 static void
49 frame_vals_move(void *addr)
50 {
51         struct ao_scheme_frame_vals     *vals = addr;
52         int                             f;
53
54         for (f = 0; f < vals->size; f++) {
55                 struct ao_scheme_val    *v = &vals->vals[f];
56
57                 ao_scheme_poly_move(&v->atom, 0);
58                 ao_scheme_poly_move(&v->val, 0);
59                 MDBG_MOVE("frame move atom %s %d val %d at %d\n",
60                           ao_scheme_poly_atom(v->atom)->name,
61                           MDBG_OFFSET(ao_scheme_ref(v->atom)),
62                           MDBG_OFFSET(ao_scheme_ref(v->val)), f);
63         }
64 }
65
66 const struct ao_scheme_type ao_scheme_frame_vals_type = {
67         .mark = frame_vals_mark,
68         .size = frame_vals_size,
69         .move = frame_vals_move,
70         .name = "frame_vals"
71 };
72
73 static int
74 frame_size(void *addr)
75 {
76         (void) addr;
77         return sizeof (struct ao_scheme_frame);
78 }
79
80 static void
81 frame_mark(void *addr)
82 {
83         struct ao_scheme_frame  *frame = addr;
84
85         for (;;) {
86                 struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
87
88                 MDBG_MOVE("frame mark %d\n", MDBG_OFFSET(frame));
89                 if (!ao_scheme_mark_memory(&ao_scheme_frame_vals_type, vals))
90                         frame_vals_mark(vals);
91                 frame = ao_scheme_poly_frame(frame->prev);
92                 MDBG_MOVE("frame next %d\n", MDBG_OFFSET(frame));
93                 if (!frame)
94                         break;
95                 if (ao_scheme_mark_memory(&ao_scheme_frame_type, frame))
96                         break;
97         }
98 }
99
100 static void
101 frame_move(void *addr)
102 {
103         struct ao_scheme_frame  *frame = addr;
104
105         for (;;) {
106                 struct ao_scheme_frame          *prev;
107                 struct ao_scheme_frame_vals     *vals;
108                 int                             ret;
109
110                 MDBG_MOVE("frame move %d\n", MDBG_OFFSET(frame));
111                 vals = ao_scheme_poly_frame_vals(frame->vals);
112                 if (!ao_scheme_move_memory(&ao_scheme_frame_vals_type, (void **) &vals))
113                         frame_vals_move(vals);
114                 if (vals != ao_scheme_poly_frame_vals(frame->vals))
115                         frame->vals = ao_scheme_frame_vals_poly(vals);
116
117                 prev = ao_scheme_poly_frame(frame->prev);
118                 if (!prev)
119                         break;
120                 ret = ao_scheme_move_memory(&ao_scheme_frame_type, (void **) &prev);
121                 if (prev != ao_scheme_poly_frame(frame->prev)) {
122                         MDBG_MOVE("frame prev moved from %d to %d\n",
123                                   MDBG_OFFSET(ao_scheme_poly_frame(frame->prev)),
124                                   MDBG_OFFSET(prev));
125                         frame->prev = ao_scheme_frame_poly(prev);
126                 }
127                 if (ret)
128                         break;
129                 frame = prev;
130         }
131 }
132
133 const struct ao_scheme_type ao_scheme_frame_type = {
134         .mark = frame_mark,
135         .size = frame_size,
136         .move = frame_move,
137         .name = "frame",
138 };
139
140 int ao_scheme_frame_print_indent;
141
142 static void
143 ao_scheme_frame_indent(int extra)
144 {
145         int                             i;
146         putchar('\n');
147         for (i = 0; i < ao_scheme_frame_print_indent+extra; i++)
148                 putchar('\t');
149 }
150
151 void
152 ao_scheme_frame_write(ao_poly p, bool write)
153 {
154         struct ao_scheme_frame          *frame = ao_scheme_poly_frame(p);
155         struct ao_scheme_frame          *clear = frame;
156         struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
157         int                             f;
158         int                             written = 0;
159
160         ao_scheme_print_start();
161         while (frame) {
162                 if (written != 0)
163                         printf(", ");
164                 if (ao_scheme_print_mark_addr(frame)) {
165                         printf("recurse...");
166                         break;
167                 }
168
169                 putchar('{');
170                 written++;
171                 for (f = 0; f < frame->num; f++) {
172                         ao_scheme_frame_indent(1);
173                         ao_scheme_poly_write(vals->vals[f].atom, write);
174                         printf(" = ");
175                         ao_scheme_poly_write(vals->vals[f].val, write);
176                 }
177                 frame = ao_scheme_poly_frame(frame->prev);
178                 ao_scheme_frame_indent(0);
179                 putchar('}');
180         }
181         if (ao_scheme_print_stop()) {
182                 while (written--) {
183                         ao_scheme_print_clear_addr(clear);
184                         clear = ao_scheme_poly_frame(clear->prev);
185                 }
186         }
187 }
188
189 static int
190 ao_scheme_frame_find(struct ao_scheme_frame *frame, int top, ao_poly atom)
191 {
192         struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
193         int                             l = 0;
194         int                             r = top - 1;
195
196         while (l <= r) {
197                 int m = (l + r) >> 1;
198                 if (vals->vals[m].atom < atom)
199                         l = m + 1;
200                 else
201                         r = m - 1;
202         }
203         return l;
204 }
205
206 ao_poly *
207 ao_scheme_frame_ref(struct ao_scheme_frame *frame, ao_poly atom)
208 {
209         struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
210         int                             l = ao_scheme_frame_find(frame, frame->num, atom);
211
212         if (l >= frame->num)
213                 return NULL;
214
215         if (vals->vals[l].atom != atom)
216                 return NULL;
217         return &vals->vals[l].val;
218 }
219
220 struct ao_scheme_frame  *ao_scheme_frame_free_list[AO_SCHEME_FRAME_FREE];
221
222 static struct ao_scheme_frame_vals *
223 ao_scheme_frame_vals_new(int num)
224 {
225         struct ao_scheme_frame_vals     *vals;
226
227         vals = ao_scheme_alloc(frame_vals_num_size(num));
228         if (!vals)
229                 return NULL;
230         vals->type = AO_SCHEME_FRAME_VALS;
231         vals->size = num;
232         memset(vals->vals, '\0', num * sizeof (struct ao_scheme_val));
233         return vals;
234 }
235
236 struct ao_scheme_frame *
237 ao_scheme_frame_new(int num)
238 {
239         struct ao_scheme_frame          *frame;
240         struct ao_scheme_frame_vals     *vals;
241
242         if (num < AO_SCHEME_FRAME_FREE && (frame = ao_scheme_frame_free_list[num])) {
243                 ao_scheme_frame_free_list[num] = ao_scheme_poly_frame(frame->prev);
244                 vals = ao_scheme_poly_frame_vals(frame->vals);
245         } else {
246                 frame = ao_scheme_alloc(sizeof (struct ao_scheme_frame));
247                 if (!frame)
248                         return NULL;
249                 frame->type = AO_SCHEME_FRAME;
250                 frame->num = 0;
251                 frame->prev = AO_SCHEME_NIL;
252                 frame->vals = AO_SCHEME_NIL;
253                 ao_scheme_frame_stash(0, frame);
254                 vals = ao_scheme_frame_vals_new(num);
255                 frame = ao_scheme_frame_fetch(0);
256                 if (!vals)
257                         return NULL;
258                 frame->vals = ao_scheme_frame_vals_poly(vals);
259                 frame->num = num;
260         }
261         frame->prev = AO_SCHEME_NIL;
262         return frame;
263 }
264
265 ao_poly
266 ao_scheme_frame_mark(struct ao_scheme_frame *frame)
267 {
268         if (!frame)
269                 return AO_SCHEME_NIL;
270         frame->type |= AO_SCHEME_FRAME_MARK;
271         return ao_scheme_frame_poly(frame);
272 }
273
274 void
275 ao_scheme_frame_free(struct ao_scheme_frame *frame)
276 {
277         if (frame && !ao_scheme_frame_marked(frame)) {
278                 int     num = frame->num;
279                 if (num < AO_SCHEME_FRAME_FREE) {
280                         struct ao_scheme_frame_vals     *vals;
281
282                         vals = ao_scheme_poly_frame_vals(frame->vals);
283                         memset(vals->vals, '\0', vals->size * sizeof (struct ao_scheme_val));
284                         frame->prev = ao_scheme_frame_poly(ao_scheme_frame_free_list[num]);
285                         ao_scheme_frame_free_list[num] = frame;
286                 }
287         }
288 }
289
290 static struct ao_scheme_frame *
291 ao_scheme_frame_realloc(struct ao_scheme_frame *frame, int new_num)
292 {
293         struct ao_scheme_frame_vals     *vals;
294         struct ao_scheme_frame_vals     *new_vals;
295         int                             copy;
296
297         if (new_num == frame->num)
298                 return frame;
299         ao_scheme_frame_stash(0, frame);
300         new_vals = ao_scheme_frame_vals_new(new_num);
301         frame = ao_scheme_frame_fetch(0);
302         if (!new_vals)
303                 return NULL;
304         vals = ao_scheme_poly_frame_vals(frame->vals);
305         copy = new_num;
306         if (copy > frame->num)
307                 copy = frame->num;
308         memcpy(new_vals->vals, vals->vals, copy * sizeof (struct ao_scheme_val));
309         frame->vals = ao_scheme_frame_vals_poly(new_vals);
310         frame->num = new_num;
311         return frame;
312 }
313
314 void
315 ao_scheme_frame_bind(struct ao_scheme_frame *frame, int num, ao_poly atom, ao_poly val)
316 {
317         struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
318         int                             l = ao_scheme_frame_find(frame, num, atom);
319
320         memmove(&vals->vals[l+1],
321                 &vals->vals[l],
322                 (num - l) * sizeof (struct ao_scheme_val));
323         vals->vals[l].atom = atom;
324         vals->vals[l].val = val;
325 }
326
327 ao_poly
328 ao_scheme_frame_add(struct ao_scheme_frame *frame, ao_poly atom, ao_poly val)
329 {
330         ao_poly *ref = frame ? ao_scheme_frame_ref(frame, atom) : NULL;
331
332         if (!ref) {
333                 int f = frame->num;
334                 ao_scheme_poly_stash(0, atom);
335                 ao_scheme_poly_stash(1, val);
336                 frame = ao_scheme_frame_realloc(frame, f + 1);
337                 val = ao_scheme_poly_fetch(1);
338                 atom = ao_scheme_poly_fetch(0);
339                 if (!frame)
340                         return AO_SCHEME_NIL;
341                 ao_scheme_frame_bind(frame, frame->num - 1, atom, val);
342         } else
343                 *ref = val;
344         return val;
345 }
346
347 struct ao_scheme_frame  *ao_scheme_frame_global;
348 struct ao_scheme_frame  *ao_scheme_frame_current;
349
350 void
351 ao_scheme_frame_init(void)
352 {
353         if (!ao_scheme_frame_global)
354                 ao_scheme_frame_global = ao_scheme_frame_new(0);
355 }