17fa141a00e014aec425b78303e3faded572241c
[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_num_size(int num)
19 {
20         return sizeof (struct ao_lisp_frame) + num * sizeof (struct ao_lisp_val);
21 }
22
23 static int
24 frame_size(void *addr)
25 {
26         struct ao_lisp_frame    *frame = addr;
27         return frame_num_size(frame->num);
28 }
29
30 static void
31 frame_mark(void *addr)
32 {
33         struct ao_lisp_frame    *frame = addr;
34         int                     f;
35
36         for (;;) {
37                 MDBG_MOVE("frame mark %d\n", MDBG_OFFSET(frame));
38                 if (!AO_LISP_IS_POOL(frame))
39                         break;
40                 for (f = 0; f < frame->num; f++) {
41                         struct ao_lisp_val      *v = &frame->vals[f];
42
43                         ao_lisp_poly_mark(v->val, 0);
44                         MDBG_MOVE("frame mark atom %s %d val %d at %d\n",
45                                   ao_lisp_poly_atom(v->atom)->name,
46                                   MDBG_OFFSET(ao_lisp_ref(v->atom)),
47                                   MDBG_OFFSET(ao_lisp_ref(v->val)), f);
48                 }
49                 frame = ao_lisp_poly_frame(frame->prev);
50                 MDBG_MOVE("frame next %d\n", MDBG_OFFSET(frame));
51                 if (!frame)
52                         break;
53                 if (ao_lisp_mark_memory(&ao_lisp_frame_type, frame))
54                         break;
55         }
56 }
57
58 static void
59 frame_move(void *addr)
60 {
61         struct ao_lisp_frame    *frame = addr;
62         int                     f;
63
64         for (;;) {
65                 struct ao_lisp_frame    *prev;
66                 int                     ret;
67
68                 MDBG_MOVE("frame move %d\n", MDBG_OFFSET(frame));
69                 if (!AO_LISP_IS_POOL(frame))
70                         break;
71                 for (f = 0; f < frame->num; f++) {
72                         struct ao_lisp_val      *v = &frame->vals[f];
73
74                         ao_lisp_poly_move(&v->atom, 0);
75                         ao_lisp_poly_move(&v->val, 0);
76                         MDBG_MOVE("frame move atom %s %d val %d at %d\n",
77                                   ao_lisp_poly_atom(v->atom)->name,
78                                   MDBG_OFFSET(ao_lisp_ref(v->atom)),
79                                   MDBG_OFFSET(ao_lisp_ref(v->val)), f);
80                 }
81                 prev = ao_lisp_poly_frame(frame->prev);
82                 if (!prev)
83                         break;
84                 ret = ao_lisp_move_memory(&ao_lisp_frame_type, (void **) &prev);
85                 if (prev != ao_lisp_poly_frame(frame->prev)) {
86                         MDBG_MOVE("frame prev moved from %d to %d\n",
87                                   MDBG_OFFSET(ao_lisp_poly_frame(frame->prev)),
88                                   MDBG_OFFSET(prev));
89                         frame->prev = ao_lisp_frame_poly(prev);
90                 }
91                 if (ret)
92                         break;
93                 frame = prev;
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         .name = "frame",
102 };
103
104 void
105 ao_lisp_frame_print(ao_poly p)
106 {
107         struct ao_lisp_frame    *frame = ao_lisp_poly_frame(p);
108         int                     f;
109
110         printf ("{");
111         if (frame) {
112                 if (frame->type & AO_LISP_FRAME_PRINT)
113                         printf("recurse...");
114                 else {
115                         frame->type |= AO_LISP_FRAME_PRINT;
116                         for (f = 0; f < frame->num; f++) {
117                                 if (f != 0)
118                                         printf(", ");
119                                 ao_lisp_poly_print(frame->vals[f].atom);
120                                 printf(" = ");
121                                 ao_lisp_poly_print(frame->vals[f].val);
122                         }
123                         if (frame->prev)
124                                 ao_lisp_poly_print(frame->prev);
125                         frame->type &= ~AO_LISP_FRAME_PRINT;
126                 }
127         }
128         printf("}");
129 }
130
131 ao_poly *
132 ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom)
133 {
134         int f;
135         for (f = 0; f < frame->num; f++)
136                 if (frame->vals[f].atom == atom)
137                         return &frame->vals[f].val;
138         return NULL;
139 }
140
141 int
142 ao_lisp_frame_set(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val)
143 {
144         while (frame) {
145                 if (!AO_LISP_IS_CONST(frame)) {
146                         ao_poly *ref = ao_lisp_frame_ref(frame, atom);
147                         if (ref) {
148                                 *ref = val;
149                                 return 1;
150                         }
151                 }
152                 frame = ao_lisp_poly_frame(frame->prev);
153         }
154         return 0;
155 }
156
157 ao_poly
158 ao_lisp_frame_get(struct ao_lisp_frame *frame, ao_poly atom)
159 {
160         while (frame) {
161                 ao_poly *ref = ao_lisp_frame_ref(frame, atom);
162                 if (ref)
163                         return *ref;
164                 frame = ao_lisp_poly_frame(frame->prev);
165         }
166         return AO_LISP_NIL;
167 }
168
169 struct ao_lisp_frame    *ao_lisp_frame_free_list[AO_LISP_FRAME_FREE];
170
171 struct ao_lisp_frame *
172 ao_lisp_frame_new(int num)
173 {
174         struct ao_lisp_frame    *frame;
175
176         if (num < AO_LISP_FRAME_FREE && (frame = ao_lisp_frame_free_list[num]))
177                 ao_lisp_frame_free_list[num] = ao_lisp_poly_frame(frame->prev);
178         else {
179                 frame = ao_lisp_alloc(frame_num_size(num));
180                 if (!frame)
181                         return NULL;
182         }
183         frame->type = AO_LISP_FRAME;
184         frame->num = num;
185         frame->prev = AO_LISP_NIL;
186         memset(frame->vals, '\0', num * sizeof (struct ao_lisp_val));
187         return frame;
188 }
189
190 ao_poly
191 ao_lisp_frame_mark(struct ao_lisp_frame *frame)
192 {
193         if (!frame)
194                 return AO_LISP_NIL;
195         frame->type |= AO_LISP_FRAME_MARK;
196         return ao_lisp_frame_poly(frame);
197 }
198
199 void
200 ao_lisp_frame_free(struct ao_lisp_frame *frame)
201 {
202         if (!ao_lisp_frame_marked(frame)) {
203                 int     num = frame->num;
204                 if (num < AO_LISP_FRAME_FREE) {
205                         frame->prev = ao_lisp_frame_poly(ao_lisp_frame_free_list[num]);
206                         ao_lisp_frame_free_list[num] = frame;
207                 }
208         }
209 }
210
211 static struct ao_lisp_frame *
212 ao_lisp_frame_realloc(struct ao_lisp_frame **frame_ref, int new_num)
213 {
214         struct ao_lisp_frame    *frame = *frame_ref;
215         struct ao_lisp_frame    *new;
216         int                     copy;
217
218         if (new_num == frame->num)
219                 return frame;
220         new = ao_lisp_frame_new(new_num);
221         if (!new)
222                 return NULL;
223         /*
224          * Re-fetch the frame as it may have moved
225          * during the allocation
226          */
227         frame = *frame_ref;
228         copy = new_num;
229         if (copy > frame->num)
230                 copy = frame->num;
231         memcpy(new->vals, frame->vals, copy * sizeof (struct ao_lisp_val));
232         new->prev = frame->prev;
233         ao_lisp_frame_free(frame);
234         return new;
235 }
236
237 int
238 ao_lisp_frame_add(struct ao_lisp_frame **frame_ref, ao_poly atom, ao_poly val)
239 {
240         struct ao_lisp_frame *frame = *frame_ref;
241         ao_poly *ref = frame ? ao_lisp_frame_ref(frame, atom) : NULL;
242
243         if (!ref) {
244                 int f;
245                 ao_lisp_poly_stash(0, atom);
246                 ao_lisp_poly_stash(1, val);
247                 if (frame) {
248                         f = frame->num;
249                         frame = ao_lisp_frame_realloc(frame_ref, f + 1);
250                 } else {
251                         f = 0;
252                         frame = ao_lisp_frame_new(1);
253                 }
254                 atom = ao_lisp_poly_fetch(0);
255                 val = ao_lisp_poly_fetch(1);
256                 if (!frame)
257                         return 0;
258                 *frame_ref = frame;
259                 frame->vals[f].atom = atom;
260                 ref = &frame->vals[f].val;
261         }
262         *ref = val;
263         return 1;
264 }