1 #include <stdlib.h>
2 #include "lib/mlrutil.h"
3 #include "lib/mlr_globals.h"
4 #include "containers/local_stack.h"
5
6 // ================================================================
_local_stack_alloc(int size,int ephemeral)7 static local_stack_frame_t* _local_stack_alloc(int size, int ephemeral) {
8 local_stack_frame_t* pframe = mlr_malloc_or_die(sizeof(local_stack_frame_t));
9
10 pframe->in_use = FALSE;
11 pframe->ephemeral = ephemeral;
12 pframe->size = size;
13 pframe->subframe_base = 0;
14 pframe->pvars = mlr_malloc_or_die(size * sizeof(local_stack_frame_entry_t));
15 for (int i = 0; i < size; i++) {
16 local_stack_frame_entry_t* pentry = &pframe->pvars[i];
17 pentry->xvalue = mlhmmv_xvalue_wrap_terminal(mv_absent());
18 pentry->name = NULL;
19 // Any type can be written here, unless otherwise specified by a typed definition
20 pentry->type_mask = TYPE_MASK_ANY;
21 }
22
23 return pframe;
24 }
25
26 // ----------------------------------------------------------------
local_stack_frame_alloc(int size)27 local_stack_frame_t* local_stack_frame_alloc(int size) {
28 return _local_stack_alloc(size, FALSE);
29 }
30
31 // ----------------------------------------------------------------
local_stack_frame_free(local_stack_frame_t * pframe)32 void local_stack_frame_free(local_stack_frame_t* pframe) {
33 if (pframe == NULL)
34 return;
35 for (int i = 0; i < pframe->size; i++) {
36 mlhmmv_xvalue_free(&pframe->pvars[i].xvalue);
37 }
38 free(pframe->pvars);
39 free(pframe);
40 }
41
42 // ----------------------------------------------------------------
local_stack_frame_enter(local_stack_frame_t * pframe)43 local_stack_frame_t* local_stack_frame_enter(local_stack_frame_t* pframe) {
44 if (!pframe->in_use) {
45 pframe->in_use = TRUE;
46 LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME NON-EPH ENTER %p %d\n", pframe, pframe->size));
47 return pframe;
48 } else {
49 local_stack_frame_t* prv = _local_stack_alloc(pframe->size, TRUE);
50 LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME EPH ENTER %p/%p %d\n", pframe, prv, pframe->size));
51 prv->in_use = TRUE;
52 return prv;
53 }
54 }
55
56 // ----------------------------------------------------------------
local_stack_frame_exit(local_stack_frame_t * pframe)57 void local_stack_frame_exit (local_stack_frame_t* pframe) {
58 MLR_INTERNAL_CODING_ERROR_UNLESS(mlhmmv_xvalue_is_absent_and_nonterminal(&pframe->pvars[0].xvalue));
59 if (!pframe->ephemeral) {
60 pframe->in_use = FALSE;
61 LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME NON-EPH EXIT %p %d\n", pframe, pframe->size));
62 } else {
63 local_stack_frame_free(pframe);
64 LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME EPH EXIT %p %d\n", pframe, pframe->size));
65 }
66 }
67
68 // ================================================================
local_stack_alloc()69 local_stack_t* local_stack_alloc() {
70 local_stack_t* pstack = mlr_malloc_or_die(sizeof(local_stack_t));
71
72 pstack->pframes = sllv_alloc();
73
74 return pstack;
75 }
76
77 // ----------------------------------------------------------------
local_stack_free(local_stack_t * pstack)78 void local_stack_free(local_stack_t* pstack) {
79 if (pstack == NULL)
80 return;
81 for (sllve_t* pe = pstack->pframes->phead; pe != NULL; pe = pe->pnext) {
82 local_stack_frame_free(pe->pvvalue);
83 }
84 sllv_free(pstack->pframes);
85 free(pstack);
86 }
87
88 // ----------------------------------------------------------------
local_stack_push(local_stack_t * pstack,local_stack_frame_t * pframe)89 void local_stack_push(local_stack_t* pstack, local_stack_frame_t* pframe) {
90 sllv_push(pstack->pframes, pframe);
91 }
92
local_stack_pop(local_stack_t * pstack)93 local_stack_frame_t* local_stack_pop(local_stack_t* pstack) {
94 return sllv_pop(pstack->pframes);
95 }
96
97 // ----------------------------------------------------------------
local_stack_frame_ref_terminal_from_indexed(local_stack_frame_t * pframe,int vardef_frame_relative_index,sllmv_t * pmvkeys)98 mv_t local_stack_frame_ref_terminal_from_indexed(local_stack_frame_t* pframe,
99 int vardef_frame_relative_index, sllmv_t* pmvkeys)
100 {
101 LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME %p GET %d\n", pframe, vardef_frame_relative_index));
102 LOCAL_STACK_BOUNDS_CHECK(pframe, "GET", FALSE, vardef_frame_relative_index);
103
104 local_stack_frame_entry_t* pentry = &pframe->pvars[vardef_frame_relative_index];
105 mlhmmv_xvalue_t* pbase_xval = &pentry->xvalue;
106
107 if (!(TYPE_MASK_MAP & pentry->type_mask)) {
108 local_stack_frame_throw_type_mismatch_for_read(pentry);
109 }
110
111 #ifdef LOCAL_STACK_TRACE_ENABLE
112 if (pbase_xval == NULL) {
113 printf("VALUE IS NULL\n");
114 } else if (pbase_xval->is_terminal) {
115 char* s = mv_alloc_format_val(&pbase_xval->terminal_mlrval);
116 printf("VALUE IS %s\n", s);
117 free(s);
118 } else if (pbase_xval->pnext_level == NULL) {
119 LOCAL_STACK_TRACE(printf("VALUE IS EMPTY\n"));
120 } else {
121 printf("VALUE IS:\n");
122 printf("PTR IS %p\n", pbase_xval->pnext_level);
123 mlhmmv_level_print_stacked(pbase_xval->pnext_level, 0, TRUE, TRUE, "", stdout);
124 }
125 #endif
126
127 // xxx this is a mess; clean it up.
128 int error = 0;
129 // Maybe null
130 mlhmmv_xvalue_t* pxval;
131 if (pmvkeys == NULL || pmvkeys->length == 0) {
132 pxval = pbase_xval;
133 } else {
134 if (pbase_xval->is_terminal) {
135 return mv_absent();
136 } else {
137 pxval = mlhmmv_level_look_up_and_ref_xvalue(pbase_xval->pnext_level, pmvkeys, &error);
138 }
139 }
140 if (pxval != NULL && pxval->is_terminal) {
141 return pxval->terminal_mlrval;
142 } else {
143 return mv_absent();
144 }
145 }
146
147 // ----------------------------------------------------------------
local_stack_frame_ref_extended_from_indexed(local_stack_frame_t * pframe,int vardef_frame_relative_index,sllmv_t * pmvkeys)148 mlhmmv_xvalue_t* local_stack_frame_ref_extended_from_indexed(local_stack_frame_t* pframe,
149 int vardef_frame_relative_index, sllmv_t* pmvkeys)
150 {
151 LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME %p GET %d\n", pframe, vardef_frame_relative_index));
152 LOCAL_STACK_BOUNDS_CHECK(pframe, "GET", FALSE, vardef_frame_relative_index);
153
154 local_stack_frame_entry_t* pentry = &pframe->pvars[vardef_frame_relative_index];
155 mlhmmv_xvalue_t* pmvalue = &pentry->xvalue;
156
157 if (!(TYPE_MASK_MAP & pentry->type_mask)) {
158 local_stack_frame_throw_type_mismatch_for_read(pentry);
159 }
160
161 #ifdef LOCAL_STACK_TRACE_ENABLE
162 if (pmvalue == NULL) {
163 printf("VALUE IS NULL\n");
164 } else if (pmvalue->is_terminal) {
165 char* s = mv_alloc_format_val(&pmvalue->terminal_mlrval);
166 printf("VALUE IS %s\n", s);
167 free(s);
168 } else if (pmvalue->pnext_level == NULL) {
169 LOCAL_STACK_TRACE(printf("VALUE IS EMPTY\n"));
170 } else {
171 printf("VALUE IS:\n");
172 printf("PTR IS %p\n", pmvalue->pnext_level);
173 mlhmmv_level_print_stacked(pmvalue->pnext_level, 0, TRUE, TRUE, "", stdout);
174 }
175 #endif
176
177 if (pmvkeys == NULL) { // base-level access
178 return pmvalue;
179 } else {
180 int error = 0;
181 // Maybe null
182 return mlhmmv_level_look_up_and_ref_xvalue(pmvalue->pnext_level, pmvkeys, &error);
183 }
184 }
185
186 // ----------------------------------------------------------------
local_stack_frame_define_terminal(local_stack_frame_t * pframe,char * variable_name,int vardef_frame_relative_index,int type_mask,mv_t val)187 void local_stack_frame_define_terminal(local_stack_frame_t* pframe, char* variable_name,
188 int vardef_frame_relative_index, int type_mask, mv_t val)
189 {
190 LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME %p SET %d\n", pframe, vardef_frame_relative_index));
191 LOCAL_STACK_BOUNDS_CHECK(pframe, "DEFINE", TRUE, vardef_frame_relative_index);
192 local_stack_frame_entry_t* pentry = &pframe->pvars[vardef_frame_relative_index];
193
194 pentry->name = variable_name; // no strdup, for performance -- caller must ensure extent
195 pentry->type_mask = type_mask;
196
197 if (!(type_mask_from_mv(&val) & pentry->type_mask)) {
198 local_stack_frame_throw_type_mismatch_for_write(pentry, &val);
199 }
200
201 mlhmmv_xvalue_free(&pentry->xvalue);
202
203 if (mv_is_absent(&val)) {
204 mv_free(&val); // xxx doc ownership semantics at header file
205 } else {
206 pentry->xvalue = mlhmmv_xvalue_wrap_terminal(val); // xxx deep-copy?
207 }
208 }
209
210 // ----------------------------------------------------------------
local_stack_frame_define_extended(local_stack_frame_t * pframe,char * variable_name,int vardef_frame_relative_index,int type_mask,mlhmmv_xvalue_t xval)211 void local_stack_frame_define_extended(local_stack_frame_t* pframe, char* variable_name,
212 int vardef_frame_relative_index, int type_mask, mlhmmv_xvalue_t xval)
213 {
214 LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME %p SET %d\n", pframe, vardef_frame_relative_index));
215 LOCAL_STACK_BOUNDS_CHECK(pframe, "ASSIGN", TRUE, vardef_frame_relative_index);
216 local_stack_frame_entry_t* pentry = &pframe->pvars[vardef_frame_relative_index];
217
218 pentry->name = variable_name; // no strdup, for performance -- caller must ensure extent
219 pentry->type_mask = type_mask;
220
221 if (xval.is_terminal) {
222 if (!(type_mask_from_mv(&xval.terminal_mlrval) & pentry->type_mask)) {
223 local_stack_frame_throw_type_mismatch_for_write(pentry, &xval.terminal_mlrval);
224 }
225 } else {
226 if (!(TYPE_MASK_MAP & pentry->type_mask)) {
227 local_stack_frame_throw_type_mismatch_for_write(pentry, &xval.terminal_mlrval);
228 }
229 }
230
231 if (!mlhmmv_xvalue_is_absent_and_nonterminal(&xval)) {
232 mlhmmv_xvalue_free(&pentry->xvalue);
233 pentry->xvalue = xval;
234 }
235 }
236
237 // ----------------------------------------------------------------
local_stack_frame_assign_terminal_indexed(local_stack_frame_t * pframe,int vardef_frame_relative_index,sllmv_t * pmvkeys,mv_t terminal_value)238 void local_stack_frame_assign_terminal_indexed(local_stack_frame_t* pframe,
239 int vardef_frame_relative_index, sllmv_t* pmvkeys,
240 mv_t terminal_value)
241 {
242 LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME %p SET %d\n", pframe, vardef_frame_relative_index));
243 LOCAL_STACK_BOUNDS_CHECK(pframe, "ASSIGN", TRUE, vardef_frame_relative_index);
244 local_stack_frame_entry_t* pentry = &pframe->pvars[vardef_frame_relative_index];
245
246 if (!(TYPE_MASK_MAP & pentry->type_mask)) {
247 local_stack_frame_throw_type_mismatch_for_write(pentry, &terminal_value);
248 }
249
250 mlhmmv_xvalue_t* pmvalue = &pentry->xvalue;
251
252 if (pmvalue->is_terminal) {
253 mv_free(&pmvalue->terminal_mlrval);
254 *pmvalue = mlhmmv_xvalue_alloc_empty_map();
255 }
256 mlhmmv_level_put_terminal(pmvalue->pnext_level, pmvkeys->phead, &terminal_value);
257
258 LOCAL_STACK_TRACE(printf("VALUE IS:\n"));
259 LOCAL_STACK_TRACE(mlhmmv_level_print_stacked(pmvalue->pnext_level, 0, TRUE, TRUE, "", stdout));
260 }
261
262 // ----------------------------------------------------------------
local_stack_frame_assign_extended_nonindexed(local_stack_frame_t * pframe,int vardef_frame_relative_index,mlhmmv_xvalue_t xval)263 void local_stack_frame_assign_extended_nonindexed(local_stack_frame_t* pframe,
264 int vardef_frame_relative_index, mlhmmv_xvalue_t xval)
265 {
266 LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME %p SET %d\n", pframe, vardef_frame_relative_index));
267 LOCAL_STACK_BOUNDS_CHECK(pframe, "ASSIGN", TRUE, vardef_frame_relative_index);
268 local_stack_frame_entry_t* pentry = &pframe->pvars[vardef_frame_relative_index];
269
270 if (xval.is_terminal) {
271 if (!(type_mask_from_mv(&xval.terminal_mlrval) & pentry->type_mask)) {
272 local_stack_frame_throw_type_mismatch_for_write(pentry, &xval.terminal_mlrval);
273 }
274 } else {
275 if (!(TYPE_MASK_MAP & pentry->type_mask)) {
276 local_stack_frame_throw_type_mismatch_for_write(pentry, &xval.terminal_mlrval);
277 }
278 }
279
280 mlhmmv_xvalue_free(&pentry->xvalue);
281 pentry->xvalue = xval;
282 }
283
284 // ----------------------------------------------------------------
local_stack_frame_assign_extended_indexed(local_stack_frame_t * pframe,int vardef_frame_relative_index,sllmv_t * pmvkeys,mlhmmv_xvalue_t new_value)285 void local_stack_frame_assign_extended_indexed(local_stack_frame_t* pframe,
286 int vardef_frame_relative_index, sllmv_t* pmvkeys,
287 mlhmmv_xvalue_t new_value)
288 {
289 LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME %p SET %d\n", pframe, vardef_frame_relative_index));
290 LOCAL_STACK_BOUNDS_CHECK(pframe, "ASSIGN", TRUE, vardef_frame_relative_index);
291 local_stack_frame_entry_t* pentry = &pframe->pvars[vardef_frame_relative_index];
292
293 if (!(TYPE_MASK_MAP & pentry->type_mask)) {
294 local_stack_frame_throw_type_xmismatch_for_write(pentry, &new_value);
295 }
296
297 mlhmmv_xvalue_t* pmvalue = &pentry->xvalue;
298
299 if (pmvalue->is_terminal) {
300 mv_free(&pmvalue->terminal_mlrval);
301 *pmvalue = mlhmmv_xvalue_alloc_empty_map();
302 }
303 mlhmmv_level_put_xvalue(pmvalue->pnext_level, pmvkeys->phead, &new_value);
304
305 LOCAL_STACK_TRACE(printf("VALUE IS:\n"));
306 LOCAL_STACK_TRACE(mlhmmv_level_print_stacked(pmvalue->pnext_level, 0, TRUE, TRUE, "", stdout));
307 }
308
309 // ----------------------------------------------------------------
310 static int local_stack_bounds_check_announce_first_call = TRUE;
311
local_stack_bounds_check(local_stack_frame_t * pframe,char * op,int set,int vardef_frame_relative_index)312 void local_stack_bounds_check(local_stack_frame_t* pframe, char* op, int set, int vardef_frame_relative_index) {
313 if (local_stack_bounds_check_announce_first_call) {
314 fprintf(stderr, "%s: local-stack bounds-checking is enabled\n", MLR_GLOBALS.bargv0);
315 local_stack_bounds_check_announce_first_call = FALSE;
316 }
317 if (vardef_frame_relative_index < 0) {
318 fprintf(stderr, "OP=%s FRAME=%p IDX=%d/%d STACK UNDERFLOW\n",
319 op, pframe, vardef_frame_relative_index, pframe->size);
320 exit(1);
321 }
322 if (set && vardef_frame_relative_index == 0) {
323 fprintf(stderr, "OP=%s FRAME=%p IDX=%d/%d ABSENT WRITE\n",
324 op, pframe, vardef_frame_relative_index, pframe->size);
325 exit(1);
326 }
327 if (vardef_frame_relative_index >= pframe->size) {
328 fprintf(stderr, "OP=%s FRAME=%p IDX=%d/%d STACK OVERFLOW\n",
329 op, pframe, vardef_frame_relative_index, pframe->size);
330 exit(1);
331 }
332 }
333
334 // ----------------------------------------------------------------
local_stack_frame_throw_type_mismatch_for_write(local_stack_frame_entry_t * pentry,mv_t * pval)335 void local_stack_frame_throw_type_mismatch_for_write(local_stack_frame_entry_t* pentry, mv_t* pval) {
336 MLR_INTERNAL_CODING_ERROR_IF(pentry->name == NULL);
337 char* sval = mv_alloc_format_val_quoting_strings(pval);
338 fprintf(stderr, "%s: %s type assertion for variable %s unmet by value %s with type %s.\n",
339 MLR_GLOBALS.bargv0, type_mask_to_desc(pentry->type_mask), pentry->name,
340 sval, mt_describe_type_simple(pval->type));
341 free(sval);
342 exit(1);
343 }
344
local_stack_frame_throw_type_xmismatch_for_write(local_stack_frame_entry_t * pentry,mlhmmv_xvalue_t * pxval)345 void local_stack_frame_throw_type_xmismatch_for_write(local_stack_frame_entry_t* pentry, mlhmmv_xvalue_t* pxval) {
346 MLR_INTERNAL_CODING_ERROR_IF(pentry->name == NULL);
347 char* sval = mv_alloc_format_val_quoting_strings(&pxval->terminal_mlrval); // xxx temp -- maybe not terminal
348 fprintf(stderr, "%s: %s type assertion for variable %s unmet by value %s with type %s.\n",
349 MLR_GLOBALS.bargv0, type_mask_to_desc(pentry->type_mask), pentry->name,
350 sval, mlhmmv_xvalue_describe_type_simple(pxval));
351 free(sval);
352 exit(1);
353 }
354
355 // ----------------------------------------------------------------
local_stack_frame_throw_type_mismatch_for_read(local_stack_frame_entry_t * pentry)356 void local_stack_frame_throw_type_mismatch_for_read(local_stack_frame_entry_t* pentry) {
357 MLR_INTERNAL_CODING_ERROR_IF(pentry->name == NULL);
358 fprintf(stderr, "%s: %s type assertion for variable %s unmet on read.\n",
359 MLR_GLOBALS.bargv0, type_mask_to_desc(pentry->type_mask), pentry->name);
360 exit(1);
361 }
362
local_stack_frame_throw_type_xmismatch_for_read(local_stack_frame_entry_t * pentry)363 void local_stack_frame_throw_type_xmismatch_for_read(local_stack_frame_entry_t* pentry) {
364 MLR_INTERNAL_CODING_ERROR_IF(pentry->name == NULL);
365 fprintf(stderr, "%s: %s type assertion for variable %s unmet on read.\n",
366 MLR_GLOBALS.bargv0, type_mask_to_desc(pentry->type_mask), pentry->name);
367 exit(1);
368 }
369