Bug Summary

File:eval_cps.c
Warning:line 1715, column 10
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'arr')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple i386-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name eval_cps.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu i686 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/joels/Current/lispbm -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -I ./include -I ./include/extensions -I platform/linux/include -D _PRELUDE -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/11/../../../../x86_64-linux-gnu/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -std=c99 -fdebug-compilation-dir=/home/joels/Current/lispbm -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/joels/Current/lispbm/test_reports/version_0.23.0/scan-build/2024-03-09-191247-1858527-1 -x c src/eval_cps.c

src/eval_cps.c

1 /*
2 Copyright 2018, 2020 - 2024 Joel Svensson svenssonjoel@yahoo.se
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 3 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,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include <lbm_memory.h>
19#include <lbm_types.h>
20#include "symrepr.h"
21#include "heap.h"
22#include "env.h"
23#include "eval_cps.h"
24#include "stack.h"
25#include "fundamental.h"
26#include "extensions.h"
27#include "tokpar.h"
28#include "lbm_channel.h"
29#include "print.h"
30#include "platform_mutex.h"
31#include "lbm_flat_value.h"
32#include "lbm_flags.h"
33
34#ifdef VISUALIZE_HEAP
35#include "heap_vis.h"
36#endif
37
38#include <setjmp.h>
39
40static jmp_buf error_jmp_buf;
41static jmp_buf critical_error_jmp_buf;
42
43#define S_TO_US(X)(lbm_uint)((X) * 1000000) (lbm_uint)((X) * 1000000)
44
45#define DEC_CONTINUATION(x)(((x) & ~0xF8000001u) >> 2) (((x) & ~LBM_CONTINUATION_INTERNAL0xF8000001u) >> LBM_ADDRESS_SHIFT2)
46#define IS_CONTINUATION(x)(((x) & 0xF8000001u) == 0xF8000001u) (((x) & LBM_CONTINUATION_INTERNAL0xF8000001u) == LBM_CONTINUATION_INTERNAL0xF8000001u)
47#define CONTINUATION(x)(((x) << 2) | 0xF8000001u) (((x) << LBM_ADDRESS_SHIFT2) | LBM_CONTINUATION_INTERNAL0xF8000001u)
48
49#define DONE(((0) << 2) | 0xF8000001u) CONTINUATION(0)(((0) << 2) | 0xF8000001u)
50#define SET_GLOBAL_ENV(((1) << 2) | 0xF8000001u) CONTINUATION(1)(((1) << 2) | 0xF8000001u)
51#define BIND_TO_KEY_REST(((2) << 2) | 0xF8000001u) CONTINUATION(2)(((2) << 2) | 0xF8000001u)
52#define IF(((3) << 2) | 0xF8000001u) CONTINUATION(3)(((3) << 2) | 0xF8000001u)
53#define PROGN_REST(((4) << 2) | 0xF8000001u) CONTINUATION(4)(((4) << 2) | 0xF8000001u)
54#define APPLICATION_ARGS(((5) << 2) | 0xF8000001u) CONTINUATION(5)(((5) << 2) | 0xF8000001u)
55#define AND(((6) << 2) | 0xF8000001u) CONTINUATION(6)(((6) << 2) | 0xF8000001u)
56#define OR(((7) << 2) | 0xF8000001u) CONTINUATION(7)(((7) << 2) | 0xF8000001u)
57#define WAIT(((8) << 2) | 0xF8000001u) CONTINUATION(8)(((8) << 2) | 0xF8000001u)
58#define MATCH(((9) << 2) | 0xF8000001u) CONTINUATION(9)(((9) << 2) | 0xF8000001u)
59#define APPLICATION_START(((10) << 2) | 0xF8000001u) CONTINUATION(10)(((10) << 2) | 0xF8000001u)
60#define EVAL_R(((11) << 2) | 0xF8000001u) CONTINUATION(11)(((11) << 2) | 0xF8000001u)
61#define RESUME(((12) << 2) | 0xF8000001u) CONTINUATION(12)(((12) << 2) | 0xF8000001u)
62#define CLOSURE_ARGS(((13) << 2) | 0xF8000001u) CONTINUATION(13)(((13) << 2) | 0xF8000001u)
63#define EXIT_ATOMIC(((14) << 2) | 0xF8000001u) CONTINUATION(14)(((14) << 2) | 0xF8000001u)
64#define READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u) CONTINUATION(15)(((15) << 2) | 0xF8000001u)
65#define READ_APPEND_CONTINUE(((16) << 2) | 0xF8000001u) CONTINUATION(16)(((16) << 2) | 0xF8000001u)
66#define READ_EVAL_CONTINUE(((17) << 2) | 0xF8000001u) CONTINUATION(17)(((17) << 2) | 0xF8000001u)
67#define READ_EXPECT_CLOSEPAR(((18) << 2) | 0xF8000001u) CONTINUATION(18)(((18) << 2) | 0xF8000001u)
68#define READ_DOT_TERMINATE(((19) << 2) | 0xF8000001u) CONTINUATION(19)(((19) << 2) | 0xF8000001u)
69#define READ_DONE(((20) << 2) | 0xF8000001u) CONTINUATION(20)(((20) << 2) | 0xF8000001u)
70#define READ_QUOTE_RESULT(((21) << 2) | 0xF8000001u) CONTINUATION(21)(((21) << 2) | 0xF8000001u)
71#define READ_COMMAAT_RESULT(((22) << 2) | 0xF8000001u) CONTINUATION(22)(((22) << 2) | 0xF8000001u)
72#define READ_COMMA_RESULT(((23) << 2) | 0xF8000001u) CONTINUATION(23)(((23) << 2) | 0xF8000001u)
73#define READ_START_ARRAY(((24) << 2) | 0xF8000001u) CONTINUATION(24)(((24) << 2) | 0xF8000001u)
74#define READ_APPEND_ARRAY(((25) << 2) | 0xF8000001u) CONTINUATION(25)(((25) << 2) | 0xF8000001u)
75#define MAP(((26) << 2) | 0xF8000001u) CONTINUATION(26)(((26) << 2) | 0xF8000001u)
76#define MATCH_GUARD(((27) << 2) | 0xF8000001u) CONTINUATION(27)(((27) << 2) | 0xF8000001u)
77#define TERMINATE(((28) << 2) | 0xF8000001u) CONTINUATION(28)(((28) << 2) | 0xF8000001u)
78#define PROGN_VAR(((29) << 2) | 0xF8000001u) CONTINUATION(29)(((29) << 2) | 0xF8000001u)
79#define SETQ(((30) << 2) | 0xF8000001u) CONTINUATION(30)(((30) << 2) | 0xF8000001u)
80#define MOVE_TO_FLASH(((31) << 2) | 0xF8000001u) CONTINUATION(31)(((31) << 2) | 0xF8000001u)
81#define MOVE_VAL_TO_FLASH_DISPATCH(((32) << 2) | 0xF8000001u) CONTINUATION(32)(((32) << 2) | 0xF8000001u)
82#define MOVE_LIST_TO_FLASH(((33) << 2) | 0xF8000001u) CONTINUATION(33)(((33) << 2) | 0xF8000001u)
83#define CLOSE_LIST_IN_FLASH(((34) << 2) | 0xF8000001u) CONTINUATION(34)(((34) << 2) | 0xF8000001u)
84#define QQ_EXPAND_START(((35) << 2) | 0xF8000001u) CONTINUATION(35)(((35) << 2) | 0xF8000001u)
85#define QQ_EXPAND(((36) << 2) | 0xF8000001u) CONTINUATION(36)(((36) << 2) | 0xF8000001u)
86#define QQ_APPEND(((37) << 2) | 0xF8000001u) CONTINUATION(37)(((37) << 2) | 0xF8000001u)
87#define QQ_EXPAND_LIST(((38) << 2) | 0xF8000001u) CONTINUATION(38)(((38) << 2) | 0xF8000001u)
88#define QQ_LIST(((39) << 2) | 0xF8000001u) CONTINUATION(39)(((39) << 2) | 0xF8000001u)
89#define KILL(((40) << 2) | 0xF8000001u) CONTINUATION(40)(((40) << 2) | 0xF8000001u)
90#define LOOP(((41) << 2) | 0xF8000001u) CONTINUATION(41)(((41) << 2) | 0xF8000001u)
91#define LOOP_CONDITION(((42) << 2) | 0xF8000001u) CONTINUATION(42)(((42) << 2) | 0xF8000001u)
92#define MERGE_REST(((43) << 2) | 0xF8000001u) CONTINUATION(43)(((43) << 2) | 0xF8000001u)
93#define MERGE_LAYER(((44) << 2) | 0xF8000001u) CONTINUATION(44)(((44) << 2) | 0xF8000001u)
94#define CLOSURE_ARGS_REST(((45) << 2) | 0xF8000001u) CONTINUATION(45)(((45) << 2) | 0xF8000001u)
95#define NUM_CONTINUATIONS46 46
96
97#define FM_NEED_GC-1 -1
98#define FM_NO_MATCH-2 -2
99#define FM_PATTERN_ERROR-3 -3
100
101typedef enum {
102 BL_OK = 0,
103 BL_NO_MEMORY,
104 BL_INCORRECT_KEY
105} binding_location_status;
106
107#define FB_OK0 0
108#define FB_TYPE_ERROR-1 -1
109
110const char* lbm_error_str_parse_eof = "End of parse stream.";
111const char* lbm_error_str_parse_dot = "Incorrect usage of '.'.";
112const char* lbm_error_str_parse_close = "Expected closing parenthesis.";
113const char* lbm_error_str_num_args = "Incorrect number of arguments.";
114const char* lbm_error_str_forbidden_in_atomic = "Operation is forbidden in an atomic block.";
115const char* lbm_error_str_no_number = "Argument(s) must be a number.";
116const char* lbm_error_str_not_a_boolean = "Argument must be t or nil (true or false).";
117const char* lbm_error_str_incorrect_arg = "Incorrect argument.";
118const char* lbm_error_str_var_outside_progn = "Usage of var outside of progn.";
119const char* lbm_error_str_flash_not_possible = "Value cannot be written to flash.";
120const char* lbm_error_str_flash_error = "Error writing to flash.";
121const char* lbm_error_str_flash_full = "Flash memory is full.";
122const char* lbm_error_str_variable_not_bound = "Variable not bound.";
123
124static lbm_value lbm_error_suspect;
125static bool_Bool lbm_error_has_suspect = false0;
126#ifdef LBM_ALWAYS_GC
127
128#define WITH_GC(y, x)(y) = (x); if (lbm_is_symbol_merror((y))) { gc(); (y) = (x); if
(lbm_is_symbol_merror((y))) { error_ctx((((0x23) << 4)
| 0x00000000u)); } }
\
129 gc(); \
130 (y) = (x); \
131 if (lbm_is_symbol_merror((y))) { \
132 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u)); \
133 }
134
135#define WITH_GC_RMBR_1(y, x, r)(y) = (x); if (lbm_is_symbol_merror((y))) { lbm_gc_mark_phase
(r); gc(); (y) = (x); if (lbm_is_symbol_merror((y))) { error_ctx
((((0x23) << 4) | 0x00000000u)); } }
\
136 lbm_gc_mark_phase(r); \
137 gc(); \
138 (y) = (x); \
139 if (lbm_is_symbol_merror((y))) { \
140 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u)); \
141 }
142
143#else
144
145#define WITH_GC(y, x)(y) = (x); if (lbm_is_symbol_merror((y))) { gc(); (y) = (x); if
(lbm_is_symbol_merror((y))) { error_ctx((((0x23) << 4)
| 0x00000000u)); } }
\
146 (y) = (x); \
147 if (lbm_is_symbol_merror((y))) { \
148 gc(); \
149 (y) = (x); \
150 if (lbm_is_symbol_merror((y))) { \
151 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u)); \
152 } \
153 /* continue executing statements below */ \
154 }
155#define WITH_GC_RMBR_1(y, x, r)(y) = (x); if (lbm_is_symbol_merror((y))) { lbm_gc_mark_phase
(r); gc(); (y) = (x); if (lbm_is_symbol_merror((y))) { error_ctx
((((0x23) << 4) | 0x00000000u)); } }
\
156 (y) = (x); \
157 if (lbm_is_symbol_merror((y))) { \
158 lbm_gc_mark_phase(r); \
159 gc(); \
160 (y) = (x); \
161 if (lbm_is_symbol_merror((y))) { \
162 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u)); \
163 } \
164 /* continue executing statements below */ \
165 }
166
167#endif
168
169typedef struct {
170 eval_context_t *first;
171 eval_context_t *last;
172} eval_context_queue_t;
173
174static int gc(void);
175static void error_ctx(lbm_value);
176static void error_at_ctx(lbm_value err_val, lbm_value at);
177static void enqueue_ctx(eval_context_queue_t *q, eval_context_t *ctx);
178static bool_Bool mailbox_add_mail(eval_context_t *ctx, lbm_value mail);
179
180// The currently executing context.
181eval_context_t *ctx_running = NULL((void*)0);
182volatile bool_Bool lbm_system_sleeping = false0;
183
184static volatile bool_Bool gc_requested = false0;
185void lbm_request_gc(void) {
186 gc_requested = true1;
187}
188
189/*
190 On ChibiOs the CH_CFG_ST_FREQUENCY setting in chconf.h sets the
191 resolution of the timer used for sleep operations. If this is set
192 to 10KHz the resolution is 100us.
193
194 The CH_CFG_ST_TIMEDELTA specifies the minimum number of ticks that
195 can be safely specified in a timeout directive (wonder if that
196 means sleep-period). The timedelta is set to 2.
197
198 If I have understood these correctly it means that the minimum
199 sleep duration possible is 2 * 100us = 200us.
200*/
201
202#define EVAL_CPS_DEFAULT_STACK_SIZE256 256
203#define EVAL_CPS_MIN_SLEEP200 200
204#define EVAL_STEPS_QUOTA10 10
205
206static volatile uint32_t eval_steps_refill = EVAL_STEPS_QUOTA10;
207static uint32_t eval_steps_quota = EVAL_STEPS_QUOTA10;
208
209void lbm_set_eval_step_quota(uint32_t quota) {
210 eval_steps_refill = quota;
211}
212
213static uint32_t eval_cps_run_state = EVAL_CPS_STATE_DEAD8;
214static volatile uint32_t eval_cps_next_state = EVAL_CPS_STATE_NONE0;
215static volatile uint32_t eval_cps_next_state_arg = 0;
216static volatile bool_Bool eval_cps_state_changed = false0;
217
218static void usleep_nonsense(uint32_t us) {
219 (void) us;
220}
221
222static bool_Bool dynamic_load_nonsense(const char *sym, const char **code) {
223 (void) sym;
224 (void) code;
225 return false0;
226}
227
228static uint32_t timestamp_nonsense(void) {
229 return 0;
230}
231
232static int printf_nonsense(const char *fmt, ...) {
233 (void) fmt;
234 return 0;
235}
236
237static void ctx_done_nonsense(eval_context_t *ctx) {
238 (void) ctx;
239}
240
241static void critical_nonsense(void) {
242 return;
243}
244
245static void (*critical_error_callback)(void) = critical_nonsense;
246static void (*usleep_callback)(uint32_t) = usleep_nonsense;
247static uint32_t (*timestamp_us_callback)(void) = timestamp_nonsense;
248static void (*ctx_done_callback)(eval_context_t *) = ctx_done_nonsense;
249static int (*printf_callback)(const char *, ...) = printf_nonsense;
250static bool_Bool (*dynamic_load_callback)(const char *, const char **) = dynamic_load_nonsense;
251
252void lbm_set_critical_error_callback(void (*fptr)(void)) {
253 if (fptr == NULL((void*)0)) critical_error_callback = critical_nonsense;
254 else critical_error_callback = fptr;
255}
256
257void lbm_set_usleep_callback(void (*fptr)(uint32_t)) {
258 if (fptr == NULL((void*)0)) usleep_callback = usleep_nonsense;
259 else usleep_callback = fptr;
260}
261
262void lbm_set_timestamp_us_callback(uint32_t (*fptr)(void)) {
263 if (fptr == NULL((void*)0)) timestamp_us_callback = timestamp_nonsense;
264 else timestamp_us_callback = fptr;
265}
266
267void lbm_set_ctx_done_callback(void (*fptr)(eval_context_t *)) {
268 if (fptr == NULL((void*)0)) ctx_done_callback = ctx_done_nonsense;
269 else ctx_done_callback = fptr;
270}
271
272void lbm_set_printf_callback(int (*fptr)(const char*, ...)){
273 if (fptr == NULL((void*)0)) printf_callback = printf_nonsense;
274 else printf_callback = fptr;
275}
276
277void lbm_set_dynamic_load_callback(bool_Bool (*fptr)(const char *, const char **)) {
278 if (fptr == NULL((void*)0)) dynamic_load_callback = dynamic_load_nonsense;
279 else dynamic_load_callback = fptr;
280}
281
282static volatile lbm_event_t *lbm_events = NULL((void*)0);
283static unsigned int lbm_events_head = 0;
284static unsigned int lbm_events_tail = 0;
285static unsigned int lbm_events_max = 0;
286static bool_Bool lbm_events_full = false0;
287static mutex_t lbm_events_mutex;
288static bool_Bool lbm_events_mutex_initialized = false0;
289static volatile lbm_cid lbm_event_handler_pid = -1;
290
291lbm_cid lbm_get_event_handler_pid(void) {
292 return lbm_event_handler_pid;
293}
294
295void lbm_set_event_handler_pid(lbm_cid pid) {
296 lbm_event_handler_pid = pid;
297}
298
299bool_Bool lbm_event_handler_exists(void) {
300 return(lbm_event_handler_pid > 0);
301}
302
303
304static bool_Bool event_internal(lbm_event_type_t event_type, lbm_uint parameter, lbm_uint buf_ptr, lbm_uint buf_len) {
305 bool_Bool r = false0;
306 if (lbm_events) {
307 mutex_lock(&lbm_events_mutex);
308 if (!lbm_events_full) {
309 lbm_event_t event;
310 event.type = event_type;
311 event.parameter = parameter;
312 event.buf_ptr = buf_ptr;
313 event.buf_len = buf_len;
314 lbm_events[lbm_events_head] = event;
315 lbm_events_head = (lbm_events_head + 1) % lbm_events_max;
316 lbm_events_full = lbm_events_head == lbm_events_tail;
317 r = true1;
318 }
319 mutex_unlock(&lbm_events_mutex);
320 }
321 return r;
322}
323
324bool_Bool lbm_event_define(lbm_value key, lbm_flat_value_t *fv) {
325 return event_internal(LBM_EVENT_DEFINE, key, (lbm_uint)fv->buf, fv->buf_size);
326}
327
328bool_Bool lbm_event_unboxed(lbm_value unboxed) {
329 lbm_uint t = lbm_type_of(unboxed);
330 if (t == LBM_TYPE_SYMBOL0x00000000u ||
331 t == LBM_TYPE_I0x00000008u ||
332 t == LBM_TYPE_U0x0000000Cu ||
333 t == LBM_TYPE_CHAR0x00000004u) {
334 if (lbm_event_handler_pid > 0) {
335 return event_internal(LBM_EVENT_FOR_HANDLER, 0, (lbm_uint)unboxed, 0);
336 }
337 }
338 return false0;
339}
340
341bool_Bool lbm_event(lbm_flat_value_t *fv) {
342 if (lbm_event_handler_pid > 0) {
343 return event_internal(LBM_EVENT_FOR_HANDLER, 0, (lbm_uint)fv->buf, fv->buf_size);
344 }
345 return false0;
346}
347
348static bool_Bool lbm_event_pop(lbm_event_t *event) {
349 mutex_lock(&lbm_events_mutex);
350 if (lbm_events_head == lbm_events_tail && !lbm_events_full) {
351 mutex_unlock(&lbm_events_mutex);
352 return false0;
353 }
354 *event = lbm_events[lbm_events_tail];
355 lbm_events_tail = (lbm_events_tail + 1) % lbm_events_max;
356 lbm_events_full = false0;
357 mutex_unlock(&lbm_events_mutex);
358 return true1;
359}
360
361bool_Bool lbm_event_queue_is_empty(void) {
362 mutex_lock(&lbm_events_mutex);
363 bool_Bool empty = false0;
364 if (lbm_events_head == lbm_events_tail && !lbm_events_full) {
365 empty = true1;
366 }
367 mutex_unlock(&lbm_events_mutex);
368 return empty;
369}
370
371static bool_Bool eval_running = false0;
372static volatile bool_Bool blocking_extension = false0;
373static mutex_t blocking_extension_mutex;
374static bool_Bool blocking_extension_mutex_initialized = false0;
375static lbm_uint blocking_extension_timeout_us = 0;
376static bool_Bool blocking_extension_timeout = false0;
377
378static uint32_t is_atomic = 0;
379
380/* Process queues */
381static eval_context_queue_t blocked = {NULL((void*)0), NULL((void*)0)};
382static eval_context_queue_t queue = {NULL((void*)0), NULL((void*)0)};
383
384/* one mutex for all queue operations */
385mutex_t qmutex;
386bool_Bool qmutex_initialized = false0;
387
388
389// MODES
390static volatile bool_Bool lbm_verbose = false0;
391
392void lbm_toggle_verbose(void) {
393 lbm_verbose = !lbm_verbose;
394}
395
396void lbm_set_verbose(bool_Bool verbose) {
397 lbm_verbose = verbose;
398}
399
400lbm_cid lbm_get_current_cid(void) {
401 if (ctx_running)
402 return ctx_running->id;
403 else
404 return -1;
405}
406
407eval_context_t *lbm_get_current_context(void) {
408 return ctx_running;
409}
410
411/****************************************************/
412/* Utilities used locally in this file */
413
414static lbm_value cons_with_gc(lbm_value head, lbm_value tail, lbm_value remember) {
415#ifdef LBM_ALWAYS_GC
416 lbm_value roots[3] = {head, tail, remember};
417 lbm_gc_mark_roots(roots, 3);
418 gc();
419 lbm_value res = lbm_heap_allocate_cell(LBM_TYPE_CONS0x10000000u, head, tail);
420 res = lbm_heap_allocate_cell(LBM_TYPE_CONS0x10000000u, head, tail);
421 if (lbm_is_symbol_merror(res)) {
422 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
423 }
424 return res;
425#else
426 lbm_value res = lbm_heap_allocate_cell(LBM_TYPE_CONS0x10000000u, head, tail);
427 if (lbm_is_symbol_merror(res)) {
428 lbm_value roots[3] = {head, tail, remember};
429 lbm_gc_mark_roots(roots,3);
430 gc();
431 res = lbm_heap_allocate_cell(LBM_TYPE_CONS0x10000000u, head, tail);
432 if (lbm_is_symbol_merror(res)) {
433 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
434 }
435 }
436 return res;
437#endif
438}
439
440static lbm_uint *get_stack_ptr(eval_context_t *ctx, unsigned int n) {
441 if (n <= ctx->K.sp) {
442 lbm_uint index = ctx->K.sp - n;
443 return &ctx->K.data[index];
444 }
445 error_ctx(ENC_SYM_STACK_ERROR(((0x27) << 4) | 0x00000000u));
446 return 0; // dead code cannot be reached, but C compiler doesn't realise.
447}
448
449// pop_stack_ptr is safe when no GC is performed and
450// the values of the stack will be dropped.
451static lbm_uint *pop_stack_ptr(eval_context_t *ctx, unsigned int n) {
452 if (n <= ctx->K.sp) {
453 ctx->K.sp -= n;
454 return &ctx->K.data[ctx->K.sp];
455 }
456 error_ctx(ENC_SYM_STACK_ERROR(((0x27) << 4) | 0x00000000u));
457 return 0; // dead code cannot be reached, but C compiler doesn't realise.
458}
459
460static lbm_uint *stack_reserve(eval_context_t *ctx, unsigned int n) {
461 if (ctx->K.sp + n < ctx->K.size) {
462 lbm_uint *ptr = &ctx->K.data[ctx->K.sp];
463 ctx->K.sp += n;
464 return ptr;
465 }
466 error_ctx(ENC_SYM_STACK_ERROR(((0x27) << 4) | 0x00000000u));
467 return 0; // dead code cannot be reached, but C compiler doesn't realise.
468}
469
470static void handle_flash_status(lbm_flash_status s) {
471 if ( s == LBM_FLASH_FULL) {
472 lbm_set_error_reason((char*)lbm_error_str_flash_full);
473 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
474 }
475 if (s == LBM_FLASH_WRITE_ERROR) {
476 lbm_set_error_reason((char*)lbm_error_str_flash_error);
477 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
478 }
479}
480
481static void lift_array_flash(lbm_value flash_cell, char *data, lbm_uint num_elt) {
482
483 lbm_array_header_t flash_array_header;
484 flash_array_header.size = num_elt;
485 flash_array_header.data = (lbm_uint*)data;
486 lbm_uint flash_array_header_ptr;
487 handle_flash_status(lbm_write_const_raw((lbm_uint*)&flash_array_header,
488 sizeof(lbm_array_header_t) / sizeof(lbm_uint),
489 &flash_array_header_ptr));
490 handle_flash_status(write_const_car(flash_cell, flash_array_header_ptr));
491 handle_flash_status(write_const_cdr(flash_cell, ENC_SYM_ARRAY_TYPE(((0x30) << 4) | 0x00000000u)));
492}
493
494static void stack_push(lbm_stack_t *s, lbm_uint val) {
495 if (s->sp < s->size) {
496 s->data[s->sp++] = val;
497 if (s->sp > s->max_sp) s->max_sp = s->sp;
498 return;
499 }
500 error_ctx(ENC_SYM_STACK_ERROR(((0x27) << 4) | 0x00000000u));
501}
502
503static void stack_push_2(lbm_stack_t *s, lbm_uint v1, lbm_uint v2) {
504 if (s->sp + 1 < s->size) {
505 lbm_uint *t = &s->data[s->sp];
506 t[0] = v1;
507 t[1] = v2;
508 s->sp += 2;
509 if (s->sp > s->max_sp) s->max_sp = s->sp;
510 return;
511 }
512 error_ctx(ENC_SYM_STACK_ERROR(((0x27) << 4) | 0x00000000u));
513}
514
515static void stack_push_3(lbm_stack_t *s, lbm_uint v1, lbm_uint v2, lbm_uint v3) {
516 if (s->sp + 2 < s->size) {
517 lbm_uint *t = &s->data[s->sp];
518 t[0] = v1;
519 t[1] = v2;
520 t[2] = v3;
521 s->sp += 3;
522 if (s->sp > s->max_sp) s->max_sp = s->sp;
523 return;
524 }
525 error_ctx(ENC_SYM_STACK_ERROR(((0x27) << 4) | 0x00000000u));
526}
527
528static void stack_push_4(lbm_stack_t *s, lbm_uint v1, lbm_uint v2, lbm_uint v3, lbm_uint v4) {
529 if (s->sp + 3 < s->size) {
530 lbm_uint *t = &s->data[s->sp];
531 t[0] = v1;
532 t[1] = v2;
533 t[2] = v3;
534 t[3] = v4;
535 s->sp += 4;
536 if (s->sp > s->max_sp) s->max_sp = s->sp;
537 return;
538 }
539 error_ctx(ENC_SYM_STACK_ERROR(((0x27) << 4) | 0x00000000u));
540}
541
542static void get_car_and_cdr(lbm_value a, lbm_value *a_car, lbm_value *a_cdr) {
543 if (lbm_is_ptr(a)) {
544 lbm_cons_t *cell = lbm_ref_cell(a);
545 *a_car = cell->car;
546 *a_cdr = cell->cdr;
547 } else if (lbm_is_symbol_nil(a)) {
548 *a_car = *a_cdr = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
549 } else {
550 error_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
551 }
552}
553
554/* car cdr caar cadr replacements that are evaluator safe. */
555static lbm_value get_car(lbm_value a) {
556 if (lbm_is_ptr(a)) {
6
Assuming the condition is false
7
Taking false branch
557 lbm_cons_t *cell = lbm_ref_cell(a);
558 return cell->car;
559 } else if (lbm_is_symbol_nil(a)) {
8
Calling 'lbm_is_symbol_nil'
11
Returning from 'lbm_is_symbol_nil'
12
Taking true branch
560 return a;
13
Returning zero (loaded from 'a')
561 }
562 error_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
563 return(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
564}
565
566static lbm_value get_cdr(lbm_value a) {
567 if (lbm_is_ptr(a)) {
568 lbm_cons_t *cell = lbm_ref_cell(a);
569 return cell->cdr;
570 } else if (lbm_is_symbol_nil(a)) {
571 return a;
572 }
573 error_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
574 return(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
575}
576
577static lbm_value get_caar(lbm_value a) {
578 if (lbm_is_ptr(a)) {
579 lbm_cons_t *cell = lbm_ref_cell(a);
580 lbm_value tmp = cell->car;
581 if (lbm_is_ptr(tmp)) {
582 return lbm_ref_cell(tmp)->car;
583 } else if (lbm_is_symbol_nil(tmp)) {
584 return tmp;
585 }
586 } else if (lbm_is_symbol_nil(a)) {
587 return a;
588 }
589 error_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
590 return(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
591}
592
593static lbm_value get_cadr(lbm_value a) {
594 if (lbm_is_ptr(a)) {
595 lbm_cons_t *cell = lbm_ref_cell(a);
596 lbm_value tmp = cell->cdr;
597 if (lbm_is_ptr(tmp)) {
598 return lbm_ref_cell(tmp)->car;
599 } else if (lbm_is_symbol_nil(tmp)) {
600 return tmp;
601 }
602 } else if (lbm_is_symbol_nil(a)) {
603 return a;
604 }
605 error_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
606 return(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
607}
608
609static lbm_value get_cddr(lbm_value a) {
610 if (lbm_is_ptr(a)) {
611 lbm_cons_t *cell = lbm_ref_cell(a);
612 lbm_value tmp = cell->cdr;
613 if (lbm_is_ptr(tmp)) {
614 return lbm_ref_cell(tmp)->cdr;
615 } else if (lbm_is_symbol_nil(tmp)) {
616 return tmp;
617 }
618 } else if (lbm_is_symbol_nil(a)) {
619 return a;
620 }
621 error_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
622 return(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
623}
624
625static lbm_value allocate_closure(lbm_value params, lbm_value body, lbm_value env) {
626
627#ifdef LBM_ALWAYS_GC
628 gc();
629 if (lbm_heap_num_free() < 4) {
630 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
631 }
632#else
633 if (lbm_heap_num_free() < 4) {
634 gc();
635 if (lbm_heap_num_free() < 4) {
636 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
637 }
638 }
639#endif
640 // The freelist will always contain just plain heap-cells.
641 // So dec_ptr is sufficient.
642 lbm_value res = lbm_heap_state.freelist;
643 if (lbm_type_of(res) == LBM_TYPE_CONS0x10000000u) {
644 lbm_cons_t *heap = lbm_heap_state.heap;
645 lbm_uint ix = lbm_dec_ptr(res);
646 heap[ix].car = ENC_SYM_CLOSURE(((0x10F) << 4) | 0x00000000u);
647 ix = lbm_dec_ptr(heap[ix].cdr);
648 heap[ix].car = params;
649 ix = lbm_dec_ptr(heap[ix].cdr);
650 heap[ix].car = body;
651 ix = lbm_dec_ptr(heap[ix].cdr);
652 heap[ix].car = env;
653 lbm_heap_state.freelist = heap[ix].cdr;
654 heap[ix].cdr = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
655 lbm_heap_state.num_alloc+=4;
656 } else {
657 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
658 }
659 return res;
660}
661
662// Allocate a binding and attach it to a list (if so desired)
663static lbm_value allocate_binding(lbm_value key, lbm_value val, lbm_value the_cdr) {
664 if (lbm_heap_num_free() < 2) {
665 gc();
666 if (lbm_heap_num_free() < 2) {
667 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
668 }
669 }
670 lbm_cons_t* heap = lbm_heap_state.heap;
671 lbm_value binding_cell = lbm_heap_state.freelist;
672 lbm_uint binding_cell_ix = lbm_dec_ptr(binding_cell);
673 lbm_value list_cell = heap[binding_cell_ix].cdr;
674 lbm_uint list_cell_ix = lbm_dec_ptr(list_cell);
675 lbm_heap_state.freelist = heap[list_cell_ix].cdr;
676 lbm_heap_state.num_alloc += 2;
677 heap[binding_cell_ix].car = key;
678 heap[binding_cell_ix].cdr = val;
679 heap[list_cell_ix].car = binding_cell;
680 heap[list_cell_ix].cdr = the_cdr;
681 return list_cell;
682}
683
684#define CLO_PARAMS0 0
685#define CLO_BODY1 1
686#define CLO_ENV2 2
687#define LOOP_BINDS0 0
688#define LOOP_COND1 1
689#define LOOP_BODY2 2
690
691// (closure params exp env) -> [params, exp, env])
692static void extract_n(lbm_value curr, lbm_value *res, unsigned int n) {
693 for (unsigned int i = 0; i < n; i ++) {
694 if (lbm_is_ptr(curr)) {
695 lbm_cons_t *cell = lbm_ref_cell(curr);
696 res[i] = cell->car;
697 curr = cell->cdr;
698 } else {
699 error_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
700 }
701 }
702}
703
704static void call_fundamental(lbm_uint fundamental, lbm_value *args, lbm_uint arg_count, eval_context_t *ctx) {
705 lbm_value res;
706 res = fundamental_table[fundamental](args, arg_count, ctx);
707 if (lbm_is_error(res)) {
708 if (lbm_is_symbol_merror(res)) {
709 gc();
710 res = fundamental_table[fundamental](args, arg_count, ctx);
711 }
712 if (lbm_is_error(res)) {
713 error_at_ctx(res, lbm_enc_sym(FUNDAMENTAL_SYMBOLS_START0x20000 | fundamental));
714 }
715 }
716 lbm_stack_drop(&ctx->K, arg_count+1);
717 ctx->app_cont = true1;
718 ctx->r = res;
719}
720
721// block_current_ctx blocks a context until it is
722// woken up externally or a timeout period of time passes.
723static void block_current_ctx(uint32_t state, lbm_uint sleep_us, bool_Bool do_cont) {
724 ctx_running->timestamp = timestamp_us_callback();
725 ctx_running->sleep_us = sleep_us;
726 ctx_running->state = state;
727 ctx_running->app_cont = do_cont;
728 enqueue_ctx(&blocked, ctx_running);
729 ctx_running = NULL((void*)0);
730}
731
732lbm_flash_status lbm_write_const_array_padded(uint8_t *data, lbm_uint n, lbm_uint *res) {
733 lbm_uint full_words = n / sizeof(lbm_uint);
734 lbm_uint n_mod = n % sizeof(lbm_uint);
735
736 if (n_mod == 0) { // perfect fit.
737 return lbm_write_const_raw((lbm_uint*)data, full_words, res);
738 } else {
739 lbm_uint last_word = 0;
740 memcpy(&last_word, &data[full_words * sizeof(lbm_uint)], n_mod);
741 if (full_words >= 1) {
742 lbm_flash_status s = lbm_write_const_raw((lbm_uint*)data, full_words, res);
743 if ( s == LBM_FLASH_WRITE_OK) {
744 lbm_uint dummy;
745 s = lbm_write_const_raw(&last_word, 1, &dummy);
746 }
747 return s;
748 } else {
749 return lbm_write_const_raw(&last_word, 1, res);
750 }
751 }
752}
753
754/****************************************************/
755/* Error message creation */
756
757#define ERROR_MESSAGE_BUFFER_SIZE_BYTES256 256
758
759void print_environments(char *buf, unsigned int size) {
760
761 lbm_value curr_l = ctx_running->curr_env;
762 printf_callback("\tCurrent local environment:\n");
763 while (lbm_type_of(curr_l) == LBM_TYPE_CONS0x10000000u) {
764 lbm_print_value(buf, (size/2) - 1, lbm_caar(curr_l));
765 lbm_print_value(buf + (size/2),size/2, lbm_cdr(lbm_car(curr_l)));
766 printf_callback("\t%s = %s\n", buf, buf+(size/2));
767 curr_l = lbm_cdr(curr_l);
768 }
769 printf_callback("\n\n");
770 printf_callback("\tCurrent global environment:\n");
771 lbm_value *glob_env = lbm_get_global_env();
772
773 for (int i = 0; i < GLOBAL_ENV_ROOTS32; i ++) {
774 lbm_value curr_g = glob_env[i];;
775 while (lbm_type_of(curr_g) == LBM_TYPE_CONS0x10000000u) {
776
777 lbm_print_value(buf, (size/2) - 1, lbm_caar(curr_g));
778 lbm_print_value(buf + (size/2),size/2, lbm_cdr(lbm_car(curr_g)));
779 printf_callback("\t%s = %s\n", buf, buf+(size/2));
780 curr_g = lbm_cdr(curr_g);
781 }
782 }
783}
784
785void print_error_message(lbm_value error, bool_Bool has_at, lbm_value at, unsigned int row, unsigned int col, lbm_int row0, lbm_int row1) {
786 if (!printf_callback) return;
787
788 /* try to allocate a lbm_print_value buffer on the lbm_memory */
789 char *buf = lbm_malloc_reserve(ERROR_MESSAGE_BUFFER_SIZE_BYTES256);
790 if (!buf) {
791 printf_callback("Error: Not enough free memory to create a human readable error message\n");
792 return;
793 }
794
795 lbm_print_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES256, error);
796 printf_callback( "*** Error: %s\n", buf);
797 if (has_at) {
798 lbm_print_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES256, at);
799 printf_callback("*** In: %s\n",buf);
800 if (lbm_error_has_suspect) {
801 lbm_print_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES256, lbm_error_suspect);
802 lbm_error_has_suspect = false0;
803 printf_callback("*** At: %s\n", buf);
804 } else {
805 lbm_print_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES256, ctx_running->curr_exp);
806 printf_callback("*** After: %s\n",buf);
807 }
808 } else {
809 lbm_print_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES256, ctx_running->curr_exp);
810 printf_callback("*** Near: %s\n",buf);
811 }
812
813 printf_callback("\n");
814
815 if (lbm_is_symbol(error) &&
816 error == ENC_SYM_RERROR(((0x20) << 4) | 0x00000000u)) {
817 printf_callback("*** Line: %u\n", row);
818 printf_callback("*** Column: %u\n", col);
819 } else if (row0 != -1 || row1 != -1 ) {
820 printf_callback("*** Between rows: (-1 unknown) \n");
821 printf_callback("*** Start: %d\n", (int32_t)row0);
822 printf_callback("*** End: %d\n", (int32_t)row1);
823 }
824
825 printf_callback("\n");
826
827 if (ctx_running->error_reason) {
828 printf_callback("Reason:\n %s\n\n", ctx_running->error_reason);
829 }
830 if (lbm_verbose) {
831 lbm_print_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES256, ctx_running->curr_exp);
832 printf_callback(" In context: %d\n", ctx_running->id);
833 printf_callback(" Current intermediate result: %s\n\n", buf);
834
835 print_environments(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES256);
836 printf_callback("\n\n");
837
838 printf_callback(" Stack:\n");
839 for (unsigned int i = 0; i < ctx_running->K.sp; i ++) {
840 lbm_print_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES256, ctx_running->K.data[i]);
841 printf_callback(" %s\n", buf);
842 }
843 }
844 lbm_free(buf);
845}
846
847/****************************************************/
848/* Tokenizing and parsing */
849
850bool_Bool create_string_channel(char *str, lbm_value *res) {
851
852 lbm_char_channel_t *chan = NULL((void*)0);
853 lbm_string_channel_state_t *st = NULL((void*)0);
854
855 st = (lbm_string_channel_state_t*)lbm_memory_allocate(sizeof(lbm_string_channel_state_t) / sizeof(lbm_uint) +1);
856 if (st == NULL((void*)0)) {
857 return false0;
858 }
859 chan = (lbm_char_channel_t*)lbm_memory_allocate(sizeof(lbm_char_channel_t) / sizeof(lbm_uint) + 1);
860 if (chan == NULL((void*)0)) {
861 lbm_memory_free((lbm_uint*)st);
862 return false0;
863 }
864
865 lbm_create_string_char_channel(st, chan, str);
866 lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_CHANNEL0x90000000u, (lbm_uint) chan, ENC_SYM_CHANNEL_TYPE(((0x37) << 4) | 0x00000000u));
867 if (lbm_type_of(cell) == LBM_TYPE_SYMBOL0x00000000u) {
868 lbm_memory_free((lbm_uint*)st);
869 lbm_memory_free((lbm_uint*)chan);
870 return false0;
871 }
872
873 *res = cell;
874 return true1;
875}
876
877bool_Bool lift_char_channel(lbm_char_channel_t *chan , lbm_value *res) {
878 lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_CHANNEL0x90000000u, (lbm_uint) chan, ENC_SYM_CHANNEL_TYPE(((0x37) << 4) | 0x00000000u));
879 if (lbm_type_of(cell) == LBM_TYPE_SYMBOL0x00000000u) {
880 return false0;
881 }
882 *res = cell;
883 return true1;
884}
885
886
887/****************************************************/
888/* Queue functions */
889
890static void queue_iterator_nm(eval_context_queue_t *q, ctx_fun f, void *arg1, void *arg2) {
891 eval_context_t *curr;
892 curr = q->first;
893
894 while (curr != NULL((void*)0)) {
895 f(curr, arg1, arg2);
896 curr = curr->next;
897 }
898}
899
900void lbm_running_iterator(ctx_fun f, void *arg1, void *arg2){
901 mutex_lock(&qmutex);
902 queue_iterator_nm(&queue, f, arg1, arg2);
903 mutex_unlock(&qmutex);
904}
905
906void lbm_blocked_iterator(ctx_fun f, void *arg1, void *arg2){
907 mutex_lock(&qmutex);
908 queue_iterator_nm(&blocked, f, arg1, arg2);
909 mutex_unlock(&qmutex);
910}
911
912static void enqueue_ctx_nm(eval_context_queue_t *q, eval_context_t *ctx) {
913 if (q->last == NULL((void*)0)) {
914 ctx->prev = NULL((void*)0);
915 ctx->next = NULL((void*)0);
916 q->first = ctx;
917 q->last = ctx;
918 } else {
919 ctx->prev = q->last;
920 ctx->next = NULL((void*)0);
921 q->last->next = ctx;
922 q->last = ctx;
923 }
924}
925
926static void enqueue_ctx(eval_context_queue_t *q, eval_context_t *ctx) {
927 mutex_lock(&qmutex);
928 enqueue_ctx_nm(q,ctx);
929 mutex_unlock(&qmutex);
930}
931
932static eval_context_t *lookup_ctx_nm(eval_context_queue_t *q, lbm_cid cid) {
933 eval_context_t *curr;
934 curr = q->first;
935 while (curr != NULL((void*)0)) {
936 if (curr->id == cid) {
937 return curr;
938 }
939 curr = curr->next;
940 }
941 return NULL((void*)0);
942}
943
944static bool_Bool drop_ctx_nm(eval_context_queue_t *q, eval_context_t *ctx) {
945
946 bool_Bool res = false0;
947 if (q->first == NULL((void*)0) || q->last == NULL((void*)0)) {
948 if (!(q->last == NULL((void*)0) && q->first == NULL((void*)0))) {
949 /* error state that should not happen */
950 return res;
951 }
952 /* Queue is empty */
953 return res;
954 }
955
956 eval_context_t *curr = q->first;
957 while (curr) {
958 if (curr->id == ctx->id) {
959 res = true1;
960 eval_context_t *tmp = curr->next;
961 if (curr->prev == NULL((void*)0)) {
962 if (curr->next == NULL((void*)0)) {
963 q->last = NULL((void*)0);
964 q->first = NULL((void*)0);
965 } else {
966 q->first = tmp;
967 tmp->prev = NULL((void*)0);
968 }
969 } else { /* curr->prev != NULL */
970 if (curr->next == NULL((void*)0)) {
971 q->last = curr->prev;
972 q->last->next = NULL((void*)0);
973 } else {
974 curr->prev->next = tmp;
975 tmp->prev = curr->prev;
976 }
977 }
978 break;
979 }
980 curr = curr->next;
981 }
982 return res;
983}
984
985/* End execution of the running context. */
986static void finish_ctx(void) {
987
988 if (!ctx_running) {
989 return;
990 }
991 /* Drop the continuation stack immediately to free up lbm_memory */
992 lbm_stack_free(&ctx_running->K);
993 ctx_done_callback(ctx_running);
994 if (lbm_memory_ptr_inside((lbm_uint*)ctx_running->name)) {
995 lbm_free(ctx_running->name);
996 }
997 if (lbm_memory_ptr_inside((lbm_uint*)ctx_running->error_reason)) {
998 lbm_memory_free((lbm_uint*)ctx_running->error_reason);
999 }
1000 lbm_memory_free((lbm_uint*)ctx_running->mailbox);
1001 lbm_memory_free((lbm_uint*)ctx_running);
1002 ctx_running = NULL((void*)0);
1003}
1004
1005static void context_exists(eval_context_t *ctx, void *cid, void *b) {
1006 if (ctx->id == *(lbm_cid*)cid) {
1007 *(bool_Bool*)b = true1;
1008 }
1009}
1010
1011bool_Bool lbm_wait_ctx(lbm_cid cid, lbm_uint timeout_ms) {
1012
1013 bool_Bool exists;
1014 uint32_t i = 0;
1015
1016 do {
1017 exists = false0;
1018 lbm_blocked_iterator(context_exists, &cid, &exists);
1019 lbm_running_iterator(context_exists, &cid, &exists);
1020
1021 if (ctx_running &&
1022 ctx_running->id == cid) {
1023 exists = true1;
1024 }
1025
1026 if (exists) {
1027 if (usleep_callback) {
1028 usleep_callback(1000);
1029 }
1030 if (timeout_ms > 0) i ++;
1031 }
1032 } while (exists && i < timeout_ms);
1033
1034 if (exists) return false0;
1035 return true1;
1036}
1037
1038void lbm_set_error_suspect(lbm_value suspect) {
1039 lbm_error_suspect = suspect;
1040 lbm_error_has_suspect = true1;
1041}
1042
1043void lbm_set_error_reason(char *error_str) {
1044 if (ctx_running != NULL((void*)0)) {
1045 ctx_running->error_reason = error_str;
1046 }
1047}
1048
1049// Not possible to CONS_WITH_GC in error_ctx_base (potential loop)
1050static void error_ctx_base(lbm_value err_val, bool_Bool has_at, lbm_value at, unsigned int row, unsigned int column) {
1051
1052 if (ctx_running->flags & EVAL_CPS_CONTEXT_FLAG_TRAP(uint32_t)0x1) {
1053 if (lbm_heap_num_free() < 3) {
1054 gc();
1055 }
1056
1057 if (lbm_heap_num_free() >= 3) {
1058 lbm_value msg = lbm_cons(err_val, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
1059 msg = lbm_cons(lbm_enc_i(ctx_running->id), msg);
1060 msg = lbm_cons(ENC_SYM_EXIT_ERROR(((0x3000C) << 4) | 0x00000000u), msg);
1061 if (lbm_is_symbol_merror(msg)) {
1062 // If this happens something is pretty seriously wrong.
1063 print_error_message(err_val,
1064 has_at,
1065 at,
1066 row,
1067 column,
1068 ctx_running->row0,
1069 ctx_running->row1);
1070 } else {
1071 lbm_find_receiver_and_send(ctx_running->parent, msg);
1072 }
1073 }
1074 } else {
1075 print_error_message(err_val,
1076 has_at,
1077 at,
1078 row,
1079 column,
1080 ctx_running->row0,
1081 ctx_running->row1);
1082 }
1083 ctx_running->r = err_val;
1084 finish_ctx();
1085 longjmp(error_jmp_buf, 1);
1086}
1087
1088static void error_at_ctx(lbm_value err_val, lbm_value at) {
1089 error_ctx_base(err_val, true1, at, 0, 0);
1090}
1091
1092static void error_ctx(lbm_value err_val) {
1093 error_ctx_base(err_val, false0, 0, 0, 0);
1094}
1095
1096static void read_error_ctx(unsigned int row, unsigned int column) {
1097 error_ctx_base(ENC_SYM_RERROR(((0x20) << 4) | 0x00000000u), false0, 0, row, column);
1098}
1099
1100void lbm_critical_error(void) {
1101 longjmp(critical_error_jmp_buf, 1);
1102}
1103
1104// successfully finish a context
1105static void ok_ctx(void) {
1106 if (ctx_running->flags & EVAL_CPS_CONTEXT_FLAG_TRAP(uint32_t)0x1) {
1107 lbm_value msg;
1108 WITH_GC(msg, lbm_heap_allocate_list_init(3,(msg) = (lbm_heap_allocate_list_init(3, (((0x3000B) << 4
) | 0x00000000u), lbm_enc_i(ctx_running->id), ctx_running->
r)); if (lbm_is_symbol_merror((msg))) { gc(); (msg) = (lbm_heap_allocate_list_init
(3, (((0x3000B) << 4) | 0x00000000u), lbm_enc_i(ctx_running
->id), ctx_running->r)); if (lbm_is_symbol_merror((msg)
)) { error_ctx((((0x23) << 4) | 0x00000000u)); } }
1109 ENC_SYM_EXIT_OK,(msg) = (lbm_heap_allocate_list_init(3, (((0x3000B) << 4
) | 0x00000000u), lbm_enc_i(ctx_running->id), ctx_running->
r)); if (lbm_is_symbol_merror((msg))) { gc(); (msg) = (lbm_heap_allocate_list_init
(3, (((0x3000B) << 4) | 0x00000000u), lbm_enc_i(ctx_running
->id), ctx_running->r)); if (lbm_is_symbol_merror((msg)
)) { error_ctx((((0x23) << 4) | 0x00000000u)); } }
1110 lbm_enc_i(ctx_running->id),(msg) = (lbm_heap_allocate_list_init(3, (((0x3000B) << 4
) | 0x00000000u), lbm_enc_i(ctx_running->id), ctx_running->
r)); if (lbm_is_symbol_merror((msg))) { gc(); (msg) = (lbm_heap_allocate_list_init
(3, (((0x3000B) << 4) | 0x00000000u), lbm_enc_i(ctx_running
->id), ctx_running->r)); if (lbm_is_symbol_merror((msg)
)) { error_ctx((((0x23) << 4) | 0x00000000u)); } }
1111 ctx_running->r))(msg) = (lbm_heap_allocate_list_init(3, (((0x3000B) << 4
) | 0x00000000u), lbm_enc_i(ctx_running->id), ctx_running->
r)); if (lbm_is_symbol_merror((msg))) { gc(); (msg) = (lbm_heap_allocate_list_init
(3, (((0x3000B) << 4) | 0x00000000u), lbm_enc_i(ctx_running
->id), ctx_running->r)); if (lbm_is_symbol_merror((msg)
)) { error_ctx((((0x23) << 4) | 0x00000000u)); } }
;
1112 lbm_find_receiver_and_send(ctx_running->parent, msg);
1113 }
1114 finish_ctx();
1115}
1116
1117static eval_context_t *dequeue_ctx_nm(eval_context_queue_t *q) {
1118 if (q->last == NULL((void*)0)) {
1119 return NULL((void*)0);
1120 }
1121 // q->first should only be NULL if q->last is.
1122 eval_context_t *res = q->first;
1123
1124 if (q->first == q->last) { // One thing in queue
1125 q->first = NULL((void*)0);
1126 q->last = NULL((void*)0);
1127 } else {
1128 q->first = q->first->next;
1129 q->first->prev = NULL((void*)0);
1130 }
1131 res->prev = NULL((void*)0);
1132 res->next = NULL((void*)0);
1133 return res;
1134}
1135
1136static void wake_up_ctxs_nm(void) {
1137 lbm_uint t_now;
1138
1139 if (timestamp_us_callback) {
1140 t_now = timestamp_us_callback();
1141 } else {
1142 t_now = 0;
1143 }
1144
1145 eval_context_queue_t *q = &blocked;
1146 eval_context_t *curr = q->first;
1147
1148 while (curr != NULL((void*)0)) {
1149 lbm_uint t_diff;
1150 eval_context_t *next = curr->next;
1151 if (curr->state != LBM_THREAD_STATE_BLOCKED(uint32_t)1) {
1152 if ( curr->timestamp > t_now) {
1153 /* There was an overflow on the counter */
1154#ifndef LBM64
1155 t_diff = (0xFFFFFFFF - curr->timestamp) + t_now;
1156#else
1157 t_diff = (0xFFFFFFFFFFFFFFFF - curr->timestamp) + t_now;
1158#endif
1159 } else {
1160 t_diff = t_now - curr->timestamp;
1161 }
1162
1163 if (t_diff >= curr->sleep_us) {
1164 eval_context_t *wake_ctx = curr;
1165 if (curr == q->last) {
1166 if (curr->prev) {
1167 q->last = curr->prev;
1168 q->last->next = NULL((void*)0);
1169 } else {
1170 q->first = NULL((void*)0);
1171 q->last = NULL((void*)0);
1172 }
1173 } else if (curr->prev == NULL((void*)0)) {
1174 q->first = curr->next;
1175 q->first->prev = NULL((void*)0);
1176 } else {
1177 curr->prev->next = curr->next;
1178 if (curr->next) {
1179 curr->next->prev = curr->prev;
1180 }
1181 }
1182 wake_ctx->next = NULL((void*)0);
1183 wake_ctx->prev = NULL((void*)0);
1184 if (curr->state == LBM_THREAD_STATE_TIMEOUT(uint32_t)2) {
1185 mailbox_add_mail(wake_ctx, ENC_SYM_TIMEOUT(((0xA) << 4) | 0x00000000u));
1186 wake_ctx->r = ENC_SYM_TIMEOUT(((0xA) << 4) | 0x00000000u);
1187 }
1188 wake_ctx->state = LBM_THREAD_STATE_READY(uint32_t)0;
1189 enqueue_ctx_nm(&queue, wake_ctx);
1190 }
1191 }
1192 curr = next;
1193 }
1194}
1195
1196static void yield_ctx(lbm_uint sleep_us) {
1197 if (timestamp_us_callback) {
1198 ctx_running->timestamp = timestamp_us_callback();
1199 ctx_running->sleep_us = sleep_us;
1200 ctx_running->state = LBM_THREAD_STATE_SLEEPING(uint32_t)3;
1201 } else {
1202 ctx_running->timestamp = 0;
1203 ctx_running->sleep_us = 0;
1204 ctx_running->state = LBM_THREAD_STATE_SLEEPING(uint32_t)3;
1205 }
1206 ctx_running->r = ENC_SYM_TRUE(((0x2) << 4) | 0x00000000u);
1207 ctx_running->app_cont = true1;
1208 enqueue_ctx(&blocked,ctx_running);
1209 ctx_running = NULL((void*)0);
1210}
1211
1212static lbm_cid lbm_create_ctx_parent(lbm_value program, lbm_value env, lbm_uint stack_size, lbm_cid parent, uint32_t context_flags, char *name) {
1213
1214 if (!lbm_is_cons(program)) return -1;
1215
1216 eval_context_t *ctx = NULL((void*)0);
1217
1218 ctx = (eval_context_t*)lbm_malloc(sizeof(eval_context_t));
1219 if (ctx == NULL((void*)0)) {
1220 lbm_uint roots[2] = {program, env};
1221 lbm_gc_mark_roots(roots, 2);
1222 gc();
1223 ctx = (eval_context_t*)lbm_malloc(sizeof(eval_context_t));
1224 }
1225 if (ctx == NULL((void*)0)) return -1;
1226
1227 if (!lbm_stack_allocate(&ctx->K, stack_size)) {
1228 lbm_uint roots[2] = {program, env};
1229 lbm_gc_mark_roots(roots, 2);
1230 gc();
1231 if (!lbm_stack_allocate(&ctx->K, stack_size)) {
1232 lbm_memory_free((lbm_uint*)ctx);
1233 return -1;
1234 }
1235 }
1236
1237 lbm_value *mailbox = NULL((void*)0);
1238 mailbox = (lbm_value*)lbm_memory_allocate(EVAL_CPS_DEFAULT_MAILBOX_SIZE10);
1239 if (mailbox == NULL((void*)0)) {
1240 lbm_value roots[2] = {program, env};
1241 lbm_gc_mark_roots(roots,2);
1242 gc();
1243 mailbox = (lbm_value *)lbm_memory_allocate(EVAL_CPS_DEFAULT_MAILBOX_SIZE10);
1244 }
1245 if (mailbox == NULL((void*)0)) {
1246 lbm_stack_free(&ctx->K);
1247 lbm_memory_free((lbm_uint*)ctx);
1248 return -1;
1249 }
1250
1251 // TODO: Limit names to 19 chars + 1 char for 0? (or something similar).
1252 if (name) {
1253 lbm_uint name_len = strlen(name) + 1;
1254 ctx->name = lbm_malloc(strlen(name) + 1);
1255 if (ctx->name == NULL((void*)0)) {
1256 lbm_value roots[2] = {program, env};
1257 lbm_gc_mark_roots(roots, 2);
1258 gc();
1259 ctx->name = lbm_malloc(strlen(name) + 1);
1260 }
1261 if (ctx->name == NULL((void*)0)) {
1262 lbm_stack_free(&ctx->K);
1263 lbm_memory_free((lbm_uint*)mailbox);
1264 lbm_memory_free((lbm_uint*)ctx);
1265 return -1;
1266 }
1267 memcpy(ctx->name, name, name_len+1);
1268 } else {
1269 ctx->name = NULL((void*)0);
1270 }
1271
1272 lbm_int cid = lbm_memory_address_to_ix((lbm_uint*)ctx);
1273
1274 ctx->program = lbm_cdr(program);
1275 ctx->curr_exp = lbm_car(program);
1276 ctx->curr_env = env;
1277 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1278 ctx->error_reason = NULL((void*)0);
1279 ctx->mailbox = mailbox;
1280 ctx->mailbox_size = EVAL_CPS_DEFAULT_MAILBOX_SIZE10;
1281 ctx->flags = context_flags;
1282 ctx->num_mail = 0;
1283 ctx->app_cont = false0;
1284 ctx->timestamp = 0;
1285 ctx->sleep_us = 0;
1286 ctx->state = LBM_THREAD_STATE_READY(uint32_t)0;
1287 ctx->prev = NULL((void*)0);
1288 ctx->next = NULL((void*)0);
1289
1290 ctx->row0 = -1;
1291 ctx->row1 = -1;
1292
1293 ctx->id = cid;
1294 ctx->parent = parent;
1295
1296 if (!lbm_push(&ctx->K, DONE(((0) << 2) | 0xF8000001u))) {
1297 lbm_memory_free((lbm_uint*)ctx->mailbox);
1298 lbm_stack_free(&ctx->K);
1299 lbm_memory_free((lbm_uint*)ctx);
1300 return -1;
1301 }
1302
1303 enqueue_ctx(&queue,ctx);
1304
1305 return ctx->id;
1306}
1307
1308lbm_cid lbm_create_ctx(lbm_value program, lbm_value env, lbm_uint stack_size, char *name) {
1309 // Creates a parentless context.
1310 return lbm_create_ctx_parent(program,
1311 env,
1312 stack_size,
1313 -1,
1314 EVAL_CPS_CONTEXT_FLAG_NOTHING(uint32_t)0x0,
1315 name);
1316}
1317
1318bool_Bool lbm_mailbox_change_size(eval_context_t *ctx, lbm_uint new_size) {
1319
1320 lbm_value *mailbox = NULL((void*)0);
1321 mailbox = (lbm_value*)lbm_memory_allocate(new_size);
1322 if (mailbox == NULL((void*)0)) {
1323 gc();
1324 mailbox = (lbm_value *)lbm_memory_allocate(new_size);
1325 }
1326 if (mailbox == NULL((void*)0)) {
1327 return false0;
1328 }
1329
1330 for (lbm_uint i = 0; i < ctx->num_mail; i ++ ) {
1331 mailbox[i] = ctx->mailbox[i];
1332 }
1333 lbm_memory_free(ctx->mailbox);
1334 ctx->mailbox = mailbox;
1335 ctx->mailbox_size = (uint32_t)new_size;
1336 return true1;
1337}
1338
1339static void mailbox_remove_mail(eval_context_t *ctx, lbm_uint ix) {
1340
1341 for (lbm_uint i = ix; i < ctx->num_mail-1; i ++) {
1342 ctx->mailbox[i] = ctx->mailbox[i+1];
1343 }
1344 ctx->num_mail --;
1345}
1346
1347static bool_Bool mailbox_add_mail(eval_context_t *ctx, lbm_value mail) {
1348
1349 if (ctx->num_mail >= ctx->mailbox_size) {
1350 mailbox_remove_mail(ctx, 0);
1351 }
1352
1353 ctx->mailbox[ctx->num_mail] = mail;
1354 ctx->num_mail ++;
1355 return true1;
1356}
1357
1358/* Advance execution to the next expression in the program */
1359static void advance_ctx(eval_context_t *ctx) {
1360 if (lbm_is_cons(ctx->program)) {
1361 stack_push(&ctx->K, DONE(((0) << 2) | 0xF8000001u));
1362 get_car_and_cdr(ctx->program, &ctx->curr_exp, &ctx->program);
1363 ctx->curr_env = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1364 } else {
1365 if (ctx_running == ctx) { // This should always be the case because of odd historical reasons.
1366 ok_ctx();
1367 }
1368 }
1369}
1370
1371bool_Bool lbm_unblock_ctx(lbm_cid cid, lbm_flat_value_t *fv) {
1372 return event_internal(LBM_EVENT_UNBLOCK_CTX, (lbm_uint)cid, (lbm_uint)fv->buf, fv->buf_size);
1373}
1374
1375bool_Bool lbm_unblock_ctx_unboxed(lbm_cid cid, lbm_value unboxed) {
1376 mutex_lock(&blocking_extension_mutex);
1377 bool_Bool r = false0;
1378 lbm_uint t = lbm_type_of(unboxed);
1379 if (t == LBM_TYPE_SYMBOL0x00000000u ||
1380 t == LBM_TYPE_I0x00000008u ||
1381 t == LBM_TYPE_U0x0000000Cu ||
1382 t == LBM_TYPE_CHAR0x00000004u) {
1383
1384 eval_context_t *found = NULL((void*)0);
1385 mutex_lock(&qmutex);
1386 found = lookup_ctx_nm(&blocked, cid);
1387 if (found) {
1388 drop_ctx_nm(&blocked,found);
1389 found->r = unboxed;
1390 if (lbm_is_error(unboxed)) {
1391 lbm_value trash;
1392 lbm_pop(&found->K, &trash); // Destructively make sure there is room on stack.
1393 lbm_push(&found->K, TERMINATE(((28) << 2) | 0xF8000001u));
1394 found->app_cont = true1;
1395 }
1396 enqueue_ctx_nm(&queue,found);
1397 r = true1;
1398 }
1399 mutex_unlock(&qmutex);
1400 }
1401 mutex_unlock(&blocking_extension_mutex);
1402 return r;
1403}
1404
1405void lbm_block_ctx_from_extension_timeout(float s) {
1406 mutex_lock(&blocking_extension_mutex);
1407 blocking_extension = true1;
1408 blocking_extension_timeout_us = S_TO_US(s)(lbm_uint)((s) * 1000000);
1409 blocking_extension_timeout = true1;
1410}
1411void lbm_block_ctx_from_extension(void) {
1412 mutex_lock(&blocking_extension_mutex);
1413 blocking_extension = true1;
1414 blocking_extension_timeout_us = 0;
1415 blocking_extension_timeout = false0;
1416}
1417
1418void lbm_undo_block_ctx_from_extension(void) {
1419 blocking_extension = false0;
1420 blocking_extension_timeout_us = 0;
1421 blocking_extension_timeout = false0;
1422 mutex_unlock(&blocking_extension_mutex);
1423}
1424
1425lbm_value lbm_find_receiver_and_send(lbm_cid cid, lbm_value msg) {
1426 mutex_lock(&qmutex);
1427 eval_context_t *found = NULL((void*)0);
1428 bool_Bool found_blocked = false0;
1429
1430 found = lookup_ctx_nm(&blocked, cid);
1431 if (found) found_blocked = true1;
1432
1433 if (found == NULL((void*)0)) {
1434 found = lookup_ctx_nm(&queue, cid);
1435 }
1436
1437 if (found) {
1438 if (!mailbox_add_mail(found, msg)) {
1439 mutex_unlock(&qmutex);
1440 return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1441 }
1442
1443 if (found_blocked){
1444 drop_ctx_nm(&blocked,found);
1445 enqueue_ctx_nm(&queue,found);
1446 }
1447 mutex_unlock(&qmutex);
1448 return ENC_SYM_TRUE(((0x2) << 4) | 0x00000000u);
1449 }
1450
1451 /* check the current context */
1452 if (ctx_running && ctx_running->id == cid) {
1453 if (!mailbox_add_mail(ctx_running, msg)) {
1454 mutex_unlock(&qmutex);
1455 return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1456 }
1457 mutex_unlock(&qmutex);
1458 return ENC_SYM_TRUE(((0x2) << 4) | 0x00000000u);
1459 }
1460 mutex_unlock(&qmutex);
1461 return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1462}
1463
1464/* Pattern matching is currently implemented as a recursive
1465 function and make use of stack relative to the size of
1466 expressions that are being matched. */
1467static bool_Bool match(lbm_value p, lbm_value e, lbm_value *env, bool_Bool *gc) {
1468
1469 lbm_value binding;
1470
1471 if (lbm_is_match_binder(p)) {
1472 lbm_value var = get_cadr(p);
1473 lbm_value bindertype = get_car(p);
1474
1475 if (!lbm_is_symbol(var)) return false0;
1476
1477 switch (lbm_dec_sym(bindertype)) {
1478 case SYM_MATCH_ANY0x41:
1479 if (lbm_dec_sym(var) == SYM_DONTCARE0x9) {
1480 return true1;
1481 }
1482 break;
1483 default: /* this should be an error case */
1484 return false0;
1485 }
1486 binding = lbm_cons(var, e);
1487 if ( lbm_type_of(binding) == LBM_TYPE_SYMBOL0x00000000u ) {
1488 *gc = true1;
1489 return false0;
1490 }
1491 *env = lbm_cons(binding, *env);
1492 if ( lbm_type_of(*env) == LBM_TYPE_SYMBOL0x00000000u ) {
1493 *gc = true1;
1494 return false0;
1495 }
1496 return true1;
1497 }
1498
1499 /* Comma-qualification experiment. */
1500 if (lbm_is_comma_qualified_symbol(p)) {
1501 lbm_value sym = get_cadr(p);
1502 lbm_value val = lbm_env_lookup(sym, *env);
1503 if (lbm_is_symbol(SYM_NOT_FOUND0x24)) {
1504 return false0;
1505 }
1506 return struct_eq(val, e);
1507 }
1508
1509 if (lbm_is_symbol(p)) {
1510 if (lbm_dec_sym(p) == SYM_DONTCARE0x9) return true1;
1511 return (p == e);
1512 }
1513 if (lbm_is_cons(p) &&
1514 lbm_is_cons(e) ) {
1515
1516 lbm_value headp, tailp;
1517 lbm_value heade, taile;
1518 get_car_and_cdr(p, &headp, &tailp);
1519 get_car_and_cdr(e, &heade, &taile); // Static analysis warns, but execution does not
1520 // past this point unless head and tail get initialized.
1521 if (!match(headp, heade, env, gc)) {
1522 return false0;
1523 }
1524 return match (tailp, taile, env, gc);
1525 }
1526 return struct_eq(p, e);
1527}
1528
1529// Find match is not very picky about syntax.
1530// A completely malformed recv form is most likely to
1531// just return no_match.
1532static int find_match(lbm_value plist, lbm_value *earr, lbm_uint num, lbm_value *e, lbm_value *env) {
1533
1534 // A pattern list is a list of pattern, expression lists.
1535 // ( (p1 e1) (p2 e2) ... (pn en))
1536 lbm_value curr_p = plist;
1537 int n = 0;
1538 bool_Bool gc = false0;
1539 for (int i = 0; i < (int)num; i ++ ) {
1540 lbm_value curr_e = earr[i];
1541 while (!lbm_is_symbol_nil(curr_p)) {
1542 lbm_value me = get_car(curr_p);
1543 if (match(get_car(me), curr_e, env, &gc)) {
1544 if (gc) return FM_NEED_GC-1;
1545 *e = get_cadr(me);
1546
1547 if (!lbm_is_symbol_nil(get_cadr(get_cdr(me)))) {
1548 return FM_PATTERN_ERROR-3;
1549 }
1550 return n;
1551 }
1552 curr_p = get_cdr(curr_p);
1553 }
1554 curr_p = plist; /* search all patterns against next exp */
1555 n ++;
1556 }
1557
1558 return FM_NO_MATCH-2;
1559}
1560
1561/****************************************************/
1562/* Garbage collection */
1563
1564static void mark_context(eval_context_t *ctx, void *arg1, void *arg2) {
1565 (void) arg1;
1566 (void) arg2;
1567 lbm_value roots[3] = {ctx->curr_exp, ctx->program, ctx->r };
1568 lbm_gc_mark_env(ctx->curr_env);
1569 lbm_gc_mark_roots(roots, 3);
1570 lbm_gc_mark_roots(ctx->mailbox, ctx->num_mail);
1571 lbm_gc_mark_aux(ctx->K.data, ctx->K.sp);
1572}
1573
1574static int gc(void) {
1575 if (ctx_running) {
1576 ctx_running->state = ctx_running->state | LBM_THREAD_STATE_GC_BIT(uint32_t)(1 << 31);
1577 }
1578
1579 gc_requested = false0;
1580 lbm_gc_state_inc();
1581
1582 // The freelist should generally be NIL when GC runs.
1583 lbm_nil_freelist();
1584 lbm_value *env = lbm_get_global_env();
1585 for (int i = 0; i < GLOBAL_ENV_ROOTS32; i ++) {
1586 lbm_gc_mark_env(env[i]);
1587 }
1588
1589 mutex_lock(&qmutex); // Lock the queues.
1590 // Any concurrent messing with the queues
1591 // while doing GC cannot possibly be good.
1592 queue_iterator_nm(&queue, mark_context, NULL((void*)0), NULL((void*)0));
1593 queue_iterator_nm(&blocked, mark_context, NULL((void*)0), NULL((void*)0));
1594
1595 if (ctx_running) {
1596 mark_context(ctx_running, NULL((void*)0), NULL((void*)0));
1597 }
1598 mutex_unlock(&qmutex);
1599
1600#ifdef VISUALIZE_HEAP
1601 heap_vis_gen_image();
1602#endif
1603
1604 int r = lbm_gc_sweep_phase();
1605 lbm_heap_new_freelist_length();
1606
1607 if (ctx_running) {
1608 ctx_running->state = ctx_running->state & ~LBM_THREAD_STATE_GC_BIT(uint32_t)(1 << 31);
1609 }
1610 return r;
1611}
1612
1613int lbm_perform_gc(void) {
1614 return gc();
1615}
1616
1617/****************************************************/
1618/* Evaluation functions */
1619
1620
1621static void eval_symbol(eval_context_t *ctx) {
1622 lbm_uint s = lbm_dec_sym(ctx->curr_exp);
1623 if (s >= RUNTIME_SYMBOLS_START0x40000) {
1624 lbm_value res = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1625 if (lbm_env_lookup_b(&res, ctx->curr_exp, ctx->curr_env) ||
1626 lbm_global_env_lookup(&res, ctx->curr_exp)) {
1627 ctx->r = res;
1628 ctx->app_cont = true1;
1629 return;
1630 }
1631 // Dynamic load attempt
1632 // Only symbols of kind RUNTIME can be dynamically loaded.
1633 const char *sym_str = lbm_get_name_by_symbol(s);
1634 const char *code_str = NULL((void*)0);
1635 if (!dynamic_load_callback(sym_str, &code_str)) {
1636 error_at_ctx(ENC_SYM_NOT_FOUND(((0x24) << 4) | 0x00000000u), ctx->curr_exp);
1637 }
1638 stack_push_3(&ctx->K, ctx->curr_exp, ctx->curr_env, RESUME(((12) << 2) | 0xF8000001u));
1639
1640 lbm_value chan;
1641 if (!create_string_channel((char *)code_str, &chan)) {
1642 gc();
1643 if (!create_string_channel((char *)code_str, &chan)) {
1644 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
1645 }
1646 }
1647
1648 lbm_value loader;
1649 WITH_GC_RMBR_1(loader, lbm_heap_allocate_list_init(2,(loader) = (lbm_heap_allocate_list_init(2, (((0x30001) <<
4) | 0x00000000u), chan)); if (lbm_is_symbol_merror((loader)
)) { lbm_gc_mark_phase(chan); gc(); (loader) = (lbm_heap_allocate_list_init
(2, (((0x30001) << 4) | 0x00000000u), chan)); if (lbm_is_symbol_merror
((loader))) { error_ctx((((0x23) << 4) | 0x00000000u));
} }
1650 ENC_SYM_READ,(loader) = (lbm_heap_allocate_list_init(2, (((0x30001) <<
4) | 0x00000000u), chan)); if (lbm_is_symbol_merror((loader)
)) { lbm_gc_mark_phase(chan); gc(); (loader) = (lbm_heap_allocate_list_init
(2, (((0x30001) << 4) | 0x00000000u), chan)); if (lbm_is_symbol_merror
((loader))) { error_ctx((((0x23) << 4) | 0x00000000u));
} }
1651 chan), chan)(loader) = (lbm_heap_allocate_list_init(2, (((0x30001) <<
4) | 0x00000000u), chan)); if (lbm_is_symbol_merror((loader)
)) { lbm_gc_mark_phase(chan); gc(); (loader) = (lbm_heap_allocate_list_init
(2, (((0x30001) << 4) | 0x00000000u), chan)); if (lbm_is_symbol_merror
((loader))) { error_ctx((((0x23) << 4) | 0x00000000u));
} }
;
1652 lbm_value evaluator;
1653 WITH_GC_RMBR_1(evaluator, lbm_heap_allocate_list_init(2,(evaluator) = (lbm_heap_allocate_list_init(2, (((0x30008) <<
4) | 0x00000000u), loader)); if (lbm_is_symbol_merror((evaluator
))) { lbm_gc_mark_phase(loader); gc(); (evaluator) = (lbm_heap_allocate_list_init
(2, (((0x30008) << 4) | 0x00000000u), loader)); if (lbm_is_symbol_merror
((evaluator))) { error_ctx((((0x23) << 4) | 0x00000000u
)); } }
1654 ENC_SYM_EVAL,(evaluator) = (lbm_heap_allocate_list_init(2, (((0x30008) <<
4) | 0x00000000u), loader)); if (lbm_is_symbol_merror((evaluator
))) { lbm_gc_mark_phase(loader); gc(); (evaluator) = (lbm_heap_allocate_list_init
(2, (((0x30008) << 4) | 0x00000000u), loader)); if (lbm_is_symbol_merror
((evaluator))) { error_ctx((((0x23) << 4) | 0x00000000u
)); } }
1655 loader), loader)(evaluator) = (lbm_heap_allocate_list_init(2, (((0x30008) <<
4) | 0x00000000u), loader)); if (lbm_is_symbol_merror((evaluator
))) { lbm_gc_mark_phase(loader); gc(); (evaluator) = (lbm_heap_allocate_list_init
(2, (((0x30008) << 4) | 0x00000000u), loader)); if (lbm_is_symbol_merror
((evaluator))) { error_ctx((((0x23) << 4) | 0x00000000u
)); } }
;
1656 ctx->curr_exp = evaluator;
1657 ctx->curr_env = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u); // dynamics should be evaluable in empty local env
1658 } else {
1659 //special symbols and extensions can be handled the same way.
1660 ctx->r = ctx->curr_exp;
1661 ctx->app_cont = true1;
1662 }
1663}
1664
1665static void eval_quote(eval_context_t *ctx) {
1666 ctx->r = get_cadr(ctx->curr_exp);
1667 ctx->app_cont = true1;
1668}
1669
1670static void eval_selfevaluating(eval_context_t *ctx) {
1671 ctx->r = ctx->curr_exp;
1672 ctx->app_cont = true1;
1673}
1674
1675static void eval_progn(eval_context_t *ctx) {
1676 lbm_value exps = get_cdr(ctx->curr_exp);
1677
1678 if (lbm_is_cons(exps)) {
1679 lbm_uint *sptr = stack_reserve(ctx, 4);
1680 sptr[0] = ctx->curr_env; // env to restore between expressions in progn
1681 sptr[1] = lbm_enc_u(0); // Has env been copied (needed for progn local bindings)
1682 sptr[3] = PROGN_REST(((4) << 2) | 0xF8000001u);
1683 get_car_and_cdr(exps, &ctx->curr_exp, &sptr[2]);
1684 if (lbm_is_symbol(sptr[2])) /* The only symbol it can be is nil */
1685 lbm_stack_drop(&ctx->K, 4);
1686 } else if (lbm_is_symbol_nil(exps)) {
1687 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1688 ctx->app_cont = true1;
1689 } else {
1690 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
1691 }
1692}
1693
1694static void eval_atomic(eval_context_t *ctx) {
1695 if (is_atomic) {
1696 lbm_set_error_reason("Atomic blocks cannot be nested!");
1697 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
1698 }
1699
1700 stack_push(&ctx->K, EXIT_ATOMIC(((14) << 2) | 0xF8000001u));
1701 is_atomic ++;
1702 eval_progn(ctx);
1703}
1704
1705
1706static void eval_callcc(eval_context_t *ctx) {
1707 lbm_value cont_array;
1708 if (!lbm_heap_allocate_array(&cont_array, ctx->K.sp * sizeof(lbm_uint))) {
1
Value assigned to 'cont_array'
2
Assuming the condition is false
3
Taking false branch
1709 gc();
1710 if (!lbm_heap_allocate_array(&cont_array, ctx->K.sp * sizeof(lbm_uint))) {
1711 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
1712 }
1713 }
1714 lbm_array_header_t *arr = (lbm_array_header_t*)get_car(cont_array);
4
Passing value via 1st parameter 'a'
5
Calling 'get_car'
14
Returning from 'get_car'
15
'arr' initialized to a null pointer value
1715 memcpy(arr->data, ctx->K.data, ctx->K.sp * sizeof(lbm_uint));
16
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'arr')
1716
1717 lbm_value acont = cons_with_gc(ENC_SYM_CONT(((0x10E) << 4) | 0x00000000u), cont_array, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
1718
1719 /* Create an application */
1720 lbm_value fun_arg = get_cadr(ctx->curr_exp);
1721 lbm_value app;
1722 WITH_GC_RMBR_1(app, lbm_heap_allocate_list_init(2,(app) = (lbm_heap_allocate_list_init(2, fun_arg, acont)); if (
lbm_is_symbol_merror((app))) { lbm_gc_mark_phase(acont); gc()
; (app) = (lbm_heap_allocate_list_init(2, fun_arg, acont)); if
(lbm_is_symbol_merror((app))) { error_ctx((((0x23) << 4
) | 0x00000000u)); } }
1723 fun_arg,(app) = (lbm_heap_allocate_list_init(2, fun_arg, acont)); if (
lbm_is_symbol_merror((app))) { lbm_gc_mark_phase(acont); gc()
; (app) = (lbm_heap_allocate_list_init(2, fun_arg, acont)); if
(lbm_is_symbol_merror((app))) { error_ctx((((0x23) << 4
) | 0x00000000u)); } }
1724 acont), acont)(app) = (lbm_heap_allocate_list_init(2, fun_arg, acont)); if (
lbm_is_symbol_merror((app))) { lbm_gc_mark_phase(acont); gc()
; (app) = (lbm_heap_allocate_list_init(2, fun_arg, acont)); if
(lbm_is_symbol_merror((app))) { error_ctx((((0x23) << 4
) | 0x00000000u)); } }
;
1725
1726 ctx->curr_exp = app;
1727}
1728
1729// (define sym exp)
1730static void eval_define(eval_context_t *ctx) {
1731 lbm_value args = get_cdr(ctx->curr_exp);
1732 lbm_value key, rest_args;
1733 get_car_and_cdr(args, &key, &rest_args);
1734 lbm_value val_exp, rest_val;
1735 get_car_and_cdr(rest_args, &val_exp, &rest_val);
1736 lbm_uint *sptr = stack_reserve(ctx, 2);
1737
1738 if (lbm_is_symbol(key) && lbm_is_symbol_nil(rest_val)) {
1739 lbm_uint sym_val = lbm_dec_sym(key);
1740
1741 sptr[0] = key;
1742
1743 if (sym_val >= RUNTIME_SYMBOLS_START0x40000) {
1744 sptr[1] = SET_GLOBAL_ENV(((1) << 2) | 0xF8000001u);
1745 if (ctx->flags & EVAL_CPS_CONTEXT_FLAG_CONST(uint32_t)0x2) {
1746 stack_push(&ctx->K, MOVE_VAL_TO_FLASH_DISPATCH(((32) << 2) | 0xF8000001u));
1747 }
1748 ctx->curr_exp = val_exp;
1749 return;
1750 }
1751 }
1752 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u), ctx->curr_exp);
1753}
1754
1755// (lambda param-list body-exp) -> (closure param-list body-exp env)
1756static void eval_lambda(eval_context_t *ctx) {
1757 lbm_value cdr = get_cdr(ctx->curr_exp);
1758 ctx->r = allocate_closure(get_car(cdr), get_cadr(cdr), ctx->curr_env);
1759 ctx->app_cont = true1;
1760}
1761
1762// (if cond-expr then-expr else-expr)
1763static void eval_if(eval_context_t *ctx) {
1764
1765 lbm_value cdr = get_cdr(ctx->curr_exp);
1766 lbm_value exp, cddr;
1767 get_car_and_cdr(cdr, &exp, &cddr);
1768
1769 lbm_uint *sptr = stack_reserve(ctx, 4);
1770 sptr[0] = get_cadr(cddr); // else_branch
1771 sptr[1] = get_car(cddr); // then_branch
1772 sptr[2] = ctx->curr_env;
1773 sptr[3] = IF(((3) << 2) | 0xF8000001u);
1774 ctx->curr_exp = exp;
1775}
1776
1777// (cond (cond-expr-1 expr-1)
1778// ...
1779// (cond-expr-N expr-N))
1780static void eval_cond(eval_context_t *ctx) {
1781 lbm_value cond1 = get_cadr(ctx->curr_exp);
1782
1783 if (lbm_is_symbol_nil(cond1)) {
1784 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1785 ctx->app_cont = true1;
1786 } else {
1787 lbm_uint len = lbm_list_length(cond1);
1788 if (len != 2) {
1789 lbm_set_error_reason("Incorrect syntax in cond");
1790 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
1791 }
1792 lbm_value condition = get_car(cond1);
1793 lbm_value body = get_cadr(cond1);
1794 lbm_value rest;
1795 rest = cons_with_gc(ENC_SYM_COND(((0x110) << 4) | 0x00000000u), get_cddr(ctx->curr_exp), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
1796 lbm_uint *sptr = stack_reserve(ctx, 4);
1797 sptr[0] = rest;
1798 sptr[1] = body;
1799 sptr[2] = ctx->curr_env;
1800 sptr[3] = IF(((3) << 2) | 0xF8000001u);
1801 ctx->curr_exp = condition;
1802 }
1803}
1804
1805static void eval_app_cont(eval_context_t *ctx) {
1806 lbm_stack_drop(&ctx->K, 1);
1807 ctx->app_cont = true1;
1808}
1809
1810// (var x (...)) - local binding inside of an progn
1811static void eval_var(eval_context_t *ctx) {
1812 lbm_value args = get_cdr(ctx->curr_exp);
1813 lbm_value sym = get_car(args);
1814 lbm_value v_exp = get_cadr(args);
1815 stack_push_2(&ctx->K, sym, PROGN_VAR(((29) << 2) | 0xF8000001u));
1816 ctx->curr_exp = v_exp;
1817}
1818
1819// (setq x (...)) - same as (set 'x (...)) or (setvar 'x (...))
1820static void eval_setq(eval_context_t *ctx) {
1821 lbm_value args = get_cdr(ctx->curr_exp);
1822 lbm_value sym = get_car(args);
1823 lbm_value v_exp = get_cadr(args);
1824 stack_push_3(&ctx->K, ctx->curr_env, sym, SETQ(((30) << 2) | 0xF8000001u));
1825 ctx->curr_exp = v_exp;
1826}
1827
1828static void eval_move_to_flash(eval_context_t *ctx) {
1829 lbm_value args = get_cdr(ctx->curr_exp);
1830 stack_push_2(&ctx->K, args, MOVE_TO_FLASH(((31) << 2) | 0xF8000001u));
1831 ctx->app_cont = true1;
1832}
1833
1834// Create a named location in an environment to later receive a value.
1835static binding_location_status create_binding_location(lbm_value key, lbm_value *env) {
1836
1837 if (lbm_is_symbol(key) &&
1838 (key == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u) ||
1839 key == ENC_SYM_DONTCARE(((0x9) << 4) | 0x00000000u)))
1840 return BL_OK;
1841
1842 if (lbm_type_of(key) == LBM_TYPE_SYMBOL0x00000000u) { // default case
1843 lbm_value binding;
1844 lbm_value new_env_tmp;
1845 binding = lbm_cons(key, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
1846 new_env_tmp = lbm_cons(binding, *env);
1847 if (lbm_is_symbol(binding) || lbm_is_symbol(new_env_tmp)) {
1848 return BL_NO_MEMORY;
1849 }
1850 *env = new_env_tmp;
1851 } else if (lbm_is_cons(key)) { // deconstruct case
1852 int r = create_binding_location(get_car(key), env);
1853 if (r == BL_OK) {
1854 r = create_binding_location(get_cdr(key), env);
1855 }
1856 return r;
1857 }
1858 return BL_OK;
1859}
1860
1861static void let_bind_values_eval(lbm_value binds, lbm_value exp, lbm_value env, eval_context_t *ctx) {
1862
1863 if (!lbm_is_cons(binds)) {
1864 // binds better be nil or there is a programmer error.
1865 ctx->curr_exp = exp;
1866 return;
1867 }
1868
1869 // Preallocate binding locations.
1870 lbm_value curr = binds;
1871 while (lbm_is_cons(curr)) {
1872 lbm_value new_env_tmp = env;
1873 lbm_value key = get_caar(curr);
1874 binding_location_status r = create_binding_location(key, &new_env_tmp);
1875 if (r != BL_OK) {
1876 if (r == BL_NO_MEMORY) {
1877 new_env_tmp = env;
1878 lbm_gc_mark_phase(env);
1879 gc();
1880 r = create_binding_location(key, &new_env_tmp);
1881 }
1882 switch(r) {
1883 case BL_OK:
1884 break;
1885 case BL_NO_MEMORY:
1886 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
1887 break;
1888 case BL_INCORRECT_KEY:
1889 error_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
1890 break;
1891 }
1892 }
1893 env = new_env_tmp;
1894 curr = get_cdr(curr);
1895 }
1896
1897 lbm_value key0 = get_caar(binds);
1898 lbm_value val0_exp = get_cadr(get_car(binds));
1899
1900 lbm_uint *sptr = stack_reserve(ctx, 5);
1901 sptr[0] = exp;
1902 sptr[1] = get_cdr(binds);
1903 sptr[2] = env;
1904 sptr[3] = key0;
1905 sptr[4] = BIND_TO_KEY_REST(((2) << 2) | 0xF8000001u);
1906 ctx->curr_exp = val0_exp;
1907 ctx->curr_env = env;
1908}
1909
1910// (loop list-of-local-bindings
1911// condition-exp
1912// body-exp)
1913static void eval_loop(eval_context_t *ctx) {
1914 lbm_value env = ctx->curr_env;
1915 lbm_value parts[3];
1916 extract_n(get_cdr(ctx->curr_exp), parts, 3);
1917 stack_push_3(&ctx->K, parts[LOOP_BODY2], parts[LOOP_COND1], LOOP_CONDITION(((42) << 2) | 0xF8000001u));
1918 let_bind_values_eval(parts[LOOP_BINDS0], parts[LOOP_COND1], env, ctx);
1919}
1920
1921// (let list-of-bindings
1922// body-exp)
1923static void eval_let(eval_context_t *ctx) {
1924 lbm_value env = ctx->curr_env;
1925 lbm_value binds = get_cadr(ctx->curr_exp); // key value pairs.
1926 lbm_value exp = get_cadr(get_cdr(ctx->curr_exp)); // exp to evaluate in the new env.
1927 let_bind_values_eval(binds, exp, env, ctx);
1928}
1929
1930// (and exp0 ... expN)
1931static void eval_and(eval_context_t *ctx) {
1932 lbm_value rest = get_cdr(ctx->curr_exp);
1933 if (lbm_is_symbol_nil(rest)) {
1934 ctx->app_cont = true1;
1935 ctx->r = ENC_SYM_TRUE(((0x2) << 4) | 0x00000000u);
1936 } else {
1937 stack_push_3(&ctx->K, ctx->curr_env, get_cdr(rest), AND(((6) << 2) | 0xF8000001u));
1938 ctx->curr_exp = get_car(rest);
1939 }
1940}
1941
1942// (or exp0 ... expN)
1943static void eval_or(eval_context_t *ctx) {
1944 lbm_value rest = get_cdr(ctx->curr_exp);
1945 if (lbm_is_symbol_nil(rest)) {
1946 ctx->app_cont = true1;
1947 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1948 } else {
1949 stack_push_3(&ctx->K, ctx->curr_env, get_cdr(rest), OR(((7) << 2) | 0xF8000001u));
1950 ctx->curr_exp = get_car(rest);
1951 }
1952}
1953
1954// Pattern matching
1955// format:
1956// (match e (pattern body)
1957// (pattern body)
1958// ... )
1959//
1960// There can be an optional pattern guard:
1961// (match e (pattern guard body)
1962// ... )
1963// a guard is a boolean expression.
1964// Guards make match, pattern matching more complicated
1965// than the recv pattern matching and requires staged execution
1966// via the continuation system rather than a while loop over a list.
1967static void eval_match(eval_context_t *ctx) {
1968
1969 lbm_value rest = get_cdr(ctx->curr_exp);
1970 if (lbm_type_of(rest) == LBM_TYPE_SYMBOL0x00000000u &&
1971 rest == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)) {
1972 // Someone wrote the program (match)
1973 ctx->app_cont = true1;
1974 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1975 } else {
1976 lbm_value cdr_rest;
1977 get_car_and_cdr(rest, &ctx->curr_exp, &cdr_rest);
1978 stack_push_3(&ctx->K, cdr_rest, ctx->curr_env, MATCH(((9) << 2) | 0xF8000001u));
1979 }
1980}
1981
1982static void receive_base(eval_context_t *ctx, lbm_value pats, float timeout_time, bool_Bool timeout) {
1983 if (ctx->num_mail == 0) {
1984 if (timeout) {
1985 block_current_ctx(LBM_THREAD_STATE_TIMEOUT(uint32_t)2, S_TO_US(timeout_time)(lbm_uint)((timeout_time) * 1000000), false0);
1986 } else {
1987 block_current_ctx(LBM_THREAD_STATE_BLOCKED(uint32_t)1,0,false0);
1988 }
1989 } else {
1990 lbm_value *msgs = ctx->mailbox;
1991 lbm_uint num = ctx->num_mail;
1992
1993 if (lbm_is_symbol_nil(pats)) {
1994 /* A receive statement without any patterns */
1995 ctx->app_cont = true1;
1996 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
1997 } else {
1998 /* The common case */
1999 lbm_value e;
2000 lbm_value new_env = ctx->curr_env;
2001 int n = find_match(pats, msgs, num, &e, &new_env);
2002 if (n == FM_NEED_GC-1) {
2003 gc();
2004 new_env = ctx->curr_env;
2005 n = find_match(pats, msgs, num, &e, &new_env);
2006 if (n == FM_NEED_GC-1) {
2007 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
2008 }
2009 }
2010 if (n == FM_PATTERN_ERROR-3) {
2011 lbm_set_error_reason("Incorrect pattern format for recv");
2012 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u),pats);
2013 } else if (n >= 0 ) { /* Match */
2014 mailbox_remove_mail(ctx, (lbm_uint)n);
2015 ctx->curr_env = new_env;
2016 ctx->curr_exp = e;
2017 } else { /* No match go back to sleep */
2018 ctx->r = ENC_SYM_NO_MATCH(((0x40) << 4) | 0x00000000u);
2019 if (timeout) {
2020 block_current_ctx(LBM_THREAD_STATE_TIMEOUT(uint32_t)2,S_TO_US(timeout_time)(lbm_uint)((timeout_time) * 1000000),false0);
2021 } else {
2022 block_current_ctx(LBM_THREAD_STATE_BLOCKED(uint32_t)1, 0,false0);
2023 }
2024 }
2025 }
2026 }
2027 return;
2028}
2029
2030static void eval_receive_timeout(eval_context_t *ctx) {
2031 if (is_atomic) {
2032 lbm_set_error_reason((char*)lbm_error_str_forbidden_in_atomic);
2033 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
2034 }
2035 lbm_value timeout_val = get_car(get_cdr(ctx->curr_exp));
2036 if (!lbm_is_number(timeout_val)) {
2037 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
2038 }
2039 float timeout_time = lbm_dec_as_float(timeout_val);
2040 lbm_value pats = get_cdr(get_cdr(ctx->curr_exp));
2041 receive_base(ctx, pats, timeout_time, true1);
2042}
2043
2044// Receive
2045// (recv (pattern expr)
2046// (pattern expr))
2047static void eval_receive(eval_context_t *ctx) {
2048
2049 if (is_atomic) {
2050 lbm_set_error_reason((char*)lbm_error_str_forbidden_in_atomic);
2051 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u), ctx->curr_exp);
2052 }
2053 lbm_value pats = get_cdr(ctx->curr_exp);
2054 receive_base(ctx, pats, 0, false0);
2055}
2056
2057/*********************************************************/
2058/* Continuation functions */
2059
2060/* cont_set_global_env
2061 sp-1 : Key-symbol
2062 */
2063static void cont_set_global_env(eval_context_t *ctx){
2064
2065 lbm_value key;
2066 lbm_value val = ctx->r;
2067
2068 lbm_pop(&ctx->K, &key);
2069 lbm_uint dec_key = lbm_dec_sym(key);
2070 lbm_uint ix_key = dec_key & GLOBAL_ENV_MASK0x1F;
2071 lbm_value *global_env = lbm_get_global_env();
2072 lbm_uint orig_env = global_env[ix_key];
2073 lbm_value new_env;
2074 // A key is a symbol and should not need to be remembered.
2075 WITH_GC(new_env, lbm_env_set(orig_env,key,val))(new_env) = (lbm_env_set(orig_env,key,val)); if (lbm_is_symbol_merror
((new_env))) { gc(); (new_env) = (lbm_env_set(orig_env,key,val
)); if (lbm_is_symbol_merror((new_env))) { error_ctx((((0x23)
<< 4) | 0x00000000u)); } }
;
2076
2077 global_env[ix_key] = new_env;
2078 ctx->r = val;
2079
2080 ctx->app_cont = true1;
2081
2082 return;
2083}
2084
2085static void cont_resume(eval_context_t *ctx) {
2086 lbm_value exp;
2087 lbm_value env;
2088 lbm_pop_2(&ctx->K, &env, &exp);
2089 ctx->curr_exp = exp;
2090 ctx->curr_env = env;
2091}
2092
2093static void cont_progn_rest(eval_context_t *ctx) {
2094 lbm_value *sptr = get_stack_ptr(ctx, 3);
2095
2096 lbm_value rest = sptr[2];
2097 lbm_value env = sptr[0];
2098
2099 lbm_value rest_car, rest_cdr;
2100 get_car_and_cdr(rest, &rest_car, &rest_cdr);
2101 if (lbm_is_symbol_nil(rest_cdr)) {
2102 // allow for tail recursion
2103 ctx->curr_exp = rest_car;
2104 ctx->curr_env = env;
2105 lbm_stack_drop(&ctx->K, 3);
2106 } else {
2107 sptr[2] = rest_cdr;
2108 stack_push(&ctx->K, PROGN_REST(((4) << 2) | 0xF8000001u));
2109 ctx->curr_exp = rest_car;
2110 ctx->curr_env = env;
2111 }
2112}
2113
2114static void cont_wait(eval_context_t *ctx) {
2115
2116 lbm_value cid_val;
2117 lbm_pop(&ctx->K, &cid_val);
2118 lbm_cid cid = (lbm_cid)lbm_dec_i(cid_val);
2119
2120 bool_Bool exists = false0;
2121
2122 lbm_blocked_iterator(context_exists, &cid, &exists);
2123 lbm_running_iterator(context_exists, &cid, &exists);
2124
2125 if (ctx_running->id == cid) {
2126 exists = true1;
2127 }
2128
2129 if (exists) {
2130 stack_push_2(&ctx->K, lbm_enc_i(cid), WAIT(((8) << 2) | 0xF8000001u));
2131 ctx->r = ENC_SYM_TRUE(((0x2) << 4) | 0x00000000u);
2132 ctx->app_cont = true1;
2133 yield_ctx(50000);
2134 } else {
2135 ctx->r = ENC_SYM_TRUE(((0x2) << 4) | 0x00000000u);
2136 ctx->app_cont = true1;
2137 }
2138}
2139
2140static lbm_value perform_setvar(lbm_value key, lbm_value val, lbm_value env) {
2141
2142 lbm_uint s = lbm_dec_sym(key);
2143 if (s >= RUNTIME_SYMBOLS_START0x40000) {
2144 lbm_value new_env = lbm_env_modify_binding(env, key, val);
2145 if (lbm_is_symbol(new_env) && new_env == ENC_SYM_NOT_FOUND(((0x24) << 4) | 0x00000000u)) {
2146 lbm_uint ix_key = lbm_dec_sym(key) & GLOBAL_ENV_MASK0x1F;
2147 lbm_value *glob_env = lbm_get_global_env();
2148 new_env = lbm_env_modify_binding(glob_env[ix_key], key, val);
2149 glob_env[ix_key] = new_env;
2150 }
2151 if (lbm_is_symbol(new_env) && new_env == ENC_SYM_NOT_FOUND(((0x24) << 4) | 0x00000000u)) {
2152 lbm_set_error_reason((char*)lbm_error_str_variable_not_bound);
2153 error_at_ctx(ENC_SYM_NOT_FOUND(((0x24) << 4) | 0x00000000u), key);
2154 }
2155 return val;
2156 }
2157 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u), ENC_SYM_SETVAR(((0x30000) << 4) | 0x00000000u));
2158 return ENC_SYM_NIL(((0x0) << 4) | 0x00000000u); // unreachable
2159}
2160
2161static void apply_setvar(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2162 if (nargs == 2 && lbm_is_symbol(args[0])) {
2163 lbm_value res;
2164 WITH_GC(res, perform_setvar(args[0], args[1], ctx->curr_env))(res) = (perform_setvar(args[0], args[1], ctx->curr_env));
if (lbm_is_symbol_merror((res))) { gc(); (res) = (perform_setvar
(args[0], args[1], ctx->curr_env)); if (lbm_is_symbol_merror
((res))) { error_ctx((((0x23) << 4) | 0x00000000u)); } }
;
2165 ctx->r = args[1];
2166 lbm_stack_drop(&ctx->K, nargs+1);
2167 ctx->app_cont = true1;
2168 } else {
2169 if (nargs == 2) lbm_set_error_reason((char*)lbm_error_str_incorrect_arg);
2170 else lbm_set_error_reason((char*)lbm_error_str_num_args);
2171 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u), ENC_SYM_SETVAR(((0x30000) << 4) | 0x00000000u));
2172 }
2173}
2174
2175static void apply_read_base(lbm_value *args, lbm_uint nargs, eval_context_t *ctx, bool_Bool program, bool_Bool incremental) {
2176 if (nargs == 1) {
2177 lbm_value chan = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2178 if (lbm_type_of_functional(args[0]) == LBM_TYPE_ARRAY0x80000000u) {
2179 if (!create_string_channel(lbm_dec_str(args[0]), &chan)) {
2180 gc();
2181 if (!create_string_channel(lbm_dec_str(args[0]), &chan)) {
2182 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
2183 }
2184 }
2185 } else if (lbm_type_of(args[0]) == LBM_TYPE_CHANNEL0x90000000u) {
2186 chan = args[0];
2187 } else {
2188 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
2189 }
2190 lbm_value *sptr = get_stack_ptr(ctx, 2);
2191
2192 //sptr[0] = Restore context flag to incremental read?
2193 // TRUE -> set incremental
2194 // NIL -> set non-incremental
2195 if (ctx->flags & EVAL_CPS_CONTEXT_FLAG_INCREMENTAL_READ(uint32_t)0x8) {
2196 sptr[0] = ENC_SYM_TRUE(((0x2) << 4) | 0x00000000u);
2197 } else {
2198 sptr[0] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2199 }
2200 sptr[1] = chan;
2201 stack_push(&ctx->K, READ_DONE(((20) << 2) | 0xF8000001u));
2202
2203 if (program) {
2204 if (incremental) {
2205 stack_push_3(&ctx->K, chan, ctx->curr_env, READ_EVAL_CONTINUE(((17) << 2) | 0xF8000001u));
2206 } else {
2207 stack_push_4(&ctx->K, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), chan, READ_APPEND_CONTINUE(((16) << 2) | 0xF8000001u));
2208 }
2209 }
2210 stack_push_3(&ctx->K, chan, lbm_enc_u(1), READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
2211 ctx->app_cont = true1;
2212 } else {
2213 lbm_set_error_reason((char*)lbm_error_str_num_args);
2214 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
2215 }
2216}
2217
2218static void apply_read_program(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2219 apply_read_base(args,nargs,ctx,true1,false0);
2220}
2221
2222static void apply_read_eval_program(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2223 ctx->flags |= EVAL_CPS_CONTEXT_FLAG_INCREMENTAL_READ(uint32_t)0x8;
2224 apply_read_base(args,nargs,ctx,true1,true1);
2225}
2226
2227static void apply_read(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2228 apply_read_base(args,nargs,ctx,false0,false0);
2229}
2230
2231static void apply_spawn_base(lbm_value *args, lbm_uint nargs, eval_context_t *ctx, uint32_t context_flags) {
2232
2233 lbm_uint stack_size = EVAL_CPS_DEFAULT_STACK_SIZE256;
2234 lbm_uint closure_pos = 0;
2235 char *name = NULL((void*)0);
2236
2237 if (nargs >= 1 &&
2238 lbm_is_closure(args[0])) {
2239 closure_pos = 0;
2240 } else if (nargs >= 2 &&
2241 lbm_is_number(args[0]) &&
2242 lbm_is_closure(args[1])) {
2243 stack_size = lbm_dec_as_u32(args[0]);
2244 closure_pos = 1;
2245 } else if (nargs >= 2 &&
2246 lbm_is_array_r(args[0]) &&
2247 lbm_is_closure(args[1])) {
2248 name = lbm_dec_str(args[0]);
2249 closure_pos = 1;
2250 }else if (nargs >= 3 &&
2251 lbm_is_array_r(args[0]) &&
2252 lbm_is_number(args[1]) &&
2253 lbm_is_closure(args[2])) {
2254 stack_size = lbm_dec_as_u32(args[1]);
2255 closure_pos = 2;
2256 name = lbm_dec_str(args[0]);
2257 } else {
2258 if (context_flags & EVAL_CPS_CONTEXT_FLAG_TRAP(uint32_t)0x1)
2259 error_at_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u),ENC_SYM_SPAWN_TRAP(((0x30005) << 4) | 0x00000000u));
2260 else
2261 error_at_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u),ENC_SYM_SPAWN(((0x30004) << 4) | 0x00000000u));
2262 }
2263
2264 lbm_value cl[3];
2265 extract_n(get_cdr(args[closure_pos]), cl, 3);
2266 lbm_value curr_param = cl[CLO_PARAMS0];
2267 lbm_value clo_env = cl[CLO_ENV2];
2268 lbm_uint i = closure_pos + 1;
2269 while (lbm_is_cons(curr_param) && i <= nargs) {
2270 lbm_value entry = cons_with_gc(get_car(curr_param), args[i], clo_env);
2271 lbm_value aug_env = cons_with_gc(entry, clo_env,ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
2272 clo_env = aug_env;
2273 curr_param = get_cdr(curr_param);
2274 i ++;
2275 }
2276
2277 lbm_stack_drop(&ctx->K, nargs+1);
2278
2279 lbm_value program = cons_with_gc(cl[CLO_BODY1], ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), clo_env);
2280
2281 lbm_cid cid = lbm_create_ctx_parent(program,
2282 clo_env,
2283 stack_size,
2284 lbm_get_current_cid(),
2285 context_flags,
2286 name);
2287 ctx->r = lbm_enc_i(cid);
2288 ctx->app_cont = true1;
2289}
2290
2291static void apply_spawn(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2292 apply_spawn_base(args,nargs,ctx, EVAL_CPS_CONTEXT_FLAG_NOTHING(uint32_t)0x0);
2293}
2294
2295static void apply_spawn_trap(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2296 apply_spawn_base(args,nargs,ctx, EVAL_CPS_CONTEXT_FLAG_TRAP(uint32_t)0x1);
2297}
2298
2299static void apply_yield(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2300 if (is_atomic) {
2301 lbm_set_error_reason((char*)lbm_error_str_forbidden_in_atomic);
2302 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u), ENC_SYM_YIELD(((0x30006) << 4) | 0x00000000u));
2303 }
2304 if (nargs == 1 && lbm_is_number(args[0])) {
2305 lbm_uint ts = lbm_dec_as_u32(args[0]);
2306 lbm_stack_drop(&ctx->K, nargs+1);
2307 yield_ctx(ts);
2308 } else {
2309 lbm_set_error_reason((char*)lbm_error_str_no_number);
2310 error_at_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u), ENC_SYM_YIELD(((0x30006) << 4) | 0x00000000u));
2311 }
2312}
2313
2314static void apply_sleep(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2315 if (is_atomic) {
2316 lbm_set_error_reason((char*)lbm_error_str_forbidden_in_atomic);
2317 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u), ENC_SYM_SLEEP(((0x30012) << 4) | 0x00000000u));
2318 }
2319 if (nargs == 1 && lbm_is_number(args[0])) {
2320 lbm_uint ts = (lbm_uint)(1000000.0f * lbm_dec_as_float(args[0]));
2321 lbm_stack_drop(&ctx->K, nargs+1);
2322 yield_ctx(ts);
2323 } else {
2324 lbm_set_error_reason((char*)lbm_error_str_no_number);
2325 error_at_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u), ENC_SYM_SLEEP(((0x30012) << 4) | 0x00000000u));
2326 }
2327}
2328
2329static void apply_wait(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2330 if (nargs == 1 && lbm_type_of(args[0]) == LBM_TYPE_I0x00000008u) {
2331 lbm_cid cid = (lbm_cid)lbm_dec_i(args[0]);
2332 lbm_stack_drop(&ctx->K, nargs+1);
2333 stack_push_2(&ctx->K, lbm_enc_i(cid), WAIT(((8) << 2) | 0xF8000001u));
2334 ctx->r = ENC_SYM_TRUE(((0x2) << 4) | 0x00000000u);
2335 ctx->app_cont = true1;
2336 yield_ctx(50000);
2337 } else {
2338 error_at_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u), ENC_SYM_WAIT(((0x30007) << 4) | 0x00000000u));
2339 }
2340}
2341
2342static void apply_eval(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2343 if ( nargs == 1) {
2344 ctx->curr_exp = args[0];
2345 } else if (nargs == 2) {
2346 ctx->curr_exp = args[1];
2347 ctx->curr_env = args[0];
2348 } else {
2349 lbm_set_error_reason((char*)lbm_error_str_num_args);
2350 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u), ENC_SYM_EVAL(((0x30008) << 4) | 0x00000000u));
2351 }
2352 lbm_stack_drop(&ctx->K, nargs+1);
2353}
2354
2355static void apply_eval_program(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2356 int prg_pos = 0;
2357 if (nargs == 2) {
2358 prg_pos = 1;
2359 ctx->curr_env = args[0];
2360 }
2361 if (nargs == 1 || nargs == 2) {
2362 lbm_value prg = args[prg_pos];
2363 lbm_value app_cont;
2364 lbm_value app_cont_prg;
2365 lbm_value new_prg;
2366 lbm_value prg_copy;
2367
2368 int len = -1;
2369 WITH_GC(prg_copy, lbm_list_copy(&len, prg))(prg_copy) = (lbm_list_copy(&len, prg)); if (lbm_is_symbol_merror
((prg_copy))) { gc(); (prg_copy) = (lbm_list_copy(&len, prg
)); if (lbm_is_symbol_merror((prg_copy))) { error_ctx((((0x23
) << 4) | 0x00000000u)); } }
;
2370 lbm_stack_drop(&ctx->K, nargs+1);
2371
2372 if (ctx->K.sp > nargs+2) { // if there is a continuation
2373 app_cont = cons_with_gc(ENC_SYM_APP_CONT(((0x111) << 4) | 0x00000000u), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), prg_copy);
2374 app_cont_prg = cons_with_gc(app_cont, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), prg_copy);
2375 new_prg = lbm_list_append(app_cont_prg, ctx->program);
2376 new_prg = lbm_list_append(prg_copy, new_prg);
2377 } else {
2378 new_prg = lbm_list_append(prg_copy, ctx->program);
2379 }
2380 if (!lbm_is_list(new_prg)) {
2381 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u), ENC_SYM_EVAL_PROGRAM(((0x30009) << 4) | 0x00000000u));
2382 }
2383 stack_push(&ctx->K, DONE(((0) << 2) | 0xF8000001u));
2384 ctx->program = get_cdr(new_prg);
2385 ctx->curr_exp = get_car(new_prg);
2386 } else {
2387 lbm_set_error_reason((char*)lbm_error_str_num_args);
2388 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u), ENC_SYM_EVAL_PROGRAM(((0x30009) << 4) | 0x00000000u));
2389 }
2390}
2391
2392static void apply_send(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2393 if (nargs == 2) {
2394 if (lbm_type_of(args[0]) == LBM_TYPE_I0x00000008u) {
2395 lbm_cid cid = (lbm_cid)lbm_dec_i(args[0]);
2396 lbm_value msg = args[1];
2397 lbm_value status = lbm_find_receiver_and_send(cid, msg);
2398 /* return the status */
2399 lbm_stack_drop(&ctx->K, nargs+1);
2400 ctx->r = status;
2401 ctx->app_cont = true1;
2402 } else {
2403 error_at_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u), ENC_SYM_SEND(((0x3000A) << 4) | 0x00000000u));
2404 }
2405 } else {
2406 lbm_set_error_reason((char*)lbm_error_str_num_args);
2407 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u), ENC_SYM_SEND(((0x3000A) << 4) | 0x00000000u));
2408 }
2409}
2410
2411static void apply_ok(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2412 lbm_value ok_val = ENC_SYM_TRUE(((0x2) << 4) | 0x00000000u);
2413 if (nargs >= 1) {
2414 ok_val = args[0];
2415 }
2416 ctx->r = ok_val;
2417 ok_ctx();
2418}
2419
2420static void apply_error(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2421 (void) ctx;
2422 lbm_value err_val = ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u);
2423 if (nargs >= 1) {
2424 err_val = args[0];
2425 }
2426 error_at_ctx(err_val, ENC_SYM_EXIT_ERROR(((0x3000C) << 4) | 0x00000000u));
2427}
2428
2429// (map f arg-list)
2430static void apply_map(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2431 if (nargs == 2 && lbm_is_cons(args[1])) {
2432 lbm_value *sptr = get_stack_ptr(ctx, 3);
2433
2434 lbm_value f = args[0];
2435 lbm_value h = get_car(args[1]);
2436 lbm_value t = get_cdr(args[1]);
2437
2438 lbm_value appli_1;
2439 lbm_value appli;
2440 WITH_GC(appli_1, lbm_heap_allocate_list(2))(appli_1) = (lbm_heap_allocate_list(2)); if (lbm_is_symbol_merror
((appli_1))) { gc(); (appli_1) = (lbm_heap_allocate_list(2));
if (lbm_is_symbol_merror((appli_1))) { error_ctx((((0x23) <<
4) | 0x00000000u)); } }
;
2441 WITH_GC_RMBR_1(appli, lbm_heap_allocate_list(2), appli_1)(appli) = (lbm_heap_allocate_list(2)); if (lbm_is_symbol_merror
((appli))) { lbm_gc_mark_phase(appli_1); gc(); (appli) = (lbm_heap_allocate_list
(2)); if (lbm_is_symbol_merror((appli))) { error_ctx((((0x23)
<< 4) | 0x00000000u)); } }
;
2442
2443 lbm_value appli_0 = get_cdr(appli_1);
2444
2445 lbm_set_car_and_cdr(appli_0, h, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
2446 lbm_set_car(appli_1, ENC_SYM_QUOTE(((0x100) << 4) | 0x00000000u));
2447
2448 lbm_set_car_and_cdr(get_cdr(appli), appli_1, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
2449 lbm_set_car(appli, f);
2450
2451 lbm_value elt = cons_with_gc(ctx->r, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), appli);
2452 stack_push_4(&ctx->K, elt, appli, appli_0, MAP(((26) << 2) | 0xF8000001u));
2453 sptr[0] = t; // reuse stack space
2454 sptr[1] = ctx->curr_env;
2455 sptr[2] = elt;
2456 ctx->curr_exp = appli;
2457 } else if (nargs == 2 && lbm_is_symbol_nil(args[1])) {
2458 lbm_stack_drop(&ctx->K, 3);
2459 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2460 ctx->app_cont = true1;
2461 return;
2462 } else {
2463 lbm_set_error_reason((char*)lbm_error_str_num_args);
2464 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u), ENC_SYM_MAP(((0x3000D) << 4) | 0x00000000u));
2465 }
2466}
2467
2468static void apply_reverse(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2469 if (nargs == 1 && lbm_is_list(args[0])) {
2470 lbm_value curr = args[0];
2471
2472 lbm_value new_list = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2473 while (lbm_is_cons(curr)) {
2474 lbm_value tmp = cons_with_gc(get_car(curr), new_list, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
2475 new_list = tmp;
2476 curr = get_cdr(curr);
2477 }
2478 lbm_stack_drop(&ctx->K, 2);
2479 ctx->r = new_list;
2480 ctx->app_cont = true1;
2481 } else {
2482 lbm_set_error_reason("Reverse requires a list argument");
2483 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u), ENC_SYM_REVERSE(((0x3000E) << 4) | 0x00000000u));
2484 }
2485}
2486
2487static void apply_flatten(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2488 if (nargs == 1) {
2489
2490 lbm_value v = flatten_value(args[0]);
2491 if ( v == ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u)) {
2492 gc();
2493 v = flatten_value(args[0]);
2494 }
2495
2496 if (lbm_is_symbol(v)) {
2497 error_at_ctx(v, ENC_SYM_FLATTEN(((0x3000F) << 4) | 0x00000000u));
2498 } else {
2499 lbm_stack_drop(&ctx->K, 2);
2500 ctx->r = v;
2501 ctx->app_cont = true1;
2502 }
2503 return;
2504 }
2505 error_at_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u), ENC_SYM_FLATTEN(((0x3000F) << 4) | 0x00000000u));
2506}
2507
2508static void apply_unflatten(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2509 if(nargs == 1 && lbm_type_of(args[0]) == LBM_TYPE_ARRAY0x80000000u) {
2510 lbm_array_header_t *array;
2511 array = (lbm_array_header_t *)get_car(args[0]);
2512
2513 lbm_flat_value_t fv;
2514 fv.buf = (uint8_t*)array->data;
2515 fv.buf_size = array->size;
2516 fv.buf_pos = 0;
2517
2518 lbm_value res;
2519
2520 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2521 if (lbm_unflatten_value(&fv, &res)) {
2522 ctx->r = res;
2523 }
2524 lbm_stack_drop(&ctx->K, 2);
2525 ctx->app_cont = true1;
2526 return;
2527 }
2528 error_at_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u), ENC_SYM_UNFLATTEN(((0x30010) << 4) | 0x00000000u));
2529}
2530
2531static void apply_kill(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2532 if (nargs == 2 && lbm_is_number(args[0])) {
2533 lbm_cid cid = lbm_dec_as_i32(args[0]);
2534
2535 if (ctx->id == cid) {
2536 ctx->r = args[1];
2537 finish_ctx();
2538 return;
2539 }
2540 mutex_lock(&qmutex);
2541 eval_context_t *found = NULL((void*)0);
2542 found = lookup_ctx_nm(&blocked, cid);
2543 if (found)
2544 drop_ctx_nm(&blocked, found);
2545 else
2546 found = lookup_ctx_nm(&queue, cid);
2547 if (found)
2548 drop_ctx_nm(&queue, found);
2549
2550 if (found) {
2551 found->K.data[found->K.sp - 1] = KILL(((40) << 2) | 0xF8000001u);
2552 found->r = args[1];
2553 found->app_cont = true1;
2554 enqueue_ctx_nm(&queue,found);
2555 ctx->r = ENC_SYM_TRUE(((0x2) << 4) | 0x00000000u);
2556 } else {
2557 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2558 }
2559 lbm_stack_drop(&ctx->K, 3);
2560 ctx->app_cont = true1;
2561 mutex_unlock(&qmutex);
2562 return;
2563 }
2564 error_at_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u), ENC_SYM_KILL(((0x30011) << 4) | 0x00000000u));
2565}
2566
2567// (merge comparator list1 list2)
2568static void apply_merge(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2569 if (nargs == 3 && lbm_is_list(args[1]) && lbm_is_list(args[2])) {
2570
2571 if (!lbm_is_closure(args[0])) {
2572 lbm_value closure;
2573 WITH_GC(closure, lbm_heap_allocate_list(4))(closure) = (lbm_heap_allocate_list(4)); if (lbm_is_symbol_merror
((closure))) { gc(); (closure) = (lbm_heap_allocate_list(4));
if (lbm_is_symbol_merror((closure))) { error_ctx((((0x23) <<
4) | 0x00000000u)); } }
;
2574 lbm_set_car(closure, ENC_SYM_CLOSURE(((0x10F) << 4) | 0x00000000u));
2575 lbm_value cl1 = lbm_cdr(closure);
2576 lbm_value par;
2577 WITH_GC_RMBR_1(par, lbm_heap_allocate_list_init(2, symbol_x, symbol_y), closure)(par) = (lbm_heap_allocate_list_init(2, symbol_x, symbol_y));
if (lbm_is_symbol_merror((par))) { lbm_gc_mark_phase(closure
); gc(); (par) = (lbm_heap_allocate_list_init(2, symbol_x, symbol_y
)); if (lbm_is_symbol_merror((par))) { error_ctx((((0x23) <<
4) | 0x00000000u)); } }
;
2578 lbm_set_car(cl1, par);
2579 lbm_value cl2 = lbm_cdr(cl1);
2580 lbm_value body;
2581 WITH_GC_RMBR_1(body, lbm_heap_allocate_list_init(3, args[0], symbol_x, symbol_y), closure)(body) = (lbm_heap_allocate_list_init(3, args[0], symbol_x, symbol_y
)); if (lbm_is_symbol_merror((body))) { lbm_gc_mark_phase(closure
); gc(); (body) = (lbm_heap_allocate_list_init(3, args[0], symbol_x
, symbol_y)); if (lbm_is_symbol_merror((body))) { error_ctx((
((0x23) << 4) | 0x00000000u)); } }
;
2582 lbm_set_car(cl2, body);
2583 lbm_value cl3 = lbm_cdr(cl2);
2584 lbm_set_car(cl3, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
2585
2586 // Replace operator on stack with closure and rest of the code is
2587 // compatible.
2588 args[0] = closure;
2589 }
2590
2591 // Copy input lists for functional behaviour at top-level
2592 // merge itself is in-place in the copied lists.
2593 lbm_value a;
2594 lbm_value b;
2595 int len_a = -1;
2596 int len_b = -1;
2597 WITH_GC(a, lbm_list_copy(&len_a, args[1]))(a) = (lbm_list_copy(&len_a, args[1])); if (lbm_is_symbol_merror
((a))) { gc(); (a) = (lbm_list_copy(&len_a, args[1])); if
(lbm_is_symbol_merror((a))) { error_ctx((((0x23) << 4)
| 0x00000000u)); } }
;
2598 WITH_GC_RMBR_1(b, lbm_list_copy(&len_b, args[2]), a)(b) = (lbm_list_copy(&len_b, args[2])); if (lbm_is_symbol_merror
((b))) { lbm_gc_mark_phase(a); gc(); (b) = (lbm_list_copy(&
len_b, args[2])); if (lbm_is_symbol_merror((b))) { error_ctx(
(((0x23) << 4) | 0x00000000u)); } }
;
2599
2600 if (len_a == 0) {
2601 ctx->r = b;
2602 lbm_stack_drop(&ctx->K, 4);
2603 ctx->app_cont = true1;
2604 return;
2605 }
2606 if (len_b == 0) {
2607 ctx->r = a;
2608 lbm_stack_drop(&ctx->K, 4);
2609 ctx->app_cont = true1;
2610 return;
2611 }
2612
2613 args[1] = a; // keep safe by replacing the original on stack.
2614 args[2] = b;
2615
2616 lbm_value a_1 = a;
2617 lbm_value a_rest = lbm_cdr(a);
2618 lbm_value b_1 = b;
2619 lbm_value b_rest = lbm_cdr(b);
2620
2621 lbm_value cl[3]; // Comparator closure
2622 extract_n(lbm_cdr(args[0]), cl, 3);
2623 lbm_value cmp_env = cl[CLO_ENV2];
2624 lbm_value par1 = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2625 lbm_value par2 = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2626 lbm_uint len = lbm_list_length(cl[CLO_PARAMS0]);
2627 if (len == 2) {
2628 par1 = get_car(cl[CLO_PARAMS0]);
2629 par2 = get_car(get_cdr(cl[CLO_PARAMS0]));
2630 lbm_value new_env0;
2631 lbm_value new_env;
2632 WITH_GC(new_env0, lbm_env_set(cmp_env, par1, lbm_car(a_1)))(new_env0) = (lbm_env_set(cmp_env, par1, lbm_car(a_1))); if (
lbm_is_symbol_merror((new_env0))) { gc(); (new_env0) = (lbm_env_set
(cmp_env, par1, lbm_car(a_1))); if (lbm_is_symbol_merror((new_env0
))) { error_ctx((((0x23) << 4) | 0x00000000u)); } }
;
2633 WITH_GC_RMBR_1(new_env, lbm_env_set(new_env0, par2, lbm_car(b_1)),new_env0)(new_env) = (lbm_env_set(new_env0, par2, lbm_car(b_1))); if (
lbm_is_symbol_merror((new_env))) { lbm_gc_mark_phase(new_env0
); gc(); (new_env) = (lbm_env_set(new_env0, par2, lbm_car(b_1
))); if (lbm_is_symbol_merror((new_env))) { error_ctx((((0x23
) << 4) | 0x00000000u)); } }
;
2634 cmp_env = new_env;
2635 } else {
2636 error_at_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u), args[0]);
2637 }
2638 lbm_set_cdr(a_1, b_1);
2639 lbm_set_cdr(b_1, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
2640 lbm_value cmp = cl[CLO_BODY1];
2641
2642 lbm_stack_drop(&ctx->K, 4); // TODO: Optimize drop 4 alloc 10 into alloc 6
2643 lbm_uint *sptr = stack_reserve(ctx, 10);
2644 sptr[0] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u); // head of merged list
2645 sptr[1] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u); // last of merged list
2646 sptr[2] = a_1;
2647 sptr[3] = a_rest;
2648 sptr[4] = b_rest;
2649 sptr[5] = cmp;
2650 sptr[6] = cmp_env;
2651 sptr[7] = par1;
2652 sptr[8] = par2;
2653 sptr[9] = MERGE_REST(((43) << 2) | 0xF8000001u);
2654 ctx->curr_exp = cl[CLO_BODY1];
2655 ctx->curr_env = cmp_env;
2656 return;
2657 }
2658 error_at_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u), ENC_SYM_MERGE(((0x30013) << 4) | 0x00000000u));
2659}
2660
2661// (sort comparator list)
2662static void apply_sort(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2663 if (nargs == 2 && lbm_is_list(args[1])) {
2664
2665 if (!lbm_is_closure(args[0])) {
2666 lbm_value closure;
2667 WITH_GC(closure, lbm_heap_allocate_list(4))(closure) = (lbm_heap_allocate_list(4)); if (lbm_is_symbol_merror
((closure))) { gc(); (closure) = (lbm_heap_allocate_list(4));
if (lbm_is_symbol_merror((closure))) { error_ctx((((0x23) <<
4) | 0x00000000u)); } }
;
2668 lbm_set_car(closure, ENC_SYM_CLOSURE(((0x10F) << 4) | 0x00000000u));
2669 lbm_value cl1 = lbm_cdr(closure);
2670 lbm_value par;
2671 WITH_GC_RMBR_1(par, lbm_heap_allocate_list_init(2, symbol_x, symbol_y), closure)(par) = (lbm_heap_allocate_list_init(2, symbol_x, symbol_y));
if (lbm_is_symbol_merror((par))) { lbm_gc_mark_phase(closure
); gc(); (par) = (lbm_heap_allocate_list_init(2, symbol_x, symbol_y
)); if (lbm_is_symbol_merror((par))) { error_ctx((((0x23) <<
4) | 0x00000000u)); } }
;
2672 lbm_set_car(cl1, par);
2673 lbm_value cl2 = lbm_cdr(cl1);
2674 lbm_value body;
2675 WITH_GC_RMBR_1(body, lbm_heap_allocate_list_init(3, args[0], symbol_x, symbol_y), closure)(body) = (lbm_heap_allocate_list_init(3, args[0], symbol_x, symbol_y
)); if (lbm_is_symbol_merror((body))) { lbm_gc_mark_phase(closure
); gc(); (body) = (lbm_heap_allocate_list_init(3, args[0], symbol_x
, symbol_y)); if (lbm_is_symbol_merror((body))) { error_ctx((
((0x23) << 4) | 0x00000000u)); } }
;
2676 lbm_set_car(cl2, body);
2677 lbm_value cl3 = lbm_cdr(cl2);
2678 lbm_set_car(cl3, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
2679
2680 // Replace operator on stack with closure and rest of the code is
2681 // compatible.
2682 args[0] = closure;
2683 }
2684
2685 int len = -1;
2686 lbm_value list_copy;
2687 WITH_GC(list_copy, lbm_list_copy(&len, args[1]))(list_copy) = (lbm_list_copy(&len, args[1])); if (lbm_is_symbol_merror
((list_copy))) { gc(); (list_copy) = (lbm_list_copy(&len,
args[1])); if (lbm_is_symbol_merror((list_copy))) { error_ctx
((((0x23) << 4) | 0x00000000u)); } }
;
2688 if (len <= 1) {
2689 lbm_stack_drop(&ctx->K, 3);
2690 ctx->r = list_copy;
2691 ctx->app_cont = true1;
2692 return;
2693 }
2694
2695 args[1] = list_copy; // Keep safe, original replaced on stack.
2696
2697 // Take the headmost 2, 1-element sublists.
2698 lbm_value a = list_copy;
2699 lbm_value b = lbm_cdr(a);
2700 lbm_value rest = lbm_cdr(b);
2701 // Do not terminate b. keep rest of list safe from GC in the following
2702 // closure extraction.
2703 //lbm_set_cdr(a, b); // This is void
2704
2705 lbm_value cl[3]; // Comparator closure
2706 extract_n(lbm_cdr(args[0]), cl, 3);
2707 lbm_value cmp_env = cl[CLO_ENV2];
2708 lbm_value par1 = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2709 lbm_value par2 = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2710 lbm_uint cl_len = lbm_list_length(cl[CLO_PARAMS0]);
2711 if (cl_len == 2) {
2712 par1 = get_car(cl[CLO_PARAMS0]);
2713 par2 = get_car(get_cdr(cl[CLO_PARAMS0]));
2714 lbm_value new_env0;
2715 lbm_value new_env;
2716 WITH_GC(new_env0, lbm_env_set(cmp_env, par1, lbm_car(a)))(new_env0) = (lbm_env_set(cmp_env, par1, lbm_car(a))); if (lbm_is_symbol_merror
((new_env0))) { gc(); (new_env0) = (lbm_env_set(cmp_env, par1
, lbm_car(a))); if (lbm_is_symbol_merror((new_env0))) { error_ctx
((((0x23) << 4) | 0x00000000u)); } }
;
2717 WITH_GC_RMBR_1(new_env, lbm_env_set(new_env0, par2, lbm_car(b)), new_env0)(new_env) = (lbm_env_set(new_env0, par2, lbm_car(b))); if (lbm_is_symbol_merror
((new_env))) { lbm_gc_mark_phase(new_env0); gc(); (new_env) =
(lbm_env_set(new_env0, par2, lbm_car(b))); if (lbm_is_symbol_merror
((new_env))) { error_ctx((((0x23) << 4) | 0x00000000u))
; } }
;
2718 cmp_env = new_env;
2719 } else {
2720 error_at_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u), args[0]);
2721 }
2722 lbm_value cmp = cl[CLO_BODY1];
2723
2724 // Terminate the comparator argument list.
2725 lbm_set_cdr(b, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
2726
2727 lbm_stack_drop(&ctx->K, 3); //TODO: optimize drop 3, alloc 20 into alloc 17
2728 lbm_uint *sptr = stack_reserve(ctx, 20);
2729 sptr[0] = cmp;
2730 sptr[1] = cmp_env;
2731 sptr[2] = par1;
2732 sptr[3] = par2;
2733 sptr[4] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u); // head of merged accumulation of sublists
2734 sptr[5] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u); // last of merged accumulation of sublists
2735 sptr[6] = rest;
2736 sptr[7] = lbm_enc_i(1);
2737 sptr[8] = lbm_enc_i(len); //TODO: 28 bit i vs 32 bit i
2738 sptr[9] = MERGE_LAYER(((44) << 2) | 0xF8000001u);
2739 sptr[10] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u); // head of merged sublist
2740 sptr[11] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u); // last of merged sublist
2741 sptr[12] = a;
2742 sptr[13] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u); // no a_rest, 1 element lists in layer 1.
2743 sptr[14] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u); // no b_rest, 1 element lists in layer 1.
2744 sptr[15] = cmp;
2745 sptr[16] = cmp_env;
2746 sptr[17] = par1;
2747 sptr[18] = par2;
2748 sptr[19] = MERGE_REST(((43) << 2) | 0xF8000001u);
2749 ctx->curr_exp = cmp;
2750 ctx->curr_env = cmp_env;
2751 return;
2752 }
2753 error_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
2754}
2755
2756static void apply_rest_args(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2757 lbm_value res;
2758 if (lbm_env_lookup_b(&res, ENC_SYM_REST_ARGS(((0x30015) << 4) | 0x00000000u), ctx->curr_env)) {
2759 if (nargs == 1 && lbm_is_number(args[0])) {
2760 int32_t ix = lbm_dec_as_i32(args[0]);
2761 res = lbm_index_list(res, ix);
2762 }
2763 ctx->r = res;
2764 } else {
2765 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2766 }
2767 lbm_stack_drop(&ctx->K, nargs+1);
2768 ctx->app_cont = true1;
2769}
2770
2771/***************************************************/
2772/* Application lookup table */
2773
2774typedef void (*apply_fun)(lbm_value *, lbm_uint, eval_context_t *);
2775static const apply_fun fun_table[] =
2776 {
2777 apply_setvar,
2778 apply_read,
2779 apply_read_program,
2780 apply_read_eval_program,
2781 apply_spawn,
2782 apply_spawn_trap,
2783 apply_yield,
2784 apply_wait,
2785 apply_eval,
2786 apply_eval_program,
2787 apply_send,
2788 apply_ok,
2789 apply_error,
2790 apply_map,
2791 apply_reverse,
2792 apply_flatten,
2793 apply_unflatten,
2794 apply_kill,
2795 apply_sleep,
2796 apply_merge,
2797 apply_sort,
2798 apply_rest_args,
2799 };
2800
2801/***************************************************/
2802/* Application of function that takes arguments */
2803/* passed over the stack. */
2804
2805static void application(eval_context_t *ctx, lbm_value *fun_args, lbm_uint arg_count) {
2806 /* If arriving here, we know that the fun is a symbol.
2807 * and can be a built in operation or an extension.
2808 */
2809 lbm_value fun = fun_args[0];
2810
2811 lbm_uint fun_val = lbm_dec_sym(fun);
2812 lbm_uint fun_kind = SYMBOL_KIND(fun_val)((fun_val) >> 16);
2813
2814 switch (fun_kind) {
2815 case SYMBOL_KIND_EXTENSION1: {
2816 extension_fptr f = extension_table[SYMBOL_IX(fun_val)((fun_val) & 0xFFFF)].fptr;
2817
2818 lbm_value ext_res;
2819 WITH_GC(ext_res, f(&fun_args[1], arg_count))(ext_res) = (f(&fun_args[1], arg_count)); if (lbm_is_symbol_merror
((ext_res))) { gc(); (ext_res) = (f(&fun_args[1], arg_count
)); if (lbm_is_symbol_merror((ext_res))) { error_ctx((((0x23)
<< 4) | 0x00000000u)); } }
;
2820 if (lbm_is_error(ext_res)) { //Error other than merror
2821 error_at_ctx(ext_res, fun);
2822 }
2823 lbm_stack_drop(&ctx->K, arg_count + 1);
2824
2825 if (blocking_extension) {
2826 blocking_extension = false0;
2827 if (blocking_extension_timeout) {
2828 blocking_extension_timeout = false0;
2829 block_current_ctx(LBM_THREAD_STATE_TIMEOUT(uint32_t)2, blocking_extension_timeout_us,true1);
2830 } else {
2831 block_current_ctx(LBM_THREAD_STATE_BLOCKED(uint32_t)1, 0,true1);
2832 }
2833 mutex_unlock(&blocking_extension_mutex);
2834 } else {
2835 ctx->app_cont = true1;
2836 ctx->r = ext_res;
2837 }
2838 } break;
2839 case SYMBOL_KIND_FUNDAMENTAL2:
2840 call_fundamental(SYMBOL_IX(fun_val)((fun_val) & 0xFFFF), &fun_args[1], arg_count, ctx);
2841 break;
2842 case SYMBOL_KIND_APPFUN3:
2843 fun_table[SYMBOL_IX(fun_val)((fun_val) & 0xFFFF)](&fun_args[1], arg_count, ctx);
2844 break;
2845 default:
2846 // Symbols that are "special" but not in the way caught above
2847 // ends up here.
2848 lbm_set_error_reason("Symbol does not represent a function");
2849 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u),fun_args[0]);
2850 break;
2851 }
2852}
2853
2854static void cont_closure_application_args(eval_context_t *ctx) {
2855 lbm_uint* sptr = get_stack_ptr(ctx, 5);
2856
2857 lbm_value arg_env = (lbm_value)sptr[0];
2858 lbm_value exp = (lbm_value)sptr[1];
2859 lbm_value clo_env = (lbm_value)sptr[2];
2860 lbm_value params = (lbm_value)sptr[3];
2861 lbm_value args = (lbm_value)sptr[4];
2862
2863 lbm_value car_params, cdr_params;
2864 get_car_and_cdr(params, &car_params, &cdr_params);
2865
2866 bool_Bool a_nil = args == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2867 bool_Bool p_nil = cdr_params == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2868
2869 lbm_value binder = allocate_binding(car_params, ctx->r, clo_env);
2870
2871 if (!a_nil && !p_nil) {
2872 lbm_value car_args, cdr_args;
2873 get_car_and_cdr(args, &car_args, &cdr_args);
2874 sptr[2] = binder;
2875 sptr[3] = cdr_params;
2876 sptr[4] = cdr_args;
2877 stack_push(&ctx->K, CLOSURE_ARGS(((13) << 2) | 0xF8000001u));
2878 ctx->curr_exp = car_args;
2879 ctx->curr_env = arg_env;
2880 } else if (p_nil && !a_nil) {
2881 lbm_value rest_binder = allocate_binding(ENC_SYM_REST_ARGS(((0x30015) << 4) | 0x00000000u), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), binder);
2882 sptr[2] = rest_binder;
2883 sptr[3] = get_cdr(args);
2884 sptr[4] = get_car(rest_binder); // last element of rest_args so far
2885 stack_push(&ctx->K, CLOSURE_ARGS_REST(((45) << 2) | 0xF8000001u));
2886 ctx->curr_exp = get_car(args);
2887 ctx->curr_env = arg_env;
2888 } else if (a_nil && p_nil) {
2889 // Arguments and parameters match up in number
2890 lbm_stack_drop(&ctx->K, 5);
2891 ctx->curr_env = binder;
2892 ctx->curr_exp = exp;
2893 } else {
2894 lbm_set_error_reason((char*)lbm_error_str_num_args);
2895 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
2896 }
2897}
2898
2899
2900static void cont_closure_args_rest(eval_context_t *ctx) {
2901 lbm_uint* sptr = get_stack_ptr(ctx, 5);
2902 lbm_value arg_env = (lbm_value)sptr[0];
2903 lbm_value exp = (lbm_value)sptr[1];
2904 lbm_value clo_env = (lbm_value)sptr[2];
2905 lbm_value args = (lbm_value)sptr[3];
2906 lbm_value last = (lbm_value)sptr[4];
2907 lbm_cons_t* heap = lbm_heap_state.heap;
2908
2909 lbm_value binding = lbm_heap_state.freelist;
2910 if (binding == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)) {
2911 gc();
2912 binding = lbm_heap_state.freelist;
2913 if (binding == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)) error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
2914 }
2915 lbm_uint binding_ix = lbm_dec_ptr(binding);
2916 lbm_heap_state.freelist = heap[binding_ix].cdr;
2917 lbm_heap_state.num_alloc += 1;
2918 heap[binding_ix].car = ctx->r;
2919 heap[binding_ix].cdr = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2920
2921
2922 lbm_set_cdr(last, binding);
2923 sptr[4] = binding;
2924
2925 if (args == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)) {
2926 lbm_stack_drop(&ctx->K, 5);
2927 ctx->curr_env = clo_env;
2928 ctx->curr_exp = exp;
2929 } else {
2930 stack_push(&ctx->K, CLOSURE_ARGS_REST(((45) << 2) | 0xF8000001u));
2931 sptr[3] = get_cdr(args);
2932 ctx->curr_exp = get_car(args);
2933 ctx->curr_env = arg_env;
2934 }
2935}
2936
2937static void cont_application_args(eval_context_t *ctx) {
2938 lbm_uint *sptr = get_stack_ptr(ctx, 3);
2939
2940 lbm_value env = sptr[0];
2941 lbm_value rest = sptr[1];
2942 lbm_value count = sptr[2];
2943
2944 ctx->curr_env = env;
2945 sptr[0] = ctx->r; // Function 1st then Arguments
2946 if (lbm_is_cons(rest)) {
2947 lbm_cons_t *cell = lbm_ref_cell(rest);
2948 sptr[1] = env;
2949 sptr[2] = cell->cdr;
2950 stack_push_2(&ctx->K, count + (1 << LBM_VAL_SHIFT4), APPLICATION_ARGS(((5) << 2) | 0xF8000001u));
2951 ctx->curr_exp = cell->car;
2952 } else {
2953 // No more arguments
2954 lbm_stack_drop(&ctx->K, 2);
2955 lbm_uint nargs = lbm_dec_u(count);
2956 lbm_value *args = get_stack_ptr(ctx, (uint32_t)(nargs + 1));
2957 application(ctx,args, nargs);
2958 }
2959}
2960
2961static void cont_and(eval_context_t *ctx) {
2962 lbm_value env;
2963 lbm_value rest;
2964 lbm_value arg = ctx->r;
2965 lbm_pop_2(&ctx->K, &rest, &env);
2966 if (lbm_is_symbol_nil(arg)) {
2967 ctx->app_cont = true1;
2968 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2969 } else if (lbm_is_symbol_nil(rest)) {
2970 ctx->app_cont = true1;
2971 } else {
2972 stack_push_3(&ctx->K, env, get_cdr(rest), AND(((6) << 2) | 0xF8000001u));
2973 ctx->curr_env = env;
2974 ctx->curr_exp = get_car(rest);
2975 }
2976}
2977
2978static void cont_or(eval_context_t *ctx) {
2979 lbm_value env;
2980 lbm_value rest;
2981 lbm_value arg = ctx->r;
2982 lbm_pop_2(&ctx->K, &rest, &env);
2983 if (!lbm_is_symbol_nil(arg)) {
2984 ctx->app_cont = true1;
2985 } else if (lbm_is_symbol_nil(rest)) {
2986 ctx->app_cont = true1;
2987 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
2988 } else {
2989 stack_push_3(&ctx->K, env, get_cdr(rest), OR(((7) << 2) | 0xF8000001u));
2990 ctx->curr_exp = get_car(rest);
2991 ctx->curr_env = env;
2992 }
2993}
2994
2995static int fill_binding_location(lbm_value key, lbm_value value, lbm_value env) {
2996 if (lbm_type_of(key) == LBM_TYPE_SYMBOL0x00000000u) {
2997 if (key == ENC_SYM_DONTCARE(((0x9) << 4) | 0x00000000u)) return FB_OK0;
2998 lbm_env_modify_binding(env,key,value);
2999 return FB_OK0;
3000 } else if (lbm_is_cons(key) &&
3001 lbm_is_cons(value)) {
3002 int r = fill_binding_location(get_car(key), get_car(value), env);
3003 if (r == FB_OK0) {
3004 r = fill_binding_location(get_cdr(key), get_cdr(value), env);
3005 }
3006 return r;
3007 }
3008 return FB_TYPE_ERROR-1;
3009}
3010
3011static void cont_bind_to_key_rest(eval_context_t *ctx) {
3012
3013 lbm_value *sptr = get_stack_ptr(ctx, 4);
3014
3015 lbm_value rest = sptr[1];
3016 lbm_value env = sptr[2];
3017 lbm_value key = sptr[3];
3018
3019 if (fill_binding_location(key, ctx->r, env) < 0) {
3020 lbm_set_error_reason("Incorrect type of name/key in let-binding");
3021 error_at_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u), key);
3022 }
3023
3024 if (lbm_is_cons(rest)) {
3025 lbm_value keyn = get_caar(rest);
3026 lbm_value valn_exp = get_cadr(get_car(rest));
3027
3028 sptr[1] = get_cdr(rest);
3029 sptr[3] = keyn;
3030 stack_push(&ctx->K, BIND_TO_KEY_REST(((2) << 2) | 0xF8000001u));
3031 ctx->curr_exp = valn_exp;
3032 ctx->curr_env = env;
3033 } else {
3034 // Otherwise evaluate the expression in the populated env
3035 ctx->curr_exp = sptr[0];
3036 ctx->curr_env = env;
3037 lbm_stack_drop(&ctx->K, 4);
3038 }
3039}
3040
3041static void cont_if(eval_context_t *ctx) {
3042
3043 lbm_value arg = ctx->r;
3044
3045 lbm_value *sptr = pop_stack_ptr(ctx, 3);
3046
3047 ctx->curr_env = sptr[2];
3048 if (lbm_is_symbol_nil(arg)) {
3049 ctx->curr_exp = sptr[0]; // else branch
3050 } else {
3051 ctx->curr_exp = sptr[1]; // then branch
3052 }
3053}
3054
3055static void cont_match(eval_context_t *ctx) {
3056 lbm_value e = ctx->r;
3057 bool_Bool do_gc = false0;
3058
3059 lbm_uint *sptr = get_stack_ptr(ctx, 2);
3060 lbm_value patterns = (lbm_value)sptr[0];
3061 lbm_value orig_env = (lbm_value)sptr[1]; // restore enclosing environment.
3062 lbm_value new_env = orig_env;
3063
3064 if (lbm_is_symbol_nil(patterns)) {
3065 // no more patterns
3066 lbm_stack_drop(&ctx->K, 2);
3067 ctx->r = ENC_SYM_NO_MATCH(((0x40) << 4) | 0x00000000u);
3068 ctx->app_cont = true1;
3069 } else if (lbm_is_cons(patterns)) {
3070 lbm_value match_case = get_car(patterns);
3071 lbm_value pattern = get_car(match_case);
3072 lbm_value n1 = get_cadr(match_case);
3073 lbm_value n2 = get_cadr(get_cdr(match_case));
3074 lbm_value body;
3075 bool_Bool check_guard = false0;
3076 if (lbm_is_symbol_nil(n2)) { // TODO: Not a very robust check.
3077 body = n1;
3078 } else {
3079 body = n2;
3080 check_guard = true1;
3081 }
3082
3083 bool_Bool is_match = match(pattern, e, &new_env, &do_gc);
3084 if (do_gc) {
3085 gc();
3086 do_gc = false0;
3087 new_env = orig_env;
3088 is_match = match(pattern, e, &new_env, &do_gc);
3089 if (do_gc) {
3090 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
3091 }
3092 }
3093 if (is_match) {
3094 if (check_guard) {
3095 lbm_value *rptr = stack_reserve(ctx,5);
3096 sptr[0] = get_cdr(patterns);
3097 sptr[1] = ctx->curr_env;
3098 rptr[0] = MATCH(((9) << 2) | 0xF8000001u);
3099 rptr[1] = new_env;
3100 rptr[2] = body;
3101 rptr[3] = e;
3102 rptr[4] = MATCH_GUARD(((27) << 2) | 0xF8000001u);
3103 ctx->curr_env = new_env;
3104 ctx->curr_exp = n1; // The guard
3105 } else {
3106 lbm_stack_drop(&ctx->K, 2);
3107 ctx->curr_env = new_env;
3108 ctx->curr_exp = body;
3109 }
3110 } else {
3111 // set up for checking of next pattern
3112 sptr[0] = get_cdr(patterns);
3113 sptr[1] = orig_env;
3114 stack_push(&ctx->K, MATCH(((9) << 2) | 0xF8000001u));
3115 // leave r unaltered
3116 ctx->app_cont = true1;
3117 }
3118 } else {
3119 error_at_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u), ENC_SYM_MATCH(((0x108) << 4) | 0x00000000u));
3120 }
3121}
3122
3123static void cont_exit_atomic(eval_context_t *ctx) {
3124 is_atomic --;
3125 ctx->app_cont = true1;
3126}
3127
3128static void cont_map(eval_context_t *ctx) {
3129 lbm_value *sptr = get_stack_ptr(ctx, 6);
3130
3131 lbm_value ls = sptr[0];
3132 lbm_value env = sptr[1];
3133 lbm_value t = sptr[3];
3134 lbm_set_car(t, ctx->r); // update car field tailmost position.
3135 if (lbm_is_cons(ls)) {
3136 lbm_value next, rest;
3137 get_car_and_cdr(ls, &next, &rest);
3138 sptr[0] = rest;
3139 stack_push(&ctx->K, MAP(((26) << 2) | 0xF8000001u));
3140 lbm_set_car(sptr[5], next); // new arguments
3141
3142 lbm_value elt = cons_with_gc(ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
3143 lbm_set_cdr(t, elt);
3144 sptr[3] = elt; // (r1 ... rN . (nil . nil))
3145 ctx->curr_exp = sptr[4];
3146 ctx->curr_env = env;
3147 } else {
3148 ctx->r = sptr[2]; //head of result list
3149 ctx->curr_env = env;
3150 lbm_stack_drop(&ctx->K, 6);
3151 ctx->app_cont = true1;
3152 }
3153}
3154
3155static void cont_match_guard(eval_context_t *ctx) {
3156 if (lbm_is_symbol_nil(ctx->r)) {
3157 lbm_value e;
3158 lbm_pop(&ctx->K, &e);
3159 lbm_stack_drop(&ctx->K, 2);
3160 ctx->r = e;
3161 ctx->app_cont = true1;
3162 } else {
3163 lbm_value body;
3164 lbm_value env;
3165 lbm_stack_drop(&ctx->K, 1);
3166 lbm_pop_2(&ctx->K, &body, &env);
3167 lbm_stack_drop(&ctx->K, 3);
3168 ctx->curr_env = env;
3169 ctx->curr_exp = body;
3170 }
3171}
3172
3173static void cont_terminate(eval_context_t *ctx) {
3174 error_ctx(ctx->r);
3175}
3176
3177static void cont_loop(eval_context_t *ctx) {
3178 lbm_value *sptr = get_stack_ptr(ctx, 2);
3179 stack_push(&ctx->K, LOOP_CONDITION(((42) << 2) | 0xF8000001u));
3180 ctx->curr_exp = sptr[1];
3181}
3182
3183static void cont_loop_condition(eval_context_t *ctx) {
3184 if (lbm_is_symbol_nil(ctx->r)) {
3185 lbm_stack_drop(&ctx->K, 2);
3186 ctx->app_cont = true1; // A loop returns nil? Makes sense to me... but in general?
3187 return;
3188 }
3189 lbm_value *sptr = get_stack_ptr(ctx, 2);
3190 stack_push(&ctx->K, LOOP(((41) << 2) | 0xF8000001u));
3191 ctx->curr_exp = sptr[0];
3192}
3193
3194static void cont_merge_rest(eval_context_t *ctx) {
3195 lbm_uint *sptr = get_stack_ptr(ctx, 9);
3196
3197 // If comparator returns true (result is in ctx->r):
3198 // "a" should be moved to the last element position in merged list.
3199 // A new element from "a_rest" should be moved into comparator argument 1 pos.
3200 // else
3201 // "b" should be moved to last element position in merged list.
3202 // A new element from "b_rest" should be moved into comparator argument 2 pos.
3203 //
3204 // If a_rest or b_rest is NIL:
3205 // we are done, the remaining elements of
3206 // non_nil list should be appended to merged list.
3207 // else
3208 // Set up for a new comparator evaluation and recurse.
3209 lbm_value a = sptr[2];
3210 lbm_value b = lbm_cdr(a);
3211 lbm_set_cdr(a, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)); // terminate 1 element list
3212
3213 if (ctx->r == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)) { // Comparison false
3214
3215 if (sptr[0] == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)) {
3216 sptr[0] = b;
3217 sptr[1] = b;
3218 } else {
3219 lbm_set_cdr(sptr[1], b);
3220 sptr[1] = b;
3221 }
3222 if (sptr[4] == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)) {
3223 lbm_set_cdr(a, sptr[3]);
3224 lbm_set_cdr(sptr[1], a);
3225 ctx->r = sptr[0];
3226 lbm_stack_drop(&ctx->K, 9);
3227 ctx->app_cont = true1;
3228 return;
3229 } else {
3230 b = sptr[4];
3231 sptr[4] = lbm_cdr(sptr[4]);
3232 lbm_set_cdr(b, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
3233 }
3234 } else {
3235 if (sptr[0] == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)) {
3236 sptr[0] = a;
3237 sptr[1] = a;
3238 } else {
3239 lbm_set_cdr(sptr[1], a);
3240 sptr[1] = a;
3241 }
3242
3243 if (sptr[3] == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)) {
3244 lbm_set_cdr(b, sptr[4]);
3245 lbm_set_cdr(sptr[1], b);
3246 ctx->r = sptr[0];
3247 lbm_stack_drop(&ctx->K, 9);
3248 ctx->app_cont = true1;
3249 return;
3250 } else {
3251 a = sptr[3];
3252 sptr[3] = lbm_cdr(sptr[3]);
3253 lbm_set_cdr(a, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
3254 }
3255 }
3256 lbm_set_cdr(a, b);
3257 sptr[2] = a;
3258
3259 lbm_value par1 = sptr[7];
3260 lbm_value par2 = sptr[8];
3261 lbm_value cmp_body = sptr[5];
3262 lbm_value cmp_env = sptr[6];
3263 // Environment should be preallocated already at this point
3264 // and the operations below should never need GC.
3265 lbm_value new_env0 = lbm_env_set(cmp_env, par1, lbm_car(a));
3266 lbm_value new_env = lbm_env_set(new_env0, par2, lbm_car(b));
3267 if (lbm_is_symbol(new_env0) || lbm_is_symbol(new_env)) {
3268 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
3269 }
3270 cmp_env = new_env;
3271
3272 stack_push(&ctx->K, MERGE_REST(((43) << 2) | 0xF8000001u));
3273 ctx->curr_exp = cmp_body;
3274 ctx->curr_env = cmp_env;
3275}
3276
3277// merge_layer stack contents
3278// s[sp-9] = cmp
3279// s[sp-8] = cmp_env
3280// s[sp-7] = par1
3281// s[sp-6] = par2
3282// s[sp-5] = acc - first cell
3283// s[sp-4] = acc - last cell
3284// s[sp-3] = rest;
3285// s[sp-2] = layer
3286// s[sp-1] = length or original list
3287//
3288// ctx->r merged sublist
3289static void cont_merge_layer(eval_context_t *ctx) {
3290 lbm_uint *sptr = get_stack_ptr(ctx, 9);
3291 int layer = lbm_dec_i(sptr[7]);
3292 int len = lbm_dec_i(sptr[8]);
3293
3294 lbm_value r_curr = ctx->r;
3295 while (lbm_is_cons(r_curr)) {
3296 lbm_value next = lbm_cdr(r_curr);
3297 if (next == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)) {
3298 break;
3299 }
3300 r_curr = next;
3301 }
3302
3303 if (sptr[4] == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)) {
3304 sptr[4] = ctx->r;
3305 sptr[5] = r_curr;
3306 } else {
3307 lbm_set_cdr(sptr[5], ctx->r); // accumulate merged sublists.
3308 sptr[5] = r_curr;
3309 }
3310
3311 lbm_value layer_rest = sptr[6];
3312 // switch layer or done ?
3313 if (layer_rest == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)) {
3314 if (layer * 2 >= len) {
3315 ctx->r = sptr[4];
3316 ctx->app_cont = true1;
3317 lbm_stack_drop(&ctx->K, 9);
3318 return;
3319 } else {
3320 // Setup for merges of the next layer
3321 layer = layer * 2;
3322 sptr[7] = lbm_enc_i(layer);
3323 layer_rest = sptr[4]; // continue on the accumulation of all sublists.
3324 sptr[5] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
3325 sptr[4] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
3326 }
3327 }
3328 // merge another sublist based on current layer.
3329 lbm_value a_list = layer_rest;
3330 // build sublist a
3331 lbm_value curr = layer_rest;
3332 for (int i = 0; i < layer-1; i ++) {
3333 if (lbm_is_cons(curr)) {
3334 curr = lbm_cdr(curr);
3335 } else {
3336 break;
3337 }
3338 }
3339 layer_rest = lbm_cdr(curr);
3340 lbm_set_cdr(curr, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)); //terminate sublist.
3341
3342 lbm_value b_list = layer_rest;
3343 // build sublist b
3344 curr = layer_rest;
3345 for (int i = 0; i < layer-1; i ++) {
3346 if (lbm_is_cons(curr)) {
3347 curr = lbm_cdr(curr);
3348 } else {
3349 break;
3350 }
3351 }
3352 layer_rest = lbm_cdr(curr);
3353 lbm_set_cdr(curr, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)); //terminate sublist.
3354
3355 sptr[6] = layer_rest;
3356
3357 if (b_list == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)) {
3358 stack_push(&ctx->K, MERGE_LAYER(((44) << 2) | 0xF8000001u));
3359 ctx->r = a_list;
3360 ctx->app_cont = true1;
3361 return;
3362 }
3363 // Set up for a merge of sublists.
3364
3365 lbm_value a_rest = lbm_cdr(a_list);
3366 lbm_value b_rest = lbm_cdr(b_list);
3367 lbm_value a = a_list;
3368 lbm_value b = b_list;
3369 lbm_set_cdr(a, b);
3370 // Terminating the b list would be incorrect here
3371 // if there was any chance that the environment update below
3372 // performs GC.
3373 lbm_set_cdr(b, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
3374
3375 lbm_value cmp_body = sptr[0];
3376 lbm_value cmp_env = sptr[1];
3377 lbm_value par1 = sptr[2];
3378 lbm_value par2 = sptr[3];
3379 // Environment should be preallocated already at this point
3380 // and the operations below should never need GC.
3381 lbm_value new_env0 = lbm_env_set(cmp_env, par1, lbm_car(a));
3382 lbm_value new_env = lbm_env_set(cmp_env, par2, lbm_car(b));
3383 if (lbm_is_symbol(new_env0) || lbm_is_symbol(new_env)) {
3384 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
3385 }
3386 cmp_env = new_env;
3387
3388 lbm_uint *merge_cont = stack_reserve(ctx, 11);
3389 merge_cont[0] = MERGE_LAYER(((44) << 2) | 0xF8000001u);
3390 merge_cont[1] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
3391 merge_cont[2] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
3392 merge_cont[3] = a;
3393 merge_cont[4] = a_rest;
3394 merge_cont[5] = b_rest;
3395 merge_cont[6] = cmp_body;
3396 merge_cont[7] = cmp_env;
3397 merge_cont[8] = par1;
3398 merge_cont[9] = par2;
3399 merge_cont[10] = MERGE_REST(((43) << 2) | 0xF8000001u);
3400 ctx->curr_exp = cmp_body;
3401 ctx->curr_env = cmp_env;
3402 return;
3403}
3404
3405/****************************************************/
3406/* READER */
3407
3408static void read_finish(lbm_char_channel_t *str, eval_context_t *ctx) {
3409
3410 /* Tokenizer reached "end of file"
3411 The parser could be in a state where it needs
3412 more tokens to correctly finish an expression.
3413
3414 Three cases
3415 1. The program / expression is malformed and the context should die.
3416 2. We are finished reading a program and should close off the
3417 internal representation with a closing parenthesis. Then
3418 apply continuation.
3419 3. We are finished reading an expression and should
3420 apply the continuation.
3421
3422 In case 3, we should find the READ_DONE at sp - 1.
3423 In case 2, we should find the READ_DONE at sp - 5.
3424
3425 */
3426
3427 if (lbm_is_symbol(ctx->r)) {
3428 lbm_uint sym_val = lbm_dec_sym(ctx->r);
3429 if (sym_val >= TOKENIZER_SYMBOLS_START0x70 &&
3430 sym_val <= TOKENIZER_SYMBOLS_END0x85) {
3431 read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
3432 }
3433 }
3434
3435 if (ctx->K.data[ctx->K.sp-1] == READ_DONE(((20) << 2) | 0xF8000001u) &&
3436 lbm_dec_u(ctx->K.data[ctx->K.sp-3]) == 0) {
3437 /* successfully finished reading an expression (CASE 3) */
3438 ctx->app_cont = true1;
3439 } else if (ctx->K.sp > 4 && ctx->K.data[ctx->K.sp - 4] == READ_DONE(((20) << 2) | 0xF8000001u)) {
3440 lbm_value env;
3441 lbm_value s;
3442 lbm_value sym;
3443 lbm_pop_3(&ctx->K, &sym, &env, &s);
3444 ctx->curr_env = env;
3445 ctx->app_cont = true1; // Program evaluated and result is in ctx->r.
3446 } else if (ctx->K.sp > 5 && ctx->K.data[ctx->K.sp - 5] == READ_DONE(((20) << 2) | 0xF8000001u)) {
3447 /* successfully finished reading a program (CASE 2) */
3448 ctx->r = ENC_SYM_CLOSEPAR(((0x71) << 4) | 0x00000000u);
3449 ctx->app_cont = true1;
3450 } else {
3451 /* Parsing failed */
3452 if (lbm_channel_row(str) == 1 &&
3453 lbm_channel_column(str) == 1 ){
3454 // eof at empty stream.
3455 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
3456 ctx->app_cont = true1;
3457 } else {
3458 lbm_set_error_reason((char*)lbm_error_str_parse_eof);
3459 read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
3460 }
3461 lbm_channel_reader_close(str);
3462 }
3463}
3464
3465/* cont_read_next_token
3466 sp-2 : Stream
3467 sp-1 : Grab row
3468*/
3469static void cont_read_next_token(eval_context_t *ctx) {
3470 lbm_value *sptr = get_stack_ptr(ctx, 2);
3471 lbm_value stream = sptr[0];
3472 lbm_value grab_row0 = sptr[1];
3473
3474 lbm_char_channel_t *chan = lbm_dec_channel(stream);
3475 if (chan == NULL((void*)0) || chan->state == NULL((void*)0)) {
3476 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
3477 }
3478
3479 if (!lbm_channel_more(chan) && lbm_channel_is_empty(chan)) {
3480 lbm_stack_drop(&ctx->K, 2);
3481 read_finish(chan, ctx);
3482 return;
3483 }
3484 /* Eat whitespace and comments */
3485 if (!tok_clean_whitespace(chan)) {
3486 sptr[0] = stream;
3487 sptr[1] = lbm_enc_u(0);
3488 stack_push(&ctx->K, READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
3489 yield_ctx(EVAL_CPS_MIN_SLEEP200);
3490 return;
3491 }
3492 /* After eating whitespace we may be at end of file/stream */
3493 if (!lbm_channel_more(chan) && lbm_channel_is_empty(chan)) {
3494 lbm_stack_drop(&ctx->K, 2);
3495 read_finish(chan, ctx);
3496 return;
3497 }
3498
3499 if (lbm_dec_u(grab_row0)) {
3500 ctx->row0 = (int32_t)lbm_channel_row(chan);
3501 }
3502
3503 /* Attempt to extract tokens from the character stream */
3504 int n = 0;
3505 lbm_value res = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
3506 unsigned int string_len = 0;
3507
3508 /*
3509 * SYNTAX
3510 */
3511 uint32_t match;
3512 n = tok_syntax(chan, &match);
3513 if (n > 0) {
3514 if (!lbm_channel_drop(chan, (unsigned int)n)) {
3515 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
3516 }
3517 ctx->app_cont = true1;
3518 lbm_uint do_next = 0;
3519 switch(match) {
3520 case TOKOPENPAR1u:
3521 sptr[0] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
3522 sptr[1] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
3523 stack_push_2(&ctx->K,
3524 stream,
3525 READ_APPEND_CONTINUE(((16) << 2) | 0xF8000001u));
3526 stack_push_3(&ctx->K, stream, lbm_enc_u(0), READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
3527 ctx->r = ENC_SYM_OPENPAR(((0x70) << 4) | 0x00000000u);
3528 return;
3529 case TOKCLOSEPAR2u: {
3530 lbm_stack_drop(&ctx->K, 2);
3531 ctx->r = ENC_SYM_CLOSEPAR(((0x71) << 4) | 0x00000000u);
3532 } return;
3533 case TOKOPENBRACK3u:
3534 sptr[0] = stream;
3535 sptr[1] = READ_START_ARRAY(((24) << 2) | 0xF8000001u);
3536 //stack_push_2(&ctx->K, stream, READ_START_ARRAY);
3537 stack_push_3(&ctx->K, stream, lbm_enc_u(0), READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
3538 ctx->r = ENC_SYM_OPENBRACK(((0x80) << 4) | 0x00000000u);
3539 return;
3540 case TOKCLOSEBRACK4u:
3541 lbm_stack_drop(&ctx->K, 2);
3542 ctx->r = ENC_SYM_CLOSEBRACK(((0x81) << 4) | 0x00000000u);
3543 return;
3544 case TOKDOT5u:
3545 lbm_stack_drop(&ctx->K, 2);
3546 ctx->r = ENC_SYM_DOT(((0x76) << 4) | 0x00000000u);
3547 return;
3548 case TOKDONTCARE6u:
3549 lbm_stack_drop(&ctx->K, 2);
3550 ctx->r = ENC_SYM_DONTCARE(((0x9) << 4) | 0x00000000u);
3551 return;
3552 case TOKQUOTE7u:
3553 do_next = READ_QUOTE_RESULT(((21) << 2) | 0xF8000001u);
3554 break;
3555 case TOKBACKQUOTE8u:
3556 sptr[0] = QQ_EXPAND_START(((35) << 2) | 0xF8000001u);
3557 sptr[1] = stream;
3558 stack_push_2(&ctx->K, lbm_enc_u(0), READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
3559 ctx->app_cont = true1;
3560 return;
3561 case TOKCOMMAAT9u:
3562 do_next = READ_COMMAAT_RESULT(((22) << 2) | 0xF8000001u);
3563 break;
3564 case TOKCOMMA10u:
3565 do_next = READ_COMMA_RESULT(((23) << 2) | 0xF8000001u);
3566 break;
3567 case TOKMATCHANY11u:
3568 lbm_stack_drop(&ctx->K, 2);
3569 ctx->r = ENC_SYM_MATCH_ANY(((0x41) << 4) | 0x00000000u);
3570 return;
3571 case TOKOPENCURL12u:
3572 sptr[0] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
3573 sptr[1] = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
3574 stack_push_2(&ctx->K,
3575 stream,
3576 READ_APPEND_CONTINUE(((16) << 2) | 0xF8000001u));
3577 ctx->r = ENC_SYM_PROGN(((0x102) << 4) | 0x00000000u);
3578 return;
3579 case TOKCLOSECURL13u:
3580 lbm_stack_drop(&ctx->K, 2);
3581 ctx->r = ENC_SYM_CLOSEPAR(((0x71) << 4) | 0x00000000u);
3582 return;
3583 case TOKCONSTSTART14u:
3584 ctx->flags |= EVAL_CPS_CONTEXT_FLAG_CONST(uint32_t)0x2;
3585 sptr[0] = stream;
3586 sptr[1] = lbm_enc_u(0);
3587 stack_push(&ctx->K, READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
3588 ctx->app_cont = true1;
3589 return;
3590 case TOKCONSTEND15u:
3591 ctx->flags &= ~EVAL_CPS_CONTEXT_FLAG_CONST(uint32_t)0x2;
3592 sptr[0] = stream;
3593 sptr[1] = lbm_enc_u(0);
3594 stack_push(&ctx->K, READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
3595 ctx->app_cont = true1;
3596 return;
3597 case TOKCONSTSYMSTR16u:
3598 ctx->flags |= EVAL_CPS_CONTEXT_FLAG_CONST_SYMBOL_STRINGS(uint32_t)0x4;
3599 sptr[0] = stream;
3600 sptr[1] = lbm_enc_u(0);
3601 stack_push(&ctx->K, READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
3602 ctx->app_cont = true1;
3603 return;
3604 default:
3605 read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
3606 }
3607 sptr[0] = do_next;
3608 sptr[1] = stream;
3609 stack_push_2(&ctx->K, lbm_enc_u(0), READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
3610 ctx->app_cont = true1;
3611 return;
3612 } else if (n < 0) goto retry_token;
3613
3614 /*
3615 * STRING
3616 */
3617 n = tok_string(chan, &string_len);
3618 if (n >= 2) {
3619 lbm_channel_drop(chan, (unsigned int)n);
3620 if (!lbm_heap_allocate_array(&res, (unsigned int)(string_len+1))) {
3621 gc();
3622 if (!lbm_heap_allocate_array(&res, (unsigned int)(string_len+1))) {
3623 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
3624 }
3625 }
3626 lbm_array_header_t *arr = (lbm_array_header_t*)get_car(res);
3627 char *data = (char*)arr->data;
3628 memset(data,0, string_len + 1);
3629 memcpy(data, tokpar_sym_str, string_len);
3630 lbm_stack_drop(&ctx->K, 2);
3631 ctx->r = res;
3632 ctx->app_cont = true1;
3633 return;
3634 } else if (n < 0) goto retry_token;
3635
3636 /*
3637 * FLOAT
3638 */
3639 token_float f_val;
3640 n = tok_double(chan, &f_val);
3641 if (n > 0) {
3642 lbm_channel_drop(chan, (unsigned int) n);
3643 switch(f_val.type) {
3644 case TOKTYPEF32107u:
3645 WITH_GC(res, lbm_enc_float((float)f_val.value))(res) = (lbm_enc_float((float)f_val.value)); if (lbm_is_symbol_merror
((res))) { gc(); (res) = (lbm_enc_float((float)f_val.value));
if (lbm_is_symbol_merror((res))) { error_ctx((((0x23) <<
4) | 0x00000000u)); } }
;
3646 break;
3647 case TOKTYPEF64108u:
3648 res = lbm_enc_double(f_val.value);
3649 break;
3650 default:
3651 read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
3652 }
3653 lbm_stack_drop(&ctx->K, 2);
3654 ctx->r = res;
3655 ctx->app_cont = true1;
3656 return;
3657 } else if (n < 0) goto retry_token;
3658
3659 /*
3660 * INTEGER
3661 */
3662 token_int int_result;
3663 n = tok_integer(chan, &int_result);
3664 if (n > 0) {
3665 lbm_channel_drop(chan, (unsigned int)n);
3666 switch(int_result.type) {
3667 case TOKTYPEBYTE100u:
3668 res = lbm_enc_char((uint8_t)(int_result.negative ? -int_result.value : int_result.value));
3669 break;
3670 case TOKTYPEI101u:
3671 res = lbm_enc_i((lbm_int)(int_result.negative ? -int_result.value : int_result.value));
3672 break;
3673 case TOKTYPEU102u:
3674 res = lbm_enc_u((lbm_uint)(int_result.negative ? -int_result.value : int_result.value));
3675 break;
3676 case TOKTYPEI32103u:
3677 WITH_GC(res, lbm_enc_i32((int32_t)(int_result.negative ? -int_result.value : int_result.value)))(res) = (lbm_enc_i32((int32_t)(int_result.negative ? -int_result
.value : int_result.value))); if (lbm_is_symbol_merror((res))
) { gc(); (res) = (lbm_enc_i32((int32_t)(int_result.negative ?
-int_result.value : int_result.value))); if (lbm_is_symbol_merror
((res))) { error_ctx((((0x23) << 4) | 0x00000000u)); } }
;
3678 break;
3679 case TOKTYPEU32104u:
3680 WITH_GC(res,lbm_enc_u32((uint32_t)(int_result.negative ? -int_result.value : int_result.value)))(res) = (lbm_enc_u32((uint32_t)(int_result.negative ? -int_result
.value : int_result.value))); if (lbm_is_symbol_merror((res))
) { gc(); (res) = (lbm_enc_u32((uint32_t)(int_result.negative
? -int_result.value : int_result.value))); if (lbm_is_symbol_merror
((res))) { error_ctx((((0x23) << 4) | 0x00000000u)); } }
;
3681 break;
3682 case TOKTYPEI64105u:
3683 WITH_GC(res,lbm_enc_i64((int64_t)(int_result.negative ? -int_result.value : int_result.value)))(res) = (lbm_enc_i64((int64_t)(int_result.negative ? -int_result
.value : int_result.value))); if (lbm_is_symbol_merror((res))
) { gc(); (res) = (lbm_enc_i64((int64_t)(int_result.negative ?
-int_result.value : int_result.value))); if (lbm_is_symbol_merror
((res))) { error_ctx((((0x23) << 4) | 0x00000000u)); } }
;
3684 break;
3685 case TOKTYPEU64106u:
3686 WITH_GC(res,lbm_enc_u64((uint64_t)(int_result.negative ? -int_result.value : int_result.value)))(res) = (lbm_enc_u64((uint64_t)(int_result.negative ? -int_result
.value : int_result.value))); if (lbm_is_symbol_merror((res))
) { gc(); (res) = (lbm_enc_u64((uint64_t)(int_result.negative
? -int_result.value : int_result.value))); if (lbm_is_symbol_merror
((res))) { error_ctx((((0x23) << 4) | 0x00000000u)); } }
;
3687 break;
3688 default:
3689 read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
3690 }
3691 lbm_stack_drop(&ctx->K, 2);
3692 ctx->r = res;
3693 ctx->app_cont = true1;
3694 return;
3695 } else if (n < 0) goto retry_token;
3696
3697 /*
3698 * SYMBOL
3699 */
3700 n = tok_symbol(chan);
3701 if (n > 0) {
3702 lbm_channel_drop(chan, (unsigned int) n);
3703 lbm_uint symbol_id;
3704
3705 if (lbm_get_symbol_by_name(tokpar_sym_str, &symbol_id)) {
3706 res = lbm_enc_sym(symbol_id);
3707 } else {
3708 int r = 0;
3709 if (strncmp(tokpar_sym_str,"ext-",4) == 0) {
3710 lbm_uint ext_id;
3711 lbm_uint ext_name_len = strlen(tokpar_sym_str)+1;
3712 char *ext_name = lbm_malloc(ext_name_len);
3713 if (!ext_name) {
3714 gc();
3715 ext_name = lbm_malloc(ext_name_len);
3716 }
3717 if (ext_name) {
3718 memcpy(ext_name, tokpar_sym_str, ext_name_len);
3719 r = lbm_add_extension(ext_name, lbm_extensions_default);
3720 if (!lbm_lookup_extension_id(ext_name, &ext_id)) {
3721 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
3722 }
3723 symbol_id = ext_id;
3724 } else {
3725 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
3726 }
3727 } else {
3728 if (ctx->flags & EVAL_CPS_CONTEXT_FLAG_CONST_SYMBOL_STRINGS(uint32_t)0x4 &&
3729 ctx->flags & EVAL_CPS_CONTEXT_FLAG_INCREMENTAL_READ(uint32_t)0x8) {
3730 r = lbm_add_symbol_flash(tokpar_sym_str, &symbol_id);
3731 } else {
3732 r = lbm_add_symbol(tokpar_sym_str, &symbol_id);
3733 if (!r) {
3734 gc();
3735 r = lbm_add_symbol(tokpar_sym_str, &symbol_id);
3736 }
3737 }
3738 }
3739 if (r) {
3740 res = lbm_enc_sym(symbol_id);
3741 } else {
3742 read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
3743 }
3744 }
3745 lbm_stack_drop(&ctx->K, 2);
3746 ctx->r = res;
3747 ctx->app_cont = true1;
3748 return;
3749 } else if (n == TOKENIZER_NEED_MORE-1) {
3750 goto retry_token;
3751 } else if (n <= TOKENIZER_STRING_ERROR-2) {
3752 read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
3753 }
3754
3755 /*
3756 * CHAR
3757 */
3758 char c_val;
3759 n = tok_char(chan, &c_val);
3760 if(n > 0) {
3761 lbm_channel_drop(chan,(unsigned int) n);
3762 lbm_stack_drop(&ctx->K, 2);
3763 ctx->r = lbm_enc_char((uint8_t)c_val);
3764 ctx->app_cont = true1;
3765 return;
3766 }else if (n < 0) goto retry_token;
3767
3768 read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
3769
3770 retry_token:
3771 if (n == TOKENIZER_NEED_MORE-1) {
3772 sptr[0] = stream;
3773 sptr[1] = lbm_enc_u(0);
3774 stack_push(&ctx->K, READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
3775 yield_ctx(EVAL_CPS_MIN_SLEEP200);
3776 return;
3777 }
3778 read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
3779}
3780
3781static void cont_read_start_array(eval_context_t *ctx) {
3782 lbm_value *sptr = get_stack_ptr(ctx, 1);
3783 lbm_value stream = sptr[0];
3784
3785 lbm_char_channel_t *str = lbm_dec_channel(stream);
3786 if (str == NULL((void*)0) || str->state == NULL((void*)0)) {
3787 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
3788 }
3789
3790 lbm_uint num_free = lbm_memory_longest_free();
3791 lbm_uint initial_size = (lbm_uint)((float)num_free * 0.9);
3792 if (initial_size == 0) {
3793 gc();
3794 num_free = lbm_memory_longest_free();
3795 initial_size = (lbm_uint)((float)num_free * 0.9);
3796 if (initial_size == 0) {
3797 lbm_channel_reader_close(str);
3798 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
3799 }
3800 }
3801
3802 if (lbm_is_number(ctx->r)) {
3803 lbm_value array;
3804 initial_size = sizeof(lbm_uint) * initial_size;
3805
3806 if (!lbm_heap_allocate_array(&array, initial_size)) {
3807 lbm_set_error_reason("Out of memory while reading.");
3808 lbm_channel_reader_close(str);
3809 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
3810 // NOTE: If array is not created evaluation ends here.
3811 // Static analysis seems unaware.
3812 }
3813
3814 sptr[0] = array;
3815 stack_push_3(&ctx->K, lbm_enc_u(initial_size), lbm_enc_u(0), stream);
3816 stack_push(&ctx->K, READ_APPEND_ARRAY(((25) << 2) | 0xF8000001u));
3817 ctx->app_cont = true1;
3818 } else {
3819 lbm_channel_reader_close(str);
3820 read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
3821 }
3822}
3823
3824static void cont_read_append_array(eval_context_t *ctx) {
3825 lbm_uint *sptr = get_stack_ptr(ctx, 4);
3826
3827 lbm_value array = sptr[0];
3828 lbm_value size = lbm_dec_as_u32(sptr[1]);
3829 lbm_value ix = lbm_dec_as_u32(sptr[2]);
3830 lbm_value stream = sptr[3];
3831
3832 if (ix >= (size - 1)) {
3833 error_ctx(ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
3834 }
3835
3836 // get_car can return nil. Whose value is 0!
3837 // So static Analysis is right about this being a potential NULL pointer.
3838 // However, if the array was created correcly to begin with, it should be fine.
3839 lbm_value arr_car = get_car(array);
3840 lbm_array_header_t *arr = (lbm_array_header_t*)arr_car;
3841
3842 if (lbm_is_number(ctx->r)) {
3843 ((uint8_t*)arr->data)[ix] = (uint8_t)lbm_dec_as_u32(ctx->r);
3844
3845 sptr[2] = lbm_enc_u(ix + 1);
3846 stack_push_4(&ctx->K, READ_APPEND_ARRAY(((25) << 2) | 0xF8000001u), stream, lbm_enc_u(0), READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
3847 ctx->app_cont = true1;
3848 } else if (lbm_is_symbol(ctx->r) && lbm_dec_sym(ctx->r) == SYM_CLOSEBRACK0x81) {
3849 lbm_uint array_size = ix / sizeof(lbm_uint);
3850
3851 if (ix % sizeof(lbm_uint) != 0) {
3852 array_size = array_size + 1;
3853 }
3854 lbm_memory_shrink((lbm_uint*)arr->data, array_size);
3855 arr->size = ix;
3856 lbm_stack_drop(&ctx->K, 4);
3857 ctx->r = array;
3858 ctx->app_cont = true1;
3859 } else {
3860 error_ctx(ENC_SYM_TERROR(((0x21) << 4) | 0x00000000u));
3861 }
3862}
3863
3864static void cont_read_append_continue(eval_context_t *ctx) {
3865 lbm_value *sptr = get_stack_ptr(ctx, 3);
3866
3867 lbm_value first_cell = sptr[0];
3868 lbm_value last_cell = sptr[1];
3869 lbm_value stream = sptr[2];
3870
3871 lbm_char_channel_t *str = lbm_dec_channel(stream);
3872 if (str == NULL((void*)0) || str->state == NULL((void*)0)) {
3873 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
3874 }
3875
3876 if (lbm_type_of(ctx->r) == LBM_TYPE_SYMBOL0x00000000u) {
3877
3878 switch(lbm_dec_sym(ctx->r)) {
3879 case SYM_CLOSEPAR0x71:
3880 if (lbm_type_of(last_cell) == LBM_TYPE_CONS0x10000000u) {
3881 lbm_set_cdr(last_cell, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u)); // terminate the list
3882 ctx->r = first_cell;
3883 } else {
3884 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
3885 }
3886 lbm_stack_drop(&ctx->K, 3);
3887 /* Skip reading another token and apply the continuation */
3888 ctx->app_cont = true1;
3889 return;
3890 case SYM_DOT0x76:
3891 stack_push(&ctx->K, READ_DOT_TERMINATE(((19) << 2) | 0xF8000001u));
3892 stack_push_3(&ctx->K, stream, lbm_enc_u(0), READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
3893 ctx->app_cont = true1;
3894 return;
3895 }
3896 }
3897 lbm_value new_cell = cons_with_gc(ctx->r, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
3898 if (lbm_is_symbol_merror(new_cell)) {
3899 lbm_channel_reader_close(str);
3900 read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
3901 return;
3902 }
3903 if (lbm_type_of(last_cell) == LBM_TYPE_CONS0x10000000u) {
3904 lbm_set_cdr(last_cell, new_cell);
3905 last_cell = new_cell;
3906 } else {
3907 first_cell = last_cell = new_cell;
3908 }
3909 sptr[0] = first_cell;
3910 sptr[1] = last_cell;
3911 sptr[2] = stream; // unchanged.
3912 stack_push(&ctx->K, READ_APPEND_CONTINUE(((16) << 2) | 0xF8000001u));
3913 stack_push_3(&ctx->K, stream, lbm_enc_u(0), READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
3914 ctx->app_cont = true1;
3915}
3916
3917static void cont_read_eval_continue(eval_context_t *ctx) {
3918 lbm_value env;
3919 lbm_value stream;
3920 lbm_pop_2(&ctx->K, &env, &stream);
3921
3922 lbm_char_channel_t *str = lbm_dec_channel(stream);
3923 if (str == NULL((void*)0) || str->state == NULL((void*)0)) {
3924 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
3925 }
3926
3927 ctx->row1 = (lbm_int)str->row(str);
3928
3929 if (lbm_type_of(ctx->r) == LBM_TYPE_SYMBOL0x00000000u) {
3930
3931 switch(lbm_dec_sym(ctx->r)) {
3932 case SYM_CLOSEPAR0x71:
3933 ctx->app_cont = true1;
3934 return;
3935 case SYM_DOT0x76:
3936 stack_push(&ctx->K, READ_DOT_TERMINATE(((19) << 2) | 0xF8000001u));
3937 stack_push_3(&ctx->K, stream, lbm_enc_u(0), READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
3938 ctx->app_cont = true1;
3939 return;
3940 }
3941 }
3942
3943 stack_push_3(&ctx->K, stream, env, READ_EVAL_CONTINUE(((17) << 2) | 0xF8000001u));
3944 stack_push_3(&ctx->K, stream, lbm_enc_u(1), READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
3945
3946 ctx->curr_env = env;
3947 ctx->curr_exp = ctx->r;
3948}
3949
3950static void cont_read_expect_closepar(eval_context_t *ctx) {
3951 lbm_value res;
3952 lbm_value stream;
3953
3954 lbm_pop_2(&ctx->K, &res, &stream);
3955
3956 lbm_char_channel_t *str = lbm_dec_channel(stream);
3957 if (str == NULL((void*)0) || str->state == NULL((void*)0)) {
3958 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
3959 }
3960
3961 if (lbm_type_of(ctx->r) == LBM_TYPE_SYMBOL0x00000000u &&
3962 lbm_dec_sym(ctx->r) == SYM_CLOSEPAR0x71) {
3963 ctx->r = res;
3964 ctx->app_cont = true1;
3965 } else {
3966 lbm_channel_reader_close(str);
3967 lbm_set_error_reason((char*)lbm_error_str_parse_close);
3968 read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
3969 }
3970}
3971
3972static void cont_read_dot_terminate(eval_context_t *ctx) {
3973 lbm_value *sptr = get_stack_ptr(ctx, 3);
3974
3975 lbm_value first_cell = sptr[0];
3976 lbm_value last_cell = sptr[1];
3977 lbm_value stream = sptr[2];
3978
3979 lbm_char_channel_t *str = lbm_dec_channel(stream);
3980 if (str == NULL((void*)0) || str->state == NULL((void*)0)) {
3981 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
3982 }
3983
3984 lbm_stack_drop(&ctx->K ,3);
3985
3986 if (lbm_type_of(ctx->r) == LBM_TYPE_SYMBOL0x00000000u &&
3987 (lbm_dec_sym(ctx->r) == SYM_CLOSEPAR0x71 ||
3988 lbm_dec_sym(ctx->r) == SYM_DOT0x76)) {
3989 lbm_channel_reader_close(str);
3990 lbm_set_error_reason((char*)lbm_error_str_parse_dot);
3991 read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
3992 } else {
3993 if (lbm_is_cons(last_cell)) {
3994 lbm_set_cdr(last_cell, ctx->r);
3995 ctx->r = first_cell;
3996 stack_push_3(&ctx->K,
3997 stream,
3998 ctx->r,
3999 READ_EXPECT_CLOSEPAR(((18) << 2) | 0xF8000001u));
4000 stack_push_3(&ctx->K, stream, lbm_enc_u(0), READ_NEXT_TOKEN(((15) << 2) | 0xF8000001u));
4001 ctx->app_cont = true1;
4002 } else {
4003 lbm_channel_reader_close(str);
4004 lbm_set_error_reason((char*)lbm_error_str_parse_dot);
4005 read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
4006 }
4007 }
4008}
4009
4010static void cont_read_done(eval_context_t *ctx) {
4011 lbm_value stream;
4012 lbm_value restore_incremental;
4013 lbm_pop_2(&ctx->K, &stream ,&restore_incremental);
4014
4015 if (restore_incremental == ENC_SYM_TRUE(((0x2) << 4) | 0x00000000u)) {
4016 ctx->flags |= EVAL_CPS_CONTEXT_FLAG_INCREMENTAL_READ(uint32_t)0x8;
4017 } else {
4018 ctx->flags &= ~EVAL_CPS_CONTEXT_FLAG_INCREMENTAL_READ(uint32_t)0x8;
4019 }
4020
4021 lbm_char_channel_t *str = lbm_dec_channel(stream);
4022 if (str == NULL((void*)0) || str->state == NULL((void*)0)) {
4023 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
4024 }
4025
4026 lbm_channel_reader_close(str);
4027 if (lbm_is_symbol(ctx->r)) {
4028 lbm_uint sym_val = lbm_dec_sym(ctx->r);
4029 if (sym_val >= TOKENIZER_SYMBOLS_START0x70 &&
4030 sym_val <= TOKENIZER_SYMBOLS_END0x85) {
4031 read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
4032 }
4033 }
4034
4035 ctx->row0 = -1;
4036 ctx->row1 = -1;
4037 ctx->app_cont = true1;
4038}
4039
4040static void cont_read_quote_result(eval_context_t *ctx) {
4041 lbm_value cell;
4042 WITH_GC(cell, lbm_heap_allocate_list_init(2,(cell) = (lbm_heap_allocate_list_init(2, (((0x100) << 4
) | 0x00000000u), ctx->r)); if (lbm_is_symbol_merror((cell
))) { gc(); (cell) = (lbm_heap_allocate_list_init(2, (((0x100
) << 4) | 0x00000000u), ctx->r)); if (lbm_is_symbol_merror
((cell))) { error_ctx((((0x23) << 4) | 0x00000000u)); }
}
4043 ENC_SYM_QUOTE,(cell) = (lbm_heap_allocate_list_init(2, (((0x100) << 4
) | 0x00000000u), ctx->r)); if (lbm_is_symbol_merror((cell
))) { gc(); (cell) = (lbm_heap_allocate_list_init(2, (((0x100
) << 4) | 0x00000000u), ctx->r)); if (lbm_is_symbol_merror
((cell))) { error_ctx((((0x23) << 4) | 0x00000000u)); }
}
4044 ctx->r))(cell) = (lbm_heap_allocate_list_init(2, (((0x100) << 4
) | 0x00000000u), ctx->r)); if (lbm_is_symbol_merror((cell
))) { gc(); (cell) = (lbm_heap_allocate_list_init(2, (((0x100
) << 4) | 0x00000000u), ctx->r)); if (lbm_is_symbol_merror
((cell))) { error_ctx((((0x23) << 4) | 0x00000000u)); }
}
;
4045 ctx->r = cell;
4046 ctx->app_cont = true1;
4047}
4048
4049static void cont_read_commaat_result(eval_context_t *ctx) {
4050 lbm_value cell2 = cons_with_gc(ctx->r,ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4051 lbm_value cell1 = cons_with_gc(ENC_SYM_COMMAAT(((0x74) << 4) | 0x00000000u), cell2, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4052 ctx->r = cell1;
4053 ctx->app_cont = true1;
4054}
4055
4056static void cont_read_comma_result(eval_context_t *ctx) {
4057 lbm_value cell2 = cons_with_gc(ctx->r,ENC_SYM_NIL(((0x0) << 4) | 0x00000000u),ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4058 lbm_value cell1 = cons_with_gc(ENC_SYM_COMMA(((0x73) << 4) | 0x00000000u), cell2, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4059 ctx->r = cell1;
4060 ctx->app_cont = true1;
4061}
4062
4063static void cont_application_start(eval_context_t *ctx) {
4064
4065 /* sptr[0] = env
4066 * sptr[1] = args
4067 * ctx->r = function
4068 */
4069
4070 if (lbm_is_symbol(ctx->r)) {
4071 stack_push(&ctx->K, lbm_enc_u(0));
4072 cont_application_args(ctx);
4073 } else if (lbm_is_cons(ctx->r)) {
4074 lbm_uint *sptr = get_stack_ptr(ctx, 2);
4075 lbm_value args = (lbm_value)sptr[1];
4076 switch (get_car(ctx->r)) {
4077 case ENC_SYM_CLOSURE(((0x10F) << 4) | 0x00000000u): {
4078 lbm_value cl[3];
4079 extract_n(get_cdr(ctx->r), cl, 3);
4080 lbm_value arg_env = (lbm_value)sptr[0];
4081 lbm_value arg0, arg_rest;
4082 get_car_and_cdr(args, &arg0, &arg_rest);
4083 sptr[1] = cl[CLO_BODY1];
4084 bool_Bool a_nil = lbm_is_symbol_nil(args);
4085 bool_Bool p_nil = lbm_is_symbol_nil(cl[CLO_PARAMS0]);
4086
4087 if (!a_nil && !p_nil) {
4088 lbm_value *reserved = stack_reserve(ctx, 4);
4089 reserved[0] = cl[CLO_ENV2];
4090 reserved[1] = cl[CLO_PARAMS0];
4091 reserved[2] = arg_rest;
4092 reserved[3] = CLOSURE_ARGS(((13) << 2) | 0xF8000001u);
4093 ctx->curr_exp = arg0;
4094 ctx->curr_env = arg_env;
4095 return;
4096 }
4097 if (a_nil && p_nil) {
4098 // No params, No args
4099 lbm_stack_drop(&ctx->K, 2);
4100 ctx->curr_exp = cl[CLO_BODY1];
4101 ctx->curr_env = cl[CLO_ENV2];
4102 return;
4103 }
4104 if (p_nil) {
4105 lbm_value rest_binder = allocate_binding(ENC_SYM_REST_ARGS(((0x30015) << 4) | 0x00000000u), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), cl[CLO_ENV2]);
4106 lbm_value *reserved = stack_reserve(ctx, 4);
4107 sptr[0] = arg_env;
4108 sptr[1] = cl[CLO_BODY1];
4109 reserved[0] = rest_binder;
4110 reserved[1] = get_cdr(args);
4111 reserved[2] = get_car(rest_binder);
4112 reserved[3] = CLOSURE_ARGS_REST(((45) << 2) | 0xF8000001u);
4113 ctx->curr_exp = get_car(args);
4114 ctx->curr_env = arg_env;
4115 return;
4116 }
4117 lbm_set_error_reason((char*)lbm_error_str_num_args);
4118 error_at_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u), ctx->r);
4119 } break;
4120 case ENC_SYM_CONT(((0x10E) << 4) | 0x00000000u):{
4121 /* Continuation created using call-cc.
4122 * ((SYM_CONT . cont-array) arg0 )
4123 */
4124 lbm_value c = get_cdr(ctx->r); /* should be the continuation array*/
4125
4126 if (!lbm_is_array_r(c)) {
4127 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
4128 }
4129
4130 lbm_uint arg_count = lbm_list_length(args);
4131 lbm_value arg = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
4132 switch (arg_count) {
4133 case 0:
4134 arg = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
4135 break;
4136 case 1:
4137 arg = get_car(args);
4138 break;
4139 default:
4140 lbm_set_error_reason((char*)lbm_error_str_num_args);
4141 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
4142 }
4143 lbm_stack_clear(&ctx->K);
4144
4145 lbm_array_header_t *arr = (lbm_array_header_t*)get_car(c);
4146
4147 ctx->K.sp = arr->size / sizeof(lbm_uint);
4148 memcpy(ctx->K.data, arr->data, arr->size);
4149
4150 ctx->curr_exp = arg;
4151 break;
4152 }
4153 case ENC_SYM_MACRO(((0x10D) << 4) | 0x00000000u):{
4154 /*
4155 * Perform macro expansion.
4156 * Macro expansion is really just evaluation in an
4157 * environment augmented with the unevaluated expressions passed
4158 * as arguments.
4159 */
4160 lbm_value env = (lbm_value)sptr[0];
4161
4162 lbm_value curr_param = get_cadr(ctx->r);
4163 lbm_value curr_arg = args;
4164 lbm_value expand_env = env;
4165 while (lbm_is_cons(curr_param) &&
4166 lbm_is_cons(curr_arg)) {
4167 lbm_value car_curr_param, cdr_curr_param;
4168 lbm_value car_curr_arg, cdr_curr_arg;
4169 get_car_and_cdr(curr_param, &car_curr_param, &cdr_curr_param);
4170 get_car_and_cdr(curr_arg, &car_curr_arg, &cdr_curr_arg);
4171
4172 lbm_value entry = cons_with_gc(car_curr_param, car_curr_arg, expand_env);
4173 lbm_value aug_env = cons_with_gc(entry, expand_env,ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4174 expand_env = aug_env;
4175
4176 curr_param = cdr_curr_param;
4177 curr_arg = cdr_curr_arg;
4178 }
4179 /* Two rounds of evaluation is performed.
4180 * First to instantiate the arguments into the macro body.
4181 * Second to evaluate the resulting program.
4182 */
4183 sptr[1] = EVAL_R(((11) << 2) | 0xF8000001u);
4184 lbm_value exp = get_cadr(get_cdr(ctx->r));
4185 ctx->curr_exp = exp;
4186 ctx->curr_env = expand_env;
4187 } break;
4188 default:
4189 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
4190 }
4191 } else {
4192 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
4193 }
4194}
4195
4196static void cont_eval_r(eval_context_t* ctx) {
4197 lbm_value env;
4198 lbm_pop(&ctx->K, &env);
4199 ctx->curr_exp = ctx->r;
4200 ctx->curr_env = env;
4201}
4202
4203/* progn + var stack
4204 sp-5 : env
4205 sp-4 : 0
4206 sp-3 : rest
4207 sp-2 : PROGN_REST
4208 sp-1 : symbol
4209 */
4210static void cont_progn_var(eval_context_t* ctx) {
4211
4212 lbm_value sym;
4213
4214 lbm_pop(&ctx->K, &sym);
4215
4216 if (ctx->K.sp >= 4) { // could potentially be inside of an progn
4217 lbm_value sv = ctx->K.data[ctx->K.sp - 1];
4218 if (IS_CONTINUATION(sv)(((sv) & 0xF8000001u) == 0xF8000001u) &&
4219 (sv == PROGN_REST(((4) << 2) | 0xF8000001u))) {
4220 lbm_uint sp = ctx->K.sp;
4221 uint32_t is_copied = lbm_dec_as_u32(ctx->K.data[sp - 3]);
4222 if (is_copied == 0) {
4223 lbm_value env;
4224 WITH_GC(env, lbm_env_copy_spine(ctx->K.data[sp - 4]))(env) = (lbm_env_copy_spine(ctx->K.data[sp - 4])); if (lbm_is_symbol_merror
((env))) { gc(); (env) = (lbm_env_copy_spine(ctx->K.data[sp
- 4])); if (lbm_is_symbol_merror((env))) { error_ctx((((0x23
) << 4) | 0x00000000u)); } }
;
4225 ctx->K.data[sp - 3] = lbm_enc_u(1);
4226 ctx->K.data[sp - 4] = env;
4227 }
4228 lbm_value new_env = ctx->K.data[sp - 4];
4229 lbm_value tmp;
4230 WITH_GC(tmp, lbm_env_set_functional(new_env, sym, ctx->r))(tmp) = (lbm_env_set_functional(new_env, sym, ctx->r)); if
(lbm_is_symbol_merror((tmp))) { gc(); (tmp) = (lbm_env_set_functional
(new_env, sym, ctx->r)); if (lbm_is_symbol_merror((tmp))) {
error_ctx((((0x23) << 4) | 0x00000000u)); } }
;
4231 ctx->K.data[ctx->K.sp - 4] = tmp;
4232 ctx->app_cont = true1; // return to progn body
4233 return;
4234 }
4235 }
4236 lbm_set_error_reason((char*)lbm_error_str_var_outside_progn);
4237 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
4238}
4239
4240static void cont_setq(eval_context_t *ctx) {
4241 lbm_value sym;
4242 lbm_value env;
4243 lbm_pop_2(&ctx->K, &sym, &env);
4244 lbm_value res;
4245 WITH_GC(res, perform_setvar(sym, ctx->r, env))(res) = (perform_setvar(sym, ctx->r, env)); if (lbm_is_symbol_merror
((res))) { gc(); (res) = (perform_setvar(sym, ctx->r, env)
); if (lbm_is_symbol_merror((res))) { error_ctx((((0x23) <<
4) | 0x00000000u)); } }
;
4246 ctx->r = res;
4247 ctx->app_cont = true1;
4248}
4249
4250lbm_flash_status request_flash_storage_cell(lbm_value val, lbm_value *res) {
4251
4252 lbm_value flash_cell;
4253 lbm_flash_status s = lbm_allocate_const_cell(&flash_cell);
4254 if (s != LBM_FLASH_WRITE_OK)
4255 return s;
4256 lbm_value new_val = val;
4257 new_val &= ~LBM_PTR_VAL_MASK0x03FFFFFCu; // clear the value part of the ptr
4258 new_val |= (flash_cell & LBM_PTR_VAL_MASK0x03FFFFFCu);
4259 new_val |= LBM_PTR_TO_CONSTANT_BIT0x04000000u;
4260 *res = new_val;
4261 return s;
4262}
4263
4264static void cont_move_to_flash(eval_context_t *ctx) {
4265
4266 lbm_value args;
4267 lbm_pop(&ctx->K, &args);
4268
4269 if (lbm_is_symbol_nil(args)) {
4270 // Done looping over arguments. return true.
4271 ctx->r = ENC_SYM_TRUE(((0x2) << 4) | 0x00000000u);
4272 ctx->app_cont = true1;
4273 return;
4274 }
4275
4276 lbm_value first_arg, rest;
4277 get_car_and_cdr(args, &first_arg, &rest);
4278
4279 lbm_value val;
4280 if (lbm_is_symbol(first_arg) && lbm_global_env_lookup(&val, first_arg)) {
4281 // Prepare to copy the rest of the arguments when done with first.
4282 stack_push_2(&ctx->K, rest, MOVE_TO_FLASH(((31) << 2) | 0xF8000001u));
4283 if (lbm_is_ptr(val) &&
4284 (!(val & LBM_PTR_TO_CONSTANT_BIT0x04000000u))) {
4285 stack_push_2(&ctx->K, first_arg, SET_GLOBAL_ENV(((1) << 2) | 0xF8000001u));
4286 stack_push(&ctx->K, MOVE_VAL_TO_FLASH_DISPATCH(((32) << 2) | 0xF8000001u));
4287 ctx->r = val;
4288 }
4289 ctx->app_cont = true1;
4290 return;
4291 }
4292 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
4293}
4294
4295static void cont_move_val_to_flash_dispatch(eval_context_t *ctx) {
4296
4297 lbm_value val = ctx->r;
4298
4299 if (lbm_is_cons(val)) {
4300 lbm_value flash_cell = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
4301 handle_flash_status(request_flash_storage_cell(val, &flash_cell));
4302 stack_push_4(&ctx->K, flash_cell, flash_cell, get_cdr(val), MOVE_LIST_TO_FLASH(((33) << 2) | 0xF8000001u));
4303 stack_push(&ctx->K, MOVE_VAL_TO_FLASH_DISPATCH(((32) << 2) | 0xF8000001u));
4304 ctx->r = get_car(val);
4305 ctx->app_cont = true1;
4306 return;
4307 }
4308
4309 if (lbm_is_ptr(val) && (val & LBM_PTR_TO_CONSTANT_BIT0x04000000u)) {
4310 ctx->r = val;
4311 ctx->app_cont = true1;
4312 return;
4313 }
4314
4315 if (lbm_is_ptr(val)) {
4316 // Request a flash storage cell.
4317 lbm_value flash_cell = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
4318 handle_flash_status(request_flash_storage_cell(val, &flash_cell));
4319 ctx->r = flash_cell;
4320 lbm_cons_t *ref = lbm_ref_cell(val);
4321 if (lbm_type_of(ref->cdr) == LBM_TYPE_SYMBOL0x00000000u) {
4322 switch (lbm_dec_sym(ref->cdr)) {
4323 case SYM_RAW_I_TYPE0x31: /* fall through */
4324 case SYM_RAW_U_TYPE0x32:
4325 case SYM_RAW_F_TYPE0x33:
4326 handle_flash_status(write_const_car(flash_cell, ref->car));
4327 handle_flash_status(write_const_cdr(flash_cell, ref->cdr));
4328 break;
4329 case SYM_IND_I_TYPE0x34: /* fall through */
4330 case SYM_IND_U_TYPE0x35:
4331 case SYM_IND_F_TYPE0x36: {
4332#ifndef LBM64
4333 /* 64 bit values are in lbm mem on 32bit platforms. */
4334 lbm_uint *lbm_mem_ptr = (lbm_uint*)ref->car;
4335 lbm_uint flash_ptr;
4336
4337 handle_flash_status(lbm_write_const_raw(lbm_mem_ptr, 2, &flash_ptr));
4338 handle_flash_status(write_const_car(flash_cell, flash_ptr));
4339 handle_flash_status(write_const_cdr(flash_cell, ref->cdr));
4340#else
4341 // There are no indirect types in LBM64
4342 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
4343#endif
4344 } break;
4345 case SYM_ARRAY_TYPE0x30: {
4346 lbm_array_header_t *arr = (lbm_array_header_t*)ref->car;
4347 // arbitrary address: flash_arr.
4348 lbm_uint flash_arr;
4349 handle_flash_status(lbm_write_const_array_padded((uint8_t*)arr->data, arr->size, &flash_arr));
4350 lift_array_flash(flash_cell,
4351 (char *)flash_arr,
4352 arr->size);
4353 } break;
4354 case SYM_CHANNEL_TYPE0x37: /* fall through */
4355 case SYM_CUSTOM_TYPE0x38:
4356 lbm_set_error_reason((char *)lbm_error_str_flash_not_possible);
4357 error_ctx(ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u));
4358 }
4359 } else {
4360 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
4361 }
4362 ctx->r = flash_cell;
4363 ctx->app_cont = true1;
4364 return;
4365 }
4366 ctx->r = val;
4367 ctx->app_cont = true1;
4368}
4369
4370static void cont_move_list_to_flash(eval_context_t *ctx) {
4371
4372 // ctx->r holds the value that should go in car
4373
4374 lbm_value *sptr = get_stack_ptr(ctx, 3);
4375
4376 lbm_value fst = sptr[0];
4377 lbm_value lst = sptr[1];
4378 lbm_value val = sptr[2];
4379
4380 handle_flash_status(write_const_car(lst, ctx->r));
4381
4382 if (lbm_is_cons(val)) {
4383 // prepare cell for rest of list
4384 lbm_value rest_cell = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
4385 handle_flash_status(request_flash_storage_cell(val, &rest_cell));
4386 handle_flash_status(write_const_cdr(lst, rest_cell));
4387 sptr[1] = rest_cell;
4388 sptr[2] = get_cdr(val);
4389 stack_push(&ctx->K, MOVE_LIST_TO_FLASH(((33) << 2) | 0xF8000001u));
4390 stack_push(&ctx->K, MOVE_VAL_TO_FLASH_DISPATCH(((32) << 2) | 0xF8000001u));
4391 ctx->r = get_car(val);
4392 } else {
4393 sptr[0] = fst;
4394 sptr[1] = lst;
4395 sptr[2] = CLOSE_LIST_IN_FLASH(((34) << 2) | 0xF8000001u);
4396 stack_push(&ctx->K, MOVE_VAL_TO_FLASH_DISPATCH(((32) << 2) | 0xF8000001u));
4397 ctx->r = val;
4398 }
4399 ctx->app_cont = true1;
4400}
4401
4402static void cont_close_list_in_flash(eval_context_t *ctx) {
4403 lbm_value fst;
4404 lbm_value lst;
4405 lbm_pop_2(&ctx->K, &lst, &fst);
4406 lbm_value val = ctx->r;
4407 handle_flash_status(write_const_cdr(lst, val));
4408 ctx->r = fst;
4409 ctx->app_cont = true1;
4410}
4411
4412static void cont_qq_expand_start(eval_context_t *ctx) {
4413 stack_push_2(&ctx->K, ctx->r, QQ_EXPAND(((36) << 2) | 0xF8000001u));
4414 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
4415 ctx->app_cont = true1;
4416}
4417
4418lbm_value quote_it(lbm_value qquoted) {
4419 if (lbm_is_symbol(qquoted) &&
4420 lbm_is_special(qquoted)) return qquoted;
4421
4422 lbm_value val = cons_with_gc(qquoted, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4423 return cons_with_gc(ENC_SYM_QUOTE(((0x100) << 4) | 0x00000000u), val, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4424}
4425
4426bool_Bool is_append(lbm_value a) {
4427 return (lbm_is_cons(a) &&
4428 lbm_is_symbol(get_car(a)) &&
4429 (lbm_dec_sym(get_car(a)) == SYM_APPEND0x20015));
4430}
4431
4432lbm_value append(lbm_value front, lbm_value back) {
4433 if (lbm_is_symbol_nil(front)) return back;
4434 if (lbm_is_symbol_nil(back)) return front;
4435
4436 if (lbm_is_quoted_list(front) &&
4437 lbm_is_quoted_list(back)) {
4438 lbm_value f = get_car(get_cdr(front));
4439 lbm_value b = get_car(get_cdr(back));
4440 return quote_it(lbm_list_append(f, b));
4441 }
4442
4443 if (is_append(back) &&
4444 lbm_is_quoted_list(get_car(get_cdr(back))) &&
4445 lbm_is_quoted_list(front)) {
4446 lbm_value ql = get_car(get_cdr(back));
4447 lbm_value f = get_car(get_cdr(front));
4448 lbm_value b = get_car(get_cdr(ql));
4449
4450 lbm_value v = lbm_list_append(f, b);
4451 lbm_set_car(get_cdr(ql), v);
4452 return back;
4453 }
4454
4455 if (is_append(back)) {
4456 back = get_cdr(back);
4457 lbm_value new = cons_with_gc(front, back, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4458 return cons_with_gc(ENC_SYM_APPEND(((0x20015) << 4) | 0x00000000u), new, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4459 }
4460
4461 lbm_value t0, t1;
4462
4463 t0 = cons_with_gc(back, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), front);
4464 t1 = cons_with_gc(front, t0, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4465 return cons_with_gc(ENC_SYM_APPEND(((0x20015) << 4) | 0x00000000u), t1, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4466}
4467
4468/* Bawden's qq-expand implementation
4469(define (qq-expand x)
4470 (cond ((tag-comma? x)
4471 (tag-data x))
4472 ((tag-comma-atsign? x)
4473 (error "Illegal"))
4474 ((tag-backquote? x)
4475 (qq-expand
4476 (qq-expand (tag-data x))))
4477 ((pair? x)
4478 `(append
4479 ,(qq-expand-list (car x))
4480 ,(qq-expand (cdr x))))
4481 (else `',x)))
4482 */
4483static void cont_qq_expand(eval_context_t *ctx) {
4484 lbm_value qquoted;
4485 lbm_pop(&ctx->K, &qquoted);
4486
4487 switch(lbm_type_of(qquoted)) {
4488 case LBM_TYPE_CONS0x10000000u: {
4489 lbm_value car_val = get_car(qquoted);
4490 lbm_value cdr_val = get_cdr(qquoted);
4491 if (lbm_type_of(car_val) == LBM_TYPE_SYMBOL0x00000000u &&
4492 lbm_dec_sym(car_val) == SYM_COMMA0x73) {
4493 ctx->r = append(ctx->r, get_car(cdr_val));
4494 ctx->app_cont = true1;
4495 } else if (lbm_type_of(car_val) == LBM_TYPE_SYMBOL0x00000000u &&
4496 lbm_dec_sym(car_val) == SYM_COMMAAT0x74) {
4497 error_ctx(ENC_SYM_RERROR(((0x20) << 4) | 0x00000000u));
4498 } else {
4499 stack_push_2(&ctx->K, ctx->r, QQ_APPEND(((37) << 2) | 0xF8000001u));
4500 stack_push_2(&ctx->K, cdr_val, QQ_EXPAND(((36) << 2) | 0xF8000001u));
4501 stack_push_2(&ctx->K, car_val, QQ_EXPAND_LIST(((38) << 2) | 0xF8000001u));
4502 ctx->app_cont = true1;
4503 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
4504 }
4505
4506 } break;
4507 default: {
4508 lbm_value res = quote_it(qquoted);
4509 ctx->r = append(ctx->r, res);
4510 ctx->app_cont = true1;
4511 }
4512 }
4513}
4514
4515static void cont_qq_append(eval_context_t *ctx) {
4516 lbm_value head;
4517 lbm_pop(&ctx->K, &head);
4518 ctx->r = append(head, ctx->r);
4519 ctx->app_cont = true1;
4520}
4521
4522/* Bawden's qq-expand-list implementation
4523(define (qq-expand-list x)
4524 (cond ((tag-comma? x)
4525 `(list ,(tag-data x)))
4526 ((tag-comma-atsign? x)
4527 (tag-data x))
4528 ((tag-backquote? x)
4529 (qq-expand-list
4530 (qq-expand (tag-data x))))
4531 ((pair? x)
4532 `(list
4533 (append
4534 ,(qq-expand-list (car x))
4535 ,(qq-expand (cdr x)))))
4536 (else `'(,x))))
4537*/
4538
4539static void cont_qq_expand_list(eval_context_t* ctx) {
4540 lbm_value l;
4541 lbm_pop(&ctx->K, &l);
4542
4543 switch(lbm_type_of(l)) {
4544 case LBM_TYPE_CONS0x10000000u: {
4545 lbm_value car_val = get_car(l);
4546 lbm_value cdr_val = get_cdr(l);
4547 if (lbm_type_of(car_val) == LBM_TYPE_SYMBOL0x00000000u &&
4548 lbm_dec_sym(car_val) == SYM_COMMA0x73) {
4549 lbm_value tl = cons_with_gc(get_car(cdr_val), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4550 lbm_value tmp = cons_with_gc(ENC_SYM_LIST(((0x20014) << 4) | 0x00000000u), tl, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4551 ctx->r = append(ctx->r, tmp);
4552 ctx->app_cont = true1;
4553 return;
4554 } else if (lbm_type_of(car_val) == LBM_TYPE_SYMBOL0x00000000u &&
4555 lbm_dec_sym(car_val) == SYM_COMMAAT0x74) {
4556 ctx->r = get_car(cdr_val);
4557 ctx->app_cont = true1;
4558 return;
4559 } else {
4560 stack_push(&ctx->K, QQ_LIST(((39) << 2) | 0xF8000001u));
4561 stack_push_2(&ctx->K, ctx->r, QQ_APPEND(((37) << 2) | 0xF8000001u));
4562 stack_push_2(&ctx->K, cdr_val, QQ_EXPAND(((36) << 2) | 0xF8000001u));
4563 stack_push_2(&ctx->K, car_val, QQ_EXPAND_LIST(((38) << 2) | 0xF8000001u));
4564 ctx->app_cont = true1;
4565 ctx->r = ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
4566 }
4567
4568 } break;
4569 default: {
4570 lbm_value a_list = cons_with_gc(l, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4571 lbm_value tl = cons_with_gc(a_list, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4572 lbm_value tmp = cons_with_gc(ENC_SYM_QUOTE(((0x100) << 4) | 0x00000000u), tl, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4573 ctx->r = append(ctx->r, tmp);
4574 ctx->app_cont = true1;
4575 }
4576 }
4577}
4578
4579static void cont_qq_list(eval_context_t *ctx) {
4580 lbm_value val = ctx->r;
4581 lbm_value apnd_app = cons_with_gc(val, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4582 lbm_value tmp = cons_with_gc(ENC_SYM_LIST(((0x20014) << 4) | 0x00000000u), apnd_app, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u));
4583 ctx->r = tmp;
4584 ctx->app_cont = true1;
4585}
4586
4587static void cont_kill(eval_context_t *ctx) {
4588 (void) ctx;
4589 finish_ctx();
4590}
4591
4592/*********************************************************/
4593/* Continuations table */
4594typedef void (*cont_fun)(eval_context_t *);
4595
4596static const cont_fun continuations[NUM_CONTINUATIONS46] =
4597 { advance_ctx, // CONT_DONE
4598 cont_set_global_env,
4599 cont_bind_to_key_rest,
4600 cont_if,
4601 cont_progn_rest,
4602 cont_application_args,
4603 cont_and,
4604 cont_or,
4605 cont_wait,
4606 cont_match,
4607 cont_application_start,
4608 cont_eval_r,
4609 cont_resume,
4610 cont_closure_application_args,
4611 cont_exit_atomic,
4612 cont_read_next_token,
4613 cont_read_append_continue,
4614 cont_read_eval_continue,
4615 cont_read_expect_closepar,
4616 cont_read_dot_terminate,
4617 cont_read_done,
4618 cont_read_quote_result,
4619 cont_read_commaat_result,
4620 cont_read_comma_result,
4621 cont_read_start_array,
4622 cont_read_append_array,
4623 cont_map,
4624 cont_match_guard,
4625 cont_terminate,
4626 cont_progn_var,
4627 cont_setq,
4628 cont_move_to_flash,
4629 cont_move_val_to_flash_dispatch,
4630 cont_move_list_to_flash,
4631 cont_close_list_in_flash,
4632 cont_qq_expand_start,
4633 cont_qq_expand,
4634 cont_qq_append,
4635 cont_qq_expand_list,
4636 cont_qq_list,
4637 cont_kill,
4638 cont_loop,
4639 cont_loop_condition,
4640 cont_merge_rest,
4641 cont_merge_layer,
4642 cont_closure_args_rest,
4643 };
4644
4645/*********************************************************/
4646/* Evaluators lookup table (special forms) */
4647typedef void (*evaluator_fun)(eval_context_t *);
4648
4649static const evaluator_fun evaluators[] =
4650 {
4651 eval_quote,
4652 eval_define,
4653 eval_progn,
4654 eval_lambda,
4655 eval_if,
4656 eval_let,
4657 eval_and,
4658 eval_or,
4659 eval_match,
4660 eval_receive,
4661 eval_receive_timeout,
4662 eval_callcc,
4663 eval_atomic,
4664 eval_selfevaluating, // macro
4665 eval_selfevaluating, // cont
4666 eval_selfevaluating, // closure
4667 eval_cond,
4668 eval_app_cont,
4669 eval_var,
4670 eval_setq,
4671 eval_move_to_flash,
4672 eval_loop,
4673 };
4674
4675
4676/*********************************************************/
4677/* Evaluator step function */
4678
4679static void evaluation_step(void){
4680 eval_context_t *ctx = ctx_running;
4681#ifdef VISUALIZE_HEAP
4682 heap_vis_gen_image();
4683#endif
4684
4685 if (ctx->app_cont) {
4686 lbm_value k;
4687 lbm_pop(&ctx->K, &k);
4688 ctx->app_cont = false0;
4689
4690 lbm_uint decoded_k = DEC_CONTINUATION(k)(((k) & ~0xF8000001u) >> 2);
4691
4692 if (decoded_k < NUM_CONTINUATIONS46) {
4693 continuations[decoded_k](ctx);
4694 } else {
4695 error_ctx(ENC_SYM_FATAL_ERROR(((0x26) << 4) | 0x00000000u));
4696 }
4697 return;
4698 }
4699
4700 if (lbm_is_symbol(ctx->curr_exp)) {
4701 eval_symbol(ctx);
4702 return;
4703 }
4704 if (lbm_is_cons(ctx->curr_exp)) {
4705 lbm_cons_t *cell = lbm_ref_cell(ctx->curr_exp);
4706 lbm_value h = cell->car;
4707 if (lbm_is_symbol(h) && ((h & ENC_SPECIAL_FORMS_MASK0xFFFFF000) == ENC_SPECIAL_FORMS_BIT0x00001000)) {
4708 lbm_uint eval_index = lbm_dec_sym(h) & SPECIAL_FORMS_INDEX_MASK0x000000FF;
4709 evaluators[eval_index](ctx);
4710 return;
4711 }
4712 /*
4713 * At this point head can be anything. It should evaluate
4714 * into a form that can be applied (closure, symbol, ...) though.
4715 */
4716 lbm_value *reserved = stack_reserve(ctx, 3);
4717 reserved[0] = ctx->curr_env;
4718 reserved[1] = cell->cdr;
4719 reserved[2] = APPLICATION_START(((10) << 2) | 0xF8000001u);
4720 ctx->curr_exp = h; // evaluate the function
4721 return;
4722 }
4723
4724 eval_selfevaluating(ctx);
4725 return;
4726}
4727
4728void lbm_pause_eval(void ) {
4729 eval_cps_next_state_arg = 0;
4730 eval_cps_next_state = EVAL_CPS_STATE_PAUSED1;
4731 if (eval_cps_next_state != eval_cps_run_state) eval_cps_state_changed = true1;
4732}
4733
4734void lbm_pause_eval_with_gc(uint32_t num_free) {
4735 eval_cps_next_state_arg = num_free;
4736 eval_cps_next_state = EVAL_CPS_STATE_PAUSED1;
4737 if (eval_cps_next_state != eval_cps_run_state) eval_cps_state_changed = true1;
4738}
4739
4740void lbm_continue_eval(void) {
4741 eval_cps_next_state = EVAL_CPS_STATE_RUNNING2;
4742 if (eval_cps_next_state != eval_cps_run_state) eval_cps_state_changed = true1;
4743}
4744
4745void lbm_kill_eval(void) {
4746 eval_cps_next_state = EVAL_CPS_STATE_KILL4;
4747 if (eval_cps_next_state != eval_cps_run_state) eval_cps_state_changed = true1;
4748}
4749
4750uint32_t lbm_get_eval_state(void) {
4751 return eval_cps_run_state;
4752}
4753
4754// Will wake up thread that is sleeping as well.
4755// Not sure this is good behavior.
4756static void handle_event_unblock_ctx(lbm_cid cid, lbm_value v) {
4757 eval_context_t *found = NULL((void*)0);
4758 mutex_lock(&qmutex);
4759
4760 found = lookup_ctx_nm(&blocked, cid);
4761 if (found) {
4762 drop_ctx_nm(&blocked,found);
4763 if (lbm_is_error(v)) {
4764 lbm_uint trash;
4765 lbm_pop(&found->K, &trash);
4766 lbm_push(&found->K, TERMINATE(((28) << 2) | 0xF8000001u));
4767 found->app_cont = true1;
4768 }
4769 found->r = v;
4770 enqueue_ctx_nm(&queue,found);
4771 }
4772 mutex_unlock(&qmutex);
4773}
4774
4775static void handle_event_define(lbm_value key, lbm_value val) {
4776 lbm_uint dec_key = lbm_dec_sym(key);
4777 lbm_uint ix_key = dec_key & GLOBAL_ENV_MASK0x1F;
4778 lbm_value *global_env = lbm_get_global_env();
4779 lbm_uint orig_env = global_env[ix_key];
4780 lbm_value new_env;
4781 // A key is a symbol and should not need to be remembered.
4782 WITH_GC(new_env, lbm_env_set(orig_env,key,val))(new_env) = (lbm_env_set(orig_env,key,val)); if (lbm_is_symbol_merror
((new_env))) { gc(); (new_env) = (lbm_env_set(orig_env,key,val
)); if (lbm_is_symbol_merror((new_env))) { error_ctx((((0x23)
<< 4) | 0x00000000u)); } }
;
4783
4784 global_env[ix_key] = new_env;
4785}
4786
4787static lbm_value get_event_value(lbm_event_t *e) {
4788 lbm_value v;
4789 if (e->buf_len > 0) {
4790 lbm_flat_value_t fv;
4791 fv.buf = (uint8_t*)e->buf_ptr;
4792 fv.buf_size = e->buf_len;
4793 fv.buf_pos = 0;
4794 if (!lbm_unflatten_value(&fv, &v)) {
4795 lbm_set_flags(LBM_FLAG_HANDLER_EVENT_DELIVERY_FAILED(1 << 1));
4796 v = ENC_SYM_EERROR(((0x22) << 4) | 0x00000000u);
4797 }
4798 // Free the flat value buffer. GC is unaware of its existence.
4799 lbm_free(fv.buf);
4800 } else {
4801 v = (lbm_value)e->buf_ptr;
4802 }
4803 return v;
4804}
4805
4806static void process_events(void) {
4807
4808 if (!lbm_events) return;
4809 lbm_event_t e;
4810
4811 while (lbm_event_pop(&e)) {
4812
4813 lbm_value event_val = get_event_value(&e);
4814 switch(e.type) {
4815 case LBM_EVENT_UNBLOCK_CTX:
4816 handle_event_unblock_ctx((lbm_cid)e.parameter, event_val);
4817 break;
4818 case LBM_EVENT_DEFINE:
4819 handle_event_define((lbm_value)e.parameter, event_val);
4820 break;
4821 case LBM_EVENT_FOR_HANDLER:
4822 if (lbm_event_handler_pid >= 0) {
4823 lbm_find_receiver_and_send(lbm_event_handler_pid, event_val);
4824 }
4825 break;
4826 }
4827 }
4828}
4829
4830/* eval_cps_run can be paused
4831 I think it would be better use a mailbox for
4832 communication between other threads and the run_eval
4833 but for now a set of variables will be used. */
4834void lbm_run_eval(void){
4835
4836 if (setjmp(critical_error_jmp_buf)_setjmp (critical_error_jmp_buf) > 0) {
4837 printf_callback("GC stack overflow!\n");
4838 critical_error_callback();
4839 // terminate evaluation thread.
4840 return;
4841 }
4842
4843 setjmp(error_jmp_buf)_setjmp (error_jmp_buf);
4844
4845 while (eval_running) {
4846 if (eval_cps_state_changed || eval_cps_run_state == EVAL_CPS_STATE_PAUSED1) {
4847 eval_cps_state_changed = false0;
4848 switch (eval_cps_next_state) {
4849 case EVAL_CPS_STATE_PAUSED1:
4850 if (eval_cps_run_state != EVAL_CPS_STATE_PAUSED1) {
4851 if (lbm_heap_num_free() < eval_cps_next_state_arg) {
4852 gc();
4853 }
4854 eval_cps_next_state_arg = 0;
4855 }
4856 eval_cps_run_state = EVAL_CPS_STATE_PAUSED1;
4857 usleep_callback(EVAL_CPS_MIN_SLEEP200);
4858 continue; /* jump back to start of eval_running loop */
4859 case EVAL_CPS_STATE_KILL4:
4860 eval_cps_run_state = EVAL_CPS_STATE_DEAD8;
4861 eval_running = false0;
4862 continue;
4863 default: // running state
4864 eval_cps_run_state = eval_cps_next_state;
4865 break;
4866 }
4867 }
4868 while (true1) {
4869 if (eval_steps_quota && ctx_running) {
4870 eval_steps_quota--;
4871 evaluation_step();
4872 } else {
4873 if (eval_cps_state_changed) break;
4874 eval_steps_quota = eval_steps_refill;
4875 if (is_atomic) {
4876 if (!ctx_running) {
4877 lbm_set_flags(LBM_FLAG_ATOMIC_MALFUNCTION(1 << 0));
4878 is_atomic = 0;
4879 }
4880 } else {
4881 if (gc_requested) {
4882 gc();
4883 }
4884 process_events();
4885 mutex_lock(&qmutex);
4886 if (ctx_running) {
4887 enqueue_ctx_nm(&queue, ctx_running);
4888 ctx_running = NULL((void*)0);
4889 }
4890 wake_up_ctxs_nm();
4891 ctx_running = dequeue_ctx_nm(&queue);
4892 mutex_unlock(&qmutex);
4893 if (!ctx_running) {
4894 lbm_system_sleeping = true1;
4895 //Fixed sleep interval to poll events regularly.
4896 usleep_callback(EVAL_CPS_MIN_SLEEP200);
4897 lbm_system_sleeping = false0;
4898 }
4899 }
4900 }
4901 }
4902 }
4903}
4904
4905lbm_cid lbm_eval_program(lbm_value lisp) {
4906 return lbm_create_ctx(lisp, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), 256, NULL((void*)0));
4907}
4908
4909lbm_cid lbm_eval_program_ext(lbm_value lisp, unsigned int stack_size) {
4910 return lbm_create_ctx(lisp, ENC_SYM_NIL(((0x0) << 4) | 0x00000000u), stack_size, NULL((void*)0));
4911}
4912
4913int lbm_eval_init() {
4914 if (!qmutex_initialized) {
4915 mutex_init(&qmutex);
4916 qmutex_initialized = true1;
4917 }
4918 if (!lbm_events_mutex_initialized) {
4919 mutex_init(&lbm_events_mutex);
4920 lbm_events_mutex_initialized = true1;
4921 }
4922 if (!blocking_extension_mutex_initialized) {
4923 mutex_init(&blocking_extension_mutex);
4924 blocking_extension_mutex_initialized = true1;
4925 }
4926
4927 mutex_lock(&qmutex);
4928 mutex_lock(&lbm_events_mutex);
4929
4930 blocked.first = NULL((void*)0);
4931 blocked.last = NULL((void*)0);
4932 queue.first = NULL((void*)0);
4933 queue.last = NULL((void*)0);
4934 ctx_running = NULL((void*)0);
4935
4936 eval_cps_run_state = EVAL_CPS_STATE_RUNNING2;
4937
4938 mutex_unlock(&lbm_events_mutex);
4939 mutex_unlock(&qmutex);
4940
4941 if (!lbm_init_env()) return 0;
4942 eval_running = true1;
4943 return 1;
4944}
4945
4946bool_Bool lbm_eval_init_events(unsigned int num_events) {
4947
4948 mutex_lock(&lbm_events_mutex);
4949 lbm_events = (lbm_event_t*)lbm_malloc(num_events * sizeof(lbm_event_t));
4950 bool_Bool r = false0;
4951 if (lbm_events) {
4952 lbm_events_max = num_events;
4953 lbm_events_head = 0;
4954 lbm_events_tail = 0;
4955 lbm_events_full = false0;
4956 lbm_event_handler_pid = -1;
4957 r = true1;
4958 }
4959 mutex_unlock(&lbm_events_mutex);
4960 return r;
4961}

./include/heap.h

1
2/*
3 Copyright 2018, 2024 Joel Svensson svenssonjoel@yahoo.se
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18/** \file heap.h */
19
20#ifndef HEAP_H_
21#define HEAP_H_
22
23#include <string.h>
24#include <stdarg.h>
25
26#include "lbm_types.h"
27#include "symrepr.h"
28#include "stack.h"
29#include "lbm_memory.h"
30#include "lbm_defines.h"
31#include "lbm_channel.h"
32
33#ifdef __cplusplus
34extern "C" {
35#endif
36
37/*
38Planning for a more space efficient heap representation.
39TODO: Need to find a good reference to read up on this.
40 - List based heap
41 - Easy to implement and somewhat efficient
42
430000 0000 Size Free bits
44003F FFFF 4MB 10
45007F FFFF 8MB 9
4600FF FFFF 16MB 8
4701FF FFFF 32MB 7
4803FF FFFF 64MB 6 * Kind of heap size I am looking for
4907FF FFFF 128MB 5
500FFF FFFF 256MB 4
511FFF FFFF 512MB 3
52
53
54--- May 9 2021 ---
55Actually now I am much more interested in way smaller memories ;)
56
570000 0000 Size Free bits
580000 0FFF 4KB 20 |
590000 1FFF 8KB 19 |
600000 3FFF 16KB 18 |
610000 7FFF 32KB 17 |
620000 FFFF 64KB 16 |
630001 FFFF 128KB 15 |
640003 FFFF 256KB 14 | - This range is very interesting.
650007 FFFF 512KB 13
66000F FFFF 1MB 12
67001F FFFF 2MB 11
68003F FFFF 4MB 10
69007F FFFF 8MB 9
7000FF FFFF 16MB 8
7101FF FFFF 32MB 7
7203FF FFFF 64MB 6
7307FF FFFF 128MB 5
740FFF FFFF 256MB 4
751FFF FFFF 512MB 3
76
77Those are the kind of platforms that are fun... so a bunch of
78wasted bits in heap pointers if we run on small MCUs.
79
80-----------------
81
82it is also the case that not all addresses will be used if all "cells" are
83of the same size, 8 bytes...
84
85value 0: 0000 0000
86value 1: 0000 0008
87value 3: 0000 0010
88value 4: 0000 0018
89
90Means bits 0,1,2 will always be empty in a valid address.
91
92Cons cells also need to be have room for 2 pointers. So each ted cell from
93memory should be 8bytes.
94
95Things that needs to be represented within these bits:
96
97 - GC MARK one per cell
98 - TYPE: type of CAR and type of cons
99
100Types I would want:
101 - Full 32bit integer. Does not leave room for identification of type
102 - Float values. Same problem
103
104
105Free bits in pointers 64MB heap:
10631 30 29 28 27 26 2 1 0
1070 0 0 0 0 0 XX XXXX XXXX XXXX XXXX XXXX X 0 0 0
108
109
110Information needed for each cell:
111 Meaning | bits total | bits per car | bits per cdr
112 GC mark | 2 | 1 | 1 - only one of them will be used (the other is wasted)
113 Type | 2x | x | x
114 Ptr/!ptr | 2 | 1 | 1
115
116
117Types (unboxed):
118 - Symbols
119 - 28bit integer ( will need signed shift right functionality )
120 - 28bit unsigned integer
121 - Character
122
123If four types is all that should be possible (unboxed). then 2 bits are needed to differentiate.
1242 + 1 + 1 = 4 => 28bits for data.
125
126bit 0: ptr/!ptr
127bit 1: gc
128bit 2-3: type (if not ptr)
129bit 3 - 24 ptr (if ptr)
130bit 4 - 31 value (if value)
131
132An unboxed value can occupy a car or cdr field in a cons cell.
133
134types (boxed) extra information in pointer to cell can contain information
135 - 32 bit integer
136 - 32 bit unsigned integer
137 - 32 bit float
138
139boxed representation:
140 [ptr| cdr]
141 |
142 [Value | Aux + GC_MARK]
143
144Kinds of pointers:
145 - Pointer to cons cell.
146 - Pointer to unboxed value (fixnums not in a list, I hope this is so rare that it can be removed )
147 - integer
148 - unsigned integer
149 - symbol
150 - float
151 - Pointer to boxed value.
152 - 32 bit integer
153 - 32 bit unsigned integer
154 - 32 bit float
155 - (Maybe something else ? Vectors/strings allocated in memory not occupied by heap?)
156 - vector of int
157 - vector of uint
158 - vector of float
159 - vector of double
160 - String
161
16213 pointer"types" -> needs 4 bits
163for 64MB heap there are 6 free bits. So with this scheme going to 128MB or 256MB heap
164is also possible
165
166 a pointer to some off heap vector/string could be represented by
167
168 [ptr | cdr]
169 |
170 [full pointer | Aux + GC_MARK]
171 |
172 [VECTOR]
173
174Aux bits could be used for storing vector size. Up to 30bits should be available there
175>> This is problematic. Now the information that something is a vector is split up
176>> between 2 cons cells. This means GC needs both of these intact to be able to make
177>> proper decision.
178>> Will try to resolve this by adding some special symbols. But these must be symbols
179>> that cannot occur normally in programs. Then an array could be:
180
181 [Full pointer | ARRAY_SYM + GC_MARK]
182 |
183 [VECTOR]
184
185>> Boxed values same treatment as above.
186>> TODO: Could this be simpler?
187
188[ VALUE | TYPE_SYM + GC_MARK]
189
190
1910000 00XX XXXX XXXX XXXX XXXX XXXX X000 : 0x03FF FFF8
1921111 AA00 0000 0000 0000 0000 0000 0000 : 0xFC00 0000 (AA bits left unused for now, future heap growth?)
193 */
194
195typedef enum {
196 LBM_FLASH_WRITE_OK,
197 LBM_FLASH_FULL,
198 LBM_FLASH_WRITE_ERROR
199} lbm_flash_status;
200
201/** Struct representing a heap cons-cell.
202 *
203 */
204typedef struct {
205 lbm_value car;
206 lbm_value cdr;
207} lbm_cons_t;
208
209/**
210 * Heap state
211 */
212typedef struct {
213 lbm_cons_t *heap;
214 lbm_value freelist; // list of free cons cells.
215 lbm_stack_t gc_stack;
216
217 lbm_uint heap_size; // In number of cells.
218 lbm_uint heap_bytes; // In bytes.
219
220 lbm_uint num_alloc; // Number of cells allocated.
221 lbm_uint num_alloc_arrays; // Number of arrays allocated.
222
223 lbm_uint gc_num; // Number of times gc has been performed.
224 lbm_uint gc_marked; // Number of cells marked by mark phase.
225 lbm_uint gc_recovered; // Number of cells recovered by sweep phase.
226 lbm_uint gc_recovered_arrays;// Number of arrays recovered by sweep.
227 lbm_uint gc_least_free; // The smallest length of the freelist.
228 lbm_uint gc_last_free; // Number of elements on the freelist
229 // after most recent GC.
230} lbm_heap_state_t;
231
232extern lbm_heap_state_t lbm_heap_state;
233
234typedef bool_Bool (*const_heap_write_fun)(lbm_uint ix, lbm_uint w);
235
236typedef struct {
237 lbm_uint *heap;
238 lbm_uint next; // next free index.
239 lbm_uint size; // in lbm_uint words. (cons-cells = words / 2)
240} lbm_const_heap_t;
241
242/**
243 * The header portion of an array stored in array and symbol memory.
244 * An array is always a byte array. use the array-extensions for
245 * storing and reading larger values from arrays.
246 */
247typedef struct {
248 lbm_uint size; /// Number of elements
249 lbm_uint *data; /// pointer to lbm_memory array or C array.
250} lbm_array_header_t;
251
252/** Lock GC mutex
253 * Locks a mutex during GC marking when using the pointer reversal algorithm.
254 * Does nothing when using stack based GC mark.
255 */
256void lbm_gc_lock(void);
257/* Unlock GC mutex
258 */
259void lbm_gc_unlock(void);
260
261/** Initialize heap storage.
262 * \param addr Pointer to an array of lbm_cons_t elements. This array must at least be aligned 4.
263 * \param num_cells Number of lbm_cons_t elements in the array.
264 * \param gc_stack_size Size of the gc_stack in number of words.
265 * \return 1 on success or 0 for failure.
266 */
267int lbm_heap_init(lbm_cons_t *addr, lbm_uint num_cells,
268 lbm_uint gc_stack_size);
269
270/** Add GC time statistics to heap_stats
271 *
272 * \param dur Duration as reported by the timestamp callback.
273 */
274void lbm_heap_new_gc_time(lbm_uint dur);
275/** Add a new free_list length to the heap_stats.
276 * Calculates a new freelist length and updates
277 * the GC statistics.
278 */
279void lbm_heap_new_freelist_length(void);
280/** Check how many lbm_cons_t cells are on the free-list
281 *
282 * \return Number of free lbm_cons_t cells.
283 */
284lbm_uint lbm_heap_num_free(void);
285/** Check how many lbm_cons_t cells are allocated.
286 *
287 * \return Number of lbm_cons_t cells that are currently allocated.
288 */
289lbm_uint lbm_heap_num_allocated(void);
290/** Size of the heap in number of lbm_cons_t cells.
291 *
292 * \return Size of the heap in number of lbm_cons_t cells.
293 */
294lbm_uint lbm_heap_size(void);
295/** Size of the heap in bytes.
296 *
297 * \return Size of heap in bytes.
298 */
299lbm_uint lbm_heap_size_bytes(void);
300/** Allocate an lbm_cons_t cell from the heap.
301 *
302 * \param type A type that can be encoded onto the cell (most often LBM_PTR_TYPE_CONS).
303 * \param car Value to write into car position of allocated cell.
304 * \param cdr Value to write into cdr position of allocated cell.
305 * \return An lbm_value referring to a cons_cell or enc_sym(SYM_MERROR) in case the heap is full.
306 */
307lbm_value lbm_heap_allocate_cell(lbm_type type, lbm_value car, lbm_value cdr);
308/** Allocate a list of n heap-cells.
309 * \param n The number of heap-cells to allocate.
310 * \return A list of heap-cells of Memory error if unable to allocate.
311 */
312lbm_value lbm_heap_allocate_list(lbm_uint n);
313/** Allocate a list of n heap-cells and initialize the values.
314 * \pram ls The result list is passed through this ptr.
315 * \param n The length of list to allocate.
316 * \param valist The values in a va_list to initialize the list with.
317 * \return True of False depending on success of allocation.
318 */
319lbm_value lbm_heap_allocate_list_init_va(unsigned int n, va_list valist);
320/** Allocate a list of n heap-cells and initialize the values.
321 * \param n The length of list to allocate.
322 * \param ... The values to initialize the list with.
323 * \return allocated list or error symbol.
324 */
325lbm_value lbm_heap_allocate_list_init(unsigned int n, ...);
326/** Decode an lbm_value representing a string into a C string
327 *
328 * \param val Value
329 * \return allocated list or error symbol
330 */
331char *lbm_dec_str(lbm_value val);
332/** Decode an lbm_value representing a char channel into an lbm_char_channel_t pointer.
333 *
334 * \param val Value
335 * \return A pointer to an lbm_char_channel_t or NULL if the value does not encode a channel.
336 */
337lbm_char_channel_t *lbm_dec_channel(lbm_value val);
338/** Decode an lbm_value representing a custom type into a lbm_uint value.
339 *
340 * \param val Value.
341 * \return The custom type payload.
342 */
343lbm_uint lbm_dec_custom(lbm_value val);
344/** Decode a numerical value as if it is char
345 *
346 * \param val Value to decode
347 * \return The value encoded in val casted to a char. Returns 0 if val does not encode a number.
348 */
349uint8_t lbm_dec_as_char(lbm_value a);
350/** Decode a numerical value as if it is unsigned
351 *
352 * \param val Value to decode
353 * \return The value encoded in val casted to an unsigned int. Returns 0 if val does not encode a number.
354 */
355uint32_t lbm_dec_as_u32(lbm_value val);
356/** Decode a numerical value as a signed integer.
357 *
358 * \param val Value to decode
359 * \return The value encoded in val casted to a signed int. Returns 0 if val does not encode a number.
360 */
361int32_t lbm_dec_as_i32(lbm_value val);
362/** Decode a numerical value as a float.
363 *
364 * \param val Value to decode.
365 * \return The value encoded in val casted to a float. Returns 0 if val does not encode a number.
366 */
367float lbm_dec_as_float(lbm_value val);
368/** Decode a numerical value as if it is a 64bit unsigned
369 *
370 * \param val Value to decode
371 * \return The value encoded in val casted to an unsigned int. Returns 0 if val does not encode a number.
372 */
373uint64_t lbm_dec_as_u64(lbm_value val);
374/** Decode a numerical value as a 64bit signed integer.
375 *
376 * \param val Value to decode
377 * \return The value encoded in val casted to a signed int. Returns 0 if val does not encode a number.
378 */
379int64_t lbm_dec_as_i64(lbm_value val);
380/** Decode a numerical value as a float.
381 *
382 * \param val Value to decode.
383 * \return The value encoded in val casted to a float. Returns 0 if val does not encode a number.
384 */
385double lbm_dec_as_double(lbm_value val);
386
387lbm_uint lbm_dec_raw(lbm_value v);
388/** Allocates an lbm_cons_t cell from the heap and populates it.
389 *
390 * \param car The value to put in the car field of the allocated lbm_cons_t.
391 * \param cdr The value to put in the cdr field of the allocated lbm_cons_t.
392 * \return A value referencing the lbm_cons_t or enc_sym(SYM_MERROR) if heap is full.
393 */
394lbm_value lbm_cons(lbm_value car, lbm_value cdr);
395
396/** Accesses the car field of an lbm_cons_t.
397 *
398 * \param cons Value
399 * \return The car field of the lbm_cons_t if cons is a reference to a heap cell.
400 * If cons is nil, the return value is nil. If the value
401 * is not cons or nil, the return value is enc_sym(SYM_TERROR) for type error.
402 */
403lbm_value lbm_car(lbm_value cons);
404/** Accesses the car field the car field of an lbm_cons_t.
405 *
406 * \param cons Value
407 * \return The car of car field or nil.
408 */
409lbm_value lbm_caar(lbm_value c);
410/** Accesses the car of the cdr of an cons cell
411 *
412 * \param c Value
413 * \return the cdr field or type error.
414 */
415lbm_value lbm_cadr(lbm_value c);
416/** Accesses the cdr field of an lbm_cons_t.
417 *
418 * \param cons Value
419 * \return The cdr field of the lbm_cons_t if cons is a reference to a heap cell.
420 * If cons is nil, the return value is nil. If the value
421 * if not cons or nil, the return value is enc_sym(SYM_TERROR) for type error.
422 */
423lbm_value lbm_cdr(lbm_value cons);
424/** Accesses the cdr of an cdr field of an lbm_cons_t.
425 *
426 * \param cons Value
427 * \return The cdr of the cdr field of the lbm_cons_t if cons is a reference to a heap cell.
428 * If cons is nil, the return value is nil. If the value
429 * if not cons or nil, the return value is enc_sym(SYM_TERROR) for type error.
430 */
431lbm_value lbm_cddr(lbm_value c);
432/** Update the value stored in the car field of a heap cell.
433 *
434 * \param c Value referring to a heap cell.
435 * \param v Value to replace the car field with.
436 * \return 1 on success and 0 if the c value does not refer to a heap cell.
437 */
438int lbm_set_car(lbm_value c, lbm_value v);
439/** Update the value stored in the cdr field of a heap cell.
440 *
441 * \param c Value referring to a heap cell.
442 * \param v Value to replace the cdr field with.
443 * \return 1 on success and 0 if the c value does not refer to a heap cell.
444 */
445int lbm_set_cdr(lbm_value c, lbm_value v);
446/** Update the value stored in the car and cdr fields of a heap cell.
447 *
448 * \param c Value referring to a heap cell.
449 * \param car_val Value to replace the car field with.
450 * \param cdr_val Value to replace the cdr field with.
451 * \return 1 on success and 0 if the c value does not refer to a heap cell.
452 */
453int lbm_set_car_and_cdr(lbm_value c, lbm_value car_val, lbm_value cdr_val);
454// List functions
455/** Calculate the length of a proper list
456 * \warning This is a dangerous function that should be used carefully. Cyclic structures on the heap
457 * may lead to the function not terminating.
458 *
459 * \param c A list
460 * \return The length of the list. Unless the value is a cyclic structure on the heap, this function will terminate.
461 */
462lbm_uint lbm_list_length(lbm_value c);
463
464/** Calculate the length of a proper list and evaluate a predicate for each element.
465 * \warning This is a dangerous function that should be used carefully. Cyclic structures on the heap
466 * may lead to the function not terminating.
467 *
468 * \param c A list
469 * \param pres Boolean result of predicate, false if predicate is false for any of the elements in the list, otherwise true.
470 * \param pred Predicate to evaluate for each element of the list.
471 */
472unsigned int lbm_list_length_pred(lbm_value c, bool_Bool *pres, bool_Bool (*pred)(lbm_value));
473/** Reverse a proper list
474 * \warning This is a dangerous function that should be used carefully. Cyclic structures on the heap
475 * may lead to the function not terminating.
476 *
477 * \param list A list
478 * \return The list reversed or enc_sym(SYM_MERROR) if heap is full.
479 */
480lbm_value lbm_list_reverse(lbm_value list);
481/** Reverse a proper list destroying the original.
482 * \warning This is a dangerous function that should be used carefully. Cyclic structures on the heap
483 * may lead to the function not terminating.
484 *
485 * \param list A list
486 * \return The list reversed
487 */
488lbm_value lbm_list_destructive_reverse(lbm_value list);
489/** Copy a list
490 * \warning This is a dangerous function that should be used carefully. Cyclic structures on the heap
491 * may lead to the function not terminating.
492 *
493 * \param m Number of elements to copy or -1 for all. If 1, m will be updated with the length of the list
494 * \param list A list.
495 * \return Reversed list or enc_sym(SYM_MERROR) if heap is full.
496 */
497lbm_value lbm_list_copy(int *m, lbm_value list);
498
499/** A destructive append of two lists
500 *
501 * \param list1 A list
502 * \param list2 A list
503 * \return list1 with list2 appended at the end.
504 */
505lbm_value lbm_list_append(lbm_value list1, lbm_value list2);
506
507/** Drop values from the head of a list.
508 * \param n Number of values to drop.
509 * \param ls List to drop values from.
510 * \return The list with the n first elements removed.
511 */
512lbm_value lbm_list_drop(unsigned int n, lbm_value ls);
513/** Index into a list.
514 * \param l List to index into.
515 * \param n Position to read out of the list.
516 * \return Value at position n of l or nil if out of bounds.
517 */
518lbm_value lbm_index_list(lbm_value l, int32_t n);
519
520// State and statistics
521/** Get a copy of the heap statistics structure.
522 *
523 * \param A pointer to an lbm_heap_state_t to populate
524 * with the current statistics.
525 */
526void lbm_get_heap_state(lbm_heap_state_t *);
527/** Get the maximum stack level of the GC stack
528 * \return maximum value the gc stack sp reached so far.
529 */
530lbm_uint lbm_get_gc_stack_max(void);
531/** Get the size of the GC stack.
532 * \return the size of the gc stack.
533 */
534lbm_uint lbm_get_gc_stack_size(void);
535// Garbage collection
536/** Increment the counter that is counting the number of times GC ran
537 *
538 */
539void lbm_gc_state_inc(void);
540/** Set the freelist to NIL. Means that no memory will be available
541 * until after a garbage collection.
542 */
543void lbm_nil_freelist(void);
544/** Mark all heap cells reachable from an environment.
545 * \param environment.
546 */
547void lbm_gc_mark_env(lbm_value);
548/** Mark heap cells reachable from the lbm_value v.
549 * \param root
550 */
551void lbm_gc_mark_phase(lbm_value root);
552/** Performs lbm_gc_mark_phase on all the values of an array.
553 * This function is similar to lbm_gc_mark_roots but performs
554 * extra checks to not traverse into non-standard values.
555 * TODO: Check if this function is really needed.
556 * \param data Array of roots to traverse from.
557 * \param n Number of elements in roots-array.
558 */
559void lbm_gc_mark_aux(lbm_uint *data, lbm_uint n);
560/** Performs lbm_gc_mark_phase on all the values in the roots array.
561 * \param roots pointer to array of roots.
562 * \param num_roots size of array of roots.
563 */
564void lbm_gc_mark_roots(lbm_uint *roots, lbm_uint num_roots);
565/** Sweep up all non marked heap cells and place them on the free list.
566 *
567 * \return 1
568 */
569int lbm_gc_sweep_phase(void);
570
571// Array functionality
572/** Allocate an array in symbols and arrays memory (lispbm_memory.h)
573 * and create a heap cell that refers to this array.
574 * \param res The resulting lbm_value is returned through this argument.
575 * \param size Array size in number of 32 bit words.
576 * \param type The type information to encode onto the heap cell.
577 * \return 1 for success of 0 for failure.
578 */
579int lbm_heap_allocate_array(lbm_value *res, lbm_uint size);
580/** Convert a C array into an lbm array. If the C array is allocated in LBM MEMORY
581 * the lifetime of the array will be managed by GC.
582 * \param res lbm_value result pointer for storage of the result array.
583 * \param data C array.
584 * \param type The type tag to assign to the resulting LBM array.
585 * \param num_elt Number of elements in the array.
586 * \return 1 for success and 0 for failure.
587 */
588int lbm_lift_array(lbm_value *value, char *data, lbm_uint num_elt);
589/** Get the size of an array value.
590 * \param arr lbm_value array to get size of.
591 * \return -1 for failure or length of array.
592 */
593lbm_int lbm_heap_array_get_size(lbm_value arr);
594/** Get a pointer to the data of an array for read only purposes.
595 * \param arr lbm_value array to get pointer from.
596 * \return NULL or valid pointer.
597 */
598const uint8_t *lbm_heap_array_get_data_ro(lbm_value arr);
599/** Get a pointer to the data of an array for read/write purposes.
600 * \param arr lbm_value array to get pointer from.
601 * \return NULL or valid pointer.
602 */
603uint8_t *lbm_heap_array_get_data_rw(lbm_value arr);
604/** Explicitly free an array.
605 * This function needs to be used with care and knowledge.
606 * \param arr Array value.
607 */
608int lbm_heap_explicit_free_array(lbm_value arr);
609/** Query the size in bytes of an lbm_type.
610 * \param t Type
611 * \return Size in bytes of type or 0 if the type represents a composite.
612 */
613lbm_uint lbm_size_of(lbm_type t);
614
615int lbm_const_heap_init(const_heap_write_fun w_fun,
616 lbm_const_heap_t *heap,
617 lbm_uint *addr,
618 lbm_uint num_words);
619
620lbm_flash_status lbm_allocate_const_cell(lbm_value *res);
621lbm_flash_status lbm_write_const_raw(lbm_uint *data, lbm_uint n, lbm_uint *res);
622lbm_flash_status write_const_cdr(lbm_value cell, lbm_value val);
623lbm_flash_status write_const_car(lbm_value cell, lbm_value val);
624lbm_uint lbm_flash_memory_usage(void);
625
626/** Query the type information of a value.
627 *
628 * \param x Value to check the type of.
629 * \return The type information.
630 */
631static inline lbm_type lbm_type_of(lbm_value x) {
632 return (x & LBM_PTR_MASK0x00000001u) ? (x & LBM_PTR_TYPE_MASK0xFC000000u) : (x & LBM_VAL_TYPE_MASK0x0000000Cu);
633}
634
635// type-of check that is safe in functional code
636static inline lbm_type lbm_type_of_functional(lbm_value x) {
637 return (x & LBM_PTR_MASK0x00000001u) ?
638 (x & (LBM_PTR_TO_CONSTANT_MASK~0x04000000u & LBM_PTR_TYPE_MASK0xFC000000u)) :
639 (x & LBM_VAL_TYPE_MASK0x0000000Cu);
640}
641
642static inline lbm_value lbm_enc_cons_ptr(lbm_uint x) {
643 return ((x << LBM_ADDRESS_SHIFT2) | LBM_TYPE_CONS0x10000000u | LBM_PTR_BIT0x00000001u);
644}
645
646static inline lbm_uint lbm_dec_ptr(lbm_value p) {
647 return ((LBM_PTR_VAL_MASK0x03FFFFFCu & p) >> LBM_ADDRESS_SHIFT2);
648}
649
650extern lbm_cons_t *lbm_heaps[2];
651
652static inline lbm_uint lbm_dec_cons_cell_ptr(lbm_value p) {
653 lbm_uint h = (p & LBM_PTR_TO_CONSTANT_BIT0x04000000u) >> LBM_PTR_TO_CONSTANT_SHIFT26;
654 return lbm_dec_ptr(p) >> h;
655}
656
657static inline lbm_cons_t *lbm_dec_heap(lbm_value p) {
658 lbm_uint h = (p & LBM_PTR_TO_CONSTANT_BIT0x04000000u) >> LBM_PTR_TO_CONSTANT_SHIFT26;
659 return lbm_heaps[h];
660}
661
662static inline lbm_value lbm_set_ptr_type(lbm_value p, lbm_type t) {
663 return ((LBM_PTR_VAL_MASK0x03FFFFFCu & p) | t | LBM_PTR_BIT0x00000001u);
664}
665
666static inline lbm_value lbm_enc_sym(lbm_uint s) {
667 return (s << LBM_VAL_SHIFT4) | LBM_TYPE_SYMBOL0x00000000u;
668}
669
670static inline lbm_value lbm_enc_i(lbm_int x) {
671 return ((lbm_uint)x << LBM_VAL_SHIFT4) | LBM_TYPE_I0x00000008u;
672}
673
674static inline lbm_value lbm_enc_u(lbm_uint x) {
675 return (x << LBM_VAL_SHIFT4) | LBM_TYPE_U0x0000000Cu;
676}
677
678/** Encode 32 bit integer into an lbm_value.
679 * \param x Value to encode.
680 * \return result encoded value.
681 */
682extern lbm_value lbm_enc_i32(int32_t x);
683
684/** Encode 32 bit unsigned integer into an lbm_value.
685 * \param x Value to encode.
686 * \return result encoded value.
687 */
688extern lbm_value lbm_enc_u32(uint32_t x);
689
690/** Encode a float into an lbm_value.
691 * \param x float value to encode.
692 * \return result encoded value.
693 */
694extern lbm_value lbm_enc_float(float x);
695
696/** Encode a 64 bit integer into an lbm_value.
697 * \param x 64 bit integer to encode.
698 * \return result encoded value.
699 */
700extern lbm_value lbm_enc_i64(int64_t x);
701
702/** Encode a 64 bit unsigned integer into an lbm_value.
703 * \param x 64 bit unsigned integer to encode.
704 * \return result encoded value.
705 */
706extern lbm_value lbm_enc_u64(uint64_t x);
707
708/** Encode a double into an lbm_value.
709 * \param x double to encode.
710 * \return result encoded value.
711 */
712extern lbm_value lbm_enc_double(double x);
713
714static inline lbm_value lbm_enc_char(uint8_t x) {
715 return ((lbm_uint)x << LBM_VAL_SHIFT4) | LBM_TYPE_CHAR0x00000004u;
716}
717
718static inline lbm_int lbm_dec_i(lbm_value x) {
719 return (lbm_int)x >> LBM_VAL_SHIFT4;
720}
721
722static inline lbm_uint lbm_dec_u(lbm_value x) {
723 return x >> LBM_VAL_SHIFT4;
724}
725
726static inline uint8_t lbm_dec_char(lbm_value x) {
727 return (uint8_t)(x >> LBM_VAL_SHIFT4);
728}
729
730static inline lbm_uint lbm_dec_sym(lbm_value x) {
731 return x >> LBM_VAL_SHIFT4;
732}
733
734/** Decode an lbm_value representing a float.
735 * \param x Value to decode.
736 * \return decoded float.
737 */
738extern float lbm_dec_float(lbm_value x);
739
740/** Decode an lbm_value representing a double.
741 * \param x Value to decode.
742 * \return decoded float.
743 */
744extern double lbm_dec_double(lbm_value x);
745
746
747static inline uint32_t lbm_dec_u32(lbm_value x) {
748#ifndef LBM64
749 return (uint32_t)lbm_car(x);
750#else
751 return (uint32_t)(x >> LBM_VAL_SHIFT4);
752#endif
753}
754
755/** Decode an lbm_value representing a 64 bit unsigned integer.
756 * \param x Value to decode.
757 * \return decoded uint64_t.
758 */
759extern uint64_t lbm_dec_u64(lbm_value x);
760
761static inline int32_t lbm_dec_i32(lbm_value x) {
762#ifndef LBM64
763 return (int32_t)lbm_car(x);
764#else
765 return (int32_t)(x >> LBM_VAL_SHIFT4);
766#endif
767}
768
769/** Decode an lbm_value representing a 64 bit integer.
770 * \param x Value to decode.
771 * \return decoded int64_t.
772 */
773extern int64_t lbm_dec_i64(lbm_value x);
774
775/**
776 * Check if a value is a heap pointer
777 * \param x Value to check
778 * \return true if x is a pointer to a heap cell, false otherwise.
779 */
780static inline bool_Bool lbm_is_ptr(lbm_value x) {
781 return (x & LBM_PTR_MASK0x00000001u);
782}
783
784/**
785 * Check if a value is a Read/Writeable cons cell
786 * \param x Value to check
787 * \return true if x is a Read/Writeable cons cell, false otherwise.
788 */
789static inline bool_Bool lbm_is_cons_rw(lbm_value x) {
790 return (lbm_type_of(x) == LBM_TYPE_CONS0x10000000u);
791}
792
793/**
794 * Check if a value is a Readable cons cell
795 * \param x Value to check
796 * \return true if x is a readable cons cell, false otherwise.
797 */
798static inline bool_Bool lbm_is_cons(lbm_value x) {
799 return lbm_is_ptr(x) && ((x & LBM_CONS_TYPE_MASK0xF0000000u) == LBM_TYPE_CONS0x10000000u);
800}
801
802/** Check if a value represents a number
803 * \param x Value to check.
804 * \return true is x represents a number and false otherwise.
805 */
806static inline bool_Bool lbm_is_number(lbm_value x) {
807 return
808 (x & LBM_PTR_BIT0x00000001u) ?
809 ((x & LBM_NUMBER_MASK0x08000000u) == LBM_NUMBER_MASK0x08000000u) :
810 (x & LBM_VAL_TYPE_MASK0x0000000Cu);
811}
812
813/** Check if value is an array that can be READ
814 * \param x Value to check.
815 * \return true if x represents a readable array and false otherwise.
816 */
817static inline bool_Bool lbm_is_array_r(lbm_value x) {
818 lbm_type t = lbm_type_of(x);
819 return ((t & LBM_PTR_TO_CONSTANT_MASK~0x04000000u) == LBM_TYPE_ARRAY0x80000000u);
820}
821
822static inline bool_Bool lbm_is_array_rw(lbm_value x) {
823 return( (lbm_type_of(x) == LBM_TYPE_ARRAY0x80000000u) && !(x & LBM_PTR_TO_CONSTANT_BIT0x04000000u));
824}
825
826static inline bool_Bool lbm_is_channel(lbm_value x) {
827 return (lbm_type_of(x) == LBM_TYPE_CHANNEL0x90000000u &&
828 lbm_type_of(lbm_cdr(x)) == LBM_TYPE_SYMBOL0x00000000u &&
829 lbm_dec_sym(lbm_cdr(x)) == SYM_CHANNEL_TYPE0x37);
830}
831static inline bool_Bool lbm_is_char(lbm_value x) {
832 return (lbm_type_of(x) == LBM_TYPE_CHAR0x00000004u);
833}
834
835static inline bool_Bool lbm_is_special(lbm_value symrep) {
836 return ((lbm_type_of(symrep) == LBM_TYPE_SYMBOL0x00000000u) &&
837 (lbm_dec_sym(symrep) < SPECIAL_SYMBOLS_END0xFFFF));
838}
839
840static inline bool_Bool lbm_is_closure(lbm_value exp) {
841 return ((lbm_is_cons(exp)) &&
842 (lbm_type_of(lbm_car(exp)) == LBM_TYPE_SYMBOL0x00000000u) &&
843 (lbm_dec_sym(lbm_car(exp)) == SYM_CLOSURE0x10F));
844}
845
846static inline bool_Bool lbm_is_continuation(lbm_value exp) {
847 return ((lbm_type_of(exp) == LBM_TYPE_CONS0x10000000u) &&
848 (lbm_type_of(lbm_car(exp)) == LBM_TYPE_SYMBOL0x00000000u) &&
849 (lbm_dec_sym(lbm_car(exp)) == SYM_CONT0x10E));
850}
851
852static inline bool_Bool lbm_is_macro(lbm_value exp) {
853 return ((lbm_type_of(exp) == LBM_TYPE_CONS0x10000000u) &&
854 (lbm_type_of(lbm_car(exp)) == LBM_TYPE_SYMBOL0x00000000u) &&
855 (lbm_dec_sym(lbm_car(exp)) == SYM_MACRO0x10D));
856}
857
858static inline bool_Bool lbm_is_match_binder(lbm_value exp) {
859 return (lbm_is_cons(exp) &&
860 (lbm_type_of(lbm_car(exp)) == LBM_TYPE_SYMBOL0x00000000u) &&
861 ((lbm_dec_sym(lbm_car(exp)) == SYM_MATCH_ANY0x41)));
862}
863
864static inline bool_Bool lbm_is_comma_qualified_symbol(lbm_value exp) {
865 return (lbm_is_cons(exp) &&
866 (lbm_type_of(lbm_car(exp)) == LBM_TYPE_SYMBOL0x00000000u) &&
867 (lbm_dec_sym(lbm_car(exp)) == SYM_COMMA0x73) &&
868 (lbm_type_of(lbm_car(lbm_cdr(exp))) == LBM_TYPE_SYMBOL0x00000000u));
869}
870
871static inline bool_Bool lbm_is_symbol(lbm_value exp) {
872 return !(exp & LBM_LOW_RESERVED_BITS0x0000000Fu);
873}
874
875static inline bool_Bool lbm_is_symbol_nil(lbm_value exp) {
876 return exp == ENC_SYM_NIL(((0x0) << 4) | 0x00000000u);
9
Assuming the condition is true
10
Returning the value 1, which participates in a condition later
877}
878
879static inline bool_Bool lbm_is_symbol_true(lbm_value exp) {
880 return (lbm_is_symbol(exp) && lbm_dec_sym(exp) == SYM_TRUE0x2);
881}
882
883static inline bool_Bool lbm_is_symbol_eval(lbm_value exp) {
884 return (lbm_is_symbol(exp) && lbm_dec_sym(exp) == SYM_EVAL0x30008);
885}
886
887static inline bool_Bool lbm_is_symbol_merror(lbm_value exp) {
888 return lbm_is_symbol(exp) && (exp == ENC_SYM_MERROR(((0x23) << 4) | 0x00000000u));
889}
890
891static inline bool_Bool lbm_is_list(lbm_value x) {
892 return (lbm_is_cons(x) || lbm_is_symbol_nil(x));
893}
894
895static inline bool_Bool lbm_is_list_rw(lbm_value x) {
896 return (lbm_is_cons_rw(x) || lbm_is_symbol_nil(x));
897}
898
899static inline bool_Bool lbm_is_quoted_list(lbm_value x) {
900 return (lbm_is_cons(x) &&
901 lbm_is_symbol(lbm_car(x)) &&
902 (lbm_dec_sym(lbm_car(x)) == SYM_QUOTE0x100) &&
903 lbm_is_cons(lbm_cdr(x)) &&
904 lbm_is_cons(lbm_car(lbm_cdr(x))));
905}
906
907#ifndef LBM64
908#define ERROR_SYMBOL_MASK0xFFFFFFF0 0xFFFFFFF0
909#else
910#define ERROR_SYMBOL_MASK0xFFFFFFF0 0xFFFFFFFFFFFFFFF0
911#endif
912
913/* all error signaling symbols are in the range 0x20 - 0x2F */
914static inline bool_Bool lbm_is_error(lbm_value v){
915 return (lbm_is_symbol(v) &&
916 ((lbm_dec_sym(v) & ERROR_SYMBOL_MASK0xFFFFFFF0) == 0x20));
917}
918
919// ref_cell: returns a reference to the cell addressed by bits 3 - 26
920// Assumes user has checked that is_ptr was set
921static inline lbm_cons_t* lbm_ref_cell(lbm_value addr) {
922 return &lbm_dec_heap(addr)[lbm_dec_cons_cell_ptr(addr)];
923 //return &lbm_heap_state.heap[lbm_dec_ptr(addr)];
924}
925
926
927// lbm_uint a = lbm_heaps[0];
928// lbm_uint b = lbm_heaps[1];
929// lbm_uint i = (addr & LBM_PTR_TO_CONSTANT_BIT) >> LBM_PTR_TO_CONSTANT_SHIFT) - 1;
930// lbm_uint h = (a & i) | (b & ~i);
931
932#ifdef __cplusplus
933}
934#endif
935#endif