Baremetal Lisp interpreter and compiler for low-resource devices
Revision | 0c8ad559cb691b8b6df62006cf5d429262639e8b (tree) |
---|---|
Time | 2020-09-08 07:58:00 |
Author | AlaskanEmily <emily@alas...> |
Commiter | AlaskanEmily |
Add defrec
@@ -21,6 +21,7 @@ | ||
21 | 21 | #include "sl_x.h" |
22 | 22 | |
23 | 23 | #define SL_I_BIND_CAP_GROWTH 64 |
24 | +#define SL_I_REC_CAP_GROWTH 32 | |
24 | 25 | #define SL_I_DEF_CAP_INIT 16 |
25 | 26 | #define SL_I_DEF_CAP_DOUBLE_MAX 256 |
26 | 27 |
@@ -110,6 +111,20 @@ static sl_s_len_t sl_i_find_def(const struct SL_I_Runtime *rt, | ||
110 | 111 | |
111 | 112 | /*****************************************************************************/ |
112 | 113 | |
114 | +static sl_s_len_t sl_i_find_rec(const struct SL_I_Runtime *rt, | |
115 | + const struct SL_S_Atom *name){ | |
116 | + | |
117 | + register sl_s_len_t i, n; | |
118 | + n = rt->num_recs; | |
119 | + for(i = 0; i < n; i++){ | |
120 | + if(SL_S_COMPARE_ATOMS(rt->recs[i].name, name)) | |
121 | + return i; | |
122 | + } | |
123 | + return n; | |
124 | +} | |
125 | + | |
126 | +/*****************************************************************************/ | |
127 | + | |
113 | 128 | static void sl_i_defun(struct SL_I_Runtime *rt, |
114 | 129 | const struct SL_S_Atom *name, |
115 | 130 | const struct SL_S_List *args, |
@@ -265,6 +280,55 @@ static void sl_i_def(struct SL_I_Runtime *rt, | ||
265 | 280 | |
266 | 281 | /*****************************************************************************/ |
267 | 282 | |
283 | +static void sl_i_defrec(struct SL_I_Runtime *rt, | |
284 | + const struct SL_S_Atom *name, | |
285 | + const struct SL_S_List *fields){ | |
286 | + | |
287 | + void *old; | |
288 | + register sl_s_len_t i; | |
289 | + struct SL_X_Record *rec; | |
290 | + | |
291 | + /* Search for an existing function of this name. */ | |
292 | + i = sl_i_find_rec(rt, name); | |
293 | + | |
294 | + /* Check if we found a matching bind or not. */ | |
295 | + if(i == rt->num_recs){ | |
296 | + /* Check if we need more room. */ | |
297 | + if(rt->cap_recs == i){ | |
298 | + /* Round up if the number of recs isn't a multiple of 32. */ | |
299 | + if(SL_I_UNLIKELY(rt->cap_recs & (SL_I_REC_CAP_GROWTH-1))) | |
300 | + rt->cap_recs += | |
301 | + SL_I_REC_CAP_GROWTH + SL_I_REC_CAP_GROWTH - | |
302 | + (rt->cap_recs & (SL_I_REC_CAP_GROWTH-1)); | |
303 | + else | |
304 | + rt->cap_recs += SL_I_REC_CAP_GROWTH; | |
305 | + /* Try to realloc */ | |
306 | + old = rt->recs; | |
307 | + rt->recs = SL_S_Malloc(sizeof(struct SL_X_Record) * rt->cap_recs); | |
308 | + if(SL_I_UNLIKELY(rt->recs == SL_S_NIL)){ | |
309 | + rt->pending_error = "Out of memory"; | |
310 | + rt->cap_recs = i; | |
311 | + rt->recs = old; | |
312 | + return; | |
313 | + } | |
314 | + SL_S_MemCopy(rt->recs, old, i * sizeof(struct SL_X_Record)); | |
315 | + SL_S_Free(old); | |
316 | + } | |
317 | + rt->num_recs++; | |
318 | + rec = rt->recs + i; | |
319 | + } | |
320 | + else{ | |
321 | + rec = rt->recs + i; | |
322 | + SL_S_DECREF(rec->name); | |
323 | + SL_S_DECREF(rec->fields); | |
324 | + } | |
325 | + | |
326 | + rec->name = name; | |
327 | + rec->fields = fields; | |
328 | +} | |
329 | + | |
330 | +/*****************************************************************************/ | |
331 | + | |
268 | 332 | SL_S_FUNC(int) SL_I_Run(struct SL_I_Runtime *rt, const struct SL_S_List *code){ |
269 | 333 | |
270 | 334 | const struct SL_S_Atom *name, *hint; |
@@ -296,6 +360,14 @@ SL_S_FUNC(int) SL_I_Run(struct SL_I_Runtime *rt, const struct SL_S_List *code){ | ||
296 | 360 | } |
297 | 361 | sl_i_def(rt, hint, name, value); |
298 | 362 | } |
363 | + else if(SL_X_IsDefrec(data) == 0){ | |
364 | + if(SL_X_ParseDefrec(data, &name, &body) != 0){ | |
365 | + rt->pending_error = "Error in defrec"; | |
366 | + return 1; | |
367 | + } | |
368 | + SL_S_INCREF(name); | |
369 | + sl_i_defrec(rt, name, body); | |
370 | + } | |
299 | 371 | else{ |
300 | 372 | SL_I_Execute(rt, code->head); |
301 | 373 | } |
@@ -79,6 +79,9 @@ struct SL_I_Runtime{ | ||
79 | 79 | struct SL_I_Bind *binds; |
80 | 80 | sl_s_len_t num_binds; |
81 | 81 | sl_s_len_t cap_binds; |
82 | + struct SL_X_Record *recs; | |
83 | + sl_s_len_t num_recs; | |
84 | + sl_s_len_t cap_recs; | |
82 | 85 | struct SL_I_Frame global, *frames; |
83 | 86 | const char *pending_error; |
84 | 87 | void *error_free_ptr; |
@@ -49,6 +49,7 @@ SL_X_ATOM(sl_x_true, "true"); | ||
49 | 49 | SL_X_ATOM(sl_x_false, "false"); |
50 | 50 | SL_X_ATOM(sl_x_defun, "defun"); |
51 | 51 | SL_X_ATOM(sl_x_def, "def"); |
52 | +SL_X_ATOM(sl_x_defrec, "defrec"); | |
52 | 53 | SL_X_ATOM(sl_x_if, "if"); |
53 | 54 | SL_X_ATOM(sl_x_let, "let"); |
54 | 55 | SL_X_ATOM(sl_x_plus, "+"); |
@@ -361,6 +362,42 @@ SL_S_PURE_FUNC(int) SL_X_IsDef(const struct SL_S_List *code){ | ||
361 | 362 | } |
362 | 363 | |
363 | 364 | /*****************************************************************************/ |
365 | +#define SL_X_DEFREC_MIN_ARITY 2 | |
366 | +static const unsigned char sl_x_defrec_flags[SL_X_DEFREC_MIN_ARITY] = { | |
367 | + SL_S_IN_ATOM, | |
368 | + SL_S_OUT_ATOM | |
369 | +}; | |
370 | + | |
371 | +SL_S_PURE_FUNC(int) SL_X_IsDefrec(const struct SL_S_List *code){ | |
372 | + const void *args[SL_X_DEFREC_MIN_ARITY]; | |
373 | + int arity; | |
374 | + | |
375 | + args[0] = SL_S_MK_ATOM(&sl_x_defrec); | |
376 | + | |
377 | + arity = SL_S_Match(code, | |
378 | + args, | |
379 | + sl_x_defrec_flags, | |
380 | + SL_X_DEFREC_MIN_ARITY, | |
381 | + SL_X_DEFREC_MIN_ARITY); | |
382 | + | |
383 | + if(arity == SL_X_DEFREC_MIN_ARITY){ | |
384 | + return 0; | |
385 | + } | |
386 | + else if(arity < 0 && (arity = -arity) > SL_X_DEFREC_MIN_ARITY){ | |
387 | + /* Test for the correct form in the fields. */ | |
388 | + code = code->tail->tail; | |
389 | + do{ | |
390 | + if(!SL_S_IS_ATOM(code->head)) | |
391 | + return 1; | |
392 | + }while((code = code->tail) != SL_S_NIL); | |
393 | + return 0; | |
394 | + } | |
395 | + else{ | |
396 | + return 1; | |
397 | + } | |
398 | +} | |
399 | + | |
400 | +/*****************************************************************************/ | |
364 | 401 | |
365 | 402 | SL_S_FUNC(int) SL_X_ParseDefun(const struct SL_S_List *code, |
366 | 403 | const struct SL_S_Atom **out_name, |
@@ -375,6 +412,7 @@ SL_S_FUNC(int) SL_X_ParseDefun(const struct SL_S_List *code, | ||
375 | 412 | *out_body = SL_S_PTR_FROM_TAG(code->tail->tail->tail); |
376 | 413 | return 0; |
377 | 414 | } |
415 | + | |
378 | 416 | /*****************************************************************************/ |
379 | 417 | |
380 | 418 | SL_S_FUNC(int) SL_X_ParseDef(const struct SL_S_List *code, |
@@ -421,6 +459,71 @@ SL_S_FUNC(int) SL_X_ParseDef(const struct SL_S_List *code, | ||
421 | 459 | |
422 | 460 | /*****************************************************************************/ |
423 | 461 | |
462 | +static struct SL_S_List *sl_x_add_rec_field( | |
463 | + const struct SL_S_Atom *name, | |
464 | + const struct SL_S_Atom *hint){ | |
465 | + | |
466 | + struct SL_S_List *arg_pair, *to; | |
467 | + | |
468 | + arg_pair = SL_S_Malloc(sizeof(struct SL_S_List)); | |
469 | + arg_pair->ref = 1; | |
470 | + arg_pair->tail = SL_S_Malloc(sizeof(struct SL_S_List)); | |
471 | + arg_pair->tail->ref = 1; | |
472 | + arg_pair->tail->tail = SL_S_NIL; | |
473 | + | |
474 | + arg_pair->head = SL_S_MK_ATOM(hint); | |
475 | + arg_pair->tail->head = SL_S_MK_ATOM(name); | |
476 | + | |
477 | + to = SL_S_Malloc(sizeof(struct SL_S_List)); | |
478 | + to->ref = 1; | |
479 | + to->head = SL_S_MK_LIST(arg_pair); | |
480 | + return to; | |
481 | +} | |
482 | + | |
483 | +SL_S_FUNC(int) SL_X_ParseDefrec(const struct SL_S_List *code, | |
484 | + const struct SL_S_Atom **out_name, | |
485 | + const struct SL_S_List **out_fields){ | |
486 | + | |
487 | + const struct SL_S_Atom *name, *hint; | |
488 | + struct SL_S_List *ret, **dest; | |
489 | + register const struct SL_S_Atom *atom; | |
490 | + register const struct SL_S_Atom **target; | |
491 | + | |
492 | + *out_name = SL_S_PTR_FROM_TAG(code->tail->head); | |
493 | + code = code->tail->tail; | |
494 | + if(code == SL_S_NIL){ | |
495 | + *out_fields = SL_S_NIL; | |
496 | + return 0; | |
497 | + } | |
498 | + | |
499 | + dest = &ret; | |
500 | + do{ | |
501 | + atom = SL_S_PTR_FROM_TAG(code->head); | |
502 | + SL_S_INCREF(atom); | |
503 | + if(atom->len > 1 && atom->text[0] == '^') | |
504 | + target = &hint; | |
505 | + else | |
506 | + target = &name; | |
507 | + if(*target != SL_S_NIL){ | |
508 | + *dest = sl_x_add_rec_field(hint, name); | |
509 | + dest = &((*dest)->tail); | |
510 | + } | |
511 | + *target = atom; | |
512 | + }while((code = code->tail) != SL_S_NIL); | |
513 | + | |
514 | + if(hint != SL_S_NIL || name != SL_S_NIL){ | |
515 | + *dest = sl_x_add_rec_field(hint, name); | |
516 | + (*dest)->tail = SL_S_NIL; | |
517 | + } | |
518 | + else{ | |
519 | + *dest = SL_S_NIL; | |
520 | + } | |
521 | + *out_fields = ret; | |
522 | + return 0; | |
523 | +} | |
524 | + | |
525 | +/*****************************************************************************/ | |
526 | + | |
424 | 527 | static struct SL_S_List *sl_x_create_args(const struct SL_S_Atom *hint, |
425 | 528 | const struct SL_S_Atom *name){ |
426 | 529 |
@@ -41,6 +41,7 @@ const extern struct SL_S_Atom | ||
41 | 41 | sl_x_nil, sl_x_true, sl_x_false, |
42 | 42 | sl_x_defun, |
43 | 43 | sl_x_def, |
44 | + sl_x_defrec, | |
44 | 45 | sl_x_if, |
45 | 46 | sl_x_let, |
46 | 47 | sl_x_comment, sl_x_dot, sl_x_tick, |
@@ -77,6 +78,14 @@ struct SL_X_Def{ | ||
77 | 78 | |
78 | 79 | /*****************************************************************************/ |
79 | 80 | |
81 | +struct SL_X_Record{ | |
82 | + const struct SL_S_Atom *name; | |
83 | + /* Each field is structured as (hint name) where hint or name may be nil */ | |
84 | + const struct SL_S_List *fields; | |
85 | +}; | |
86 | + | |
87 | +/*****************************************************************************/ | |
88 | + | |
80 | 89 | SL_S_PURE_FUNC(int) SL_X_IsRuntimeConstant(const void *value); |
81 | 90 | |
82 | 91 | /*****************************************************************************/ |
@@ -101,8 +110,13 @@ SL_S_PURE_FUNC(int) SL_X_IsDef(const struct SL_S_List *code); | ||
101 | 110 | |
102 | 111 | /*****************************************************************************/ |
103 | 112 | /* Returns 0 on success. */ |
113 | +SL_S_PURE_FUNC(int) SL_X_IsDefrec(const struct SL_S_List *code); | |
114 | + | |
115 | +/*****************************************************************************/ | |
116 | +/* Returns 0 on success. */ | |
104 | 117 | SL_S_PURE_FUNC(int) SL_X_IsImport(const struct SL_S_List *code); |
105 | 118 | |
119 | +/*****************************************************************************/ | |
106 | 120 | /* Returns 0 on success. |
107 | 121 | * Does not do increfs, so you've been warned. |
108 | 122 | */ |
@@ -122,6 +136,15 @@ SL_S_FUNC(int) SL_X_ParseDef(const struct SL_S_List *code, | ||
122 | 136 | |
123 | 137 | /*****************************************************************************/ |
124 | 138 | /* Returns 0 on success. |
139 | + * This DOES incref the fields, unlike the other parsers. | |
140 | + * This does no incref the name. | |
141 | + */ | |
142 | +SL_S_FUNC(int) SL_X_ParseDefrec(const struct SL_S_List *code, | |
143 | + const struct SL_S_Atom **out_name, | |
144 | + const struct SL_S_List **out_fields); | |
145 | + | |
146 | +/*****************************************************************************/ | |
147 | +/* Returns 0 on success. | |
125 | 148 | * The args is a list of lists, of the structure ((hint name) (hint name) ...) |
126 | 149 | */ |
127 | 150 | SL_S_FUNC(struct SL_S_List) *SL_X_ParseArgs(const struct SL_S_List *args); |
@@ -0,0 +1,6 @@ | ||
1 | +; Any copyright is dedicated to the Public Domain. | |
2 | +; https://creativecommons.org/publicdomain/zero/1.0/ | |
3 | + | |
4 | +(defrec foo | |
5 | + ^int i | |
6 | + x) |