GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/joels/Current/lispbm/src/eval_cps.c Lines: 2803 3245 86.4 %
Date: 2024-12-26 17:59:19 Branches: 882 1330 66.3 %

Line Branch Exec Source
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
#include <stdarg.h>
40
41
static jmp_buf error_jmp_buf;
42
static jmp_buf critical_error_jmp_buf;
43
44
#define S_TO_US(X) (lbm_uint)((X) * 1000000)
45
46
#define DEC_CONTINUATION(x) (((x) & ~LBM_CONTINUATION_INTERNAL) >> LBM_ADDRESS_SHIFT)
47
#define IS_CONTINUATION(x) (((x) & LBM_CONTINUATION_INTERNAL) == LBM_CONTINUATION_INTERNAL)
48
#define CONTINUATION(x) (((x) << LBM_ADDRESS_SHIFT) | LBM_CONTINUATION_INTERNAL)
49
50
#define DONE                  CONTINUATION(0)
51
#define SET_GLOBAL_ENV        CONTINUATION(1)
52
#define BIND_TO_KEY_REST      CONTINUATION(2)
53
#define IF                    CONTINUATION(3)
54
#define PROGN_REST            CONTINUATION(4)
55
#define APPLICATION_ARGS      CONTINUATION(5)
56
#define AND                   CONTINUATION(6)
57
#define OR                    CONTINUATION(7)
58
#define WAIT                  CONTINUATION(8)
59
#define MATCH                 CONTINUATION(9)
60
#define APPLICATION_START     CONTINUATION(10)
61
#define EVAL_R                CONTINUATION(11)
62
#define RESUME                CONTINUATION(12)
63
#define CLOSURE_ARGS          CONTINUATION(13)
64
#define EXIT_ATOMIC           CONTINUATION(14)
65
#define READ_NEXT_TOKEN       CONTINUATION(15)
66
#define READ_APPEND_CONTINUE  CONTINUATION(16)
67
#define READ_EVAL_CONTINUE    CONTINUATION(17)
68
#define READ_EXPECT_CLOSEPAR  CONTINUATION(18)
69
#define READ_DOT_TERMINATE    CONTINUATION(19)
70
#define READ_DONE             CONTINUATION(20)
71
#define READ_START_ARRAY      CONTINUATION(21)
72
#define READ_APPEND_ARRAY     CONTINUATION(22)
73
#define MAP                   CONTINUATION(23)
74
#define MATCH_GUARD           CONTINUATION(24)
75
#define TERMINATE             CONTINUATION(25)
76
#define PROGN_VAR             CONTINUATION(26)
77
#define SETQ                  CONTINUATION(27)
78
#define MOVE_TO_FLASH         CONTINUATION(28)
79
#define MOVE_VAL_TO_FLASH_DISPATCH CONTINUATION(29)
80
#define MOVE_LIST_TO_FLASH    CONTINUATION(30)
81
#define CLOSE_LIST_IN_FLASH   CONTINUATION(31)
82
#define QQ_EXPAND_START       CONTINUATION(32)
83
#define QQ_EXPAND             CONTINUATION(33)
84
#define QQ_APPEND             CONTINUATION(34)
85
#define QQ_EXPAND_LIST        CONTINUATION(35)
86
#define QQ_LIST               CONTINUATION(36)
87
#define KILL                  CONTINUATION(37)
88
#define LOOP                  CONTINUATION(38)
89
#define LOOP_CONDITION        CONTINUATION(39)
90
#define MERGE_REST            CONTINUATION(40)
91
#define MERGE_LAYER           CONTINUATION(41)
92
#define CLOSURE_ARGS_REST     CONTINUATION(42)
93
#define MOVE_ARRAY_ELTS_TO_FLASH CONTINUATION(43)
94
#define POP_READER_FLAGS      CONTINUATION(44)
95
#define EXCEPTION_HANDLER     CONTINUATION(45)
96
#define RECV_TO               CONTINUATION(46)
97
#define WRAP_RESULT           CONTINUATION(47)
98
#define RECV_TO_RETRY         CONTINUATION(48)
99
#define NUM_CONTINUATIONS     49
100
101
#define FM_NEED_GC       -1
102
#define FM_NO_MATCH      -2
103
#define FM_PATTERN_ERROR -3
104
105
typedef enum {
106
  BL_OK = 0,
107
  BL_NO_MEMORY,
108
  BL_INCORRECT_KEY
109
} binding_location_status;
110
111
#define FB_OK             0
112
#define FB_TYPE_ERROR    -1
113
114
const char* lbm_error_str_parse_eof = "End of parse stream.";
115
const char* lbm_error_str_parse_dot = "Incorrect usage of '.'.";
116
const char* lbm_error_str_parse_close = "Expected closing parenthesis.";
117
const char* lbm_error_str_num_args = "Incorrect number of arguments.";
118
const char* lbm_error_str_forbidden_in_atomic = "Operation is forbidden in an atomic block.";
119
const char* lbm_error_str_no_number = "Argument(s) must be a number.";
120
const char* lbm_error_str_not_a_boolean = "Argument must be t or nil (true or false).";
121
const char* lbm_error_str_incorrect_arg = "Incorrect argument.";
122
const char* lbm_error_str_var_outside_progn = "Usage of var outside of progn.";
123
const char* lbm_error_str_flash_not_possible = "Value cannot be written to flash.";
124
const char* lbm_error_str_flash_error = "Error writing to flash.";
125
const char* lbm_error_str_flash_full = "Flash memory is full.";
126
const char* lbm_error_str_variable_not_bound = "Variable not bound.";
127
const char* lbm_error_str_read_no_mem = "Out of memory while reading.";
128
129
static lbm_value lbm_error_suspect;
130
static bool lbm_error_has_suspect = false;
131
#ifdef LBM_ALWAYS_GC
132
133
#define WITH_GC(y, x)                           \
134
  gc();                                         \
135
  (y) = (x);                                    \
136
  if (lbm_is_symbol_merror((y))) {              \
137
    error_ctx(ENC_SYM_MERROR);                  \
138
  }
139
140
#define WITH_GC_RMBR_1(y, x, r)                 \
141
  lbm_gc_mark_phase(r);                         \
142
  gc();                                         \
143
  (y) = (x);                                    \
144
  if (lbm_is_symbol_merror((y))) {              \
145
    error_ctx(ENC_SYM_MERROR);                  \
146
  }
147
148
#else
149
150
#define WITH_GC(y, x)                           \
151
  (y) = (x);                                    \
152
  if (lbm_is_symbol_merror((y))) {              \
153
    gc();                                       \
154
    (y) = (x);                                  \
155
    if (lbm_is_symbol_merror((y))) {            \
156
      error_ctx(ENC_SYM_MERROR);                \
157
    }                                           \
158
    /* continue executing statements below */   \
159
  }
160
#define WITH_GC_RMBR_1(y, x, r)                 \
161
  (y) = (x);                                    \
162
  if (lbm_is_symbol_merror((y))) {              \
163
    lbm_gc_mark_phase(r);                       \
164
    gc();                                       \
165
    (y) = (x);                                  \
166
    if (lbm_is_symbol_merror((y))) {            \
167
      error_ctx(ENC_SYM_MERROR);                \
168
    }                                           \
169
    /* continue executing statements below */   \
170
  }
171
172
#endif
173
174
/**************************************************************/
175
/* */
176
typedef struct {
177
  eval_context_t *first;
178
  eval_context_t *last;
179
} eval_context_queue_t;
180
181
#ifdef CLEAN_UP_CLOSURES
182
static lbm_value clean_cl_env_symbol = ENC_SYM_NIL;
183
#endif
184
185
static int gc(void);
186
static void error_ctx(lbm_value);
187
static void error_at_ctx(lbm_value err_val, lbm_value at);
188
static void enqueue_ctx(eval_context_queue_t *q, eval_context_t *ctx);
189
static bool mailbox_add_mail(eval_context_t *ctx, lbm_value mail);
190
191
// The currently executing context.
192
eval_context_t *ctx_running = NULL;
193
volatile bool  lbm_system_sleeping = false;
194
195
static volatile bool gc_requested = false;
196
4368
void lbm_request_gc(void) {
197
4368
  gc_requested = true;
198
4368
}
199
200
/*
201
   On ChibiOs the CH_CFG_ST_FREQUENCY setting in chconf.h sets the
202
   resolution of the timer used for sleep operations.  If this is set
203
   to 10KHz the resolution is 100us.
204
205
   The CH_CFG_ST_TIMEDELTA specifies the minimum number of ticks that
206
   can be safely specified in a timeout directive (wonder if that
207
   means sleep-period). The timedelta is set to 2.
208
209
   If I have understood these correctly it means that the minimum
210
   sleep duration possible is 2 * 100us = 200us.
211
*/
212
213
#define EVAL_CPS_DEFAULT_STACK_SIZE 256
214
#define EVAL_CPS_MIN_SLEEP 200
215
#define EVAL_STEPS_QUOTA   10
216
217
static volatile uint32_t eval_steps_refill = EVAL_STEPS_QUOTA;
218
static uint32_t eval_steps_quota = EVAL_STEPS_QUOTA;
219
220
28
void lbm_set_eval_step_quota(uint32_t quota) {
221
28
  eval_steps_refill = quota;
222
28
}
223
224
static uint32_t          eval_cps_run_state = EVAL_CPS_STATE_DEAD;
225
static volatile uint32_t eval_cps_next_state = EVAL_CPS_STATE_NONE;
226
static volatile uint32_t eval_cps_next_state_arg = 0;
227
static volatile bool     eval_cps_state_changed = false;
228
229
static void usleep_nonsense(uint32_t us) {
230
  (void) us;
231
}
232
233
static bool dynamic_load_nonsense(const char *sym, const char **code) {
234
  (void) sym;
235
  (void) code;
236
  return false;
237
}
238
239
static uint32_t timestamp_nonsense(void) {
240
  return 0;
241
}
242
243
static int printf_nonsense(const char *fmt, ...) {
244
  (void) fmt;
245
  return 0;
246
}
247
248
static void ctx_done_nonsense(eval_context_t *ctx) {
249
  (void) ctx;
250
}
251
252
static void critical_nonsense(void) {
253
  return;
254
}
255
256
static void user_callback_nonsense(void *arg) {
257
  (void) arg;
258
  return;
259
}
260
261
static void (*critical_error_callback)(void) = critical_nonsense;
262
static void (*usleep_callback)(uint32_t) = usleep_nonsense;
263
static uint32_t (*timestamp_us_callback)(void) = timestamp_nonsense;
264
static void (*ctx_done_callback)(eval_context_t *) = ctx_done_nonsense;
265
static int (*printf_callback)(const char *, ...) = printf_nonsense;
266
static bool (*dynamic_load_callback)(const char *, const char **) = dynamic_load_nonsense;
267
static void (*user_callback)(void *) = user_callback_nonsense;
268
269
void lbm_set_user_callback(void (*fptr)(void *)) {
270
  if (fptr == NULL) user_callback = user_callback_nonsense;
271
  else user_callback = fptr;
272
}
273
274
21756
void lbm_set_critical_error_callback(void (*fptr)(void)) {
275
21756
  if (fptr == NULL) critical_error_callback = critical_nonsense;
276
21756
  else critical_error_callback = fptr;
277
21756
}
278
279
21756
void lbm_set_usleep_callback(void (*fptr)(uint32_t)) {
280
21756
  if (fptr == NULL) usleep_callback = usleep_nonsense;
281
21756
  else usleep_callback = fptr;
282
21756
}
283
284
21756
void lbm_set_timestamp_us_callback(uint32_t (*fptr)(void)) {
285
21756
  if (fptr == NULL) timestamp_us_callback = timestamp_nonsense;
286
21756
  else timestamp_us_callback = fptr;
287
21756
}
288
289
21756
void lbm_set_ctx_done_callback(void (*fptr)(eval_context_t *)) {
290
21756
  if (fptr == NULL) ctx_done_callback = ctx_done_nonsense;
291
21756
  else ctx_done_callback = fptr;
292
21756
}
293
294
21756
void lbm_set_printf_callback(int (*fptr)(const char*, ...)){
295
21756
  if (fptr == NULL) printf_callback = printf_nonsense;
296
21756
  else printf_callback = fptr;
297
21756
}
298
299
21756
void lbm_set_dynamic_load_callback(bool (*fptr)(const char *, const char **)) {
300
21756
  if (fptr == NULL) dynamic_load_callback = dynamic_load_nonsense;
301
21756
  else  dynamic_load_callback = fptr;
302
21756
}
303
304
static volatile lbm_event_t *lbm_events = NULL;
305
static unsigned int lbm_events_head = 0;
306
static unsigned int lbm_events_tail = 0;
307
static unsigned int lbm_events_max  = 0;
308
static bool         lbm_events_full = false;
309
static mutex_t      lbm_events_mutex;
310
static bool         lbm_events_mutex_initialized = false;
311
static volatile lbm_cid  lbm_event_handler_pid = -1;
312
313
lbm_cid lbm_get_event_handler_pid(void) {
314
  return lbm_event_handler_pid;
315
}
316
317
224
void lbm_set_event_handler_pid(lbm_cid pid) {
318
224
  lbm_event_handler_pid = pid;
319
224
}
320
321
bool lbm_event_handler_exists(void) {
322
  return(lbm_event_handler_pid > 0);
323
}
324
325
326
6770
static bool event_internal(lbm_event_type_t event_type, lbm_uint parameter, lbm_uint buf_ptr, lbm_uint buf_len) {
327
6770
  bool r = false;
328
6770
  if (lbm_events) {
329
6770
    mutex_lock(&lbm_events_mutex);
330
6770
    if (!lbm_events_full) {
331
      lbm_event_t event;
332
6770
      event.type = event_type;
333
6770
      event.parameter = parameter;
334
6770
      event.buf_ptr = buf_ptr;
335
6770
      event.buf_len = buf_len;
336
6770
      lbm_events[lbm_events_head] = event;
337
6770
      lbm_events_head = (lbm_events_head + 1) % lbm_events_max;
338
6770
      lbm_events_full = lbm_events_head == lbm_events_tail;
339
6770
      r = true;
340
    }
341
6770
    mutex_unlock(&lbm_events_mutex);
342
  }
343
6770
  return r;
344
}
345
346
bool lbm_event_define(lbm_value key, lbm_flat_value_t *fv) {
347
  return event_internal(LBM_EVENT_DEFINE, key, (lbm_uint)fv->buf, fv->buf_size);
348
}
349
350
bool lbm_event_run_user_callback(void *arg) {
351
  return event_internal(LBM_EVENT_RUN_USER_CALLBACK, (lbm_uint)arg, 0, 0);
352
}
353
354
bool lbm_event_unboxed(lbm_value unboxed) {
355
  lbm_uint t = lbm_type_of(unboxed);
356
  if (t == LBM_TYPE_SYMBOL ||
357
      t == LBM_TYPE_I ||
358
      t == LBM_TYPE_U ||
359
      t == LBM_TYPE_CHAR) {
360
    if (lbm_event_handler_pid > 0) {
361
      return event_internal(LBM_EVENT_FOR_HANDLER, 0, (lbm_uint)unboxed, 0);
362
    }
363
  }
364
  return false;
365
}
366
367
6686
bool lbm_event(lbm_flat_value_t *fv) {
368
6686
  if (lbm_event_handler_pid > 0) {
369
6686
    return event_internal(LBM_EVENT_FOR_HANDLER, 0, (lbm_uint)fv->buf, fv->buf_size);
370
  }
371
  return false;
372
}
373
374
93333387
static bool lbm_event_pop(lbm_event_t *event) {
375
93333387
  mutex_lock(&lbm_events_mutex);
376

93333387
  if (lbm_events_head == lbm_events_tail && !lbm_events_full) {
377
93326621
    mutex_unlock(&lbm_events_mutex);
378
93326621
    return false;
379
  }
380
6766
  *event = lbm_events[lbm_events_tail];
381
6766
  lbm_events_tail = (lbm_events_tail + 1) % lbm_events_max;
382
6766
  lbm_events_full = false;
383
6766
  mutex_unlock(&lbm_events_mutex);
384
6766
  return true;
385
}
386
387
bool lbm_event_queue_is_empty(void) {
388
  mutex_lock(&lbm_events_mutex);
389
  bool empty = false;
390
  if (lbm_events_head == lbm_events_tail && !lbm_events_full) {
391
    empty = true;
392
  }
393
  mutex_unlock(&lbm_events_mutex);
394
  return empty;
395
}
396
397
static bool              eval_running = false;
398
static volatile bool     blocking_extension = false;
399
static mutex_t           blocking_extension_mutex;
400
static bool              blocking_extension_mutex_initialized = false;
401
static lbm_uint          blocking_extension_timeout_us = 0;
402
static bool              blocking_extension_timeout = false;
403
404
static bool              is_atomic = false;
405
406
/* Process queues */
407
static eval_context_queue_t blocked  = {NULL, NULL};
408
static eval_context_queue_t queue    = {NULL, NULL};
409
410
/* one mutex for all queue operations */
411
mutex_t qmutex;
412
bool    qmutex_initialized = false;
413
414
415
// MODES
416
static volatile bool lbm_verbose = false;
417
418
void lbm_toggle_verbose(void) {
419
  lbm_verbose = !lbm_verbose;
420
}
421
422
21756
void lbm_set_verbose(bool verbose) {
423
21756
  lbm_verbose = verbose;
424
21756
}
425
426
1064
lbm_cid lbm_get_current_cid(void) {
427
1064
  if (ctx_running)
428
1064
    return ctx_running->id;
429
  else
430
    return -1;
431
}
432
433
eval_context_t *lbm_get_current_context(void) {
434
  return ctx_running;
435
}
436
437
/****************************************************/
438
/* Utilities used locally in this file              */
439
440
381108
static inline lbm_array_header_t *assume_array(lbm_value a){
441
381108
  return (lbm_array_header_t*)lbm_ref_cell(a)->car;
442
}
443
444
4395661
static lbm_value cons_with_gc(lbm_value head, lbm_value tail, lbm_value remember) {
445
#ifdef LBM_ALWAYS_GC
446
  lbm_value always_gc_roots[3] = {head, tail, remember};
447
  lbm_gc_mark_roots(always_gc_roots,3);
448
  gc();
449
#endif
450
4395661
  lbm_value res = lbm_heap_state.freelist;
451
4395661
  if (lbm_is_symbol_nil(res)) {
452
1136
    lbm_value roots[3] = {head, tail, remember};
453
1136
    lbm_gc_mark_roots(roots,3);
454
1136
    gc();
455
1136
    res = lbm_heap_state.freelist;
456
1136
    if (lbm_is_symbol_nil(res)) {
457
      error_ctx(ENC_SYM_MERROR);
458
    }
459
  }
460
4395661
  lbm_uint heap_ix = lbm_dec_ptr(res);
461
4395661
  lbm_heap_state.freelist = lbm_heap_state.heap[heap_ix].cdr;
462
4395661
  lbm_heap_state.num_alloc++;
463
4395661
  lbm_heap_state.heap[heap_ix].car = head;
464
4395661
  lbm_heap_state.heap[heap_ix].cdr = tail;
465
4395661
  res = lbm_set_ptr_type(res, LBM_TYPE_CONS);
466
4395661
  return res;
467
}
468
469
469450965
static lbm_uint *get_stack_ptr(eval_context_t *ctx, unsigned int n) {
470
469450965
  if (n <= ctx->K.sp) {
471
469450965
    lbm_uint index = ctx->K.sp - n;
472
469450965
    return &ctx->K.data[index];
473
  }
474
  error_ctx(ENC_SYM_STACK_ERROR);
475
  return 0; // dead code cannot be reached, but C compiler doesn't realise.
476
}
477
478
// pop_stack_ptr is safe when no GC is performed and
479
// the values of the stack will be dropped.
480
21770892
static lbm_uint *pop_stack_ptr(eval_context_t *ctx, unsigned int n) {
481
21770892
  if (n <= ctx->K.sp) {
482
21770892
    ctx->K.sp -= n;
483
21770892
    return &ctx->K.data[ctx->K.sp];
484
  }
485
  error_ctx(ENC_SYM_STACK_ERROR);
486
  return 0; // dead code cannot be reached, but C compiler doesn't realise.
487
}
488
489
493975776
static inline lbm_uint *stack_reserve(eval_context_t *ctx, unsigned int n) {
490
493975776
  if (ctx->K.sp + n < ctx->K.size) {
491
493975776
    lbm_uint *ptr = &ctx->K.data[ctx->K.sp];
492
493975776
    ctx->K.sp += n;
493
493975776
    return ptr;
494
  }
495
  error_ctx(ENC_SYM_STACK_ERROR);
496
  return 0; // dead code cannot be reached, but C compiler doesn't realise.
497
}
498
499
7196
static void handle_flash_status(lbm_flash_status s) {
500
7196
  if ( s == LBM_FLASH_FULL) {
501
    lbm_set_error_reason((char*)lbm_error_str_flash_full);
502
    error_ctx(ENC_SYM_EERROR);
503
  }
504
7196
  if (s == LBM_FLASH_WRITE_ERROR) {
505
    lbm_set_error_reason((char*)lbm_error_str_flash_error);
506
    error_ctx(ENC_SYM_FATAL_ERROR);
507
  }
508
7196
}
509
510
84
static void lift_array_flash(lbm_value flash_cell, bool bytearray,  char *data, lbm_uint num_elt) {
511
512
  lbm_array_header_t flash_array_header;
513
84
  flash_array_header.size = num_elt;
514
84
  flash_array_header.data = (lbm_uint*)data;
515
84
  lbm_uint flash_array_header_ptr = 0;
516
84
  handle_flash_status(lbm_write_const_raw((lbm_uint*)&flash_array_header,
517
                                          sizeof(lbm_array_header_t) / sizeof(lbm_uint),
518
                                          &flash_array_header_ptr));
519
84
  handle_flash_status(write_const_car(flash_cell, flash_array_header_ptr));
520
84
  lbm_uint t = bytearray ? ENC_SYM_ARRAY_TYPE : ENC_SYM_LISPARRAY_TYPE;
521
84
  handle_flash_status(write_const_cdr(flash_cell, t));
522
84
}
523
524
119720544
static void get_car_and_cdr(lbm_value a, lbm_value *a_car, lbm_value *a_cdr) {
525
119720544
  if (lbm_is_ptr(a)) {
526
119402884
    lbm_cons_t *cell = lbm_ref_cell(a);
527
119402884
    *a_car = cell->car;
528
119402884
    *a_cdr = cell->cdr;
529
317660
  } else if (lbm_is_symbol_nil(a)) {
530
317660
    *a_car = *a_cdr = ENC_SYM_NIL;
531
  } else {
532
    *a_car = *a_cdr = ENC_SYM_NIL;
533
    error_ctx(ENC_SYM_TERROR);
534
  }
535
119720544
}
536
537
/* car cdr caar cadr replacements that are evaluator safe. */
538
114794657
static lbm_value get_car(lbm_value a) {
539
114794657
  if (lbm_is_ptr(a)) {
540
114794657
    lbm_cons_t *cell = lbm_ref_cell(a);
541
114794657
    return cell->car;
542
  } else if (lbm_is_symbol_nil(a)) {
543
    return a;
544
  }
545
  error_ctx(ENC_SYM_TERROR);
546
  return(ENC_SYM_TERROR);
547
}
548
549
139610443
static lbm_value get_cdr(lbm_value a) {
550
139610443
  if (lbm_is_ptr(a)) {
551
139610415
    lbm_cons_t *cell = lbm_ref_cell(a);
552
139610415
    return cell->cdr;
553
28
  } else if (lbm_is_symbol_nil(a)) {
554
28
    return a;
555
  }
556
  error_ctx(ENC_SYM_TERROR);
557
  return(ENC_SYM_TERROR);
558
}
559
560
27382597
static lbm_value get_cadr(lbm_value a) {
561
27382597
  if (lbm_is_ptr(a)) {
562
27382597
    lbm_cons_t *cell = lbm_ref_cell(a);
563
27382597
    lbm_value tmp = cell->cdr;
564
27382597
    if (lbm_is_ptr(tmp)) {
565
27372237
      return lbm_ref_cell(tmp)->car;
566
10360
    } else if (lbm_is_symbol_nil(tmp)) {
567
10360
      return tmp;
568
    }
569
  } else if (lbm_is_symbol_nil(a)) {
570
    return a;
571
  }
572
  error_ctx(ENC_SYM_TERROR);
573
  return(ENC_SYM_TERROR);
574
}
575
576
// Allocate a binding and attach it to a list (if so desired)
577
60009397
static lbm_value allocate_binding(lbm_value key, lbm_value val, lbm_value the_cdr) {
578
#ifdef LBM_ALWAYS_GC
579
  lbm_gc_mark_phase(key);
580
  lbm_gc_mark_phase(val);
581
  lbm_gc_mark_phase(the_cdr);
582
  gc();
583
  if (lbm_heap_num_free() < 2) {
584
    error_ctx(ENC_SYM_MERROR);
585
  }
586
#else
587
60009397
  if (lbm_heap_num_free() < 2) {
588
83306
    lbm_gc_mark_phase(key);
589
83306
    lbm_gc_mark_phase(val);
590
83306
    lbm_gc_mark_phase(the_cdr);
591
83306
    gc();
592
83306
    if (lbm_heap_num_free() < 2) {
593
28
      error_ctx(ENC_SYM_MERROR);
594
    }
595
  }
596
#endif
597
  // If num_free is calculated correctly, freelist is definitely a cons-cell.
598
60009369
  lbm_cons_t* heap = lbm_heap_state.heap;
599
60009369
  lbm_value binding_cell = lbm_heap_state.freelist;
600
60009369
  lbm_uint binding_cell_ix = lbm_dec_ptr(binding_cell);
601
60009369
  lbm_value list_cell = heap[binding_cell_ix].cdr;
602
60009369
  lbm_uint list_cell_ix = lbm_dec_ptr(list_cell);
603
60009369
  lbm_heap_state.freelist = heap[list_cell_ix].cdr;
604
60009369
  lbm_heap_state.num_alloc += 2;
605
60009369
  heap[binding_cell_ix].car = key;
606
60009369
  heap[binding_cell_ix].cdr = val;
607
60009369
  heap[list_cell_ix].car = binding_cell;
608
60009369
  heap[list_cell_ix].cdr = the_cdr;
609
60009369
  return list_cell;
610
}
611
612
#define CLO_PARAMS 0
613
#define CLO_BODY   1
614
#define CLO_ENV    2
615
#define LOOP_BINDS 0
616
#define LOOP_COND  1
617
#define LOOP_BODY  2
618
619
// (a b c) -> [a b c]
620
57802989
static lbm_value extract_n(lbm_value curr, lbm_value *res, unsigned int n) {
621
218966604
  for (unsigned int i = 0; i < n; i ++) {
622
161163615
    if (lbm_is_ptr(curr)) {
623
161163587
      lbm_cons_t *cell = lbm_ref_cell(curr);
624
161163587
      res[i] = cell->car;
625
161163587
      curr = cell->cdr;
626
    } else {
627
28
      res[i] = ENC_SYM_NIL;
628
    }
629
  }
630
57802989
  return curr; // Rest of list is returned here.
631
}
632
633
73276137
static void call_fundamental(lbm_uint fundamental, lbm_value *args, lbm_uint arg_count, eval_context_t *ctx) {
634
  lbm_value res;
635
#ifdef LBM_ALWAYS_GC
636
  gc();
637
#endif
638
73276137
  res = fundamental_table[fundamental](args, arg_count, ctx);
639
73276137
  if (lbm_is_error(res)) {
640
216220
    if (lbm_is_symbol_merror(res)) {
641
211628
      gc();
642
211628
      res = fundamental_table[fundamental](args, arg_count, ctx);
643
    }
644
216220
    if (lbm_is_error(res)) {
645
4656
      error_at_ctx(res, lbm_enc_sym(FUNDAMENTAL_SYMBOLS_START | fundamental));
646
    }
647
  }
648
73271481
  lbm_stack_drop(&ctx->K, arg_count+1);
649
73271481
  ctx->app_cont = true;
650
73271481
  ctx->r = res;
651
73271481
}
652
653
28
static void atomic_error(void) {
654
28
  is_atomic = false;
655
28
  lbm_set_error_reason((char*)lbm_error_str_forbidden_in_atomic);
656
28
  error_ctx(ENC_SYM_EERROR);
657
}
658
659
// block_current_ctx blocks a context until it is
660
// woken up externally or a timeout period of time passes.
661
// Blocking while in an atomic block would have bad consequences.
662
3324
static void block_current_ctx(uint32_t state, lbm_uint sleep_us,  bool do_cont) {
663
3324
  if (is_atomic) atomic_error();
664
3324
  ctx_running->timestamp = timestamp_us_callback();
665
3324
  ctx_running->sleep_us = sleep_us;
666
3324
  ctx_running->state  = state;
667
3324
  ctx_running->app_cont = do_cont;
668
3324
  enqueue_ctx(&blocked, ctx_running);
669
3324
  ctx_running = NULL;
670
3324
}
671
672
// reblock an essentially already blocked context.
673
// Same as block but sets no new timestamp or sleep_us.
674
static void reblock_current_ctx(uint32_t state, bool do_cont) {
675
  if (is_atomic) atomic_error();
676
  ctx_running->state  = state;
677
  ctx_running->app_cont = do_cont;
678
  enqueue_ctx(&blocked, ctx_running);
679
  ctx_running = NULL;
680
}
681
682
683
126
lbm_flash_status lbm_write_const_array_padded(uint8_t *data, lbm_uint n, lbm_uint *res) {
684
126
  lbm_uint full_words = n / sizeof(lbm_uint);
685
126
  lbm_uint n_mod = n % sizeof(lbm_uint);
686
687
126
  if (n_mod == 0) { // perfect fit.
688
56
    return lbm_write_const_raw((lbm_uint*)data, full_words, res);
689
  } else {
690
70
    lbm_uint last_word = 0;
691
70
    memcpy(&last_word, &data[full_words * sizeof(lbm_uint)], n_mod);
692
70
    if (full_words >= 1) {
693
14
      lbm_flash_status s = lbm_write_const_raw((lbm_uint*)data, full_words, res);
694
14
      if ( s == LBM_FLASH_WRITE_OK) {
695
        lbm_uint dummy;
696
14
        s = lbm_write_const_raw(&last_word, 1, &dummy);
697
      }
698
14
      return s;
699
    } else {
700
56
      return lbm_write_const_raw(&last_word, 1, res);
701
    }
702
  }
703
}
704
705
/****************************************************/
706
/* Error message creation                           */
707
708
#define ERROR_MESSAGE_BUFFER_SIZE_BYTES 256
709
710
8324
void print_environments(char *buf, unsigned int size) {
711
712
8324
  lbm_value curr_l = ctx_running->curr_env;
713
8324
  printf_callback("\tCurrent local environment:\n");
714
8552
  while (lbm_type_of(curr_l) == LBM_TYPE_CONS) {
715
228
    lbm_print_value(buf, (size/2) - 1, lbm_caar(curr_l));
716
228
    lbm_print_value(buf + (size/2),size/2, lbm_cdr(lbm_car(curr_l)));
717
228
    printf_callback("\t%s = %s\n", buf, buf+(size/2));
718
228
    curr_l = lbm_cdr(curr_l);
719
  }
720
8324
  printf_callback("\n\n");
721
8324
  printf_callback("\tCurrent global environment:\n");
722
8324
  lbm_value *glob_env = lbm_get_global_env();
723
724
274692
  for (int i = 0; i < GLOBAL_ENV_ROOTS; i ++) {
725
266368
    lbm_value curr_g = glob_env[i];;
726
312380
    while (lbm_type_of(curr_g) == LBM_TYPE_CONS) {
727
728
46012
      lbm_print_value(buf, (size/2) - 1, lbm_caar(curr_g));
729
46012
      lbm_print_value(buf + (size/2),size/2, lbm_cdr(lbm_car(curr_g)));
730
46012
      printf_callback("\t%s = %s\n", buf, buf+(size/2));
731
46012
      curr_g = lbm_cdr(curr_g);
732
    }
733
  }
734
8324
}
735
736
24720
void print_error_value(char *buf, lbm_uint bufsize, char *pre, lbm_value v, bool lookup) {
737
738
24720
  lbm_print_value(buf, bufsize, v);
739
24720
  printf_callback("%s %s\n",pre, buf);
740
24720
  if (lookup) {
741
16396
    if (lbm_is_symbol(v)) {
742
9392
      if (lbm_dec_sym(v) >= RUNTIME_SYMBOLS_START) {
743
1124
	lbm_value res = ENC_SYM_NIL;
744

2188
	if (lbm_env_lookup_b(&res, v, ctx_running->curr_env) ||
745
1064
	    lbm_global_env_lookup(&res, v)) {
746
788
	  lbm_print_value(buf, bufsize, res);
747
788
	  printf_callback("      bound to: %s\n", buf);
748
	} else {
749
336
	  printf_callback("      UNDEFINED\n");
750
	}
751
      }
752
    }
753
  }
754
24720
}
755
756
8324
void print_error_message(lbm_value error,
757
                         bool has_at,
758
                         lbm_value at,
759
                         unsigned int row,
760
                         unsigned int col,
761
                         lbm_int row0,
762
                         lbm_int row1,
763
                         lbm_int cid,
764
                         char *name) {
765
  /* try to allocate a lbm_print_value buffer on the lbm_memory */
766
8324
  char *buf = lbm_malloc_reserve(ERROR_MESSAGE_BUFFER_SIZE_BYTES);
767
8324
  if (!buf) {
768
    printf_callback("Error: Not enough free memory to create a human readable error message\n");
769
    return;
770
  }
771
772
8324
  print_error_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES,"   Error:", error, false);
773
8324
  if (name) {
774
    printf_callback(  "   CTX: %d \"%s\"\n", cid, name);
775
  } else {
776
8324
    printf_callback(  "   CTX: %d\n", cid);
777
  }
778
8324
  print_error_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES,"   Current:", ctx_running->curr_exp, true);
779
8324
  if (lbm_error_has_suspect) {
780
1232
      print_error_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES,"   At:", lbm_error_suspect, true);
781
1232
      lbm_error_has_suspect = false;
782
7092
  } else if (has_at) {
783
6840
    print_error_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES,"   In:", at, true);
784
  }
785
786
8324
  printf_callback("\n");
787
788

8324
  if (lbm_is_symbol(error) &&
789
      error == ENC_SYM_RERROR) {
790
    printf_callback("   Line:   %u\n", row);
791
    printf_callback("   Column: %u\n", col);
792
8324
  } else if (row0 >= 0) {
793
4060
    if (row1 < 0) printf_callback("   Starting at row: %d\n", row0);
794
4060
    else printf_callback("   Between row %d and %d\n", row0, row1);
795
  }
796
797
8324
  printf_callback("\n");
798
799
8324
  if (ctx_running->error_reason) {
800
1736
    printf_callback("   Reason: %s\n\n", ctx_running->error_reason);
801
  }
802
8324
  if (lbm_verbose) {
803
8324
    lbm_print_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES, ctx_running->r);
804
8324
    printf_callback("   Current intermediate result: %s\n\n", buf);
805
806
8324
    print_environments(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES);
807
8324
    printf_callback("\n\n");
808
809
8324
    printf_callback("   Stack:\n");
810
169760
    for (unsigned int i = 0; i < ctx_running->K.sp; i ++) {
811
161436
      lbm_print_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES, ctx_running->K.data[i]);
812
161436
      printf_callback("     %s\n", buf);
813
    }
814
  }
815
8324
  lbm_free(buf);
816
}
817
818
/****************************************************/
819
/* Tokenizing and parsing                           */
820
821
310042
bool create_string_channel(char *str, lbm_value *res, lbm_value dep) {
822
823
310042
  lbm_char_channel_t *chan = NULL;
824
310042
  lbm_string_channel_state_t *st = NULL;
825
826
310042
  st = (lbm_string_channel_state_t*)lbm_malloc(sizeof(lbm_string_channel_state_t));
827
310042
  if (st == NULL) {
828
1018
    return false;
829
  }
830
309024
  chan = (lbm_char_channel_t*)lbm_malloc(sizeof(lbm_char_channel_t));
831
309024
  if (chan == NULL) {
832
268
    lbm_free(st);
833
268
    return false;
834
  }
835
836
308756
  lbm_create_string_char_channel(st, chan, str);
837
308756
  lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_CHANNEL, (lbm_uint) chan, ENC_SYM_CHANNEL_TYPE);
838
308756
  if (cell == ENC_SYM_MERROR) {
839
    lbm_free(st);
840
    lbm_free(chan);
841
    return false;
842
  }
843
844
308756
  lbm_char_channel_set_dependency(chan, dep);
845
846
308756
  *res = cell;
847
308756
  return true;
848
}
849
850
21756
bool lift_char_channel(lbm_char_channel_t *chan , lbm_value *res) {
851
21756
  lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_CHANNEL, (lbm_uint) chan, ENC_SYM_CHANNEL_TYPE);
852
21756
  if (cell == ENC_SYM_MERROR) {
853
    return false;
854
  }
855
21756
  *res = cell;
856
21756
  return true;
857
}
858
859
860
/****************************************************/
861
/* Queue functions                                  */
862
863
695916
static void queue_iterator_nm(eval_context_queue_t *q, ctx_fun f, void *arg1, void *arg2) {
864
  eval_context_t *curr;
865
695916
  curr = q->first;
866
867
709242
  while (curr != NULL) {
868
13326
    f(curr, arg1, arg2);
869
13326
    curr = curr->next;
870
  }
871
695916
}
872
873
void lbm_all_ctxs_iterator(ctx_fun f, void *arg1, void *arg2) {
874
  mutex_lock(&qmutex);
875
  queue_iterator_nm(&blocked, f, arg1, arg2);
876
  queue_iterator_nm(&queue, f, arg1, arg2);
877
  if (ctx_running) f(ctx_running, arg1, arg2);
878
  mutex_unlock(&qmutex);
879
}
880
881
84
void lbm_running_iterator(ctx_fun f, void *arg1, void *arg2){
882
84
  mutex_lock(&qmutex);
883
84
  queue_iterator_nm(&queue, f, arg1, arg2);
884
84
  mutex_unlock(&qmutex);
885
84
}
886
887
84
void lbm_blocked_iterator(ctx_fun f, void *arg1, void *arg2){
888
84
  mutex_lock(&qmutex);
889
84
  queue_iterator_nm(&blocked, f, arg1, arg2);
890
84
  mutex_unlock(&qmutex);
891
84
}
892
893
91259993
static void enqueue_ctx_nm(eval_context_queue_t *q, eval_context_t *ctx) {
894
91259993
  if (q->last == NULL) {
895
88255769
    ctx->prev = NULL;
896
88255769
    ctx->next = NULL;
897
88255769
    q->first = ctx;
898
88255769
    q->last  = ctx;
899
  } else {
900
3004224
    ctx->prev = q->last;
901
3004224
    ctx->next = NULL;
902
3004224
    q->last->next = ctx;
903
3004224
    q->last = ctx;
904
  }
905
91259993
}
906
907
57392
static void enqueue_ctx(eval_context_queue_t *q, eval_context_t *ctx) {
908
57392
  mutex_lock(&qmutex);
909
57392
  enqueue_ctx_nm(q,ctx);
910
57392
  mutex_unlock(&qmutex);
911
57392
}
912
913
17976
static eval_context_t *lookup_ctx_nm(eval_context_queue_t *q, lbm_cid cid) {
914
  eval_context_t *curr;
915
17976
  curr = q->first;
916
17976
  while (curr != NULL) {
917
4199
    if (curr->id == cid) {
918
4199
      return curr;
919
    }
920
    curr = curr->next;
921
  }
922
13777
  return NULL;
923
}
924
925
3183
static bool drop_ctx_nm(eval_context_queue_t *q, eval_context_t *ctx) {
926
927
3183
  bool res = false;
928

3183
  if (q->first == NULL || q->last == NULL) {
929
    if (!(q->last == NULL && q->first == NULL)) {
930
      /* error state that should not happen */
931
      return res;
932
    }
933
    /* Queue is empty */
934
    return res;
935
  }
936
937
3183
  eval_context_t *curr = q->first;
938
3183
  while (curr) {
939
3183
    if (curr->id == ctx->id) {
940
3183
      res = true;
941
3183
      eval_context_t *tmp = curr->next;
942
3183
      if (curr->prev == NULL) {
943
3183
        if (curr->next == NULL) {
944
3169
          q->last = NULL;
945
3169
          q->first = NULL;
946
        } else {
947
14
          q->first = tmp;
948
14
          tmp->prev = NULL;
949
        }
950
      } else { /* curr->prev != NULL */
951
        if (curr->next == NULL) {
952
          q->last = curr->prev;
953
          q->last->next = NULL;
954
        } else {
955
          curr->prev->next = tmp;
956
          tmp->prev = curr->prev;
957
        }
958
      }
959
3183
      break;
960
    }
961
    curr = curr->next;
962
  }
963
3183
  return res;
964
}
965
966
/* End execution of the running context. */
967
22562
static void finish_ctx(void) {
968
969
22562
  if (!ctx_running) {
970
    return;
971
  }
972
  /* Drop the continuation stack immediately to free up lbm_memory */
973
22562
  lbm_stack_free(&ctx_running->K);
974
22562
  ctx_done_callback(ctx_running);
975
976
22562
  lbm_free(ctx_running->name); //free name if in LBM_MEM
977
22562
  lbm_memory_free((lbm_uint*)ctx_running->error_reason); //free error_reason if in LBM_MEM
978
979
22562
  lbm_memory_free((lbm_uint*)ctx_running->mailbox);
980
22562
  lbm_memory_free((lbm_uint*)ctx_running);
981
22562
  ctx_running = NULL;
982
}
983
984
140
static void context_exists(eval_context_t *ctx, void *cid, void *b) {
985
140
  if (ctx->id == *(lbm_cid*)cid) {
986
28
    *(bool*)b = true;
987
  }
988
140
}
989
990
1232
void lbm_set_error_suspect(lbm_value suspect) {
991
1232
  lbm_error_suspect = suspect;
992
1232
  lbm_error_has_suspect = true;
993
1232
}
994
995
1316
void lbm_set_error_reason(char *error_str) {
996
1316
  if (ctx_running != NULL) {
997
1316
    ctx_running->error_reason = error_str;
998
  }
999
1316
}
1000
1001
// Not possible to CONS_WITH_GC in error_ctx_base (potential loop)
1002
8324
static void error_ctx_base(lbm_value err_val, bool has_at, lbm_value at, unsigned int row, unsigned int column) {
1003
1004
8324
  print_error_message(err_val,
1005
                      has_at,
1006
                      at,
1007
                      row,
1008
                      column,
1009
8324
                      ctx_running->row0,
1010
8324
                      ctx_running->row1,
1011
8324
                      ctx_running->id,
1012
8324
                      ctx_running->name);
1013
1014
8324
  if (ctx_running->flags & EVAL_CPS_CONTEXT_FLAG_TRAP) {
1015
196
    if (lbm_heap_num_free() < 3) {
1016
      gc();
1017
    }
1018
1019
196
    if (lbm_heap_num_free() >= 3) {
1020
196
      lbm_value msg = lbm_cons(err_val, ENC_SYM_NIL);
1021
196
      msg = lbm_cons(lbm_enc_i(ctx_running->id), msg);
1022
196
      msg = lbm_cons(ENC_SYM_EXIT_ERROR, msg);
1023
196
      if (!lbm_is_symbol_merror(msg)) {
1024
196
        lbm_find_receiver_and_send(ctx_running->parent, msg);
1025
      }
1026
    }
1027
    // context dies.
1028

8128
  } else if ((ctx_running->flags & EVAL_CPS_CONTEXT_FLAG_TRAP_UNROLL_RETURN) &&
1029
      (err_val != ENC_SYM_FATAL_ERROR)) {
1030
    lbm_uint v;
1031
28896
    while (ctx_running->K.sp > 0) {
1032
28896
      lbm_pop(&ctx_running->K, &v);
1033
28896
      if (v == EXCEPTION_HANDLER) { // context continues executing.
1034
8120
        lbm_value *sptr = get_stack_ptr(ctx_running, 2);
1035
8120
        lbm_set_car(sptr[0], ENC_SYM_EXIT_ERROR);
1036
8120
        stack_reserve(ctx_running, 1)[0] = EXCEPTION_HANDLER;
1037
8120
        ctx_running->app_cont = true;
1038
8120
        ctx_running->r = err_val;
1039
8120
        longjmp(error_jmp_buf, 1);
1040
      }
1041
    }
1042
    err_val = ENC_SYM_FATAL_ERROR;
1043
  }
1044
204
  ctx_running->r = err_val;
1045
204
  finish_ctx();
1046
204
  longjmp(error_jmp_buf, 1);
1047
}
1048
1049
8072
static void error_at_ctx(lbm_value err_val, lbm_value at) {
1050
8072
  error_ctx_base(err_val, true, at, 0, 0);
1051
}
1052
1053
252
static void error_ctx(lbm_value err_val) {
1054
252
  error_ctx_base(err_val, false, 0, 0, 0);
1055
}
1056
1057
static void read_error_ctx(unsigned int row, unsigned int column) {
1058
  error_ctx_base(ENC_SYM_RERROR, false, 0, row, column);
1059
}
1060
1061
void lbm_critical_error(void) {
1062
  longjmp(critical_error_jmp_buf, 1);
1063
}
1064
1065
// successfully finish a context
1066
22358
static void ok_ctx(void) {
1067
22358
  if (ctx_running->flags & EVAL_CPS_CONTEXT_FLAG_TRAP) {
1068
    lbm_value msg;
1069

140
    WITH_GC(msg, lbm_heap_allocate_list_init(3,
1070
                                             ENC_SYM_EXIT_OK,
1071
                                             lbm_enc_i(ctx_running->id),
1072
                                             ctx_running->r));
1073
140
    lbm_find_receiver_and_send(ctx_running->parent, msg);
1074
  }
1075
22358
  finish_ctx();
1076
22358
}
1077
1078
93326620
static eval_context_t *dequeue_ctx_nm(eval_context_queue_t *q) {
1079
93326620
  if (q->last == NULL) {
1080
2101312
    return NULL;
1081
  }
1082
  // q->first should only be NULL if q->last is.
1083
91225308
  eval_context_t *res = q->first;
1084
1085
91225308
  if (q->first == q->last) { // One thing in queue
1086
88223427
    q->first = NULL;
1087
88223427
    q->last  = NULL;
1088
   } else {
1089
3001881
    q->first = q->first->next;
1090
3001881
    q->first->prev = NULL;
1091
  }
1092
91225308
  res->prev = NULL;
1093
91225308
  res->next = NULL;
1094
91225308
  return res;
1095
}
1096
1097
93326620
static void wake_up_ctxs_nm(void) {
1098
  lbm_uint t_now;
1099
1100
93326620
  if (timestamp_us_callback) {
1101
93326620
    t_now = timestamp_us_callback();
1102
  } else {
1103
    t_now = 0;
1104
  }
1105
1106
93326620
  eval_context_queue_t *q = &blocked;
1107
93326620
  eval_context_t *curr = q->first;
1108
1109
96684382
  while (curr != NULL) {
1110
    lbm_uint t_diff;
1111
3357762
    eval_context_t *next = curr->next;
1112
3357762
    if (LBM_IS_STATE_WAKE_UP_WAKABLE(curr->state)) {
1113
3125364
      if ( curr->timestamp > t_now) {
1114
        /* There was an overflow on the counter */
1115
#ifndef LBM64
1116
        t_diff = (0xFFFFFFFF - curr->timestamp) + t_now;
1117
#else
1118
        t_diff = (0xFFFFFFFFFFFFFFFF - curr->timestamp) + t_now;
1119
#endif
1120
      } else {
1121
3125364
        t_diff = t_now - curr->timestamp;
1122
      }
1123
1124
3125364
      if (t_diff >= curr->sleep_us) {
1125
31355
        eval_context_t *wake_ctx = curr;
1126
31355
        if (curr == q->last) {
1127
31314
          if (curr->prev) {
1128
2288
            q->last = curr->prev;
1129
2288
            q->last->next = NULL;
1130
          } else {
1131
29026
            q->first = NULL;
1132
29026
            q->last = NULL;
1133
          }
1134
41
        } else if (curr->prev == NULL) {
1135
41
          q->first = curr->next;
1136
41
          q->first->prev = NULL;
1137
        } else {
1138
          curr->prev->next = curr->next;
1139
          if (curr->next) {
1140
            curr->next->prev = curr->prev;
1141
          }
1142
        }
1143
31355
        wake_ctx->next = NULL;
1144
31355
        wake_ctx->prev = NULL;
1145
31355
        if (LBM_IS_STATE_TIMEOUT(curr->state)) {
1146
140
          mailbox_add_mail(wake_ctx, ENC_SYM_TIMEOUT);
1147
140
          wake_ctx->r = ENC_SYM_TIMEOUT;
1148
        }
1149
31355
        wake_ctx->state = LBM_THREAD_STATE_READY;
1150
31355
        enqueue_ctx_nm(&queue, wake_ctx);
1151
      }
1152
    }
1153
3357762
    curr = next;
1154
  }
1155
93326620
}
1156
1157
31304
static void yield_ctx(lbm_uint sleep_us) {
1158
31304
  if (is_atomic) atomic_error();
1159
31276
  if (timestamp_us_callback) {
1160
31276
    ctx_running->timestamp = timestamp_us_callback();
1161
31276
    ctx_running->sleep_us = sleep_us;
1162
31276
    ctx_running->state = LBM_THREAD_STATE_SLEEPING;
1163
  } else {
1164
    ctx_running->timestamp = 0;
1165
    ctx_running->sleep_us = 0;
1166
    ctx_running->state = LBM_THREAD_STATE_SLEEPING;
1167
  }
1168
31276
  ctx_running->r = ENC_SYM_TRUE;
1169
31276
  ctx_running->app_cont = true;
1170
31276
  enqueue_ctx(&blocked,ctx_running);
1171
31276
  ctx_running = NULL;
1172
31276
}
1173
1174
22820
static 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) {
1175
1176
22820
  if (!lbm_is_cons(program)) return -1;
1177
1178
22820
  eval_context_t *ctx = NULL;
1179
#ifdef LBM_ALWAYS_GC
1180
  {
1181
    lbm_uint roots[2] = {program, env};
1182
    lbm_gc_mark_roots(roots, 2);
1183
    gc();
1184
  }
1185
#endif
1186
22820
  ctx = (eval_context_t*)lbm_malloc(sizeof(eval_context_t));
1187
22820
  if (ctx == NULL) {
1188
    lbm_uint roots[2] = {program, env};
1189
    lbm_gc_mark_roots(roots, 2);
1190
    gc();
1191
    ctx = (eval_context_t*)lbm_malloc(sizeof(eval_context_t));
1192
  }
1193
22820
  if (ctx == NULL) return -1;
1194
#ifdef LBM_ALWAYS_GC
1195
  {
1196
    lbm_uint roots[2] = {program, env};
1197
    lbm_gc_mark_roots(roots, 2);
1198
    gc();
1199
  }
1200
#endif
1201
22820
  if (!lbm_stack_allocate(&ctx->K, stack_size)) {
1202
28
    lbm_uint roots[2] = {program, env};
1203
28
    lbm_gc_mark_roots(roots, 2);
1204
28
    gc();
1205
28
    if (!lbm_stack_allocate(&ctx->K, stack_size)) {
1206
28
      lbm_memory_free((lbm_uint*)ctx);
1207
28
      return -1;
1208
    }
1209
  }
1210
1211
22792
  lbm_value *mailbox = NULL;
1212
#ifdef LBM_ALWAYS_GC
1213
  {
1214
    lbm_uint roots[2] = {program, env};
1215
    lbm_gc_mark_roots(roots, 2);
1216
    gc();
1217
  }
1218
#endif
1219
22792
  mailbox = (lbm_value*)lbm_memory_allocate(EVAL_CPS_DEFAULT_MAILBOX_SIZE);
1220
22792
  if (mailbox == NULL) {
1221
    lbm_value roots[2] = {program, env};
1222
    lbm_gc_mark_roots(roots,2);
1223
    gc();
1224
    mailbox = (lbm_value *)lbm_memory_allocate(EVAL_CPS_DEFAULT_MAILBOX_SIZE);
1225
  }
1226
22792
  if (mailbox == NULL) {
1227
    lbm_stack_free(&ctx->K);
1228
    lbm_memory_free((lbm_uint*)ctx);
1229
    return -1;
1230
  }
1231
1232
  // TODO: Limit names to 19 chars + 1 char for 0? (or something similar).
1233
22792
  if (name) {
1234
140
    lbm_uint name_len = strlen(name) + 1;
1235
#ifdef LBM_ALWAYS_GC
1236
    {
1237
      lbm_uint roots[2] = {program, env};
1238
      lbm_gc_mark_roots(roots, 2);
1239
      gc();
1240
    }
1241
#endif
1242
140
    ctx->name = lbm_malloc(name_len);
1243
140
    if (ctx->name == NULL) {
1244
      lbm_value roots[2] = {program, env};
1245
      lbm_gc_mark_roots(roots, 2);
1246
      gc();
1247
      ctx->name = lbm_malloc(name_len);
1248
    }
1249
140
    if (ctx->name == NULL) {
1250
      lbm_stack_free(&ctx->K);
1251
      lbm_memory_free((lbm_uint*)mailbox);
1252
      lbm_memory_free((lbm_uint*)ctx);
1253
      return -1;
1254
    }
1255
140
    memcpy(ctx->name, name, name_len);
1256
  } else {
1257
22652
     ctx->name = NULL;
1258
  }
1259
1260
22792
  lbm_int cid = lbm_memory_address_to_ix((lbm_uint*)ctx);
1261
1262
22792
  ctx->program = lbm_cdr(program);
1263
22792
  ctx->curr_exp = lbm_car(program);
1264
22792
  ctx->curr_env = env;
1265
22792
  ctx->r = ENC_SYM_NIL;
1266
22792
  ctx->error_reason = NULL;
1267
22792
  ctx->mailbox = mailbox;
1268
22792
  ctx->mailbox_size = EVAL_CPS_DEFAULT_MAILBOX_SIZE;
1269
22792
  ctx->flags = context_flags;
1270
22792
  ctx->num_mail = 0;
1271
22792
  ctx->app_cont = false;
1272
22792
  ctx->timestamp = 0;
1273
22792
  ctx->sleep_us = 0;
1274
22792
  ctx->state = LBM_THREAD_STATE_READY;
1275
22792
  ctx->prev = NULL;
1276
22792
  ctx->next = NULL;
1277
1278
22792
  ctx->row0 = -1;
1279
22792
  ctx->row1 = -1;
1280
1281
22792
  ctx->id = cid;
1282
22792
  ctx->parent = parent;
1283
1284
22792
  if (!lbm_push(&ctx->K, DONE)) {
1285
    lbm_memory_free((lbm_uint*)ctx->mailbox);
1286
    lbm_stack_free(&ctx->K);
1287
    lbm_memory_free((lbm_uint*)ctx);
1288
    return -1;
1289
  }
1290
1291
22792
  enqueue_ctx(&queue,ctx);
1292
1293
22792
  return ctx->id;
1294
}
1295
1296
21756
lbm_cid lbm_create_ctx(lbm_value program, lbm_value env, lbm_uint stack_size, char *name) {
1297
  // Creates a parentless context.
1298
21756
  return lbm_create_ctx_parent(program,
1299
                               env,
1300
                               stack_size,
1301
                               -1,
1302
                               EVAL_CPS_CONTEXT_FLAG_NOTHING,
1303
                               name);
1304
}
1305
1306
140
bool lbm_mailbox_change_size(eval_context_t *ctx, lbm_uint new_size) {
1307
1308
140
  lbm_value *mailbox = NULL;
1309
#ifdef LBM_ALWAYS_GC
1310
  gc();
1311
#endif
1312
140
  mailbox = (lbm_value*)lbm_memory_allocate(new_size);
1313
140
  if (mailbox == NULL) {
1314
28
    gc();
1315
28
    mailbox = (lbm_value *)lbm_memory_allocate(new_size);
1316
  }
1317
140
  if (mailbox == NULL) {
1318
28
    return false;
1319
  }
1320
1321
112
  for (lbm_uint i = 0; i < ctx->num_mail; i ++ ) {
1322
    mailbox[i] = ctx->mailbox[i];
1323
  }
1324
112
  lbm_memory_free(ctx->mailbox);
1325
112
  ctx->mailbox = mailbox;
1326
112
  ctx->mailbox_size = (uint32_t)new_size;
1327
112
  return true;
1328
}
1329
1330
6188
static void mailbox_remove_mail(eval_context_t *ctx, lbm_uint ix) {
1331
1332
22122
  for (lbm_uint i = ix; i < ctx->num_mail-1; i ++) {
1333
15934
    ctx->mailbox[i] = ctx->mailbox[i+1];
1334
  }
1335
6188
  ctx->num_mail --;
1336
6188
}
1337
1338
7140
static bool mailbox_add_mail(eval_context_t *ctx, lbm_value mail) {
1339
1340
7140
  if (ctx->num_mail >= ctx->mailbox_size) {
1341
588
    mailbox_remove_mail(ctx, 0);
1342
  }
1343
1344
7140
  ctx->mailbox[ctx->num_mail] = mail;
1345
7140
  ctx->num_mail ++;
1346
7140
  return true;
1347
}
1348
1349
/**************************************************************
1350
 * Advance execution to the next expression in the program.
1351
 * Assumes programs are not malformed. Apply_eval_program
1352
 * ensures programs are lists ending in nil. The reader
1353
 * ensures this likewise.
1354
 *************************************************************/
1355
65195
static void advance_ctx(eval_context_t *ctx) {
1356
65195
  if (ctx->program) { // fast not-nil check,  assume cons if not nil.
1357
42920
    stack_reserve(ctx, 1)[0] = DONE;
1358
42920
    lbm_cons_t *cell = lbm_ref_cell(ctx->program);
1359
42920
    ctx->curr_exp = cell->car;
1360
42920
    ctx->program = cell->cdr;
1361
42920
    ctx->curr_env = ENC_SYM_NIL;
1362
  } else {
1363
22275
    if (ctx_running == ctx) {  // This should always be the case because of odd historical reasons.
1364
22275
      ok_ctx();
1365
    }
1366
  }
1367
65195
}
1368
1369
84
bool lbm_unblock_ctx(lbm_cid cid, lbm_flat_value_t *fv) {
1370
84
  return event_internal(LBM_EVENT_UNBLOCK_CTX, (lbm_uint)cid, (lbm_uint)fv->buf, fv->buf_size);
1371
}
1372
1373
28
bool lbm_unblock_ctx_r(lbm_cid cid) {
1374
28
  mutex_lock(&blocking_extension_mutex);
1375
28
  bool r = false;
1376
28
  eval_context_t *found = NULL;
1377
28
  mutex_lock(&qmutex);
1378
28
  found = lookup_ctx_nm(&blocked, cid);
1379

28
  if (found && (LBM_IS_STATE_UNBLOCKABLE(found->state))) {
1380
28
    drop_ctx_nm(&blocked,found);
1381
28
    found->state = LBM_THREAD_STATE_READY;
1382
28
    enqueue_ctx_nm(&queue,found);
1383
28
    r = true;
1384
  }
1385
28
  mutex_unlock(&qmutex);
1386
28
  mutex_unlock(&blocking_extension_mutex);
1387
28
  return r;
1388
}
1389
1390
// unblock unboxed is also safe for rmbr:ed things.
1391
bool lbm_unblock_ctx_unboxed(lbm_cid cid, lbm_value unboxed) {
1392
  mutex_lock(&blocking_extension_mutex);
1393
  bool r = false;
1394
  eval_context_t *found = NULL;
1395
  mutex_lock(&qmutex);
1396
  found = lookup_ctx_nm(&blocked, cid);
1397
  if (found && (LBM_IS_STATE_UNBLOCKABLE(found->state))) {
1398
    drop_ctx_nm(&blocked,found);
1399
    found->r = unboxed;
1400
    if (lbm_is_error(unboxed)) {
1401
      get_stack_ptr(found, 1)[0] = TERMINATE; // replace TOS
1402
      found->app_cont = true;
1403
    }
1404
    found->state = LBM_THREAD_STATE_READY;
1405
    enqueue_ctx_nm(&queue,found);
1406
    r = true;
1407
  }
1408
  mutex_unlock(&qmutex);
1409
  mutex_unlock(&blocking_extension_mutex);
1410
  return r;
1411
}
1412
1413
112
static bool lbm_block_ctx_base(bool timeout, float t_s) {
1414
112
  mutex_lock(&blocking_extension_mutex);
1415
112
  blocking_extension = true;
1416
112
  if (timeout) {
1417
    blocking_extension_timeout_us = S_TO_US(t_s);
1418
    blocking_extension_timeout = true;
1419
  } else {
1420
112
    blocking_extension_timeout = false;
1421
  }
1422
112
  return true;
1423
}
1424
1425
void lbm_block_ctx_from_extension_timeout(float s) {
1426
  lbm_block_ctx_base(true, s);
1427
}
1428
1429
112
void lbm_block_ctx_from_extension(void) {
1430
112
  lbm_block_ctx_base(false, 0);
1431
112
}
1432
1433
// todo: May need to pop rmbrs from stack, if present.
1434
// Suspect that the letting the discard cont run is really not a problem.
1435
// Either way will be quite confusing what happens to allocated things when undoing block.
1436
void lbm_undo_block_ctx_from_extension(void) {
1437
  blocking_extension = false;
1438
  blocking_extension_timeout_us = 0;
1439
  blocking_extension_timeout = false;
1440
  mutex_unlock(&blocking_extension_mutex);
1441
}
1442
1443
#define LBM_RECEIVER_FOUND 0
1444
#define LBM_RECEIVER_FOUND_MAIL_DELIVERY_FAILED -1
1445
#define LBM_RECEIVER_NOT_FOUND -2
1446
1447
10350
int lbm_find_receiver_and_send(lbm_cid cid, lbm_value msg) {
1448
10350
  mutex_lock(&qmutex);
1449
10350
  eval_context_t *found = NULL;
1450
1451
10350
  found = lookup_ctx_nm(&blocked, cid);
1452
10350
  if (found) {
1453
3002
    if (LBM_IS_STATE_RECV(found->state)) { // only if unblock receivers here.
1454
2988
      drop_ctx_nm(&blocked,found);
1455
2988
      found->state = LBM_THREAD_STATE_READY;
1456
2988
      enqueue_ctx_nm(&queue,found);
1457
    }
1458
3002
    if (!mailbox_add_mail(found, msg)) {
1459
      mutex_unlock(&qmutex);
1460
      return LBM_RECEIVER_FOUND_MAIL_DELIVERY_FAILED;
1461
    }
1462
3002
    mutex_unlock(&qmutex);
1463
3002
    return LBM_RECEIVER_FOUND;
1464
  }
1465
1466
7348
  found = lookup_ctx_nm(&queue, cid);
1467
7348
  if (found) {
1468
1002
    if (!mailbox_add_mail(found, msg)) {
1469
      mutex_unlock(&qmutex);
1470
      return LBM_RECEIVER_FOUND_MAIL_DELIVERY_FAILED;
1471
    }
1472
1002
    mutex_unlock(&qmutex);
1473
1002
    return LBM_RECEIVER_FOUND;
1474
  }
1475
1476
  /* check the current context */
1477

6346
  if (ctx_running && ctx_running->id == cid) {
1478
2996
    if (!mailbox_add_mail(ctx_running, msg)) {
1479
      mutex_unlock(&qmutex);
1480
      return LBM_RECEIVER_FOUND_MAIL_DELIVERY_FAILED;
1481
    }
1482
2996
    mutex_unlock(&qmutex);
1483
2996
    return LBM_RECEIVER_FOUND;
1484
  }
1485
3350
  mutex_unlock(&qmutex);
1486
3350
  return LBM_RECEIVER_NOT_FOUND;
1487
}
1488
1489
// a match binder looks like (? x) or (? _) for example.
1490
// It is a list of two elements where the first is a ? and the second is a symbol.
1491
23476
static inline lbm_value get_match_binder_variable(lbm_value exp) {
1492
23476
  lbm_value var = ENC_SYM_NIL; // 0 false
1493
23476
  if (lbm_is_cons(exp)) {
1494
15608
    lbm_cons_t *e_cell = lbm_ref_cell(exp);
1495
15608
    lbm_value bt = e_cell->car;
1496

15608
    if (bt == ENC_SYM_MATCH_ANY && lbm_is_cons(e_cell->cdr)) {
1497
8804
      var = lbm_ref_cell(e_cell->cdr)->car;
1498
    }
1499
  }
1500
23476
  return var;
1501
}
1502
1503
/* Pattern matching is currently implemented as a recursive
1504
   function and make use of stack relative to the size of
1505
   expressions that are being matched. */
1506
23476
static bool match(lbm_value p, lbm_value e, lbm_value *env, bool *gc) {
1507
23476
  bool r = false;
1508
23476
  lbm_value var = get_match_binder_variable(p);
1509
23476
  if (var) {
1510
8804
    lbm_value binding = lbm_cons(var, e);
1511
8804
    if (lbm_is_cons(binding)) {
1512
8792
      lbm_value new_env = lbm_cons(binding, *env);
1513
8792
      if (lbm_is_cons(new_env)) {
1514
8792
        *env = new_env;
1515
8792
        r = true;
1516
      }
1517
    }
1518
8804
    *gc = !r;
1519
14672
  } else  if (lbm_is_symbol(p)) {
1520
6188
    if (p == ENC_SYM_DONTCARE) r = true;
1521
4816
    else r = (p == e);
1522

8484
  } else if (lbm_is_cons(p) && lbm_is_cons(e) ) {
1523
5628
    lbm_cons_t *p_cell = lbm_ref_cell(p);
1524
5628
    lbm_cons_t *e_cell = lbm_ref_cell(e);
1525
5628
    lbm_value headp = p_cell->car;
1526
5628
    lbm_value tailp = p_cell->cdr;
1527
5628
    lbm_value heade = e_cell->car;
1528
5628
    lbm_value taile = e_cell->cdr;
1529
5628
    r = match(headp, heade, env, gc);
1530

5628
    r = r && match (tailp, taile, env, gc);
1531
  } else {
1532
2856
    r = struct_eq(p, e);
1533
  }
1534
23476
  return r;
1535
}
1536
1537
// Find match is not very picky about syntax.
1538
// A completely malformed recv form is most likely to
1539
// just return no_match.
1540
5686
static int find_match(lbm_value plist, lbm_value *earr, lbm_uint num, lbm_value *e, lbm_value *env) {
1541
1542
  // A pattern list is a list of pattern, expression lists.
1543
  // ( (p1 e1) (p2 e2) ... (pn en))
1544
5686
  lbm_value curr_p = plist;
1545
5686
  int n = 0;
1546
5686
  bool need_gc = false;
1547
6286
  for (int i = 0; i < (int)num; i ++ ) {
1548
6200
    lbm_value curr_e = earr[i];
1549
7528
    while (!lbm_is_symbol_nil(curr_p)) {
1550
6928
      lbm_value me = get_car(curr_p);
1551
6928
      if (match(get_car(me), curr_e, env, &need_gc)) {
1552
5600
        if (need_gc) return FM_NEED_GC;
1553
5600
        *e = get_cadr(me);
1554
1555
5600
        if (!lbm_is_symbol_nil(get_cadr(get_cdr(me)))) {
1556
          return FM_PATTERN_ERROR;
1557
        }
1558
5600
        return n;
1559
      }
1560
1328
      curr_p = get_cdr(curr_p);
1561
    }
1562
600
    curr_p = plist;       /* search all patterns against next exp */
1563
600
    n ++;
1564
  }
1565
1566
86
  return FM_NO_MATCH;
1567
}
1568
1569
/****************************************************/
1570
/* Garbage collection                               */
1571
1572
361032
static void mark_context(eval_context_t *ctx, void *arg1, void *arg2) {
1573
  (void) arg1;
1574
  (void) arg2;
1575
361032
  lbm_value roots[3] = {ctx->curr_exp, ctx->program, ctx->r };
1576
361032
  lbm_gc_mark_env(ctx->curr_env);
1577
361032
  lbm_gc_mark_roots(roots, 3);
1578
361032
  lbm_gc_mark_roots(ctx->mailbox, ctx->num_mail);
1579
361032
  lbm_gc_mark_aux(ctx->K.data, ctx->K.sp);
1580
361032
}
1581
1582
347874
static int gc(void) {
1583
347874
  if (ctx_running) {
1584
347846
    ctx_running->state = ctx_running->state | LBM_THREAD_STATE_GC_BIT;
1585
  }
1586
1587
347874
  gc_requested = false;
1588
347874
  lbm_gc_state_inc();
1589
1590
  // The freelist should generally be NIL when GC runs.
1591
347874
  lbm_nil_freelist();
1592
347874
  lbm_value *env = lbm_get_global_env();
1593
11479842
  for (int i = 0; i < GLOBAL_ENV_ROOTS; i ++) {
1594
11131968
    lbm_gc_mark_env(env[i]);
1595
  }
1596
1597
347874
  mutex_lock(&qmutex); // Lock the queues.
1598
                       // Any concurrent messing with the queues
1599
                       // while doing GC cannot possibly be good.
1600
347874
  queue_iterator_nm(&queue, mark_context, NULL, NULL);
1601
347874
  queue_iterator_nm(&blocked, mark_context, NULL, NULL);
1602
1603
347874
  if (ctx_running) {
1604
347846
    mark_context(ctx_running, NULL, NULL);
1605
  }
1606
347874
  mutex_unlock(&qmutex);
1607
1608
#ifdef VISUALIZE_HEAP
1609
  heap_vis_gen_image();
1610
#endif
1611
1612
347874
  int r = lbm_gc_sweep_phase();
1613
347874
  lbm_heap_new_freelist_length();
1614
347874
  lbm_memory_update_min_free();
1615
1616
347874
  if (ctx_running) {
1617
347846
    ctx_running->state = ctx_running->state & ~LBM_THREAD_STATE_GC_BIT;
1618
  }
1619
347874
  return r;
1620
}
1621
1622
13812
int lbm_perform_gc(void) {
1623
13812
  return gc();
1624
}
1625
1626
/****************************************************/
1627
/* Evaluation functions                             */
1628
1629
1630
224405517
static void eval_symbol(eval_context_t *ctx) {
1631
224405517
  lbm_uint s = lbm_dec_sym(ctx->curr_exp);
1632
224405517
  if (s >= RUNTIME_SYMBOLS_START) {
1633
145527452
    lbm_value res = ENC_SYM_NIL;
1634

171573176
    if (lbm_env_lookup_b(&res, ctx->curr_exp, ctx->curr_env) ||
1635
26045724
        lbm_global_env_lookup(&res, ctx->curr_exp)) {
1636
145522580
      ctx->r =  res;
1637
145522580
      ctx->app_cont = true;
1638
145522580
      return;
1639
    }
1640
    // Dynamic load attempt
1641
    // Only symbols of kind RUNTIME can be dynamically loaded.
1642
4872
    const char *sym_str = lbm_get_name_by_symbol(s);
1643
4872
    const char *code_str = NULL;
1644
4872
    if (!dynamic_load_callback(sym_str, &code_str)) {
1645
56
      error_at_ctx(ENC_SYM_NOT_FOUND, ctx->curr_exp);
1646
    }
1647
4816
    lbm_value *sptr = stack_reserve(ctx, 3);
1648
4816
    sptr[0] = ctx->curr_exp;
1649
4816
    sptr[1] = ctx->curr_env;
1650
4816
    sptr[2] = RESUME;
1651
1652
4816
    lbm_value chan = ENC_SYM_NIL;
1653
#ifdef LBM_ALWAYS_GC
1654
    gc();
1655
#endif
1656
4816
    if (!create_string_channel((char *)code_str, &chan, ENC_SYM_NIL)) {
1657
      gc();
1658
      if (!create_string_channel((char *)code_str, &chan, ENC_SYM_NIL)) {
1659
        error_ctx(ENC_SYM_MERROR);
1660
      }
1661
    }
1662
1663
    // Here, chan has either been assigned or execution has terminated.
1664
1665
    lbm_value loader;
1666

4816
    WITH_GC_RMBR_1(loader, lbm_heap_allocate_list_init(2,
1667
                                                       ENC_SYM_READ,
1668
                                                       chan), chan);
1669
    lbm_value evaluator;
1670

4816
    WITH_GC_RMBR_1(evaluator, lbm_heap_allocate_list_init(2,
1671
                                                          ENC_SYM_EVAL,
1672
                                                          loader), loader);
1673
4816
    ctx->curr_exp = evaluator;
1674
4816
    ctx->curr_env = ENC_SYM_NIL; // dynamics should be evaluable in empty local env
1675
  } else {
1676
    //special symbols and extensions can be handled the same way.
1677
78878065
    ctx->r = ctx->curr_exp;
1678
78878065
    ctx->app_cont = true;
1679
  }
1680
}
1681
1682
// (quote e) => e
1683
4660365
static void eval_quote(eval_context_t *ctx) {
1684
4660365
  ctx->r = get_cadr(ctx->curr_exp);
1685
4660365
  ctx->app_cont = true;
1686
4660365
}
1687
1688
// a => a
1689
96775722
static void eval_selfevaluating(eval_context_t *ctx) {
1690
96775722
  ctx->r = ctx->curr_exp;
1691
96775722
  ctx->app_cont = true;
1692
96775722
}
1693
1694
// (progn e1 ... en)
1695
14309814
static void eval_progn(eval_context_t *ctx) {
1696
14309814
  lbm_value exps = get_cdr(ctx->curr_exp);
1697
1698
14309814
  if (lbm_is_cons(exps)) {
1699
14309786
    lbm_cons_t *cell = lbm_ref_cell(exps); // already checked that it's cons.
1700
14309786
    ctx->curr_exp = cell->car;
1701
14309786
    if (lbm_is_cons(cell->cdr)) { // malformed progn not ending in nil is tolerated
1702
11507602
      lbm_uint *sptr = stack_reserve(ctx, 4);
1703
11507602
      sptr[0] = ctx->curr_env; // env to restore between expressions in progn
1704
11507602
      sptr[1] = lbm_enc_u(0);  // Has env been copied (needed for progn local bindings)
1705
11507602
      sptr[2] = cell->cdr;     // Requirement: sptr[2] is a cons.
1706
11507602
      sptr[3] = PROGN_REST;
1707
    }
1708
28
  } else if (lbm_is_symbol_nil(exps)) { // Empty progn is nil
1709
28
    ctx->r = ENC_SYM_NIL;
1710
28
    ctx->app_cont = true;
1711
  } else {
1712
    error_ctx(ENC_SYM_EERROR);
1713
  }
1714
14309814
}
1715
1716
// (atomic e1 ... en)
1717
252
static void eval_atomic(eval_context_t *ctx) {
1718
252
  if (is_atomic) atomic_error();
1719
252
  stack_reserve(ctx, 1)[0] = EXIT_ATOMIC;
1720
252
  is_atomic = true;
1721
252
  eval_progn(ctx);
1722
252
}
1723
1724
/* (call-cc (lambda (k) .... ))  */
1725
364
static void eval_callcc(eval_context_t *ctx) {
1726
  lbm_value cont_array;
1727
364
  lbm_uint *sptr0 = stack_reserve(ctx, 1);
1728
364
  sptr0[0] = is_atomic ? ENC_SYM_TRUE : ENC_SYM_NIL;
1729
#ifdef LBM_ALWAYS_GC
1730
  gc();
1731
#endif
1732
364
  if (!lbm_heap_allocate_lisp_array(&cont_array, ctx->K.sp)) {
1733
    gc();
1734
    lbm_heap_allocate_lisp_array(&cont_array, ctx->K.sp);
1735
  }
1736
364
  if (lbm_is_ptr(cont_array)) {
1737
364
    lbm_array_header_t *arr = assume_array(cont_array);
1738
364
    memcpy(arr->data, ctx->K.data, ctx->K.sp * sizeof(lbm_uint));
1739
    // The stored stack contains the is_atomic flag.
1740
    // This flag is overwritten in the following execution path.
1741
1742
364
    lbm_value acont = cons_with_gc(ENC_SYM_CONT, cont_array, ENC_SYM_NIL);
1743
364
    lbm_value arg_list = cons_with_gc(acont, ENC_SYM_NIL, ENC_SYM_NIL);
1744
    // Go directly into application evaluation without passing go
1745
364
    lbm_uint *sptr = stack_reserve(ctx, 2);
1746
364
    sptr0[0] = ctx->curr_env;
1747
364
    sptr[0] = arg_list;
1748
364
    sptr[1] = APPLICATION_START;
1749
364
    ctx->curr_exp = get_cadr(ctx->curr_exp);
1750
  } else {
1751
    // failed to create continuation array.
1752
    error_ctx(ENC_SYM_MERROR);
1753
  }
1754
364
}
1755
1756
// (define sym exp)
1757
#define KEY 1
1758
#define VAL 2
1759
4267760
static void eval_define(eval_context_t *ctx) {
1760
  lbm_value parts[3];
1761
4267760
  lbm_value rest = extract_n(ctx->curr_exp, parts, 3);
1762
4267760
  lbm_uint *sptr = stack_reserve(ctx, 2);
1763

4267760
  if (lbm_is_symbol(parts[KEY]) && lbm_is_symbol_nil(rest)) {
1764
4267760
    lbm_uint sym_val = lbm_dec_sym(parts[KEY]);
1765
4267760
    sptr[0] = parts[KEY];
1766
4267760
    if (sym_val >= RUNTIME_SYMBOLS_START) {
1767
4267760
      sptr[1] = SET_GLOBAL_ENV;
1768
4267760
      if (ctx->flags & EVAL_CPS_CONTEXT_FLAG_CONST) {
1769
14
        stack_reserve(ctx, 1)[0] = MOVE_VAL_TO_FLASH_DISPATCH;
1770
      }
1771
4267760
      ctx->curr_exp = parts[VAL];
1772
4267760
      return;
1773
    }
1774
  }
1775
  error_at_ctx(ENC_SYM_EERROR, ctx->curr_exp);
1776
}
1777
1778
/* Allocate closure is only used in eval_lambda currently.
1779
   Inlining it should use no extra storage.
1780
 */
1781
12012
static inline lbm_value allocate_closure(lbm_value params, lbm_value body, lbm_value env) {
1782
1783
#ifdef LBM_ALWAYS_GC
1784
  gc();
1785
  if (lbm_heap_num_free() < 4) {
1786
    error_ctx(ENC_SYM_MERROR);
1787
  }
1788
#else
1789
12012
  if (lbm_heap_num_free() < 4) {
1790
    gc();
1791
    if (lbm_heap_num_free() < 4) {
1792
      error_ctx(ENC_SYM_MERROR);
1793
    }
1794
  }
1795
#endif
1796
  // The freelist will always contain just plain heap-cells.
1797
  // So dec_ptr is sufficient.
1798
12012
  lbm_value res = lbm_heap_state.freelist;
1799
  // CONS check is not needed. If num_free is correct, then freelist is a cons-cell.
1800
12012
  lbm_cons_t *heap = lbm_heap_state.heap;
1801
12012
  lbm_uint ix = lbm_dec_ptr(res);
1802
12012
  heap[ix].car = ENC_SYM_CLOSURE;
1803
12012
  ix = lbm_dec_ptr(heap[ix].cdr);
1804
12012
  heap[ix].car = params;
1805
12012
  ix = lbm_dec_ptr(heap[ix].cdr);
1806
12012
  heap[ix].car = body;
1807
12012
  ix = lbm_dec_ptr(heap[ix].cdr);
1808
12012
  heap[ix].car = env;
1809
12012
  lbm_heap_state.freelist = heap[ix].cdr;
1810
12012
  heap[ix].cdr = ENC_SYM_NIL;
1811
12012
  lbm_heap_state.num_alloc+=4;
1812
12012
  return res;
1813
}
1814
1815
/* Eval lambda is cheating, a lot! It does this
1816
   for performance reasons. The cheats are that
1817
   1. When  closure is created, a reference to the local env
1818
   in which the lambda was evaluated is added to the closure.
1819
   Ideally it should have created a list of free variables in the function
1820
   and then looked up the values of these creating a new environment.
1821
   2. The global env is considered global constant. As there is no copying
1822
   of environment bindings into the closure, undefine may break closures.
1823
1824
   some obscure programs such as test_setq_local_closure.lisp does not
1825
   work properly due to this cheating.
1826
 */
1827
// (lambda param-list body-exp) -> (closure param-list body-exp env)
1828
12012
static void eval_lambda(eval_context_t *ctx) {
1829
  lbm_value vals[3];
1830
12012
  extract_n(ctx->curr_exp, vals, 3);
1831
12012
  ctx->r = allocate_closure(vals[1],vals[2], ctx->curr_env);
1832
#ifdef CLEAN_UP_CLOSURES
1833
  lbm_uint sym_id  = 0;
1834
  if (clean_cl_env_symbol) {
1835
    lbm_value tail = cons_with_gc(ctx->r, ENC_SYM_NIL, ENC_SYM_NIL);
1836
    lbm_value app = cons_with_gc(clean_cl_env_symbol, tail, tail);
1837
    ctx->curr_exp = app;
1838
  } else if (lbm_get_symbol_by_name("clean-cl-env", &sym_id)) {
1839
    clean_cl_env_symbol = lbm_enc_sym(sym_id);
1840
    lbm_value tail = cons_with_gc(ctx->r, ENC_SYM_NIL, ENC_SYM_NIL);
1841
    lbm_value app = cons_with_gc(clean_cl_env_symbol, tail, tail);
1842
    ctx->curr_exp = app;
1843
  } else {
1844
    ctx->app_cont = true;
1845
  }
1846
#else
1847
12012
  ctx->app_cont = true;
1848
#endif
1849
12012
}
1850
1851
// (if cond-expr then-expr else-expr)
1852
21761324
static void eval_if(eval_context_t *ctx) {
1853
21761324
  lbm_value cdr = get_cdr(ctx->curr_exp);
1854
21761324
  lbm_value *sptr = stack_reserve(ctx, 3);
1855
21761324
  sptr[0] = get_cdr(cdr);
1856
21761324
  sptr[1] = ctx->curr_env;
1857
21761324
  sptr[2] = IF;
1858
21761324
  ctx->curr_exp = get_car(cdr);
1859
21761324
}
1860
1861
// (cond (cond-expr-1 expr-1)
1862
//         ...
1863
//       (cond-expr-N expr-N))
1864
1316
static void eval_cond(eval_context_t *ctx) {
1865
  lbm_value cond1[2];
1866
1316
  lbm_value rest_conds = extract_n(ctx->curr_exp, cond1, 2);
1867
1868
  // end recursion at (cond )
1869
1316
  if (lbm_is_symbol_nil(cond1[1])) {
1870
28
    ctx->r = ENC_SYM_NIL;
1871
28
    ctx->app_cont = true;
1872
  } else {
1873
    // Cond is one of the few places where a bit of syntax checking takes place at runtime..
1874
    // Maybe dont bother?
1875
1288
    lbm_uint len = lbm_list_length(cond1[1]);
1876
1288
    if (len != 2) {
1877
      lbm_set_error_reason("Incorrect syntax in cond");
1878
      error_ctx(ENC_SYM_EERROR);
1879
    }
1880
    lbm_value cond_expr[2];
1881
1288
    extract_n(cond1[1], cond_expr, 2);
1882
    lbm_value rest;
1883

1288
    WITH_GC(rest, lbm_heap_allocate_list_init(2,
1884
                                              cond_expr[1], // Then branch
1885
                                              cons_with_gc(ENC_SYM_COND, rest_conds , ENC_SYM_NIL)));
1886
1288
    lbm_value *sptr = stack_reserve(ctx, 3);
1887
1288
    sptr[0] = rest;
1888
1288
    sptr[1] = ctx->curr_env;
1889
1288
    sptr[2] = IF;
1890
1288
    ctx->curr_exp = cond_expr[0]; //condition;
1891
  }
1892
1316
}
1893
1894
11489
static void eval_app_cont(eval_context_t *ctx) {
1895
11489
  lbm_stack_drop(&ctx->K, 1);
1896
11489
  ctx->app_cont = true;
1897
11489
}
1898
1899
// Create a named location in an environment to later receive a value.
1900
40969534
static binding_location_status create_binding_location_internal(lbm_value key, lbm_value *env) {
1901
40969534
  if (lbm_type_of(key) == LBM_TYPE_SYMBOL) { // default case
1902

26935440
    if (key == ENC_SYM_NIL || key == ENC_SYM_DONTCARE) return BL_OK;
1903
    lbm_value binding;
1904
    lbm_value new_env_tmp;
1905
21325332
    binding = lbm_cons(key, ENC_SYM_PLACEHOLDER);
1906
21325332
    new_env_tmp = lbm_cons(binding, *env);
1907

21325332
    if (lbm_is_symbol(binding) || lbm_is_symbol(new_env_tmp)) {
1908
21656
      return BL_NO_MEMORY;
1909
    }
1910
21303676
    *env = new_env_tmp;
1911
14034094
  } else if (lbm_is_cons(key)) { // deconstruct case
1912
14034094
    int r = create_binding_location_internal(get_car(key), env);
1913
14034094
    if (r == BL_OK) {
1914
14027470
      r = create_binding_location_internal(get_cdr(key), env);
1915
    }
1916
14034094
    return r;
1917
  }
1918
21303676
  return BL_OK;
1919
}
1920
1921
12886314
static void create_binding_location(lbm_value key, lbm_value *env) {
1922
1923
12886314
  lbm_value env_tmp = *env;
1924
#ifdef LBM_ALWAYS_GC
1925
  lbm_gc_mark_phase(env_tmp);
1926
  gc();
1927
#endif
1928
12886314
  binding_location_status r = create_binding_location_internal(key, &env_tmp);
1929
12886314
  if (r != BL_OK) {
1930
21656
    if (r == BL_NO_MEMORY) {
1931
21656
      env_tmp = *env;
1932
21656
      lbm_gc_mark_phase(env_tmp);
1933
21656
      gc();
1934
21656
      r = create_binding_location_internal(key, &env_tmp);
1935
    }
1936

21656
    switch(r) {
1937
21656
    case BL_OK:
1938
21656
      break;
1939
    case BL_NO_MEMORY:
1940
      error_ctx(ENC_SYM_MERROR);
1941
      break;
1942
    case BL_INCORRECT_KEY:
1943
      error_ctx(ENC_SYM_TERROR);
1944
      break;
1945
    }
1946
12864658
  }
1947
12886314
  *env = env_tmp;
1948
12886314
}
1949
1950
12128844
static void let_bind_values_eval(lbm_value binds, lbm_value exp, lbm_value env, eval_context_t *ctx) {
1951
12128844
  if (lbm_is_cons(binds)) {
1952
      // Preallocate binding locations.
1953
12128844
      lbm_value curr = binds;
1954
24371592
      while (lbm_is_cons(curr)) {
1955
12242748
        lbm_value new_env_tmp = env;
1956
12242748
        lbm_cons_t *cell = lbm_ref_cell(curr); // already checked that cons.
1957
12242748
        lbm_value car_curr = cell->car;
1958
12242748
        lbm_value cdr_curr = cell->cdr;
1959
12242748
        lbm_value key = get_car(car_curr);
1960
12242748
        create_binding_location(key, &new_env_tmp);
1961
12242748
        env = new_env_tmp;
1962
12242748
        curr = cdr_curr;
1963
      }
1964
1965
12128844
      lbm_cons_t *cell = lbm_ref_cell(binds); // already checked that cons.
1966
12128844
      lbm_value car_binds = cell->car;
1967
12128844
      lbm_value cdr_binds = cell->cdr;
1968
      lbm_value key_val[2];
1969
12128844
      extract_n(car_binds, key_val, 2);
1970
1971
12128844
      lbm_uint *sptr = stack_reserve(ctx, 5);
1972
12128844
      sptr[0] = exp;
1973
12128844
      sptr[1] = cdr_binds;
1974
12128844
      sptr[2] = env;
1975
12128844
      sptr[3] = key_val[0];
1976
12128844
      sptr[4] = BIND_TO_KEY_REST;
1977
12128844
      ctx->curr_exp = key_val[1];
1978
12128844
      ctx->curr_env = env;
1979
    } else {
1980
      ctx->curr_exp = exp;
1981
    }
1982
12128844
}
1983
1984
// (var x (...)) - local binding inside of an progn
1985
// var has to take, place root-level nesting within progn.
1986
// (progn ... (var a 10) ...) OK!
1987
// (progn ... (something (var a 10)) ... ) NOT OK!
1988
/* progn stack
1989
   sp-4 : env
1990
   sp-3 : 0
1991
   sp-2 : rest
1992
   sp-1 : PROGN_REST
1993
*/
1994
643566
static void eval_var(eval_context_t *ctx) {
1995
643566
  if (ctx->K.sp >= 4) { // Possibly in progn
1996
643566
    lbm_value sv = ctx->K.data[ctx->K.sp - 1];
1997

643566
    if (IS_CONTINUATION(sv) && (sv == PROGN_REST)) {
1998
643566
      lbm_uint sp = ctx->K.sp;
1999
643566
      uint32_t is_copied = lbm_dec_as_u32(ctx->K.data[sp-3]);
2000
643566
      if (is_copied == 0) {
2001
        lbm_value env;
2002

631918
        WITH_GC(env, lbm_env_copy_spine(ctx->K.data[sp-4]));
2003
631918
        ctx->K.data[sp-3] = lbm_enc_u(1);
2004
631918
        ctx->K.data[sp-4] = env;
2005
      }
2006
643566
      lbm_value new_env = ctx->K.data[sp-4];
2007
643566
      lbm_value args = get_cdr(ctx->curr_exp);
2008
643566
      lbm_value key = get_car(args);
2009
2010
643566
      create_binding_location(key, &new_env);
2011
2012
643566
      ctx->K.data[sp-4] = new_env;
2013
2014
643566
      lbm_value v_exp = get_cadr(args);
2015
643566
      lbm_value *sptr = stack_reserve(ctx, 3);
2016
643566
      sptr[0] = new_env;
2017
643566
      sptr[1] = key;
2018
643566
      sptr[2] = PROGN_VAR;
2019
      // Activating the new environment before the evaluation of the value to be bound.
2020
      // This would normally shadow the existing value, but create_binding_location sets
2021
      // the binding to be $placeholder, which is ignored when looking up the value.
2022
      // The way closures work, the var-variable needs to be in scope during val
2023
      // evaluation for a recursive closure to be possible.
2024
643566
      ctx->curr_env = new_env;
2025
643566
      ctx->curr_exp = v_exp;
2026
643566
      return;
2027
    }
2028
  }
2029
  lbm_set_error_reason((char*)lbm_error_str_var_outside_progn);
2030
  error_ctx(ENC_SYM_EERROR);
2031
}
2032
2033
// (setq x (...)) - same as (set 'x (...)) or (setvar 'x (...))
2034
// does not error when given incorrect number of arguments.
2035
1775494
static void eval_setq(eval_context_t *ctx) {
2036
  lbm_value parts[3];
2037
1775494
  extract_n(ctx->curr_exp, parts, 3);
2038
1775494
  lbm_value *sptr = stack_reserve(ctx, 3);
2039
1775494
  sptr[0] = ctx->curr_env;
2040
1775494
  sptr[1] = parts[1];
2041
1775494
  sptr[2] = SETQ;
2042
1775494
  ctx->curr_exp = parts[2];
2043
1775494
}
2044
2045
364
static void eval_move_to_flash(eval_context_t *ctx) {
2046
364
  lbm_value args = get_cdr(ctx->curr_exp);
2047
364
  lbm_value *sptr = stack_reserve(ctx,2);
2048
364
  sptr[0] = args;
2049
364
  sptr[1] = MOVE_TO_FLASH;
2050
364
  ctx->app_cont = true;
2051
364
}
2052
2053
// (loop list-of-local-bindings
2054
//       condition-exp
2055
//       body-exp)
2056
280
static void eval_loop(eval_context_t *ctx) {
2057
280
  lbm_value env              = ctx->curr_env;
2058
  lbm_value parts[3];
2059
280
  extract_n(get_cdr(ctx->curr_exp), parts, 3);
2060
280
  lbm_value *sptr = stack_reserve(ctx, 3);
2061
280
  sptr[0] = parts[LOOP_BODY];
2062
280
  sptr[1] = parts[LOOP_COND];
2063
280
  sptr[2] = LOOP_CONDITION;
2064
280
  let_bind_values_eval(parts[LOOP_BINDS], parts[LOOP_COND], env, ctx);
2065
280
}
2066
2067
/* (trap expression)
2068
 *
2069
 * suggested use:
2070
 * (match (trap expression)
2071
 *   ((exit-error (? err)) (error-handler err))
2072
 *   ((exit-ok    (? v))   (value-handler v)))
2073
 */
2074
8288
static void eval_trap(eval_context_t *ctx) {
2075
2076
8288
  lbm_value expr = get_cadr(ctx->curr_exp);
2077
  lbm_value retval;
2078

8288
  WITH_GC(retval, lbm_heap_allocate_list(2));
2079
8288
  lbm_set_car(retval, ENC_SYM_EXIT_OK); // Assume things will go well.
2080
8288
  lbm_uint *sptr = stack_reserve(ctx,3);
2081
8288
  sptr[0] = retval;
2082
8288
  sptr[1] = ctx->flags;
2083
8288
  sptr[2] = EXCEPTION_HANDLER;
2084
8288
  ctx->flags |= EVAL_CPS_CONTEXT_FLAG_TRAP_UNROLL_RETURN;
2085
8288
  ctx->curr_exp = expr;
2086
8288
}
2087
2088
// (let list-of-binding s
2089
//      body-exp)
2090
12128564
static void eval_let(eval_context_t *ctx) {
2091
12128564
  lbm_value env      = ctx->curr_env;
2092
  lbm_value parts[3];
2093
12128564
  extract_n(ctx->curr_exp, parts, 3);
2094
12128564
  let_bind_values_eval(parts[1], parts[2], env, ctx);
2095
12128564
}
2096
2097
// (and exp0 ... expN)
2098
1982064
static void eval_and(eval_context_t *ctx) {
2099
1982064
  lbm_value rest = get_cdr(ctx->curr_exp);
2100
1982064
  if (lbm_is_symbol_nil(rest)) {
2101
28
    ctx->app_cont = true;
2102
28
    ctx->r = ENC_SYM_TRUE;
2103
  } else {
2104
1982036
    lbm_value *sptr = stack_reserve(ctx, 3);
2105
1982036
    sptr[0] = ctx->curr_env;
2106
1982036
    sptr[1] = get_cdr(rest);
2107
1982036
    sptr[2] = AND;
2108
1982036
    ctx->curr_exp = get_car(rest);
2109
  }
2110
1982064
}
2111
2112
// (or exp0 ... expN)
2113
7224
static void eval_or(eval_context_t *ctx) {
2114
7224
  lbm_value rest = get_cdr(ctx->curr_exp);
2115
7224
  if (lbm_is_symbol_nil(rest)) {
2116
28
    ctx->app_cont = true;
2117
28
    ctx->r = ENC_SYM_NIL;
2118
  } else {
2119
7196
    lbm_value *sptr = stack_reserve(ctx, 3);
2120
7196
    sptr[0] = ctx->curr_env;
2121
7196
    sptr[1] = get_cdr(rest);
2122
7196
    sptr[2] = OR;
2123
7196
    ctx->curr_exp = get_car(rest);
2124
  }
2125
7224
}
2126
2127
// Pattern matching
2128
// format:
2129
// (match e (pattern body)
2130
//          (pattern body)
2131
//          ...  )
2132
//
2133
// There can be an optional pattern guard:
2134
// (match e (pattern guard body)
2135
//          ... )
2136
// a guard is a boolean expression.
2137
// Guards make match, pattern matching more complicated
2138
// than the recv pattern matching and requires staged execution
2139
// via the continuation system rather than a while loop over a list.
2140
3052
static void eval_match(eval_context_t *ctx) {
2141
2142
3052
  lbm_value rest = get_cdr(ctx->curr_exp);
2143
3052
  if (lbm_is_cons(rest)) {
2144
3052
    lbm_cons_t *cell = lbm_ref_cell(rest);
2145
3052
    lbm_value cdr_rest = cell->cdr;
2146
3052
    ctx->curr_exp = cell->car;
2147
3052
    lbm_value *sptr = stack_reserve(ctx, 3);
2148
3052
    sptr[0] = cdr_rest;
2149
3052
    sptr[1] = ctx->curr_env;
2150
3052
    sptr[2] = MATCH;
2151
  } else {
2152
    // syntax error to not include at least one pattern
2153
    error_ctx(ENC_SYM_EERROR);
2154
  }
2155
3052
}
2156
2157
8560
static void receive_base(eval_context_t *ctx, lbm_value pats) {
2158
8560
  if (ctx->num_mail == 0) {
2159
3070
      block_current_ctx(LBM_THREAD_STATE_RECV_BL,0,false);
2160
  } else {
2161
5490
    lbm_value *msgs = ctx->mailbox;
2162
5490
    lbm_uint  num   = ctx->num_mail;
2163
2164
    lbm_value e;
2165
5490
    lbm_value new_env = ctx->curr_env;
2166
#ifdef LBM_ALWAYS_GC
2167
    gc();
2168
#endif
2169
5490
    int n = find_match(pats, msgs, num, &e, &new_env);
2170
5490
    if (n == FM_NEED_GC) {
2171
      gc();
2172
      new_env = ctx->curr_env;
2173
      n = find_match(pats, msgs, num, &e, &new_env);
2174
      if (n == FM_NEED_GC) {
2175
        error_ctx(ENC_SYM_MERROR);
2176
      }
2177
    }
2178
5490
    if (n == FM_PATTERN_ERROR) {
2179
      lbm_set_error_reason("Incorrect pattern format for recv");
2180
      error_at_ctx(ENC_SYM_EERROR,pats);
2181
5490
    } else if (n >= 0 ) { /* Match */
2182
5488
      mailbox_remove_mail(ctx, (lbm_uint)n);
2183
5488
      ctx->curr_env = new_env;
2184
5488
      ctx->curr_exp = e;
2185
    } else { /* No match  go back to sleep */
2186
2
      ctx->r = ENC_SYM_NO_MATCH;
2187
2
      block_current_ctx(LBM_THREAD_STATE_RECV_BL, 0,false);
2188
    }
2189
  }
2190
8560
  return;
2191
}
2192
2193
// Receive-timeout
2194
// (recv-to timeout (pattern expr)
2195
//                  (pattern expr))
2196
252
static void eval_receive_timeout(eval_context_t *ctx) {
2197
252
  if (is_atomic) atomic_error();
2198
252
  lbm_value timeout_val = get_cadr(ctx->curr_exp);
2199
252
  lbm_value pats = get_cdr(get_cdr(ctx->curr_exp));
2200
252
  if (lbm_is_symbol_nil(pats)) {
2201
56
    lbm_set_error_reason((char*)lbm_error_str_num_args);
2202
56
    error_at_ctx(ENC_SYM_EERROR, ctx->curr_exp);
2203
  } else {
2204
196
    lbm_value *sptr = stack_reserve(ctx, 2);
2205
196
    sptr[0] = pats;
2206
196
    sptr[1] = RECV_TO;
2207
196
    ctx->curr_exp = timeout_val;
2208
  }
2209
196
}
2210
2211
// Receive
2212
// (recv (pattern expr)
2213
//       (pattern expr))
2214
8588
static void eval_receive(eval_context_t *ctx) {
2215
8588
  if (is_atomic) atomic_error();
2216
8588
  lbm_value pats = get_cdr(ctx->curr_exp);
2217
8588
  if (lbm_is_symbol_nil(pats)) {
2218
28
    lbm_set_error_reason((char*)lbm_error_str_num_args);
2219
28
    error_at_ctx(ENC_SYM_EERROR,ctx->curr_exp);
2220
  } else {
2221
8560
    receive_base(ctx, pats);
2222
  }
2223
8560
}
2224
2225
/*********************************************************/
2226
/*  Continuation functions                               */
2227
2228
// cont_set_global_env:
2229
//
2230
//   s[sp-1] = Key-symbol
2231
//
2232
//   ctx->r = Value
2233
4268264
static void cont_set_global_env(eval_context_t *ctx){
2234
2235
  lbm_value key;
2236
4268264
  lbm_value val = ctx->r;
2237
2238
4268264
  lbm_pop(&ctx->K, &key);
2239
4268264
  lbm_uint dec_key = lbm_dec_sym(key);
2240
4268264
  lbm_uint ix_key  = dec_key & GLOBAL_ENV_MASK;
2241
4268264
  lbm_value *global_env = lbm_get_global_env();
2242
4268264
  lbm_uint orig_env = global_env[ix_key];
2243
  lbm_value new_env;
2244
  // A key is a symbol and should not need to be remembered.
2245

4268264
  WITH_GC(new_env, lbm_env_set(orig_env,key,val));
2246
2247
4268264
  global_env[ix_key] = new_env;
2248
4268264
  ctx->r = val;
2249
2250
4268264
  ctx->app_cont = true;
2251
2252
4268264
  return;
2253
}
2254
2255
// cont_resume:
2256
//
2257
// s[sp-2] = Expression
2258
// s[sp-1] = Environment
2259
//
2260
// ctx->r = Irrelevant.
2261
4816
static void cont_resume(eval_context_t *ctx) {
2262
4816
  lbm_pop_2(&ctx->K, &ctx->curr_env, &ctx->curr_exp);
2263
4816
}
2264
2265
// cont_progn_rest:
2266
//
2267
// s[sp-3] = Environment to evaluate each expression in.
2268
// s[sp-2] = Flag indicating if env has been copied.
2269
// s[sp-1] = list of expressions to evaluate.
2270
//
2271
// ctx->r = Result of last evaluated expression.
2272
13861867
static void cont_progn_rest(eval_context_t *ctx) {
2273
13861867
  lbm_value *sptr = get_stack_ptr(ctx, 3);
2274
2275
13861867
  lbm_value env  = sptr[0];
2276
  // eval_progn and cont_progn_rest both ensure that sptr[2] is a list
2277
  // whenever cont_progn_rest is called.
2278
2279
13861867
  lbm_cons_t *rest_cell = lbm_ref_cell(sptr[2]);
2280
13861867
  lbm_value rest_cdr = rest_cell->cdr;
2281
13861867
  ctx->curr_exp = rest_cell->car;;
2282
13861867
  ctx->curr_env = env;
2283
13861867
  if (lbm_is_cons(rest_cdr)) {
2284
2354528
    sptr[2] = rest_cdr; // Requirement: rest_cdr is a cons
2285
2354528
    stack_reserve(ctx, 1)[0] = PROGN_REST;
2286
  } else {
2287
    // Nothing is pushed to stack for final element in progn. (tail-call req)
2288
11507339
    lbm_stack_drop(&ctx->K, 3);
2289
  }
2290
13861867
}
2291
2292
84
static void cont_wait(eval_context_t *ctx) {
2293
2294
  lbm_value cid_val;
2295
84
  lbm_pop(&ctx->K, &cid_val);
2296
84
  lbm_cid cid = (lbm_cid)lbm_dec_i(cid_val);
2297
2298
84
  bool exists = false;
2299
2300
84
  lbm_blocked_iterator(context_exists, &cid, &exists);
2301
84
  lbm_running_iterator(context_exists, &cid, &exists);
2302
2303
84
  if (ctx_running->id == cid) {
2304
    exists = true;
2305
  }
2306
2307
84
  if (exists) {
2308
28
    lbm_value *sptr = stack_reserve(ctx, 2);
2309
28
    sptr[0] = lbm_enc_i(cid);
2310
28
    sptr[1] = WAIT;
2311
28
    ctx->r = ENC_SYM_TRUE;
2312
28
    ctx->app_cont = true;
2313
28
    yield_ctx(50000);
2314
  } else {
2315
56
    ctx->r = ENC_SYM_TRUE;
2316
56
    ctx->app_cont = true;
2317
  }
2318
84
}
2319
2320
1775788
static lbm_value perform_setvar(lbm_value key, lbm_value val, lbm_value env) {
2321
2322
1775788
  lbm_uint s = lbm_dec_sym(key);
2323
1775788
  if (s >= RUNTIME_SYMBOLS_START) {
2324
1775760
    lbm_value new_env = lbm_env_modify_binding(env, key, val);
2325

1775760
    if (lbm_is_symbol(new_env) && new_env == ENC_SYM_NOT_FOUND) {
2326
841372
      lbm_uint ix_key = lbm_dec_sym(key) & GLOBAL_ENV_MASK;
2327
841372
      lbm_value *glob_env = lbm_get_global_env();
2328
841372
      new_env = lbm_env_modify_binding(glob_env[ix_key], key, val);
2329
841372
      glob_env[ix_key] = new_env;
2330
    }
2331

1775760
    if (lbm_is_symbol(new_env) && new_env == ENC_SYM_NOT_FOUND) {
2332
28
      lbm_set_error_reason((char*)lbm_error_str_variable_not_bound);
2333
28
      error_at_ctx(ENC_SYM_NOT_FOUND, key);
2334
    }
2335
1775732
    return val;
2336
  }
2337
28
  error_at_ctx(ENC_SYM_EERROR, ENC_SYM_SETVAR);
2338
  return ENC_SYM_NIL; // unreachable
2339
}
2340
2341
420
static void apply_setvar(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2342

420
  if (nargs == 2 && lbm_is_symbol(args[0])) {
2343
    lbm_value res;
2344

308
    WITH_GC(res, perform_setvar(args[0], args[1], ctx->curr_env));
2345
308
    ctx->r = args[1];
2346
308
    lbm_stack_drop(&ctx->K, nargs+1);
2347
308
    ctx->app_cont = true;
2348
  } else {
2349
112
    if (nargs == 2) lbm_set_error_reason((char*)lbm_error_str_incorrect_arg);
2350
56
    else lbm_set_error_reason((char*)lbm_error_str_num_args);
2351
112
    error_at_ctx(ENC_SYM_EERROR, ENC_SYM_SETVAR);
2352
  }
2353
308
}
2354
2355
2356
#define READING_EXPRESSION             ((0 << LBM_VAL_SHIFT) | LBM_TYPE_U)
2357
#define READING_PROGRAM                ((1 << LBM_VAL_SHIFT) | LBM_TYPE_U)
2358
#define READING_PROGRAM_INCREMENTALLY  ((2 << LBM_VAL_SHIFT) | LBM_TYPE_U)
2359
2360
330652
static void apply_read_base(lbm_value *args, lbm_uint nargs, eval_context_t *ctx, bool program, bool incremental) {
2361
330652
  if (nargs == 1) {
2362
330624
    lbm_value chan = ENC_SYM_NIL;
2363
330624
    if (lbm_type_of_functional(args[0]) == LBM_TYPE_ARRAY) {
2364
304052
      char *str = lbm_dec_str(args[0]);
2365
304052
      if (str) {
2366
#ifdef LBM_ALWAYS_GC
2367
        gc();
2368
#endif
2369
303940
        if (!create_string_channel(lbm_dec_str(args[0]), &chan, args[0])) {
2370
1286
          gc();
2371
1286
          if (!create_string_channel(lbm_dec_str(args[0]), &chan, args[0])) {
2372
            error_ctx(ENC_SYM_MERROR);
2373
          }
2374
        }
2375
      } else {
2376
112
        error_ctx(ENC_SYM_EERROR);
2377
      }
2378
26572
    } else if (lbm_type_of(args[0]) == LBM_TYPE_CHANNEL) {
2379
26572
      chan = args[0];
2380
      // Streaming transfers can freeze the evaluator if the stream is cut while
2381
      // the reader is reading inside of an atomic block.
2382
      // It is generally not advisable to read in an atomic block but now it is also
2383
      // enforced in the case where it can cause problems.
2384

26572
      if (lbm_channel_may_block(lbm_dec_channel(chan)) && is_atomic) {
2385
       lbm_set_error_reason((char*)lbm_error_str_forbidden_in_atomic);
2386
       is_atomic = false;
2387
       error_ctx(ENC_SYM_EERROR);
2388
      }
2389
    } else {
2390
      error_ctx(ENC_SYM_EERROR);
2391
    }
2392
330512
    lbm_value *sptr = get_stack_ptr(ctx, 2);
2393
2394
    // If we are inside a reader, its settings are stored.
2395
330512
    sptr[0] = lbm_enc_u(ctx->flags);  // flags stored.
2396
330512
    sptr[1] = chan;
2397
330512
    lbm_value  *rptr = stack_reserve(ctx,2);
2398

330512
    if (!program && !incremental) {
2399
297080
      rptr[0] = READING_EXPRESSION;
2400

33432
    } else if (program && !incremental) {
2401
11270
      rptr[0] = READING_PROGRAM;
2402

22162
    } else if (program && incremental) {
2403
22162
      rptr[0] = READING_PROGRAM_INCREMENTALLY;
2404
    }  // the last combo is illegal
2405
330512
    rptr[1] = READ_DONE;
2406
2407
    // Each reader starts in a fresh situation
2408
330512
    ctx->flags &= ~EVAL_CPS_CONTEXT_READER_FLAGS_MASK;
2409
330512
    ctx->r = ENC_SYM_NIL; // set r to a known state.
2410
2411
330512
    if (program) {
2412
33432
      if (incremental) {
2413
22162
        ctx->flags |= EVAL_CPS_CONTEXT_FLAG_INCREMENTAL_READ;
2414
22162
        lbm_value  *rptr1 = stack_reserve(ctx,3);
2415
22162
        rptr1[0] = chan;
2416
22162
        rptr1[1] = ctx->curr_env;
2417
22162
        rptr1[2] = READ_EVAL_CONTINUE;
2418
      } else {
2419
11270
        ctx->flags &= ~EVAL_CPS_CONTEXT_FLAG_INCREMENTAL_READ;
2420
11270
        lbm_value  *rptr1 = stack_reserve(ctx,4);
2421
11270
        rptr1[0] = ENC_SYM_NIL;
2422
11270
        rptr1[1] = ENC_SYM_NIL;
2423
11270
        rptr1[2] = chan;
2424
11270
        rptr1[3] = READ_APPEND_CONTINUE;
2425
      }
2426
    }
2427
330512
    rptr = stack_reserve(ctx,3); // reuse of variable rptr
2428
330512
    rptr[0] = chan;
2429
330512
    rptr[1] = lbm_enc_u(1);
2430
330512
    rptr[2] = READ_NEXT_TOKEN;
2431
330512
    ctx->app_cont = true;
2432
  } else {
2433
28
    lbm_set_error_reason((char*)lbm_error_str_num_args);
2434
28
    error_ctx(ENC_SYM_EERROR);
2435
  }
2436
330512
}
2437
2438
11354
static void apply_read_program(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2439
11354
  apply_read_base(args,nargs,ctx,true,false);
2440
11270
}
2441
2442
22162
static void apply_read_eval_program(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2443
22162
  apply_read_base(args,nargs,ctx,true,true);
2444
22162
}
2445
2446
297136
static void apply_read(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2447
297136
  apply_read_base(args,nargs,ctx,false,false);
2448
297080
}
2449
2450
1064
static void apply_spawn_base(lbm_value *args, lbm_uint nargs, eval_context_t *ctx, uint32_t context_flags) {
2451
2452
1064
  lbm_uint stack_size = EVAL_CPS_DEFAULT_STACK_SIZE;
2453
1064
  lbm_uint closure_pos = 0;
2454
1064
  char *name = NULL;
2455
  // allowed arguments:
2456
  // (spawn opt-name opt-stack-size closure arg1 ... argN)
2457
2458

2128
  if (nargs >= 1 &&
2459
1064
      lbm_is_closure(args[0])) {
2460
840
    closure_pos = 0;
2461

448
  } else if (nargs >= 2 &&
2462
308
      lbm_is_number(args[0]) &&
2463
84
      lbm_is_closure(args[1])) {
2464
84
    stack_size = lbm_dec_as_u32(args[0]);
2465
84
    closure_pos = 1;
2466

280
  } else if (nargs >= 2 &&
2467
280
             lbm_is_array_r(args[0]) &&
2468
140
             lbm_is_closure(args[1])) {
2469
    name = lbm_dec_str(args[0]);
2470
    closure_pos = 1;
2471

280
  } else if (nargs >= 3 &&
2472
280
             lbm_is_array_r(args[0]) &&
2473
280
             lbm_is_number(args[1]) &&
2474
140
             lbm_is_closure(args[2])) {
2475
140
    stack_size = lbm_dec_as_u32(args[1]);
2476
140
    closure_pos = 2;
2477
140
    name = lbm_dec_str(args[0]);
2478
  } else {
2479
    if (context_flags & EVAL_CPS_CONTEXT_FLAG_TRAP)
2480
      error_at_ctx(ENC_SYM_TERROR,ENC_SYM_SPAWN_TRAP);
2481
    else
2482
      error_at_ctx(ENC_SYM_TERROR,ENC_SYM_SPAWN);
2483
  }
2484
2485
  lbm_value cl[3];
2486
1064
  extract_n(get_cdr(args[closure_pos]), cl, 3);
2487
1064
  lbm_value curr_param = cl[CLO_PARAMS];
2488
1064
  lbm_value clo_env    = cl[CLO_ENV];
2489
1064
  lbm_uint i = closure_pos + 1;
2490

1820
  while (lbm_is_cons(curr_param) && i <= nargs) {
2491
756
    lbm_value entry = cons_with_gc(get_car(curr_param), args[i], clo_env);
2492
756
    lbm_value aug_env = cons_with_gc(entry, clo_env,ENC_SYM_NIL);
2493
756
    clo_env = aug_env;
2494
756
    curr_param = get_cdr(curr_param);
2495
756
    i ++;
2496
  }
2497
2498
1064
  lbm_stack_drop(&ctx->K, nargs+1);
2499
2500
1064
  lbm_value program = cons_with_gc(cl[CLO_BODY], ENC_SYM_NIL, clo_env);
2501
2502
1064
  lbm_cid cid = lbm_create_ctx_parent(program,
2503
                                      clo_env,
2504
                                      stack_size,
2505
                                      lbm_get_current_cid(),
2506
                                      context_flags,
2507
                                      name);
2508
1064
  ctx->r = lbm_enc_i(cid);
2509
1064
  ctx->app_cont = true;
2510
1064
  if (cid == -1) error_ctx(ENC_SYM_MERROR); // Kill parent and signal out of memory.
2511
1036
}
2512
2513
728
static void apply_spawn(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2514
728
  apply_spawn_base(args,nargs,ctx, EVAL_CPS_CONTEXT_FLAG_NOTHING);
2515
700
}
2516
2517
336
static void apply_spawn_trap(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2518
336
  apply_spawn_base(args,nargs,ctx, EVAL_CPS_CONTEXT_FLAG_TRAP);
2519
336
}
2520
2521
28401
static void apply_yield(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2522

56802
  if (nargs == 1 && lbm_is_number(args[0])) {
2523
28401
    lbm_uint ts = lbm_dec_as_u32(args[0]);
2524
28401
    lbm_stack_drop(&ctx->K, nargs+1);
2525
28401
    yield_ctx(ts);
2526
  } else {
2527
    lbm_set_error_reason((char*)lbm_error_str_no_number);
2528
    error_at_ctx(ENC_SYM_TERROR, ENC_SYM_YIELD);
2529
  }
2530
28401
}
2531
2532
2128
static void apply_sleep(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2533

4228
  if (nargs == 1 && lbm_is_number(args[0])) {
2534
2128
    lbm_uint ts = (lbm_uint)(1000000.0f * lbm_dec_as_float(args[0]));
2535
2128
    lbm_stack_drop(&ctx->K, nargs+1);
2536
2128
    yield_ctx(ts);
2537
  } else {
2538
    lbm_set_error_reason((char*)lbm_error_str_no_number);
2539
    error_at_ctx(ENC_SYM_TERROR, ENC_SYM_SLEEP);
2540
  }
2541
2100
}
2542
2543
56
static void apply_wait(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2544

112
  if (nargs == 1 && lbm_type_of(args[0]) == LBM_TYPE_I) {
2545
56
    lbm_cid cid = (lbm_cid)lbm_dec_i(args[0]);
2546
56
    lbm_value *sptr = get_stack_ptr(ctx, 2);
2547
56
    sptr[0] = lbm_enc_i(cid);
2548
56
    sptr[1] = WAIT;
2549
56
    ctx->r = ENC_SYM_TRUE;
2550
56
    ctx->app_cont = true;
2551
56
    yield_ctx(50000);
2552
  } else {
2553
    error_at_ctx(ENC_SYM_TERROR, ENC_SYM_WAIT);
2554
  }
2555
56
}
2556
2557
/* (eval expr)
2558
   (eval env expr) */
2559
3181500
static void apply_eval(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2560
3181500
  if ( nargs == 1) {
2561
3181500
    ctx->curr_exp = args[0];
2562
  } else if (nargs == 2) {
2563
    ctx->curr_exp = args[1];
2564
    ctx->curr_env = args[0];
2565
  } else {
2566
    lbm_set_error_reason((char*)lbm_error_str_num_args);
2567
    error_at_ctx(ENC_SYM_EERROR, ENC_SYM_EVAL);
2568
  }
2569
3181500
  lbm_stack_drop(&ctx->K, nargs+1);
2570
3181500
}
2571
2572
11494
static void apply_eval_program(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2573
11494
  int prg_pos = 0;
2574
11494
  if (nargs == 2) {
2575
    prg_pos = 1;
2576
    ctx->curr_env = args[0]; // No check that args[0] is an actual env.
2577
  }
2578

11494
  if (nargs == 1 || nargs == 2) {
2579
11494
    lbm_value prg = args[prg_pos]; // No check that this is a program.
2580
    lbm_value app_cont;
2581
    lbm_value app_cont_prg;
2582
    lbm_value new_prg;
2583
    lbm_value prg_copy;
2584
2585
11494
    int len = -1;
2586

11494
    WITH_GC(prg_copy, lbm_list_copy(&len, prg));
2587
11494
    lbm_stack_drop(&ctx->K, nargs+1);
2588
    // There is always a continuation (DONE).
2589
    // If ctx->program is nil, the stack should contain DONE.
2590
    // after adding an intermediate done for prg, stack becomes DONE, DONE.
2591
11494
    app_cont = cons_with_gc(ENC_SYM_APP_CONT, ENC_SYM_NIL, prg_copy);
2592
11494
    app_cont_prg = cons_with_gc(app_cont, ENC_SYM_NIL, prg_copy);
2593
11494
    new_prg = lbm_list_append(app_cont_prg, ctx->program);
2594
11494
    new_prg = lbm_list_append(prg_copy, new_prg);
2595
    // new_prg is guaranteed to be a cons cell or nil
2596
    // even if the eval-program application is syntactically broken.
2597
11494
    stack_reserve(ctx, 1)[0] = DONE;
2598
11494
    ctx->program = get_cdr(new_prg);
2599
11494
    ctx->curr_exp = get_car(new_prg);
2600
  } else {
2601
    lbm_set_error_reason((char*)lbm_error_str_num_args);
2602
    error_at_ctx(ENC_SYM_EERROR, ENC_SYM_EVAL_PROGRAM);
2603
  }
2604
11494
}
2605
2606
3332
static void apply_send(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2607
3332
  if (nargs == 2) {
2608
3332
    if (lbm_type_of(args[0]) == LBM_TYPE_I) {
2609
3332
      lbm_cid cid = (lbm_cid)lbm_dec_i(args[0]);
2610
3332
      lbm_value msg = args[1];
2611
3332
      int r = lbm_find_receiver_and_send(cid, msg);
2612
      /* return the status */
2613
3332
      lbm_stack_drop(&ctx->K, nargs+1);
2614
3332
      ctx->r = r == 0 ? ENC_SYM_TRUE : ENC_SYM_NIL;
2615
3332
      ctx->app_cont = true;
2616
    } else {
2617
      error_at_ctx(ENC_SYM_TERROR, ENC_SYM_SEND);
2618
    }
2619
  } else {
2620
    lbm_set_error_reason((char*)lbm_error_str_num_args);
2621
    error_at_ctx(ENC_SYM_EERROR, ENC_SYM_SEND);
2622
  }
2623
3332
}
2624
2625
static void apply_ok(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2626
  lbm_value ok_val = ENC_SYM_TRUE;
2627
  if (nargs >= 1) {
2628
    ok_val = args[0];
2629
  }
2630
  ctx->r = ok_val;
2631
  ok_ctx();
2632
}
2633
2634
28
static void apply_error(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2635
  (void) ctx;
2636
28
  lbm_value err_val = ENC_SYM_EERROR;
2637
28
  if (nargs >= 1) {
2638
28
    err_val = args[0];
2639
  }
2640
28
  error_at_ctx(err_val, ENC_SYM_EXIT_ERROR);
2641
}
2642
2643
// ////////////////////////////////////////////////////////////
2644
// Map takes a function f and a list ls as arguments.
2645
// The function f is applied to each element of ls.
2646
//
2647
// Normally when applying a function to an argument this happens:
2648
//   1. the function is evaluated
2649
//   2. the argument is evaluated
2650
//   3. the result of evaluating the function is applied to the result of evaluating
2651
//      the argument.
2652
//
2653
// When doing (map f arg-list) I assume one means to apply f to each element of arg-list
2654
// exactly as those elements are. That is, no evaluation of the argument.
2655
// The implementation of map below makes sure that the elements of the arg-list are not
2656
// evaluated by wrapping them each in a `quote`.
2657
//
2658
// Map creates a structure in memory that looks like this (f (quote dummy . nil) . nil).
2659
// Then, for each element from arg-list (example a1 ... aN) the object
2660
// (f (quote aM . nil) . nil) is created by substituting dummy for an element of the list.
2661
// after this substitution the evaluator is fired up to evaluate the entire (f (quote aM . nil) . nil)
2662
// structure resulting in an element for the result list.
2663
//
2664
// Here comes the fun part, if you (map quote arg-list), then the object
2665
// (quote (quote aM . nil) . nil) is created and evaluated. Now note that quote just gives back
2666
// exactly what you give to it when evaluated.
2667
// So (quote (quote aM . nil) . nil) gives you as result (quote aM . nil) and now also note that
2668
// this is a list, and a list is really just an address on the heap!
2669
// This leads to the very fun behavior that:
2670
//
2671
// # (map quote '(1 2 3 4))
2672
// > ((quote 4) (quote 4) (quote 4) (quote 4))
2673
//
2674
// A potential fix is to instead of creating the object (f (quote aM . nil) . nil)
2675
// we create the object (f var) for some unique var and then extend the environment
2676
// for each round of evaluation with a binding var => aM.
2677
2678
// (map f arg-list)
2679
728
static void apply_map(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2680

728
  if (nargs == 2 && lbm_is_cons(args[1])) {
2681
616
    lbm_value *sptr = get_stack_ptr(ctx, 3);
2682
2683
616
    lbm_value f = args[0];
2684
616
    lbm_cons_t *args1_cell = lbm_ref_cell(args[1]);
2685
616
    lbm_value h = args1_cell->car;
2686
616
    lbm_value t = args1_cell->cdr;
2687
2688
    lbm_value appli_1;
2689
    lbm_value appli;
2690

616
    WITH_GC(appli_1, lbm_heap_allocate_list(2));
2691

616
    WITH_GC_RMBR_1(appli, lbm_heap_allocate_list(2), appli_1);
2692
2693
616
    lbm_value appli_0 = get_cdr(appli_1);
2694
2695
616
    lbm_set_car_and_cdr(appli_0, h, ENC_SYM_NIL);
2696
616
    lbm_set_car(appli_1, ENC_SYM_QUOTE);
2697
2698
616
    lbm_set_car_and_cdr(get_cdr(appli), appli_1, ENC_SYM_NIL);
2699
616
    lbm_set_car(appli, f);
2700
2701
616
    lbm_value elt = cons_with_gc(ctx->r, ENC_SYM_NIL, appli);
2702
616
    sptr[0] = t;     // reuse stack space
2703
616
    sptr[1] = ctx->curr_env;
2704
616
    sptr[2] = elt;
2705
616
    lbm_value *rptr = stack_reserve(ctx,4);
2706
616
    rptr[0] = elt;
2707
616
    rptr[1] = appli;
2708
616
    rptr[2] = appli_0;
2709
616
    rptr[3] = MAP;
2710
616
    ctx->curr_exp = appli;
2711

112
  } else if (nargs == 2 && lbm_is_symbol_nil(args[1])) {
2712
112
    lbm_stack_drop(&ctx->K, 3);
2713
112
    ctx->r = ENC_SYM_NIL;
2714
112
    ctx->app_cont = true;
2715
  } else {
2716
    lbm_set_error_reason((char*)lbm_error_str_num_args);
2717
    error_at_ctx(ENC_SYM_EERROR, ENC_SYM_MAP);
2718
  }
2719
728
}
2720
2721
140
static void apply_reverse(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2722

140
  if (nargs == 1 && lbm_is_list(args[0])) {
2723
140
    lbm_value curr = args[0];
2724
2725
140
    lbm_value new_list = ENC_SYM_NIL;
2726
3332
    while (lbm_is_cons(curr)) {
2727
3192
      lbm_cons_t *curr_cell = lbm_ref_cell(curr); // known cons.
2728
3192
      lbm_value tmp = cons_with_gc(curr_cell->car, new_list, ENC_SYM_NIL);
2729
3192
      new_list = tmp;
2730
3192
      curr = curr_cell->cdr;
2731
    }
2732
140
    lbm_stack_drop(&ctx->K, 2);
2733
140
    ctx->r = new_list;
2734
140
    ctx->app_cont = true;
2735
  } else {
2736
    lbm_set_error_reason("Reverse requires a list argument");
2737
    error_at_ctx(ENC_SYM_EERROR, ENC_SYM_REVERSE);
2738
  }
2739
140
}
2740
2741
34622
static void apply_flatten(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2742
34622
  if (nargs == 1) {
2743
#ifdef LBM_ALWAYS_GC
2744
    gc();
2745
#endif
2746
34594
    lbm_value v = flatten_value(args[0]);
2747
34594
    if ( v == ENC_SYM_MERROR) {
2748
2
      gc();
2749
2
      v = flatten_value(args[0]);
2750
    }
2751
2752
34594
    if (lbm_is_symbol(v)) {
2753
56
      error_at_ctx(v, ENC_SYM_FLATTEN);
2754
    } else {
2755
34538
      lbm_stack_drop(&ctx->K, 2);
2756
34538
      ctx->r = v;
2757
34538
      ctx->app_cont = true;
2758
    }
2759
34538
    return;
2760
  }
2761
28
  error_at_ctx(ENC_SYM_TERROR, ENC_SYM_FLATTEN);
2762
}
2763
2764
34510
static void apply_unflatten(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2765

34510
  if(nargs == 1 && lbm_type_of(args[0]) == LBM_TYPE_ARRAY) {
2766
    lbm_array_header_t *array;
2767
34510
    array = (lbm_array_header_t *)get_car(args[0]);
2768
2769
    lbm_flat_value_t fv;
2770
34510
    fv.buf = (uint8_t*)array->data;
2771
34510
    fv.buf_size = array->size;
2772
34510
    fv.buf_pos = 0;
2773
2774
    lbm_value res;
2775
2776
34510
    ctx->r = ENC_SYM_NIL;
2777
34510
    if (lbm_unflatten_value(&fv, &res)) {
2778
34510
      ctx->r =  res;
2779
    }
2780
34510
    lbm_stack_drop(&ctx->K, 2);
2781
34510
    ctx->app_cont = true;
2782
34510
    return;
2783
  }
2784
  error_at_ctx(ENC_SYM_TERROR, ENC_SYM_UNFLATTEN);
2785
}
2786
2787
83
static void apply_kill(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2788

83
  if (nargs == 2 && lbm_is_number(args[0])) {
2789
83
    lbm_cid cid = lbm_dec_as_i32(args[0]);
2790
2791
83
    if (ctx->id == cid) {
2792
      ctx->r = args[1];
2793
      finish_ctx();
2794
      return;
2795
    }
2796
83
    mutex_lock(&qmutex);
2797
83
    eval_context_t *found = NULL;
2798
83
    found = lookup_ctx_nm(&blocked, cid);
2799
83
    if (found)
2800
      drop_ctx_nm(&blocked, found);
2801
    else
2802
83
      found = lookup_ctx_nm(&queue, cid);
2803
83
    if (found)
2804
83
      drop_ctx_nm(&queue, found);
2805
2806
83
    if (found) {
2807
83
      found->K.data[found->K.sp - 1] = KILL;
2808
83
      found->r = args[1];
2809
83
      found->app_cont = true;
2810
83
      found->state = LBM_THREAD_STATE_READY;
2811
83
      enqueue_ctx_nm(&queue,found);
2812
83
      ctx->r = ENC_SYM_TRUE;
2813
    } else {
2814
      ctx->r = ENC_SYM_NIL;
2815
    }
2816
83
    lbm_stack_drop(&ctx->K, 3);
2817
83
    ctx->app_cont = true;
2818
83
    mutex_unlock(&qmutex);
2819
83
    return;
2820
  }
2821
  error_at_ctx(ENC_SYM_TERROR, ENC_SYM_KILL);
2822
}
2823
2824
282828
static lbm_value cmp_to_clo(lbm_value cmp) {
2825
  lbm_value closure;
2826

282828
  WITH_GC(closure, lbm_heap_allocate_list(4));
2827
282828
  lbm_set_car(closure, ENC_SYM_CLOSURE);
2828
282828
  lbm_value cl1 = lbm_cdr(closure);
2829
  lbm_value par;
2830

282828
  WITH_GC_RMBR_1(par, lbm_heap_allocate_list_init(2, symbol_x, symbol_y), closure);
2831
282828
  lbm_set_car(cl1, par);
2832
282828
  lbm_value cl2 = lbm_cdr(cl1);
2833
  lbm_value body;
2834

282828
  WITH_GC_RMBR_1(body, lbm_heap_allocate_list_init(3, cmp, symbol_x, symbol_y), closure);
2835
282828
  lbm_set_car(cl2, body);
2836
282828
  lbm_value cl3 = lbm_cdr(cl2);
2837
282828
  lbm_set_car(cl3, ENC_SYM_NIL);
2838
282828
  return closure;
2839
}
2840
2841
// (merge comparator list1 list2)
2842
420
static void apply_merge(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2843

420
  if (nargs == 3 && lbm_is_list(args[1]) && lbm_is_list(args[2])) {
2844
2845
420
    if (!lbm_is_closure(args[0])) {
2846
28
      args[0] = cmp_to_clo(args[0]);
2847
    }
2848
2849
    // Copy input lists for functional behaviour at top-level
2850
    // merge itself is in-place in the copied lists.
2851
    lbm_value a;
2852
    lbm_value b;
2853
420
    int len_a = -1;
2854
420
    int len_b = -1;
2855

420
    WITH_GC(a, lbm_list_copy(&len_a, args[1]));
2856

420
    WITH_GC_RMBR_1(b, lbm_list_copy(&len_b, args[2]), a);
2857
2858
420
    if (len_a == 0) {
2859
56
      ctx->r = b;
2860
56
      lbm_stack_drop(&ctx->K, 4);
2861
56
      ctx->app_cont = true;
2862
56
      return;
2863
    }
2864
364
    if (len_b == 0) {
2865
56
      ctx->r = a;
2866
56
      lbm_stack_drop(&ctx->K, 4);
2867
56
      ctx->app_cont = true;
2868
56
      return;
2869
    }
2870
2871
308
    args[1] = a; // keep safe by replacing the original on stack.
2872
308
    args[2] = b;
2873
2874
308
    lbm_value a_1 = a;
2875
308
    lbm_value a_rest = lbm_cdr(a);
2876
308
    lbm_value b_1 = b;
2877
308
    lbm_value b_rest = lbm_cdr(b);
2878
2879
    lbm_value cl[3]; // Comparator closure
2880
308
    extract_n(lbm_cdr(args[0]), cl, 3);
2881
308
    lbm_value cmp_env = cl[CLO_ENV];
2882
308
    lbm_value par1 = ENC_SYM_NIL;
2883
308
    lbm_value par2 = ENC_SYM_NIL;
2884
308
    lbm_uint len = lbm_list_length(cl[CLO_PARAMS]);
2885
308
    if (len == 2) {
2886
308
      par1 = get_car(cl[CLO_PARAMS]);
2887
308
      par2 = get_cadr(cl[CLO_PARAMS]);
2888
      lbm_value new_env0;
2889
      lbm_value new_env;
2890

308
      WITH_GC(new_env0, lbm_env_set(cmp_env, par1, lbm_car(a_1)));
2891

308
      WITH_GC_RMBR_1(new_env, lbm_env_set(new_env0, par2, lbm_car(b_1)),new_env0);
2892
308
      cmp_env = new_env;
2893
    } else {
2894
      error_at_ctx(ENC_SYM_TERROR, args[0]);
2895
    }
2896
308
    lbm_set_cdr(a_1, b_1);
2897
308
    lbm_set_cdr(b_1, ENC_SYM_NIL);
2898
308
    lbm_value cmp = cl[CLO_BODY];
2899
2900
308
    lbm_stack_drop(&ctx->K, 4); // TODO: Optimize drop 4 alloc 10 into alloc 6
2901
308
    lbm_uint *sptr = stack_reserve(ctx, 10);
2902
308
    sptr[0] = ENC_SYM_NIL; // head of merged list
2903
308
    sptr[1] = ENC_SYM_NIL; // last of merged list
2904
308
    sptr[2] = a_1;
2905
308
    sptr[3] = a_rest;
2906
308
    sptr[4] = b_rest;
2907
308
    sptr[5] = cmp;
2908
308
    sptr[6] = cmp_env;
2909
308
    sptr[7] = par1;
2910
308
    sptr[8] = par2;
2911
308
    sptr[9] = MERGE_REST;
2912
308
    ctx->curr_exp = cl[CLO_BODY];
2913
308
    ctx->curr_env = cmp_env;
2914
308
    return;
2915
  }
2916
  error_at_ctx(ENC_SYM_TERROR, ENC_SYM_MERGE);
2917
}
2918
2919
// (sort comparator list)
2920
283136
static void apply_sort(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2921

283136
  if (nargs == 2 && lbm_is_list(args[1])) {
2922
2923
283136
    if (!lbm_is_closure(args[0])) {
2924
282800
      args[0] = cmp_to_clo(args[0]);
2925
    }
2926
2927
283136
    int len = -1;
2928
    lbm_value list_copy;
2929

283136
    WITH_GC(list_copy, lbm_list_copy(&len, args[1]));
2930
283136
    if (len <= 1) {
2931
28
      lbm_stack_drop(&ctx->K, 3);
2932
28
      ctx->r = list_copy;
2933
28
      ctx->app_cont = true;
2934
28
      return;
2935
    }
2936
2937
283108
    args[1] = list_copy; // Keep safe, original replaced on stack.
2938
2939
    // Take the headmost 2, 1-element sublists.
2940
283108
    lbm_value a = list_copy;
2941
283108
    lbm_value b = lbm_cdr(a);
2942
283108
    lbm_value rest = lbm_cdr(b);
2943
    // Do not terminate b. keep rest of list safe from GC in the following
2944
    // closure extraction.
2945
    //lbm_set_cdr(a, b); // This is void
2946
2947
    lbm_value cl[3]; // Comparator closure
2948
283108
    extract_n(lbm_cdr(args[0]), cl, 3);
2949
283108
    lbm_value cmp_env = cl[CLO_ENV];
2950
283108
    lbm_value par1 = ENC_SYM_NIL;
2951
283108
    lbm_value par2 = ENC_SYM_NIL;
2952
283108
    lbm_uint cl_len = lbm_list_length(cl[CLO_PARAMS]);
2953
283108
    if (cl_len == 2) {
2954
283108
      par1 = get_car(cl[CLO_PARAMS]);
2955
283108
      par2 = get_cadr(cl[CLO_PARAMS]);
2956
      lbm_value new_env0;
2957
      lbm_value new_env;
2958

283108
      WITH_GC(new_env0, lbm_env_set(cmp_env, par1, lbm_car(a)));
2959

283108
      WITH_GC_RMBR_1(new_env, lbm_env_set(new_env0, par2, lbm_car(b)), new_env0);
2960
283108
      cmp_env = new_env;
2961
    } else {
2962
      error_at_ctx(ENC_SYM_TERROR, args[0]);
2963
    }
2964
283108
    lbm_value cmp = cl[CLO_BODY];
2965
2966
    // Terminate the comparator argument list.
2967
283108
    lbm_set_cdr(b, ENC_SYM_NIL);
2968
2969
283108
    lbm_stack_drop(&ctx->K, 3);  //TODO: optimize drop 3, alloc 20 into alloc 17
2970
283108
    lbm_uint *sptr = stack_reserve(ctx, 20);
2971
283108
    sptr[0] = cmp;
2972
283108
    sptr[1] = cmp_env;
2973
283108
    sptr[2] = par1;
2974
283108
    sptr[3] = par2;
2975
283108
    sptr[4] = ENC_SYM_NIL; // head of merged accumulation of sublists
2976
283108
    sptr[5] = ENC_SYM_NIL; // last of merged accumulation of sublists
2977
283108
    sptr[6] = rest;
2978
283108
    sptr[7] = lbm_enc_i(1);
2979
283108
    sptr[8] = lbm_enc_i(len); //TODO: 28 bit i vs 32 bit i
2980
283108
    sptr[9] = MERGE_LAYER;
2981
283108
    sptr[10] = ENC_SYM_NIL; // head of merged sublist
2982
283108
    sptr[11] = ENC_SYM_NIL; // last of merged sublist
2983
283108
    sptr[12] = a;
2984
283108
    sptr[13] = ENC_SYM_NIL; // no a_rest, 1 element lists in layer 1.
2985
283108
    sptr[14] = ENC_SYM_NIL; // no b_rest, 1 element lists in layer 1.
2986
283108
    sptr[15] = cmp;
2987
283108
    sptr[16] = cmp_env;
2988
283108
    sptr[17] = par1;
2989
283108
    sptr[18] = par2;
2990
283108
    sptr[19] = MERGE_REST;
2991
283108
    ctx->curr_exp = cmp;
2992
283108
    ctx->curr_env = cmp_env;
2993
283108
    return;
2994
  }
2995
  error_ctx(ENC_SYM_TERROR);
2996
}
2997
2998
616308
static void apply_rest_args(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2999
  lbm_value res;
3000
616308
  if (lbm_env_lookup_b(&res, ENC_SYM_REST_ARGS, ctx->curr_env)) {
3001

616280
    if (nargs == 1 && lbm_is_number(args[0])) {
3002
56140
      int32_t ix = lbm_dec_as_i32(args[0]);
3003
56140
      res = lbm_index_list(res, ix);
3004
    }
3005
616280
    ctx->r = res;
3006
  } else {
3007
28
    ctx->r = ENC_SYM_NIL;
3008
  }
3009
616308
  lbm_stack_drop(&ctx->K, nargs+1);
3010
616308
  ctx->app_cont = true;
3011
616308
}
3012
3013
/* (rotate list-expr dist/dir-expr) */
3014
84
static void apply_rotate(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
3015

84
  if (nargs == 2 && lbm_is_list(args[0]) && lbm_is_number(args[1])) {
3016
84
    int len = -1;
3017
    lbm_value ls;
3018

84
    WITH_GC(ls, lbm_list_copy(&len, args[0]));
3019
84
    int dist = lbm_dec_as_i32(args[1]);
3020

84
    if (len > 0 && dist != 0) {
3021
56
      int d = dist;
3022
56
      if (dist > 0) {
3023
28
        ls = lbm_list_destructive_reverse(ls);
3024
      } else {
3025
28
        d = -dist;
3026
      }
3027
3028
56
      lbm_value start = ls;
3029
56
      lbm_value end = ENC_SYM_NIL;
3030
56
      lbm_value curr = start;
3031
308
      while (lbm_is_cons(curr)) {
3032
252
        end = curr;
3033
252
        curr = get_cdr(curr);
3034
      }
3035
3036
168
      for (int i = 0; i < d; i ++) {
3037
112
        lbm_value a = start;
3038
112
        start = lbm_cdr(start);
3039
112
        lbm_set_cdr(a, ENC_SYM_NIL);
3040
112
        lbm_set_cdr(end, a);
3041
112
        end = a;
3042
      }
3043
56
      ls = start;
3044
56
      if (dist > 0) {
3045
28
        ls = lbm_list_destructive_reverse(ls);
3046
      }
3047
    }
3048
84
    lbm_stack_drop(&ctx->K, nargs+1);
3049
84
    ctx->app_cont = true;
3050
84
    ctx->r = ls;
3051
84
    return;
3052
  }
3053
  error_ctx(ENC_SYM_EERROR);
3054
}
3055
3056
/***************************************************/
3057
/* Application lookup table                        */
3058
3059
typedef void (*apply_fun)(lbm_value *, lbm_uint, eval_context_t *);
3060
static const apply_fun fun_table[] =
3061
  {
3062
   apply_setvar,
3063
   apply_read,
3064
   apply_read_program,
3065
   apply_read_eval_program,
3066
   apply_spawn,
3067
   apply_spawn_trap,
3068
   apply_yield,
3069
   apply_wait,
3070
   apply_eval,
3071
   apply_eval_program,
3072
   apply_send,
3073
   apply_ok,
3074
   apply_error,
3075
   apply_map,
3076
   apply_reverse,
3077
   apply_flatten,
3078
   apply_unflatten,
3079
   apply_kill,
3080
   apply_sleep,
3081
   apply_merge,
3082
   apply_sort,
3083
   apply_rest_args,
3084
   apply_rotate,
3085
  };
3086
3087
/***************************************************/
3088
/* Application of function that takes arguments    */
3089
/* passed over the stack.                          */
3090
3091
77990953
static void application(eval_context_t *ctx, lbm_value *fun_args, lbm_uint arg_count) {
3092
  /* If arriving here, we know that the fun is a symbol.
3093
   *  and can be a built in operation or an extension.
3094
   */
3095
77990953
  lbm_value fun = fun_args[0];
3096
3097
77990953
  lbm_uint fun_val = lbm_dec_sym(fun);
3098
77990953
  lbm_uint fun_kind = SYMBOL_KIND(fun_val);
3099
3100

77990953
  switch (fun_kind) {
3101
185710
  case SYMBOL_KIND_EXTENSION: {
3102
185710
    extension_fptr f = extension_table[SYMBOL_IX(fun_val)].fptr;
3103
3104
    lbm_value ext_res;
3105

185710
    WITH_GC(ext_res, f(&fun_args[1], arg_count));
3106
185710
    if (lbm_is_error(ext_res)) { //Error other than merror
3107
2996
      error_at_ctx(ext_res, fun);
3108
    }
3109
182714
    lbm_stack_drop(&ctx->K, arg_count + 1);
3110
3111
182714
    ctx->app_cont = true;
3112
182714
    ctx->r = ext_res;
3113
3114
182714
    if (blocking_extension) {
3115
112
      if (is_atomic) {
3116
        // Check atomic_error explicitly so that the mutex
3117
        // can be released if there is an error.
3118
        blocking_extension = false;
3119
        mutex_unlock(&blocking_extension_mutex);
3120
        atomic_error();
3121
      }
3122
112
      blocking_extension = false;
3123
112
      if (blocking_extension_timeout) {
3124
        blocking_extension_timeout = false;
3125
        block_current_ctx(LBM_THREAD_STATE_TIMEOUT, blocking_extension_timeout_us,true);
3126
      } else {
3127
112
        block_current_ctx(LBM_THREAD_STATE_BLOCKED, 0,true);
3128
      }
3129
112
      mutex_unlock(&blocking_extension_mutex);
3130
    }
3131
182714
  }  break;
3132
73276137
  case SYMBOL_KIND_FUNDAMENTAL:
3133
73276137
    call_fundamental(SYMBOL_IX(fun_val), &fun_args[1], arg_count, ctx);
3134
73271481
    break;
3135
4529106
  case SYMBOL_KIND_APPFUN:
3136
4529106
    fun_table[SYMBOL_IX(fun_val)](&fun_args[1], arg_count, ctx);
3137
4528686
    break;
3138
  default:
3139
    // Symbols that are "special" but not in the way caught above
3140
    // ends up here.
3141
    lbm_set_error_reason("Symbol does not represent a function");
3142
    error_at_ctx(ENC_SYM_EERROR,fun_args[0]);
3143
    break;
3144
  }
3145
77982881
}
3146
3147
59421145
static void cont_closure_application_args(eval_context_t *ctx) {
3148
59421145
  lbm_uint* sptr = get_stack_ptr(ctx, 5);
3149
3150
59421145
  lbm_value arg_env = (lbm_value)sptr[0];
3151
59421145
  lbm_value exp     = (lbm_value)sptr[1];
3152
59421145
  lbm_value clo_env = (lbm_value)sptr[2];
3153
59421145
  lbm_value params  = (lbm_value)sptr[3];
3154
59421145
  lbm_value args    = (lbm_value)sptr[4];
3155
3156
  lbm_value car_params, cdr_params;
3157
59421145
  get_car_and_cdr(params, &car_params, &cdr_params);
3158
3159
59421145
  bool a_nil = lbm_is_symbol_nil(args);
3160
59421145
  bool p_nil = lbm_is_symbol_nil(cdr_params);
3161
3162
59421145
  lbm_value binder = allocate_binding(car_params, ctx->r, clo_env);
3163
3164

59421117
  if (!a_nil && !p_nil) {
3165
    lbm_value car_args, cdr_args;
3166
33209876
    get_car_and_cdr(args, &car_args, &cdr_args);
3167
33209876
    sptr[2] = binder;
3168
33209876
    sptr[3] = cdr_params;
3169
33209876
    sptr[4] = cdr_args;
3170
33209876
    stack_reserve(ctx,1)[0] = CLOSURE_ARGS;
3171
33209876
    ctx->curr_exp = car_args;
3172
33209876
    ctx->curr_env = arg_env;
3173

26211241
  } else if (a_nil && p_nil) {
3174
    // Arguments and parameters match up in number
3175
26183017
    lbm_stack_drop(&ctx->K, 5);
3176
26183017
    ctx->curr_env = binder;
3177
26183017
    ctx->curr_exp = exp;
3178
28224
  } else if (p_nil) {
3179
28224
    lbm_value rest_binder = allocate_binding(ENC_SYM_REST_ARGS, ENC_SYM_NIL, binder);
3180
28224
    sptr[2] = rest_binder;
3181
28224
    sptr[3] = get_cdr(args);
3182
28224
    sptr[4] = get_car(rest_binder); // last element of rest_args so far
3183
28224
    stack_reserve(ctx,1)[0] = CLOSURE_ARGS_REST;
3184
28224
    ctx->curr_exp = get_car(args);
3185
28224
    ctx->curr_env = arg_env;
3186
  }  else {
3187
    lbm_set_error_reason((char*)lbm_error_str_num_args);
3188
    error_ctx(ENC_SYM_EERROR);
3189
  }
3190
59421117
}
3191
3192
3193
5797008
static void cont_closure_args_rest(eval_context_t *ctx) {
3194
5797008
  lbm_uint* sptr = get_stack_ptr(ctx, 5);
3195
5797008
  lbm_value arg_env = (lbm_value)sptr[0];
3196
5797008
  lbm_value exp     = (lbm_value)sptr[1];
3197
5797008
  lbm_value clo_env = (lbm_value)sptr[2];
3198
5797008
  lbm_value args    = (lbm_value)sptr[3];
3199
5797008
  lbm_value last    = (lbm_value)sptr[4];
3200
5797008
  lbm_cons_t* heap = lbm_heap_state.heap;
3201
#ifdef LBM_ALWAYS_GC
3202
  gc();
3203
#endif
3204
5797008
  lbm_value binding = lbm_heap_state.freelist;
3205
5797008
  if (binding == ENC_SYM_NIL) {
3206
7498
    gc();
3207
7498
    binding = lbm_heap_state.freelist;
3208
7498
    if (binding == ENC_SYM_NIL) error_ctx(ENC_SYM_MERROR);
3209
  }
3210
5797008
  lbm_uint binding_ix = lbm_dec_ptr(binding);
3211
5797008
  lbm_heap_state.freelist = heap[binding_ix].cdr;
3212
5797008
  lbm_heap_state.num_alloc += 1;
3213
5797008
  heap[binding_ix].car = ctx->r;
3214
5797008
  heap[binding_ix].cdr = ENC_SYM_NIL;
3215
3216
3217
5797008
  lbm_set_cdr(last, binding);
3218
5797008
  sptr[4] = binding;
3219
3220
5797008
  if (args == ENC_SYM_NIL) {
3221
588252
    lbm_stack_drop(&ctx->K, 5);
3222
588252
    ctx->curr_env = clo_env;
3223
588252
    ctx->curr_exp = exp;
3224
  } else {
3225
5208756
    stack_reserve(ctx,1)[0] = CLOSURE_ARGS_REST;
3226
5208756
    sptr[3] = get_cdr(args);
3227
5208756
    ctx->curr_exp = get_car(args);
3228
5208756
    ctx->curr_env = arg_env;
3229
  }
3230
5797008
}
3231
3232
247670299
static void cont_application_args(eval_context_t *ctx) {
3233
247670299
  lbm_uint *sptr = get_stack_ptr(ctx, 3);
3234
3235
247670299
  lbm_value env = sptr[0];
3236
247670299
  lbm_value rest = sptr[1];
3237
247670299
  lbm_value count = sptr[2];
3238
3239
247670299
  ctx->curr_env = env;
3240
247670299
  sptr[0] = ctx->r; // Function 1st then Arguments
3241
247670299
  if (lbm_is_cons(rest)) {
3242
169679346
    lbm_cons_t *cell = lbm_ref_cell(rest);
3243
169679346
    sptr[1] = env;
3244
169679346
    sptr[2] = cell->cdr;
3245
169679346
    lbm_value *rptr = stack_reserve(ctx,2);
3246
169679346
    rptr[0] = count + (1 << LBM_VAL_SHIFT);
3247
169679346
    rptr[1] = APPLICATION_ARGS;
3248
169679346
    ctx->curr_exp = cell->car;
3249
  } else {
3250
    // No more arguments
3251
77990953
    lbm_stack_drop(&ctx->K, 2);
3252
77990953
    lbm_uint nargs = lbm_dec_u(count);
3253
77990953
    lbm_value *args = get_stack_ptr(ctx, (uint32_t)(nargs + 1));
3254
77990953
    application(ctx,args, nargs);
3255
  }
3256
247662227
}
3257
3258
3985940
static void cont_and(eval_context_t *ctx) {
3259
  lbm_value env;
3260
  lbm_value rest;
3261
3985940
  lbm_value arg = ctx->r;
3262
3985940
  lbm_pop_2(&ctx->K, &rest, &env);
3263
3985940
  if (lbm_is_symbol_nil(arg)) {
3264
280056
    ctx->app_cont = true;
3265
280056
    ctx->r = ENC_SYM_NIL;
3266
3705884
  } else if (lbm_is_symbol_nil(rest)) {
3267
1701980
    ctx->app_cont = true;
3268
  } else {
3269
2003904
    lbm_value *sptr = stack_reserve(ctx, 3);
3270
2003904
    sptr[0] = env;
3271
2003904
    sptr[1] = get_cdr(rest);
3272
2003904
    sptr[2] = AND;
3273
2003904
    ctx->curr_env = env;
3274
2003904
    ctx->curr_exp = get_car(rest);
3275
  }
3276
3985940
}
3277
3278
15988
static void cont_or(eval_context_t *ctx) {
3279
  lbm_value env;
3280
  lbm_value rest;
3281
15988
  lbm_value arg = ctx->r;
3282
15988
  lbm_pop_2(&ctx->K, &rest, &env);
3283
15988
  if (!lbm_is_symbol_nil(arg)) {
3284
840
    ctx->app_cont = true;
3285
15148
  } else if (lbm_is_symbol_nil(rest)) {
3286
6356
    ctx->app_cont = true;
3287
6356
    ctx->r = ENC_SYM_NIL;
3288
  } else {
3289
8792
    lbm_value *sptr = stack_reserve(ctx, 3);
3290
8792
    sptr[0] = env;
3291
8792
    sptr[1] = get_cdr(rest);
3292
8792
    sptr[2] = OR;
3293
8792
    ctx->curr_exp = get_car(rest);
3294
8792
    ctx->curr_env = env;
3295
  }
3296
15988
}
3297
3298
40888386
static int fill_binding_location(lbm_value key, lbm_value value, lbm_value env) {
3299
40888386
  if (lbm_type_of(key) == LBM_TYPE_SYMBOL) {
3300
26887350
    if (key == ENC_SYM_DONTCARE) return FB_OK;
3301
24087238
    lbm_env_modify_binding(env,key,value);
3302
24087238
    return FB_OK;
3303

28002072
  } else if (lbm_is_cons(key) &&
3304
14001036
             lbm_is_cons(value)) {
3305
14001036
    int r = fill_binding_location(get_car(key), get_car(value), env);
3306
14001036
    if (r == FB_OK) {
3307
14001036
      r = fill_binding_location(get_cdr(key), get_cdr(value), env);
3308
    }
3309
14001036
    return r;
3310
  }
3311
  return FB_TYPE_ERROR;
3312
}
3313
3314
12242748
static void cont_bind_to_key_rest(eval_context_t *ctx) {
3315
3316
12242748
  lbm_value *sptr = get_stack_ptr(ctx, 4);
3317
3318
12242748
  lbm_value rest = sptr[1];
3319
12242748
  lbm_value env  = sptr[2];
3320
12242748
  lbm_value key  = sptr[3];
3321
3322
12242748
  if (fill_binding_location(key, ctx->r, env) < 0) {
3323
    lbm_set_error_reason("Incorrect type of name/key in let-binding");
3324
    error_at_ctx(ENC_SYM_TERROR, key);
3325
  }
3326
3327
12242748
  if (lbm_is_cons(rest)) {
3328
113904
    lbm_value car_rest = get_car(rest);
3329
    lbm_value key_val[2];
3330
113904
    extract_n(car_rest, key_val, 2);
3331
3332
113904
    sptr[1] = get_cdr(rest);
3333
113904
    sptr[3] = key_val[0];
3334
113904
    stack_reserve(ctx,1)[0] = BIND_TO_KEY_REST;
3335
113904
    ctx->curr_exp = key_val[1];
3336
113904
    ctx->curr_env = env;
3337
  } else {
3338
    // Otherwise evaluate the expression in the populated env
3339
12128844
    ctx->curr_exp = sptr[0];
3340
12128844
    ctx->curr_env = env;
3341
12128844
    lbm_stack_drop(&ctx->K, 4);
3342
  }
3343
12242748
}
3344
3345
21762604
static void cont_if(eval_context_t *ctx) {
3346
3347
21762604
  lbm_value arg = ctx->r;
3348
3349
21762604
  lbm_value *sptr = pop_stack_ptr(ctx, 2);
3350
3351
21762604
  ctx->curr_env = sptr[1];
3352
21762604
  if (lbm_is_symbol_nil(arg)) {
3353
21739278
    ctx->curr_exp = get_cadr(sptr[0]); // else branch
3354
  } else {
3355
23326
    ctx->curr_exp = get_car(sptr[0]); // then branch
3356
  }
3357
21762604
}
3358
3359
5936
static void cont_match(eval_context_t *ctx) {
3360
5936
  lbm_value e = ctx->r;
3361
5936
  bool  do_gc = false;
3362
3363
5936
  lbm_uint *sptr = get_stack_ptr(ctx, 2);
3364
5936
  lbm_value patterns = (lbm_value)sptr[0];
3365
5936
  lbm_value orig_env = (lbm_value)sptr[1]; // restore enclosing environment.
3366
5936
  lbm_value new_env = orig_env;
3367
3368
5936
  if (lbm_is_symbol_nil(patterns)) {
3369
    // no more patterns
3370
    lbm_stack_drop(&ctx->K, 2);
3371
    ctx->r = ENC_SYM_NO_MATCH;
3372
    ctx->app_cont = true;
3373
5936
  } else if (lbm_is_cons(patterns)) {
3374
5936
    lbm_value match_case = get_car(patterns);
3375
5936
    lbm_value pattern = get_car(match_case);
3376
5936
    lbm_value n1      = get_cadr(match_case);
3377
5936
    lbm_value n2      = get_cadr(get_cdr(match_case));
3378
    lbm_value body;
3379
5936
    bool check_guard = false;
3380
5936
    if (lbm_is_symbol_nil(n2)) { // TODO: Not a very robust check.
3381
4676
      body = n1;
3382
    } else {
3383
1260
      body = n2;
3384
1260
      check_guard = true;
3385
    }
3386
#ifdef LBM_ALWAYS_GC
3387
    gc();
3388
#endif
3389
5936
    bool is_match = match(pattern, e, &new_env, &do_gc);
3390
5936
    if (do_gc) {
3391
      gc();
3392
      do_gc = false;
3393
      new_env = orig_env;
3394
      is_match = match(pattern, e, &new_env, &do_gc);
3395
      if (do_gc) {
3396
        error_ctx(ENC_SYM_MERROR);
3397
      }
3398
    }
3399
5936
    if (is_match) {
3400
3528
      if (check_guard) {
3401
1260
        lbm_value *rptr = stack_reserve(ctx,5);
3402
1260
        sptr[0] = get_cdr(patterns);
3403
1260
        sptr[1] = ctx->curr_env;
3404
1260
        rptr[0] = MATCH;
3405
1260
        rptr[1] = new_env;
3406
1260
        rptr[2] = body;
3407
1260
        rptr[3] = e;
3408
1260
        rptr[4] = MATCH_GUARD;
3409
1260
        ctx->curr_env = new_env;
3410
1260
        ctx->curr_exp = n1; // The guard
3411
      } else {
3412
2268
        lbm_stack_drop(&ctx->K, 2);
3413
2268
        ctx->curr_env = new_env;
3414
2268
        ctx->curr_exp = body;
3415
      }
3416
    } else {
3417
      // set up for checking of next pattern
3418
2408
      sptr[0] = get_cdr(patterns);
3419
2408
      sptr[1] = orig_env;
3420
2408
      stack_reserve(ctx,1)[0] = MATCH;
3421
      // leave r unaltered
3422
2408
      ctx->app_cont = true;
3423
    }
3424
  } else {
3425
    error_at_ctx(ENC_SYM_TERROR, ENC_SYM_MATCH);
3426
  }
3427
5936
}
3428
3429
224
static void cont_exit_atomic(eval_context_t *ctx) {
3430
224
  is_atomic = false; // atomic blocks cannot nest!
3431
224
  ctx->app_cont = true;
3432
224
}
3433
3434
// cont_map:
3435
//
3436
// sptr[0]: s[sp-6] = Rest of the input list.
3437
// sptr[1]: s[sp-5] = Environment to restore for the eval of each application.
3438
// sptr[2]: s[sp-4] = Result list.
3439
// sptr[3]: s[sp-3] = Cell that goes into result list after being populated with application result.
3440
// sptr[4]: s[sp-2] = Ref to application.
3441
// sptr[5]: s[sp-1] = Ref to application argument.
3442
//
3443
// ctx->r  = eval result of previous application.
3444
2016
static void cont_map(eval_context_t *ctx) {
3445
2016
  lbm_value *sptr = get_stack_ptr(ctx, 6);
3446
2016
  lbm_value ls  = sptr[0];
3447
2016
  lbm_value env = sptr[1];
3448
2016
  lbm_value t   = sptr[3];
3449
2016
  lbm_set_car(t, ctx->r); // update car field tailmost position.
3450
2016
  if (lbm_is_cons(ls)) {
3451
1400
    lbm_cons_t *cell = lbm_ref_cell(ls); // already checked that cons.
3452
1400
    lbm_value next = cell->car;
3453
1400
    lbm_value rest = cell->cdr;
3454
1400
    sptr[0] = rest;
3455
1400
    stack_reserve(ctx,1)[0] = MAP;
3456
1400
    lbm_set_car(sptr[5], next); // new arguments
3457
3458
1400
    lbm_value elt = cons_with_gc(ENC_SYM_NIL, ENC_SYM_NIL, ENC_SYM_NIL);
3459
1400
    lbm_set_cdr(t, elt);
3460
1400
    sptr[3] = elt;  // (r1 ... rN . (nil . nil))
3461
1400
    ctx->curr_exp = sptr[4];
3462
1400
    ctx->curr_env = env;
3463
  } else {
3464
616
    ctx->r = sptr[2]; //head of result list
3465
616
    ctx->curr_env = env;
3466
616
    lbm_stack_drop(&ctx->K, 6);
3467
616
    ctx->app_cont = true;
3468
  }
3469
2016
}
3470
3471
1260
static void cont_match_guard(eval_context_t *ctx) {
3472
1260
  if (lbm_is_symbol_nil(ctx->r)) {
3473
    lbm_value e;
3474
476
    lbm_pop(&ctx->K, &e);
3475
476
    lbm_stack_drop(&ctx->K, 2);
3476
476
    ctx->r = e;
3477
476
    ctx->app_cont = true;
3478
  } else {
3479
    lbm_value body;
3480
    lbm_value env;
3481
784
    lbm_stack_drop(&ctx->K, 1);
3482
784
    lbm_pop_2(&ctx->K, &body, &env);
3483
784
    lbm_stack_drop(&ctx->K, 3);
3484
784
    ctx->curr_env = env;
3485
784
    ctx->curr_exp = body;
3486
  }
3487
1260
}
3488
3489
28
static void cont_terminate(eval_context_t *ctx) {
3490
28
  error_ctx(ctx->r);
3491
}
3492
3493
925148
static void cont_loop(eval_context_t *ctx) {
3494
925148
  lbm_value *sptr = get_stack_ptr(ctx, 2);
3495
925148
  stack_reserve(ctx,1)[0] = LOOP_CONDITION;
3496
925148
  ctx->curr_exp = sptr[1];
3497
925148
}
3498
3499
925428
static void cont_loop_condition(eval_context_t *ctx) {
3500
925428
  if (lbm_is_symbol_nil(ctx->r)) {
3501
280
    lbm_stack_drop(&ctx->K, 2);
3502
280
    ctx->app_cont = true;  // A loop returns nil? Makes sense to me... but in general?
3503
280
    return;
3504
  }
3505
925148
  lbm_value *sptr = get_stack_ptr(ctx, 2);
3506
925148
  stack_reserve(ctx,1)[0] = LOOP;
3507
925148
  ctx->curr_exp = sptr[0];
3508
}
3509
3510
8791580
static void cont_merge_rest(eval_context_t *ctx) {
3511
8791580
  lbm_uint *sptr = get_stack_ptr(ctx, 9);
3512
3513
  // If comparator returns true (result is in ctx->r):
3514
  //   "a" should be moved to the last element position in merged list.
3515
  //   A new element from "a_rest" should be moved into comparator argument 1 pos.
3516
  // else
3517
  //   "b" should be moved to last element position in merged list.
3518
  //   A new element from "b_rest" should be moved into comparator argument 2 pos.
3519
  //
3520
  // If a_rest or b_rest is NIL:
3521
  //   we are done, the remaining elements of
3522
  //   non_nil list should be appended to merged list.
3523
  // else
3524
  //   Set up for a new comparator evaluation and recurse.
3525
8791580
  lbm_value a = sptr[2];
3526
8791580
  lbm_value b = lbm_cdr(a);
3527
8791580
  lbm_set_cdr(a, ENC_SYM_NIL); // terminate 1 element list
3528
3529
8791580
  if (ctx->r == ENC_SYM_NIL) { // Comparison false
3530
3531
5102216
    if (sptr[0] == ENC_SYM_NIL) {
3532
1983576
      sptr[0] = b;
3533
1983576
      sptr[1] = b;
3534
    } else {
3535
3118640
      lbm_set_cdr(sptr[1], b);
3536
3118640
      sptr[1] = b;
3537
    }
3538
5102216
    if (sptr[4] == ENC_SYM_NIL) {
3539
2549456
      lbm_set_cdr(a, sptr[3]);
3540
2549456
      lbm_set_cdr(sptr[1], a);
3541
2549456
      ctx->r = sptr[0];
3542
2549456
      lbm_stack_drop(&ctx->K, 9);
3543
2549456
      ctx->app_cont = true;
3544
2549456
      return;
3545
    } else {
3546
2552760
      b = sptr[4];
3547
2552760
      sptr[4] = lbm_cdr(sptr[4]);
3548
2552760
      lbm_set_cdr(b, ENC_SYM_NIL);
3549
    }
3550
  } else {
3551
3689364
    if (sptr[0] == ENC_SYM_NIL) {
3552
1134812
      sptr[0] = a;
3553
1134812
      sptr[1] = a;
3554
    } else {
3555
2554552
      lbm_set_cdr(sptr[1], a);
3556
2554552
      sptr[1] = a;
3557
    }
3558
3559
3689364
    if (sptr[3] == ENC_SYM_NIL) {
3560
568932
      lbm_set_cdr(b, sptr[4]);
3561
568932
      lbm_set_cdr(sptr[1], b);
3562
568932
      ctx->r = sptr[0];
3563
568932
      lbm_stack_drop(&ctx->K, 9);
3564
568932
      ctx->app_cont = true;
3565
568932
      return;
3566
    } else {
3567
3120432
      a = sptr[3];
3568
3120432
      sptr[3] = lbm_cdr(sptr[3]);
3569
3120432
      lbm_set_cdr(a, ENC_SYM_NIL);
3570
    }
3571
  }
3572
5673192
  lbm_set_cdr(a, b);
3573
5673192
  sptr[2] = a;
3574
3575
5673192
  lbm_value par1 = sptr[7];
3576
5673192
  lbm_value par2 = sptr[8];
3577
5673192
  lbm_value cmp_body = sptr[5];
3578
5673192
  lbm_value cmp_env = sptr[6];
3579
  // Environment should be preallocated already at this point
3580
  // and the operations below should never need GC.
3581
5673192
  lbm_value new_env0 = lbm_env_set(cmp_env, par1, lbm_car(a));
3582
5673192
  lbm_value new_env = lbm_env_set(new_env0, par2, lbm_car(b));
3583

5673192
  if (lbm_is_symbol(new_env0) || lbm_is_symbol(new_env)) {
3584
    error_ctx(ENC_SYM_FATAL_ERROR);
3585
  }
3586
5673192
  cmp_env = new_env;
3587
3588
5673192
  stack_reserve(ctx,1)[0] = MERGE_REST;
3589
5673192
  ctx->curr_exp = cmp_body;
3590
5673192
  ctx->curr_env = cmp_env;
3591
}
3592
3593
// merge_layer stack contents
3594
// s[sp-9] = cmp
3595
// s[sp-8] = cmp_env
3596
// s[sp-7] = par1
3597
// s[sp-6] = par2
3598
// s[sp-5] = acc - first cell
3599
// s[sp-4] = acc - last cell
3600
// s[sp-3] = rest;
3601
// s[sp-2] = layer
3602
// s[sp-1] = length or original list
3603
//
3604
// ctx->r merged sublist
3605
3401272
static void cont_merge_layer(eval_context_t *ctx) {
3606
3401272
  lbm_uint *sptr = get_stack_ptr(ctx, 9);
3607
3401272
  lbm_int layer = lbm_dec_i(sptr[7]);
3608
3401272
  lbm_int len = lbm_dec_i(sptr[8]);
3609
3610
3401272
  lbm_value r_curr = ctx->r;
3611
13620600
  while (lbm_is_cons(r_curr)) {
3612
13620600
    lbm_value next = lbm_cdr(r_curr);
3613
13620600
    if (next == ENC_SYM_NIL) {
3614
3401272
      break;
3615
    }
3616
10219328
    r_curr = next;
3617
  }
3618
3619
3401272
  if (sptr[4] == ENC_SYM_NIL) {
3620
1132348
    sptr[4] = ctx->r;
3621
1132348
    sptr[5] = r_curr;
3622
  } else {
3623
2268924
    lbm_set_cdr(sptr[5], ctx->r); // accumulate merged sublists.
3624
2268924
    sptr[5] = r_curr;
3625
  }
3626
3627
3401272
  lbm_value layer_rest = sptr[6];
3628
  // switch layer or done ?
3629
3401272
  if (layer_rest == ENC_SYM_NIL) {
3630
1132348
    if (layer * 2 >= len) {
3631
283108
      ctx->r = sptr[4];
3632
283108
      ctx->app_cont = true;
3633
283108
      lbm_stack_drop(&ctx->K, 9);
3634
283108
      return;
3635
    } else {
3636
      // Setup for merges of the next layer
3637
849240
      layer = layer * 2;
3638
849240
      sptr[7] = lbm_enc_i(layer);
3639
849240
      layer_rest = sptr[4]; // continue on the accumulation of all sublists.
3640
849240
      sptr[5] = ENC_SYM_NIL;
3641
849240
      sptr[4] = ENC_SYM_NIL;
3642
    }
3643
  }
3644
  // merge another sublist based on current layer.
3645
3118164
  lbm_value a_list = layer_rest;
3646
  // build sublist a
3647
3118164
  lbm_value curr = layer_rest;
3648
7661080
  for (int i = 0; i < layer-1; i ++) {
3649
4543028
    if (lbm_is_cons(curr)) {
3650
4542916
      curr = lbm_cdr(curr);
3651
    } else {
3652
112
      break;
3653
    }
3654
  }
3655
3118164
  layer_rest = lbm_cdr(curr);
3656
3118164
  lbm_set_cdr(curr, ENC_SYM_NIL); //terminate sublist.
3657
3658
3118164
  lbm_value b_list = layer_rest;
3659
  // build sublist b
3660
3118164
  curr = layer_rest;
3661
5959800
  for (int i = 0; i < layer-1; i ++) {
3662
3407796
    if (lbm_is_cons(curr)) {
3663
2841636
      curr = lbm_cdr(curr);
3664
    } else {
3665
566160
      break;
3666
    }
3667
  }
3668
3118164
  layer_rest = lbm_cdr(curr);
3669
3118164
  lbm_set_cdr(curr, ENC_SYM_NIL); //terminate sublist.
3670
3671
3118164
  sptr[6] = layer_rest;
3672
3673
3118164
  if (b_list == ENC_SYM_NIL) {
3674
283192
    stack_reserve(ctx,1)[0] = MERGE_LAYER;
3675
283192
    ctx->r = a_list;
3676
283192
    ctx->app_cont = true;
3677
283192
    return;
3678
  }
3679
  // Set up for a merge of sublists.
3680
3681
2834972
  lbm_value a_rest = lbm_cdr(a_list);
3682
2834972
  lbm_value b_rest = lbm_cdr(b_list);
3683
2834972
  lbm_value a = a_list;
3684
2834972
  lbm_value b = b_list;
3685
2834972
  lbm_set_cdr(a, b);
3686
  // Terminating the b list would be incorrect here
3687
  // if there was any chance that the environment update below
3688
  // performs GC.
3689
2834972
  lbm_set_cdr(b, ENC_SYM_NIL);
3690
3691
2834972
  lbm_value cmp_body = sptr[0];
3692
2834972
  lbm_value cmp_env = sptr[1];
3693
2834972
  lbm_value par1 = sptr[2];
3694
2834972
  lbm_value par2 = sptr[3];
3695
  // Environment should be preallocated already at this point
3696
  // and the operations below should never need GC.
3697
2834972
  lbm_value new_env0 = lbm_env_set(cmp_env, par1, lbm_car(a));
3698
2834972
  lbm_value new_env = lbm_env_set(cmp_env, par2, lbm_car(b));
3699

2834972
  if (lbm_is_symbol(new_env0) || lbm_is_symbol(new_env)) {
3700
    error_ctx(ENC_SYM_FATAL_ERROR);
3701
  }
3702
2834972
  cmp_env = new_env;
3703
3704
2834972
  lbm_uint *merge_cont = stack_reserve(ctx, 11);
3705
2834972
  merge_cont[0] = MERGE_LAYER;
3706
2834972
  merge_cont[1] = ENC_SYM_NIL;
3707
2834972
  merge_cont[2] = ENC_SYM_NIL;
3708
2834972
  merge_cont[3] = a;
3709
2834972
  merge_cont[4] = a_rest;
3710
2834972
  merge_cont[5] = b_rest;
3711
2834972
  merge_cont[6] = cmp_body;
3712
2834972
  merge_cont[7] = cmp_env;
3713
2834972
  merge_cont[8] = par1;
3714
2834972
  merge_cont[9] = par2;
3715
2834972
  merge_cont[10] = MERGE_REST;
3716
2834972
  ctx->curr_exp = cmp_body;
3717
2834972
  ctx->curr_env = cmp_env;
3718
2834972
  return;
3719
}
3720
3721
/****************************************************/
3722
/*   READER                                         */
3723
3724
33422
static void read_finish(lbm_char_channel_t *str, eval_context_t *ctx) {
3725
3726
  /* Tokenizer reached "end of file"
3727
     The parser could be in a state where it needs
3728
     more tokens to correctly finish an expression.
3729
3730
     Four cases
3731
     1. The program / expression is malformed and the context should die.
3732
     2. We are finished reading a program and should close off the
3733
     internal representation with a closing parenthesis. Then
3734
     apply continuation.
3735
     3. We are finished reading an expression and should
3736
     apply the continuation
3737
     4. We are finished read-and-evaluating
3738
3739
     In case 2, we should find the READ_DONE at sp - 5.
3740
     In case 3, we should find the READ_DONE at sp - 1.
3741
     In case 4, we should find the READ_DONE at sp - 4.
3742
3743
     case 3 should not end up here, but rather end up in
3744
     cont_read_done.
3745
  */
3746
3747
33422
  if (lbm_is_symbol(ctx->r)) {
3748
10792
    lbm_uint sym_val = lbm_dec_sym(ctx->r);
3749

10792
    if (sym_val >= TOKENIZER_SYMBOLS_START &&
3750
        sym_val <= TOKENIZER_SYMBOLS_END) {
3751
      read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
3752
    }
3753
  }
3754
3755

33422
  if (ctx->K.sp > 4  && (ctx->K.data[ctx->K.sp - 4] == READ_DONE) &&
3756
22152
      (ctx->K.data[ctx->K.sp - 5] == READING_PROGRAM_INCREMENTALLY)) {
3757
    /* read and evaluate is done */
3758
    lbm_value env;
3759
    lbm_value s;
3760
    lbm_value sym;
3761
22152
    lbm_pop_3(&ctx->K, &sym, &env, &s);
3762
22152
    ctx->curr_env = env;
3763
22152
    ctx->app_cont = true; // Program evaluated and result is in ctx->r.
3764

11270
  } else if (ctx->K.sp > 5 && (ctx->K.data[ctx->K.sp - 5] == READ_DONE) &&
3765
11270
             (ctx->K.data[ctx->K.sp - 6] == READING_PROGRAM)) {
3766
    /* successfully finished reading a program  (CASE 2) */
3767
11270
    ctx->r = ENC_SYM_CLOSEPAR;
3768
11270
    ctx->app_cont = true;
3769
  } else {
3770
    if (lbm_channel_row(str) == 1 && lbm_channel_column(str) == 1) {
3771
      // (read "") evaluates to nil.
3772
      ctx->r = ENC_SYM_NIL;
3773
      ctx->app_cont = true;
3774
    } else {
3775
      lbm_channel_reader_close(str);
3776
      lbm_set_error_reason((char*)lbm_error_str_parse_eof);
3777
      read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
3778
    }
3779
  }
3780
33422
}
3781
3782
/* cont_read_next_token
3783
   sp-2 : Stream
3784
   sp-1 : Grab row
3785
*/
3786
5708000
static void cont_read_next_token(eval_context_t *ctx) {
3787
5708000
  lbm_value *sptr = get_stack_ptr(ctx, 2);
3788
5708000
  lbm_value stream = sptr[0];
3789
5708000
  lbm_value grab_row0 = sptr[1];
3790
3791
5708000
  lbm_char_channel_t *chan = lbm_dec_channel(stream);
3792

5708000
  if (chan == NULL || chan->state == NULL) {
3793
    error_ctx(ENC_SYM_FATAL_ERROR);
3794
  }
3795
3796

5708000
  if (!lbm_channel_more(chan) && lbm_channel_is_empty(chan)) {
3797
11872
    lbm_stack_drop(&ctx->K, 2);
3798
11872
    read_finish(chan, ctx);
3799
5708000
    return;
3800
  }
3801
  /* Eat whitespace and comments */
3802
5696128
  if (!tok_clean_whitespace(chan)) {
3803
679
    sptr[0] = stream;
3804
679
    sptr[1] = lbm_enc_u(0);
3805
679
    stack_reserve(ctx,1)[0] = READ_NEXT_TOKEN;
3806
679
    yield_ctx(EVAL_CPS_MIN_SLEEP);
3807
679
    return;
3808
  }
3809
  /* After eating whitespace we may be at end of file/stream */
3810

5695449
  if (!lbm_channel_more(chan) && lbm_channel_is_empty(chan)) {
3811
21550
    lbm_stack_drop(&ctx->K, 2);
3812
21550
    read_finish(chan, ctx);
3813
21550
    return;
3814
  }
3815
3816
5673899
  if (lbm_dec_u(grab_row0)) {
3817
378465
    ctx->row0 = (int32_t)lbm_channel_row(chan);
3818
378465
    ctx->row1 = -1; // a new start, end is unknown
3819
  }
3820
3821
  /* Attempt to extract tokens from the character stream */
3822
5673899
  int n = 0;
3823
5673899
  lbm_value res = ENC_SYM_NIL;
3824
5673899
  unsigned int string_len = 0;
3825
3826
  /*
3827
   * SYNTAX
3828
   */
3829
  uint32_t tok_match;
3830
5673899
  n = tok_syntax(chan, &tok_match);
3831
5673899
  if (n > 0) {
3832
1408118
    if (!lbm_channel_drop(chan, (unsigned int)n)) {
3833
      error_ctx(ENC_SYM_FATAL_ERROR);
3834
    }
3835
1408118
    ctx->app_cont = true;
3836



1408118
    switch(tok_match) {
3837
668107
    case TOKOPENPAR: {
3838
668107
      sptr[0] = ENC_SYM_NIL;
3839
668107
      sptr[1] = ENC_SYM_NIL;
3840
668107
      lbm_value *rptr = stack_reserve(ctx,5);
3841
668107
      rptr[0] = stream;
3842
668107
      rptr[1] = READ_APPEND_CONTINUE;
3843
668107
      rptr[2] = stream;
3844
668107
      rptr[3] = lbm_enc_u(0);
3845
668107
      rptr[4] = READ_NEXT_TOKEN;
3846
668107
      ctx->r = ENC_SYM_OPENPAR;
3847
668107
    } return;
3848
668107
    case TOKCLOSEPAR: {
3849
668107
      lbm_stack_drop(&ctx->K, 2);
3850
668107
      ctx->r = ENC_SYM_CLOSEPAR;
3851
668107
    } return;
3852
3304
    case TOKOPENBRACK: {
3853
3304
      sptr[0] = stream;
3854
3304
      sptr[1] = READ_START_ARRAY;
3855
3304
      lbm_value *rptr = stack_reserve(ctx, 3);
3856
3304
      rptr[0] = stream;
3857
3304
      rptr[1] = lbm_enc_u(0);
3858
3304
      rptr[2] = READ_NEXT_TOKEN;
3859
3304
      ctx->r = ENC_SYM_OPENBRACK;
3860
3304
    } return;
3861
3304
    case TOKCLOSEBRACK:
3862
3304
      lbm_stack_drop(&ctx->K, 2);
3863
3304
      ctx->r = ENC_SYM_CLOSEBRACK;
3864
3304
      return;
3865
6216
    case TOKDOT:
3866
6216
      lbm_stack_drop(&ctx->K, 2);
3867
6216
      ctx->r = ENC_SYM_DOT;
3868
6216
      return;
3869
1036
    case TOKDONTCARE:
3870
1036
      lbm_stack_drop(&ctx->K, 2);
3871
1036
      ctx->r = ENC_SYM_DONTCARE;
3872
1036
      return;
3873
27524
    case TOKQUOTE:
3874
27524
      sptr[0] = ENC_SYM_QUOTE;
3875
27524
      sptr[1] = WRAP_RESULT;
3876
27524
      break;
3877
5040
    case TOKBACKQUOTE: {
3878
5040
      sptr[0] = QQ_EXPAND_START;
3879
5040
      sptr[1] = stream;
3880
5040
      lbm_value *rptr = stack_reserve(ctx, 2);
3881
5040
      rptr[0] = lbm_enc_u(0);
3882
5040
      rptr[1] = READ_NEXT_TOKEN;
3883
5040
      ctx->app_cont = true;
3884
5040
    } return;
3885
56
    case TOKCOMMAAT:
3886
56
      sptr[0] = ENC_SYM_COMMAAT;
3887
56
      sptr[1] = WRAP_RESULT;
3888
56
      break;
3889
13944
    case TOKCOMMA:
3890
13944
      sptr[0] = ENC_SYM_COMMA;
3891
13944
      sptr[1] = WRAP_RESULT;
3892
13944
      break;
3893
6832
    case TOKMATCHANY:
3894
6832
      lbm_stack_drop(&ctx->K, 2);
3895
6832
      ctx->r = ENC_SYM_MATCH_ANY;
3896
6832
      return;
3897
2296
    case TOKOPENCURL: {
3898
2296
      sptr[0] = ENC_SYM_NIL;
3899
2296
      sptr[1] = ENC_SYM_NIL;
3900
2296
      lbm_value *rptr = stack_reserve(ctx,2);
3901
2296
      rptr[0] = stream;
3902
2296
      rptr[1] = READ_APPEND_CONTINUE;
3903
2296
      ctx->r = ENC_SYM_PROGN;
3904
2296
    } return;
3905
2296
    case TOKCLOSECURL:
3906
2296
      lbm_stack_drop(&ctx->K, 2);
3907
2296
      ctx->r = ENC_SYM_CLOSEPAR;
3908
2296
      return;
3909
56
    case TOKCONSTSTART: /* fall through */
3910
    case TOKCONSTEND: {
3911
56
      if (tok_match == TOKCONSTSTART)  ctx->flags |= EVAL_CPS_CONTEXT_FLAG_CONST;
3912
56
      if (tok_match == TOKCONSTEND)    ctx->flags &= ~EVAL_CPS_CONTEXT_FLAG_CONST;
3913
56
      sptr[0] = stream;
3914
56
      sptr[1] = lbm_enc_u(0);
3915
56
      stack_reserve(ctx,1)[0] = READ_NEXT_TOKEN;
3916
56
      ctx->app_cont = true;
3917
56
    } return;
3918
    default:
3919
      read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
3920
    }
3921
    // read next token
3922
41524
    lbm_value *rptr = stack_reserve(ctx, 3);
3923
41524
    rptr[0] = stream;
3924
41524
    rptr[1] = lbm_enc_u(0);
3925
41524
    rptr[2] = READ_NEXT_TOKEN;
3926
41524
    ctx->app_cont = true;
3927
41524
    return;
3928
4265781
  } else if (n < 0) goto retry_token;
3929
3930
  /*
3931
   *  STRING
3932
   */
3933
4265781
  n = tok_string(chan, &string_len);
3934
4265781
  if (n >= 2) {
3935
9380
    lbm_channel_drop(chan, (unsigned int)n);
3936
#ifdef LBM_ALWAYS_GC
3937
    gc();
3938
#endif
3939
9380
    if (!lbm_heap_allocate_array(&res, (unsigned int)(string_len+1))) {
3940
      gc();
3941
      lbm_heap_allocate_array(&res, (unsigned int)(string_len+1));
3942
    }
3943
9380
    if (lbm_is_ptr(res)) {
3944
9380
      lbm_array_header_t *arr = assume_array(res);
3945
9380
      char *data = (char*)arr->data;
3946
9380
      memset(data,0, string_len + 1);
3947
9380
      memcpy(data, tokpar_sym_str, string_len);
3948
9380
      lbm_stack_drop(&ctx->K, 2);
3949
9380
      ctx->r = res;
3950
9380
      ctx->app_cont = true;
3951
9380
      return;
3952
    } else {
3953
      error_ctx(ENC_SYM_MERROR);
3954
    }
3955
4256401
  } else if (n < 0) goto retry_token;
3956
3957
  /*
3958
   * FLOAT
3959
   */
3960
  token_float f_val;
3961
4256401
  n = tok_double(chan, &f_val);
3962
4256401
  if (n > 0) {
3963
13188
    lbm_channel_drop(chan, (unsigned int) n);
3964
13188
    switch(f_val.type) {
3965
10164
    case TOKTYPEF32:
3966

10164
      WITH_GC(res, lbm_enc_float((float)f_val.value));
3967
10164
      break;
3968
3024
    case TOKTYPEF64:
3969
3024
      res = lbm_enc_double(f_val.value);
3970
3024
      break;
3971
    default:
3972
      read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
3973
    }
3974
13188
    lbm_stack_drop(&ctx->K, 2);
3975
13188
    ctx->r = res;
3976
13188
    ctx->app_cont = true;
3977
13188
    return;
3978
4243213
  } else if (n < 0) goto retry_token;
3979
3980
  /*
3981
   * INTEGER
3982
   */
3983
  token_int int_result;
3984
4243212
  n = tok_integer(chan, &int_result);
3985
4243212
  if (n > 0) {
3986
3357087
    lbm_channel_drop(chan, (unsigned int)n);
3987


3357087
    switch(int_result.type) {
3988
2212
    case TOKTYPEBYTE:
3989
2212
      res = lbm_enc_char((uint8_t)(int_result.negative ? -int_result.value : int_result.value));
3990
2212
      break;
3991
3336031
    case TOKTYPEI:
3992
3336031
      res = lbm_enc_i((lbm_int)(int_result.negative ? -int_result.value : int_result.value));
3993
3336031
      break;
3994
3500
    case TOKTYPEU:
3995
3500
      res = lbm_enc_u((lbm_uint)(int_result.negative ? -int_result.value : int_result.value));
3996
3500
      break;
3997
3668
    case TOKTYPEI32:
3998


3668
      WITH_GC(res, lbm_enc_i32((int32_t)(int_result.negative ? -int_result.value : int_result.value)));
3999
3668
      break;
4000
4480
    case TOKTYPEU32:
4001


4480
      WITH_GC(res,lbm_enc_u32((uint32_t)(int_result.negative ? -int_result.value : int_result.value)));
4002
4480
      break;
4003
3780
    case TOKTYPEI64:
4004


3780
      WITH_GC(res,lbm_enc_i64((int64_t)(int_result.negative ? -int_result.value : int_result.value)));
4005
3780
      break;
4006
3416
    case TOKTYPEU64:
4007


3416
      WITH_GC(res,lbm_enc_u64((uint64_t)(int_result.negative ? -int_result.value : int_result.value)));
4008
3416
      break;
4009
    default:
4010
      read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
4011
    }
4012
3357087
    lbm_stack_drop(&ctx->K, 2);
4013
3357087
    ctx->r = res;
4014
3357087
    ctx->app_cont = true;
4015
3357087
    return;
4016
886125
  } else if (n < 0) goto retry_token;
4017
4018
  /*
4019
   * SYMBOL
4020
   */
4021
886125
  n = tok_symbol(chan);
4022
886125
  if (n > 0) {
4023
885946
    lbm_channel_drop(chan, (unsigned int) n);
4024
    lbm_uint symbol_id;
4025
885946
    if (!lbm_get_symbol_by_name(tokpar_sym_str, &symbol_id)) {
4026
100002
      int r = 0;
4027
100002
      if (n > 4 &&
4028
23758
          tokpar_sym_str[0] == 'e' &&
4029
406
          tokpar_sym_str[1] == 'x' &&
4030
42
          tokpar_sym_str[2] == 't' &&
4031
56
          tokpar_sym_str[3] == '-') {
4032
        lbm_uint ext_id;
4033
14
        lbm_uint ext_name_len = (lbm_uint)n + 1;
4034
#ifdef LBM_ALWAYS_GC
4035
        gc();
4036
#endif
4037
14
        char *ext_name = lbm_malloc(ext_name_len);
4038
14
        if (!ext_name) {
4039
          gc();
4040
          ext_name = lbm_malloc(ext_name_len);
4041
        }
4042
14
        if (ext_name) {
4043
14
          memcpy(ext_name, tokpar_sym_str, ext_name_len);
4044
14
          r = lbm_add_extension(ext_name, lbm_extensions_default);
4045
14
          if (!lbm_lookup_extension_id(ext_name, &ext_id)) {
4046
            error_ctx(ENC_SYM_FATAL_ERROR);
4047
          }
4048
14
          symbol_id = ext_id;
4049
        } else {
4050
          error_ctx(ENC_SYM_MERROR);
4051
        }
4052
      } else {
4053
99988
        if (ctx->flags & EVAL_CPS_CONTEXT_FLAG_CONST &&
4054
140
            ctx->flags & EVAL_CPS_CONTEXT_FLAG_INCREMENTAL_READ) {
4055
70
          r = lbm_add_symbol_base(tokpar_sym_str, &symbol_id, true); //flash
4056
70
          if (!r) {
4057
            lbm_set_error_reason((char*)lbm_error_str_flash_error);
4058
            error_ctx(ENC_SYM_FATAL_ERROR);
4059
          }
4060
        } else {
4061
#ifdef LBM_ALWAYS_GC
4062
          gc();
4063
#endif
4064
99918
          r = lbm_add_symbol_base(tokpar_sym_str, &symbol_id,false); //ram
4065
99918
          if (!r) {
4066
            gc();
4067
            r = lbm_add_symbol_base(tokpar_sym_str, &symbol_id,false); //ram
4068
          }
4069
        }
4070
      }
4071
100002
      if (!r) {
4072
        read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
4073
      }
4074
    }
4075
885946
    lbm_stack_drop(&ctx->K, 2);
4076
885946
    ctx->r = lbm_enc_sym(symbol_id);
4077
885946
    ctx->app_cont = true;
4078
885946
    return;
4079
179
  } else if (n == TOKENIZER_NEED_MORE) {
4080
11
    goto retry_token;
4081
168
  } else if (n <= TOKENIZER_STRING_ERROR) {
4082
    read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
4083
  }
4084
4085
  /*
4086
   * CHAR
4087
   */
4088
  char c_val;
4089
168
  n = tok_char(chan, &c_val);
4090
168
  if(n > 0) {
4091
168
    lbm_channel_drop(chan,(unsigned int) n);
4092
168
    lbm_stack_drop(&ctx->K, 2);
4093
168
    ctx->r = lbm_enc_char((uint8_t)c_val);
4094
168
    ctx->app_cont = true;
4095
168
    return;
4096
  }else if (n < 0) goto retry_token;
4097
4098
  read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
4099
4100
12
 retry_token:
4101
12
  if (n == TOKENIZER_NEED_MORE) {
4102
12
    sptr[0] = stream;
4103
12
    sptr[1] = lbm_enc_u(0);
4104
12
    stack_reserve(ctx,1)[0] = READ_NEXT_TOKEN;
4105
12
    yield_ctx(EVAL_CPS_MIN_SLEEP);
4106
12
    return;
4107
  }
4108
  read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
4109
}
4110
4111
3304
static void cont_read_start_array(eval_context_t *ctx) {
4112
3304
  lbm_value *sptr = get_stack_ptr(ctx, 1);
4113
3304
  lbm_value stream = sptr[0];
4114
4115
3304
  lbm_char_channel_t *str = lbm_dec_channel(stream);
4116

3304
  if (str == NULL || str->state == NULL) {
4117
    error_ctx(ENC_SYM_FATAL_ERROR);
4118
  }
4119
3304
  if (ctx->r == ENC_SYM_CLOSEBRACK) {
4120
    lbm_value array;
4121
4122
56
    if (!lbm_heap_allocate_array(&array, 0)) {
4123
      gc();
4124
      if (!lbm_heap_allocate_array(&array, 0)) {
4125
        lbm_set_error_reason((char*)lbm_error_str_read_no_mem);
4126
        lbm_channel_reader_close(str);
4127
        error_ctx(ENC_SYM_FATAL_ERROR); // Terminates ctx
4128
      }
4129
    }
4130
56
    lbm_stack_drop(&ctx->K, 1);
4131
56
    ctx->r = array;
4132
56
    ctx->app_cont = true;
4133
3248
  } else if (lbm_is_number(ctx->r)) {
4134
#ifdef LBM_ALWAYS_GC
4135
    gc();
4136
#endif
4137
3248
    lbm_uint num_free = lbm_memory_longest_free();
4138
3248
    lbm_uint initial_size = (lbm_uint)((float)num_free * 0.9);
4139
3248
    if (initial_size == 0) {
4140
      gc();
4141
      num_free = lbm_memory_longest_free();
4142
      initial_size = (lbm_uint)((float)num_free * 0.9);
4143
      if (initial_size == 0) {
4144
        lbm_channel_reader_close(str);
4145
        error_ctx(ENC_SYM_MERROR);
4146
      }
4147
    }
4148
    lbm_value array;
4149
3248
    initial_size = sizeof(lbm_uint) * initial_size;
4150
4151
    // Keep in mind that this allocation can fail for both
4152
    // lbm_memory and heap reasons.
4153
3248
    if (!lbm_heap_allocate_array(&array, initial_size)) {
4154
      gc();
4155
      if (!lbm_heap_allocate_array(&array, initial_size)) {
4156
        lbm_set_error_reason((char*)lbm_error_str_read_no_mem);
4157
        lbm_channel_reader_close(str);
4158
        error_ctx(ENC_SYM_FATAL_ERROR);
4159
        // NOTE: If array is not created evaluation ends here.
4160
        // Static analysis seems unaware.
4161
      }
4162
    }
4163
4164
3248
    sptr[0] = array;
4165
3248
    lbm_value *rptr = stack_reserve(ctx, 4);
4166
3248
    rptr[0] = lbm_enc_u(initial_size);
4167
3248
    rptr[1] = lbm_enc_u(0);
4168
3248
    rptr[2] = stream;
4169
3248
    rptr[3] = READ_APPEND_ARRAY;
4170
3248
    ctx->app_cont = true;
4171
  } else {
4172
    lbm_channel_reader_close(str);
4173
    read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
4174
  }
4175
3304
}
4176
4177
371000
static void cont_read_append_array(eval_context_t *ctx) {
4178
371000
  lbm_uint *sptr = get_stack_ptr(ctx, 4);
4179
4180
371000
  lbm_value array  = sptr[0];
4181
371000
  lbm_value size   = lbm_dec_as_u32(sptr[1]);
4182
371000
  lbm_value ix     = lbm_dec_as_u32(sptr[2]);
4183
371000
  lbm_value stream = sptr[3];
4184
4185
371000
  if (ix >= (size - 1)) {
4186
    error_ctx(ENC_SYM_MERROR);
4187
  }
4188
4189
  // if sptr[0] is not an array something is very very wrong.
4190
  // Not robust against a garbage on stack. But how would garbage get onto stack?
4191
371000
  lbm_array_header_t *arr = assume_array(array);
4192
371000
  if (lbm_is_number(ctx->r)) {
4193
367752
    ((uint8_t*)arr->data)[ix] = (uint8_t)lbm_dec_as_u32(ctx->r);
4194
4195
367752
    sptr[2] = lbm_enc_u(ix + 1);
4196
367752
    lbm_value *rptr = stack_reserve(ctx, 4);
4197
367752
    rptr[0] = READ_APPEND_ARRAY;
4198
367752
    rptr[1] = stream;
4199
367752
    rptr[2] = lbm_enc_u(0);
4200
367752
    rptr[3] = READ_NEXT_TOKEN;
4201
367752
    ctx->app_cont = true;
4202

3248
  } else if (lbm_is_symbol(ctx->r) && ctx->r == ENC_SYM_CLOSEBRACK) {
4203
3248
    lbm_uint array_size = ix / sizeof(lbm_uint);
4204
4205
3248
    if (ix % sizeof(lbm_uint) != 0) {
4206
2436
      array_size = array_size + 1;
4207
    }
4208
3248
    lbm_memory_shrink((lbm_uint*)arr->data, array_size);
4209
3248
    arr->size = ix;
4210
3248
    lbm_stack_drop(&ctx->K, 4);
4211
3248
    ctx->r = array;
4212
3248
    ctx->app_cont = true;
4213
  } else {
4214
    error_ctx(ENC_SYM_TERROR);
4215
  }
4216
371000
}
4217
4218
4890126
static void cont_read_append_continue(eval_context_t *ctx) {
4219
4890126
  lbm_value *sptr = get_stack_ptr(ctx, 3);
4220
4221
4890126
  lbm_value first_cell = sptr[0];
4222
4890126
  lbm_value last_cell  = sptr[1];
4223
4890126
  lbm_value stream     = sptr[2];
4224
4225
4890126
  lbm_char_channel_t *str = lbm_dec_channel(stream);
4226

4890126
  if (str == NULL || str->state == NULL) {
4227
    error_ctx(ENC_SYM_FATAL_ERROR);
4228
  }
4229
4230
4890126
  if (lbm_type_of(ctx->r) == LBM_TYPE_SYMBOL) {
4231
4232
1532619
    switch(ctx->r) {
4233
675457
    case ENC_SYM_CLOSEPAR:
4234
675457
      if (lbm_type_of(last_cell) == LBM_TYPE_CONS) {
4235
672797
        lbm_set_cdr(last_cell, ENC_SYM_NIL); // terminate the list
4236
672797
        ctx->r = first_cell;
4237
      } else {
4238
2660
        ctx->r = ENC_SYM_NIL;
4239
      }
4240
675457
      lbm_stack_drop(&ctx->K, 3);
4241
      /* Skip reading another token and apply the continuation */
4242
675457
      ctx->app_cont = true;
4243
675457
      return;
4244
6216
    case ENC_SYM_DOT: {
4245
6216
      lbm_value *rptr = stack_reserve(ctx, 4);
4246
6216
      rptr[0] = READ_DOT_TERMINATE;
4247
6216
      rptr[1] = stream;
4248
6216
      rptr[2] = lbm_enc_u(0);
4249
6216
      rptr[3] = READ_NEXT_TOKEN;
4250
6216
      ctx->app_cont = true;
4251
6216
    } return;
4252
    }
4253
  }
4254
4208453
  lbm_value new_cell = cons_with_gc(ctx->r, ENC_SYM_NIL, ENC_SYM_NIL);
4255
4208453
  if (lbm_is_symbol_merror(new_cell)) {
4256
    lbm_channel_reader_close(str);
4257
    read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
4258
    return;
4259
  }
4260
4208453
  if (lbm_type_of(last_cell) == LBM_TYPE_CONS) {
4261
3529440
    lbm_set_cdr(last_cell, new_cell);
4262
3529440
    last_cell = new_cell;
4263
  } else {
4264
679013
    first_cell = last_cell = new_cell;
4265
  }
4266
4208453
  sptr[0] = first_cell;
4267
4208453
  sptr[1] = last_cell;
4268
4208453
  sptr[2] = stream;    // unchanged.
4269
4208453
  lbm_value *rptr = stack_reserve(ctx, 4);
4270
4208453
  rptr[0] = READ_APPEND_CONTINUE;
4271
4208453
  rptr[1] = stream;
4272
4208453
  rptr[2] = lbm_enc_u(0);
4273
4208453
  rptr[3] = READ_NEXT_TOKEN;
4274
4208453
  ctx->app_cont = true;
4275
}
4276
4277
70139
static void cont_read_eval_continue(eval_context_t *ctx) {
4278
  lbm_value env;
4279
  lbm_value stream;
4280
70139
  lbm_pop_2(&ctx->K, &env, &stream);
4281
4282
70139
  lbm_char_channel_t *str = lbm_dec_channel(stream);
4283

70139
  if (str && str->state) {
4284
70139
    ctx->row1 = (lbm_int)str->row(str);
4285
70139
    if (lbm_type_of(ctx->r) == LBM_TYPE_SYMBOL) {
4286
5600
      switch(ctx->r) {
4287
      case ENC_SYM_CLOSEPAR:
4288
        ctx->app_cont = true;
4289
        return;
4290
      case ENC_SYM_DOT:
4291
        // A dot here is a syntax error.
4292
        lbm_set_error_reason((char*)lbm_error_str_parse_dot);
4293
        read_error_ctx(lbm_channel_row(str),lbm_channel_column(str));
4294
        return;
4295
      }
4296
    }
4297
70139
    lbm_value *rptr = stack_reserve(ctx, 8);
4298
70139
    rptr[0] = stream;
4299
70139
    rptr[1] = env;
4300
70139
    rptr[2] = READ_EVAL_CONTINUE;
4301
70139
    rptr[3] = stream;
4302
70139
    rptr[4] = lbm_enc_u(1);
4303
70139
    rptr[5] = READ_NEXT_TOKEN;
4304
70139
    rptr[6] = lbm_enc_u(ctx->flags);
4305
70139
    rptr[7] = POP_READER_FLAGS;
4306
4307
70139
    ctx->curr_env = env;
4308
70139
    ctx->curr_exp = ctx->r;
4309
  } else {
4310
    error_ctx(ENC_SYM_FATAL_ERROR);
4311
  }
4312
}
4313
4314
6216
static void cont_read_expect_closepar(eval_context_t *ctx) {
4315
  lbm_value res;
4316
  lbm_value stream;
4317
4318
6216
  lbm_pop_2(&ctx->K, &res, &stream);
4319
4320
6216
  lbm_char_channel_t *str = lbm_dec_channel(stream);
4321

6216
  if (str == NULL || str->state == NULL) {
4322
    error_ctx(ENC_SYM_FATAL_ERROR);
4323
  }
4324
4325
6216
  if (lbm_type_of(ctx->r) == LBM_TYPE_SYMBOL &&
4326
6216
      ctx->r == ENC_SYM_CLOSEPAR) {
4327
6216
    ctx->r = res;
4328
6216
    ctx->app_cont = true;
4329
  } else {
4330
    lbm_channel_reader_close(str);
4331
    lbm_set_error_reason((char*)lbm_error_str_parse_close);
4332
    read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
4333
  }
4334
6216
}
4335
4336
6216
static void cont_read_dot_terminate(eval_context_t *ctx) {
4337
6216
  lbm_value *sptr = get_stack_ptr(ctx, 3);
4338
4339
6216
  lbm_value last_cell  = sptr[1];
4340
6216
  lbm_value stream = sptr[2];
4341
4342
6216
  lbm_char_channel_t *str = lbm_dec_channel(stream);
4343

6216
  if (str == NULL || str->state == NULL) {
4344
    error_ctx(ENC_SYM_FATAL_ERROR);
4345
  }
4346
4347
6216
  lbm_stack_drop(&ctx->K ,3);
4348
4349
6216
  if (lbm_type_of(ctx->r) == LBM_TYPE_SYMBOL &&
4350
1736
      (ctx->r == ENC_SYM_CLOSEPAR ||
4351
1736
       ctx->r == ENC_SYM_DOT)) {
4352
    lbm_channel_reader_close(str);
4353
    lbm_set_error_reason((char*)lbm_error_str_parse_dot);
4354
    read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
4355
  } else {
4356
6216
    if (lbm_is_cons(last_cell)) {
4357
6216
      lbm_set_cdr(last_cell, ctx->r);
4358
6216
      ctx->r = sptr[0]; // first cell
4359
6216
      lbm_value *rptr = stack_reserve(ctx, 6);
4360
6216
      rptr[0] = stream;
4361
6216
      rptr[1] = ctx->r;
4362
6216
      rptr[2] = READ_EXPECT_CLOSEPAR;
4363
6216
      rptr[3] = stream;
4364
6216
      rptr[4] = lbm_enc_u(0);
4365
6216
      rptr[5] = READ_NEXT_TOKEN;
4366
6216
      ctx->app_cont = true;
4367
    } else {
4368
      lbm_channel_reader_close(str);
4369
      lbm_set_error_reason((char*)lbm_error_str_parse_dot);
4370
      read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
4371
    }
4372
  }
4373
6216
}
4374
4375
330502
static void cont_read_done(eval_context_t *ctx) {
4376
  lbm_value stream;
4377
  lbm_value f_val;
4378
  lbm_value reader_mode;
4379
330502
  lbm_pop_3(&ctx->K, &reader_mode, &stream, &f_val);
4380
4381
330502
  uint32_t flags = lbm_dec_as_u32(f_val);
4382
330502
  ctx->flags &= ~EVAL_CPS_CONTEXT_READER_FLAGS_MASK;
4383
330502
  ctx->flags |= (flags & EVAL_CPS_CONTEXT_READER_FLAGS_MASK);
4384
4385
330502
  lbm_char_channel_t *str = lbm_dec_channel(stream);
4386

330502
  if (str == NULL || str->state == NULL) {
4387
    error_ctx(ENC_SYM_FATAL_ERROR);
4388
  }
4389
4390
330502
  lbm_channel_reader_close(str);
4391
330502
  if (lbm_is_symbol(ctx->r)) {
4392
22460
    lbm_uint sym_val = lbm_dec_sym(ctx->r);
4393

22460
    if (sym_val >= TOKENIZER_SYMBOLS_START &&
4394
        sym_val <= TOKENIZER_SYMBOLS_END) {
4395
      read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
4396
    }
4397
  }
4398
330502
  ctx->row0 = -1;
4399
330502
  ctx->row1 = -1;
4400
330502
  ctx->app_cont = true;
4401
330502
}
4402
4403
41524
static void cont_wrap_result(eval_context_t *ctx) {
4404
  lbm_value cell;
4405
  lbm_value wrapper;
4406
41524
  lbm_pop(&ctx->K, &wrapper);
4407

41524
  WITH_GC(cell, lbm_heap_allocate_list_init(2,
4408
                                            wrapper,
4409
                                            ctx->r));
4410
41524
  ctx->r = cell;
4411
41524
  ctx->app_cont = true;
4412
41524
}
4413
4414
105086426
static void cont_application_start(eval_context_t *ctx) {
4415
4416
  /* sptr[0] = env
4417
   * sptr[1] = args
4418
   * ctx->r  = function
4419
   */
4420
4421
105086426
  if (lbm_is_symbol(ctx->r)) {
4422
77990995
    stack_reserve(ctx,1)[0] = lbm_enc_u(0);
4423
77990995
    cont_application_args(ctx);
4424
27095431
  } else if (lbm_is_cons(ctx->r)) {
4425
27095431
    lbm_uint *sptr = get_stack_ptr(ctx, 2);
4426
27095431
    lbm_value args = (lbm_value)sptr[1];
4427

27095431
    switch (get_car(ctx->r)) {
4428
27089047
    case ENC_SYM_CLOSURE: {
4429
      lbm_value cl[3];
4430
27089047
      extract_n(get_cdr(ctx->r), cl, 3);
4431
27089047
      lbm_value arg_env = (lbm_value)sptr[0];
4432
      lbm_value arg0, arg_rest;
4433
27089047
      get_car_and_cdr(args, &arg0, &arg_rest);
4434
27089047
      sptr[1] = cl[CLO_BODY];
4435
27089047
      bool a_nil = lbm_is_symbol_nil(args);
4436
27089047
      bool p_nil = lbm_is_symbol_nil(cl[CLO_PARAMS]);
4437
27089047
      lbm_value *reserved = stack_reserve(ctx, 4);
4438
4439

27089047
      if (!a_nil && !p_nil) {
4440
26211359
        reserved[0] = cl[CLO_ENV];
4441
26211359
        reserved[1] = cl[CLO_PARAMS];
4442
26211359
        reserved[2] = arg_rest;
4443
26211359
        reserved[3] = CLOSURE_ARGS;
4444
26211359
        ctx->curr_exp = arg0;
4445
26211359
        ctx->curr_env = arg_env;
4446

877688
      } else if (a_nil && p_nil) {
4447
        // No params, No args
4448
317660
        lbm_stack_drop(&ctx->K, 6);
4449
317660
        ctx->curr_exp = cl[CLO_BODY];
4450
317660
        ctx->curr_env = cl[CLO_ENV];
4451
560028
      } else if (p_nil) {
4452
560028
        reserved[1] = get_cdr(args);      // protect cdr(args) from allocate_binding
4453
560028
        ctx->curr_exp = get_car(args);    // protect car(args) from allocate binding
4454
560028
        ctx->curr_env = arg_env;
4455
560028
        lbm_value rest_binder = allocate_binding(ENC_SYM_REST_ARGS, ENC_SYM_NIL, cl[CLO_ENV]);
4456
560028
        reserved[0] = rest_binder;
4457
560028
        reserved[2] = get_car(rest_binder);
4458
560028
        reserved[3] = CLOSURE_ARGS_REST;
4459
      } else {
4460
        lbm_set_error_reason((char*)lbm_error_str_num_args);
4461
        error_at_ctx(ENC_SYM_EERROR, ctx->r);
4462
      }
4463
27089047
    } break;
4464
196
    case ENC_SYM_CONT:{
4465
      /* Continuation created using call-cc.
4466
       * ((SYM_CONT . cont-array) arg0 )
4467
       */
4468
196
      lbm_value c = get_cdr(ctx->r); /* should be the continuation array*/
4469
4470
196
      if (!lbm_is_lisp_array_r(c)) {
4471
        error_ctx(ENC_SYM_FATAL_ERROR);
4472
      }
4473
4474
196
      lbm_uint arg_count = lbm_list_length(args);
4475
196
      lbm_value arg = ENC_SYM_NIL;
4476
      switch (arg_count) {
4477
56
      case 0:
4478
56
        arg = ENC_SYM_NIL;
4479
56
        break;
4480
140
      case 1:
4481
140
        arg = get_car(args);
4482
140
        break;
4483
      default:
4484
        lbm_set_error_reason((char*)lbm_error_str_num_args);
4485
        error_ctx(ENC_SYM_EERROR);
4486
      }
4487
196
      lbm_stack_clear(&ctx->K);
4488
4489
196
      lbm_array_header_t *arr = assume_array(c);
4490
196
      ctx->K.sp = arr->size / sizeof(lbm_uint);
4491
196
      memcpy(ctx->K.data, arr->data, arr->size);
4492
4493
      lbm_value atomic;
4494
196
      lbm_pop(&ctx->K, &atomic);
4495
196
      is_atomic = atomic ? 1 : 0;
4496
4497
196
      ctx->curr_exp = arg;
4498
196
      break;
4499
    }
4500
6188
    case ENC_SYM_MACRO:{
4501
      /*
4502
       * Perform macro expansion.
4503
       * Macro expansion is really just evaluation in an
4504
       * environment augmented with the unevaluated expressions passed
4505
       * as arguments.
4506
       */
4507
6188
      lbm_value env = (lbm_value)sptr[0];
4508
4509
6188
      lbm_value curr_param = get_cadr(ctx->r);
4510
6188
      lbm_value curr_arg = args;
4511
6188
      lbm_value expand_env = env;
4512

43484
      while (lbm_is_cons(curr_param) &&
4513
18648
             lbm_is_cons(curr_arg)) {
4514
18648
        lbm_cons_t *param_cell = lbm_ref_cell(curr_param); // already checked that cons.
4515
18648
        lbm_cons_t *arg_cell = lbm_ref_cell(curr_arg);
4516
18648
        lbm_value car_curr_param = param_cell->car;
4517
18648
        lbm_value cdr_curr_param = param_cell->cdr;
4518
18648
        lbm_value car_curr_arg = arg_cell->car;
4519
18648
        lbm_value cdr_curr_arg = arg_cell->cdr;
4520
4521
18648
        lbm_value entry = cons_with_gc(car_curr_param, car_curr_arg, expand_env);
4522
18648
        lbm_value aug_env = cons_with_gc(entry, expand_env,ENC_SYM_NIL);
4523
18648
        expand_env = aug_env;
4524
4525
18648
        curr_param = cdr_curr_param;
4526
18648
        curr_arg   = cdr_curr_arg;
4527
      }
4528
      /* Two rounds of evaluation is performed.
4529
       * First to instantiate the arguments into the macro body.
4530
       * Second to evaluate the resulting program.
4531
       */
4532
6188
      sptr[1] = EVAL_R;
4533
6188
      lbm_value exp = get_cadr(get_cdr(ctx->r));
4534
6188
      ctx->curr_exp = exp;
4535
6188
      ctx->curr_env = expand_env;
4536
6188
    } break;
4537
    default:
4538
      error_ctx(ENC_SYM_EERROR);
4539
    }
4540
  } else {
4541
    error_ctx(ENC_SYM_EERROR);
4542
  }
4543
105084858
}
4544
4545
6188
static void cont_eval_r(eval_context_t* ctx) {
4546
  lbm_value env;
4547
6188
  lbm_pop(&ctx->K, &env);
4548
6188
  ctx->curr_exp = ctx->r;
4549
6188
  ctx->curr_env = env;
4550
6188
}
4551
4552
643566
static void cont_progn_var(eval_context_t* ctx) {
4553
4554
  lbm_value key;
4555
  lbm_value env;
4556
4557
643566
  lbm_pop_2(&ctx->K, &key, &env);
4558
4559
643566
  if (fill_binding_location(key, ctx->r, env) < 0) {
4560
    lbm_set_error_reason("Incorrect type of name/key in let-binding");
4561
    error_at_ctx(ENC_SYM_TERROR, key);
4562
  }
4563
4564
643566
  ctx->app_cont = true;
4565
643566
}
4566
4567
1775480
static void cont_setq(eval_context_t *ctx) {
4568
  lbm_value sym;
4569
  lbm_value env;
4570
1775480
  lbm_pop_2(&ctx->K, &sym, &env);
4571
  lbm_value res;
4572

1775480
  WITH_GC(res, perform_setvar(sym, ctx->r, env));
4573
1775424
  ctx->r = res;
4574
1775424
  ctx->app_cont = true;
4575
1775424
}
4576
4577
2408
lbm_flash_status request_flash_storage_cell(lbm_value val, lbm_value *res) {
4578
4579
  lbm_value flash_cell;
4580
2408
  lbm_flash_status s = lbm_allocate_const_cell(&flash_cell);
4581
2408
  if (s != LBM_FLASH_WRITE_OK)
4582
    return s;
4583
2408
  lbm_value new_val = val;
4584
2408
  new_val &= ~LBM_PTR_VAL_MASK; // clear the value part of the ptr
4585
2408
  new_val |= (flash_cell & LBM_PTR_VAL_MASK);
4586
2408
  new_val |= LBM_PTR_TO_CONSTANT_BIT;
4587
2408
  *res = new_val;
4588
2408
  return s;
4589
}
4590
4591
840
static void cont_move_to_flash(eval_context_t *ctx) {
4592
4593
  lbm_value args;
4594
840
  lbm_pop(&ctx->K, &args);
4595
4596
840
  if (lbm_is_symbol_nil(args)) {
4597
    // Done looping over arguments. return true.
4598
364
    ctx->r = ENC_SYM_TRUE;
4599
364
    ctx->app_cont = true;
4600
840
    return;
4601
  }
4602
4603
  lbm_value first_arg, rest;
4604
476
  get_car_and_cdr(args, &first_arg, &rest);
4605
4606
  lbm_value val;
4607

476
  if (lbm_is_symbol(first_arg) && lbm_global_env_lookup(&val, first_arg)) {
4608
    // Prepare to copy the rest of the arguments when done with first.
4609
476
    lbm_value *rptr = stack_reserve(ctx, 2);
4610
476
    rptr[0] = rest;
4611
476
    rptr[1] = MOVE_TO_FLASH;
4612
476
    if (lbm_is_ptr(val) &&
4613
476
        (!(val & LBM_PTR_TO_CONSTANT_BIT))) {
4614
476
      lbm_value * rptr1 = stack_reserve(ctx, 3);
4615
476
      rptr1[0] = first_arg;
4616
476
      rptr1[1] = SET_GLOBAL_ENV;
4617
476
      rptr1[2] = MOVE_VAL_TO_FLASH_DISPATCH;
4618
476
      ctx->r = val;
4619
    }
4620
476
    ctx->app_cont = true;
4621
476
    return;
4622
  }
4623
  error_ctx(ENC_SYM_EERROR);
4624
}
4625
4626
3388
static void cont_move_val_to_flash_dispatch(eval_context_t *ctx) {
4627
4628
3388
  lbm_value val = ctx->r;
4629
4630
3388
  if (lbm_is_cons(val)) {
4631
798
    lbm_value *rptr = stack_reserve(ctx, 5);
4632
798
    rptr[0] = ENC_SYM_NIL; // fst cell of list
4633
798
    rptr[1] = ENC_SYM_NIL; // last cell of list
4634
798
    rptr[2] = get_cdr(val);
4635
798
    rptr[3] = MOVE_LIST_TO_FLASH;
4636
798
    rptr[4] = MOVE_VAL_TO_FLASH_DISPATCH;
4637
798
    ctx->r = get_car(val);
4638
798
    ctx->app_cont = true;
4639
798
    return;
4640
  }
4641
4642

2590
  if (lbm_is_ptr(val) && (val & LBM_PTR_TO_CONSTANT_BIT)) {
4643
    //ctx->r unchanged
4644
    ctx->app_cont = true;
4645
    return;
4646
  }
4647
4648
2590
  if (lbm_is_ptr(val)) {
4649
280
    lbm_cons_t *ref = lbm_ref_cell(val);
4650
280
    if (lbm_type_of(ref->cdr) == LBM_TYPE_SYMBOL) {
4651

280
      switch (ref->cdr) {
4652
140
      case ENC_SYM_RAW_I_TYPE: /* fall through */
4653
      case ENC_SYM_RAW_U_TYPE:
4654
      case ENC_SYM_RAW_F_TYPE: {
4655
140
        lbm_value flash_cell = ENC_SYM_NIL;
4656
140
        handle_flash_status(request_flash_storage_cell(val, &flash_cell));
4657
140
        handle_flash_status(write_const_car(flash_cell, ref->car));
4658
140
        handle_flash_status(write_const_cdr(flash_cell, ref->cdr));
4659
140
        ctx->r = flash_cell;
4660
140
      } break;
4661
56
      case ENC_SYM_IND_I_TYPE: /* fall through */
4662
      case ENC_SYM_IND_U_TYPE:
4663
      case ENC_SYM_IND_F_TYPE: {
4664
#ifndef LBM64
4665
        /* 64 bit values are in lbm mem on 32bit platforms. */
4666
56
        lbm_uint *lbm_mem_ptr = (lbm_uint*)ref->car;
4667
        lbm_uint flash_ptr;
4668
4669
56
        handle_flash_status(lbm_write_const_raw(lbm_mem_ptr, 2, &flash_ptr));
4670
56
        lbm_value flash_cell = ENC_SYM_NIL;
4671
56
        handle_flash_status(request_flash_storage_cell(val, &flash_cell));
4672
56
        handle_flash_status(write_const_car(flash_cell, flash_ptr));
4673
56
        handle_flash_status(write_const_cdr(flash_cell, ref->cdr));
4674
56
        ctx->r = flash_cell;
4675
#else
4676
        // There are no indirect types in LBM64
4677
        error_ctx(ENC_SYM_FATAL_ERROR);
4678
#endif
4679
56
      } break;
4680
28
      case ENC_SYM_LISPARRAY_TYPE: {
4681
28
        lbm_array_header_t *arr = (lbm_array_header_t*)ref->car;
4682
28
        lbm_uint size = arr->size / sizeof(lbm_uint);
4683
28
        lbm_uint flash_addr = 0;
4684
28
        lbm_value *arrdata = (lbm_value *)arr->data;
4685
28
        lbm_value flash_cell = ENC_SYM_NIL;
4686
28
        handle_flash_status(request_flash_storage_cell(val, &flash_cell));
4687
28
        handle_flash_status(lbm_allocate_const_raw(size, &flash_addr));
4688
28
        lift_array_flash(flash_cell,
4689
                         false,
4690
                         (char *)flash_addr,
4691
                         arr->size);
4692
        // Move array contents to flash recursively
4693
28
        lbm_value *rptr = stack_reserve(ctx, 5);
4694
28
        rptr[0] = flash_cell;
4695
28
        rptr[1] = lbm_enc_u(0);
4696
28
        rptr[2] = val;
4697
28
        rptr[3] = MOVE_ARRAY_ELTS_TO_FLASH;
4698
28
        rptr[4] = MOVE_VAL_TO_FLASH_DISPATCH;
4699
28
        ctx->r = arrdata[0];
4700
28
        ctx->app_cont = true;
4701
28
        return;
4702
      }
4703
56
      case ENC_SYM_ARRAY_TYPE: {
4704
56
        lbm_array_header_t *arr = (lbm_array_header_t*)ref->car;
4705
        // arbitrary address: flash_arr.
4706
56
        lbm_uint flash_arr = 0;
4707
56
        handle_flash_status(lbm_write_const_array_padded((uint8_t*)arr->data, arr->size, &flash_arr));
4708
56
        lbm_value flash_cell = ENC_SYM_NIL;
4709
56
        handle_flash_status(request_flash_storage_cell(val, &flash_cell));
4710
56
        lift_array_flash(flash_cell,
4711
                         true,
4712
                         (char *)flash_arr,
4713
                         arr->size);
4714
56
        ctx->r = flash_cell;
4715
56
      } break;
4716
      case ENC_SYM_CHANNEL_TYPE: /* fall through */
4717
      case ENC_SYM_CUSTOM_TYPE:
4718
        lbm_set_error_reason((char *)lbm_error_str_flash_not_possible);
4719
        error_ctx(ENC_SYM_EERROR);
4720
      }
4721
252
    } else {
4722
      error_ctx(ENC_SYM_FATAL_ERROR);
4723
    }
4724
252
    ctx->app_cont = true;
4725
252
    return;
4726
  }
4727
2310
  ctx->r = val;
4728
2310
  ctx->app_cont = true;
4729
}
4730
4731
2016
static void cont_move_list_to_flash(eval_context_t *ctx) {
4732
4733
  // ctx->r holds the value that should go in car
4734
4735
2016
  lbm_value *sptr = get_stack_ptr(ctx, 3);
4736
4737
2016
  lbm_value fst = sptr[0];
4738
2016
  lbm_value lst = sptr[1];
4739
2016
  lbm_value val = sptr[2];
4740
4741
4742
2016
  lbm_value new_lst = ENC_SYM_NIL;
4743
  // Allocate element ptr storage after storing the element to flash.
4744
2016
  handle_flash_status(request_flash_storage_cell(lbm_enc_cons_ptr(LBM_PTR_NULL), &new_lst));
4745
4746
2016
  if (lbm_is_symbol_nil(fst)) {
4747
798
    lst = new_lst;
4748
798
    fst = new_lst;
4749
798
    handle_flash_status(write_const_car(lst, ctx->r));
4750
  } else {
4751
1218
    handle_flash_status(write_const_cdr(lst, new_lst)); // low before high
4752
1218
    handle_flash_status(write_const_car(new_lst, ctx->r));
4753
1218
    lst = new_lst;
4754
  }
4755
4756
2016
  if (lbm_is_cons(val)) {
4757
1218
    sptr[0] = fst;
4758
1218
    sptr[1] = lst;//rest_cell;
4759
1218
    sptr[2] = get_cdr(val);
4760
1218
    lbm_value *rptr = stack_reserve(ctx, 2);
4761
1218
    rptr[0] = MOVE_LIST_TO_FLASH;
4762
1218
    rptr[1] = MOVE_VAL_TO_FLASH_DISPATCH;
4763
1218
    ctx->r = get_car(val);
4764
  } else {
4765
798
    sptr[0] = fst;
4766
798
    sptr[1] = lst;
4767
798
    sptr[2] = CLOSE_LIST_IN_FLASH;
4768
798
    stack_reserve(ctx, 1)[0] = MOVE_VAL_TO_FLASH_DISPATCH;
4769
798
    ctx->r =  val;
4770
  }
4771
2016
  ctx->app_cont = true;
4772
2016
}
4773
4774
798
static void cont_close_list_in_flash(eval_context_t *ctx) {
4775
  lbm_value fst;
4776
  lbm_value lst;
4777
798
  lbm_pop_2(&ctx->K, &lst, &fst);
4778
798
  lbm_value val = ctx->r;
4779
798
  handle_flash_status(write_const_cdr(lst, val));
4780
798
  ctx->r = fst;
4781
798
  ctx->app_cont = true;
4782
798
}
4783
4784
84
static void cont_move_array_elts_to_flash(eval_context_t *ctx) {
4785
84
  lbm_value *sptr = get_stack_ptr(ctx, 3);
4786
  // sptr[2] = source array in RAM
4787
  // sptr[1] = current index
4788
  // sptr[0] = target array in flash
4789
84
  lbm_array_header_t *src_arr = assume_array(sptr[2]);
4790
84
  lbm_uint size = src_arr->size / sizeof(lbm_uint);
4791
84
  lbm_value *srcdata = (lbm_value *)src_arr->data;
4792
4793
84
  lbm_array_header_t *tgt_arr = assume_array(sptr[0]);
4794
84
  lbm_uint *tgtdata = (lbm_value *)tgt_arr->data;
4795
84
  lbm_uint ix = lbm_dec_as_u32(sptr[1]);
4796
84
  handle_flash_status(lbm_const_write(&tgtdata[ix], ctx->r));
4797
84
  if (ix >= size-1) {
4798
28
    ctx->r = sptr[0];
4799
28
    lbm_stack_drop(&ctx->K, 3);
4800
28
    ctx->app_cont = true;
4801
28
    return;
4802
  }
4803
56
  sptr[1] = lbm_enc_u(ix + 1);
4804
56
  lbm_value *rptr = stack_reserve(ctx, 2);
4805
56
  rptr[0] = MOVE_ARRAY_ELTS_TO_FLASH;
4806
56
  rptr[1] = MOVE_VAL_TO_FLASH_DISPATCH;
4807
56
  ctx->r = srcdata[ix+1];
4808
56
  ctx->app_cont = true;
4809
56
  return;
4810
}
4811
4812
5040
static void cont_qq_expand_start(eval_context_t *ctx) {
4813
5040
  lbm_value *rptr = stack_reserve(ctx, 2);
4814
5040
  rptr[0] = ctx->r;
4815
5040
  rptr[1] = QQ_EXPAND;
4816
5040
  ctx->r = ENC_SYM_NIL;
4817
5040
  ctx->app_cont = true;
4818
5040
}
4819
4820
10220
lbm_value quote_it(lbm_value qquoted) {
4821

19992
  if (lbm_is_symbol(qquoted) &&
4822
19544
      lbm_is_special(qquoted)) return qquoted;
4823
4824
448
  lbm_value val = cons_with_gc(qquoted, ENC_SYM_NIL, ENC_SYM_NIL);
4825
448
  return cons_with_gc(ENC_SYM_QUOTE, val, ENC_SYM_NIL);
4826
}
4827
4828
37856
bool is_append(lbm_value a) {
4829
75656
  return (lbm_is_cons(a) &&
4830

75656
          lbm_is_symbol(get_car(a)) &&
4831
37800
          (get_car(a) == ENC_SYM_APPEND));
4832
}
4833
4834
63672
lbm_value append(lbm_value front, lbm_value back) {
4835
63672
  if (lbm_is_symbol_nil(front)) return back;
4836
29344
  if (lbm_is_symbol_nil(back)) return front;
4837
4838

29960
  if (lbm_is_quoted_list(front) &&
4839
10388
      lbm_is_quoted_list(back)) {
4840
448
    lbm_value f = get_cadr(front);
4841
448
    lbm_value b = get_cadr(back);
4842
448
    return quote_it(lbm_list_append(f, b));
4843
  }
4844
4845

28672
  if (is_append(back) &&
4846
9940
      lbm_is_quoted_list(get_cadr(back)) &&
4847
392
       lbm_is_quoted_list(front)) {
4848
392
    lbm_value ql = get_cadr(back);
4849
392
    lbm_value f = get_cadr(front);
4850
392
    lbm_value b = get_cadr(ql);
4851
4852
392
    lbm_value v = lbm_list_append(f, b);
4853
392
    lbm_set_car(get_cdr(ql), v);
4854
392
    return back;
4855
  }
4856
4857
18732
  if (is_append(back)) {
4858
9156
    back  = get_cdr(back);
4859
9156
    lbm_value new = cons_with_gc(front, back, ENC_SYM_NIL);
4860
9156
    return cons_with_gc(ENC_SYM_APPEND, new, ENC_SYM_NIL);
4861
  }
4862
4863
  lbm_value t0, t1;
4864
4865
9576
  t0 = cons_with_gc(back, ENC_SYM_NIL, front);
4866
9576
  t1 = cons_with_gc(front, t0, ENC_SYM_NIL);
4867
9576
  return cons_with_gc(ENC_SYM_APPEND, t1, ENC_SYM_NIL);
4868
}
4869
4870
/* Bawden's qq-expand implementation
4871
(define (qq-expand x)
4872
  (cond ((tag-comma? x)
4873
         (tag-data x))
4874
        ((tag-comma-atsign? x)
4875
         (error "Illegal"))
4876
        ((tag-backquote? x)
4877
         (qq-expand
4878
          (qq-expand (tag-data x))))
4879
        ((pair? x)
4880
         `(append
4881
           ,(qq-expand-list (car x))
4882
           ,(qq-expand (cdr x))))
4883
        (else `',x)))
4884
 */
4885
34384
static void cont_qq_expand(eval_context_t *ctx) {
4886
  lbm_value qquoted;
4887
34384
  lbm_pop(&ctx->K, &qquoted);
4888
4889
34384
  switch(lbm_type_of(qquoted)) {
4890
24612
  case LBM_TYPE_CONS: {
4891
24612
    lbm_value car_val = get_car(qquoted);
4892
24612
    lbm_value cdr_val = get_cdr(qquoted);
4893

24612
    if (lbm_type_of(car_val) == LBM_TYPE_SYMBOL &&
4894
        car_val == ENC_SYM_COMMA) {
4895
28
      ctx->r = append(ctx->r, get_car(cdr_val));
4896
28
      ctx->app_cont = true;
4897

24584
    } else if (lbm_type_of(car_val) == LBM_TYPE_SYMBOL &&
4898
               car_val == ENC_SYM_COMMAAT) {
4899
      error_ctx(ENC_SYM_RERROR);
4900
    } else {
4901
24584
      lbm_value *rptr = stack_reserve(ctx, 6);
4902
24584
      rptr[0] = ctx->r;
4903
24584
      rptr[1] = QQ_APPEND;
4904
24584
      rptr[2] = cdr_val;
4905
24584
      rptr[3] = QQ_EXPAND;
4906
24584
      rptr[4] = car_val;
4907
24584
      rptr[5] = QQ_EXPAND_LIST;
4908
24584
      ctx->app_cont = true;
4909
24584
      ctx->r = ENC_SYM_NIL;
4910
    }
4911
4912
24612
  } break;
4913
9772
  default: {
4914
9772
    lbm_value res = quote_it(qquoted);
4915
9772
    ctx->r = append(ctx->r, res);
4916
9772
    ctx->app_cont = true;
4917
  }
4918
  }
4919
34384
}
4920
4921
29344
static void cont_qq_append(eval_context_t *ctx) {
4922
  lbm_value head;
4923
29344
  lbm_pop(&ctx->K, &head);
4924
29344
  ctx->r = append(head, ctx->r);
4925
29344
  ctx->app_cont = true;
4926
29344
}
4927
4928
/* Bawden's qq-expand-list implementation
4929
(define (qq-expand-list x)
4930
  (cond ((tag-comma? x)
4931
         `(list ,(tag-data x)))
4932
        ((tag-comma-atsign? x)
4933
         (tag-data x))
4934
        ((tag-backquote? x)
4935
         (qq-expand-list
4936
          (qq-expand (tag-data x))))
4937
        ((pair? x)
4938
         `(list
4939
           (append
4940
            ,(qq-expand-list (car x))
4941
            ,(qq-expand (cdr x)))))
4942
        (else `'(,x))))
4943
*/
4944
4945
29344
static void cont_qq_expand_list(eval_context_t* ctx) {
4946
  lbm_value l;
4947
29344
  lbm_pop(&ctx->K, &l);
4948
4949
29344
  ctx->app_cont = true;
4950
29344
  switch(lbm_type_of(l)) {
4951
18732
  case LBM_TYPE_CONS: {
4952
18732
    lbm_value car_val = get_car(l);
4953
18732
    lbm_value cdr_val = get_cdr(l);
4954

18732
    if (lbm_type_of(car_val) == LBM_TYPE_SYMBOL &&
4955
        car_val == ENC_SYM_COMMA) {
4956
13916
      lbm_value tl = cons_with_gc(get_car(cdr_val), ENC_SYM_NIL, ENC_SYM_NIL);
4957
13916
      lbm_value tmp = cons_with_gc(ENC_SYM_LIST, tl, ENC_SYM_NIL);
4958
13916
      ctx->r = append(ctx->r, tmp);
4959
13972
      return;
4960

4816
    } else if (lbm_type_of(car_val) == LBM_TYPE_SYMBOL &&
4961
               car_val == ENC_SYM_COMMAAT) {
4962
56
      ctx->r = get_car(cdr_val);
4963
56
      return;
4964
    } else {
4965
4760
      lbm_value *rptr = stack_reserve(ctx, 7);
4966
4760
      rptr[0] = QQ_LIST;
4967
4760
      rptr[1] = ctx->r;
4968
4760
      rptr[2] = QQ_APPEND;
4969
4760
      rptr[3] = cdr_val;
4970
4760
      rptr[4] = QQ_EXPAND;
4971
4760
      rptr[5] = car_val;
4972
4760
      rptr[6] = QQ_EXPAND_LIST;
4973
4760
      ctx->r = ENC_SYM_NIL;
4974
    }
4975
4976
4760
  } break;
4977
10612
  default: {
4978
10612
    lbm_value a_list = cons_with_gc(l, ENC_SYM_NIL, ENC_SYM_NIL);
4979
10612
    lbm_value tl = cons_with_gc(a_list, ENC_SYM_NIL, ENC_SYM_NIL);
4980
10612
    lbm_value tmp = cons_with_gc(ENC_SYM_QUOTE, tl, ENC_SYM_NIL);
4981
10612
    ctx->r = append(ctx->r, tmp);
4982
  }
4983
  }
4984
}
4985
4986
4760
static void cont_qq_list(eval_context_t *ctx) {
4987
4760
  lbm_value val = ctx->r;
4988
4760
  lbm_value apnd_app = cons_with_gc(val, ENC_SYM_NIL, ENC_SYM_NIL);
4989
4760
  lbm_value tmp = cons_with_gc(ENC_SYM_LIST, apnd_app, ENC_SYM_NIL);
4990
4760
  ctx->r = tmp;
4991
4760
  ctx->app_cont = true;
4992
4760
}
4993
4994
83
static void cont_kill(eval_context_t *ctx) {
4995
  (void) ctx;
4996
83
  ok_ctx();
4997
83
}
4998
4999
70134
static void cont_pop_reader_flags(eval_context_t *ctx) {
5000
  lbm_value flags;
5001
70134
  lbm_pop(&ctx->K, &flags);
5002
70134
  ctx->flags = ctx->flags & ~EVAL_CPS_CONTEXT_READER_FLAGS_MASK;
5003
70134
  ctx->flags |= (lbm_dec_as_u32(flags) & EVAL_CPS_CONTEXT_READER_FLAGS_MASK);
5004
  // r is unchanged.
5005
70134
  ctx->app_cont = true;
5006
70134
}
5007
5008
8288
static void cont_exception_handler(eval_context_t *ctx) {
5009
8288
  lbm_value *sptr = pop_stack_ptr(ctx, 2);
5010
8288
  lbm_value retval = sptr[0];
5011
8288
  lbm_value flags = sptr[1];
5012
8288
  lbm_set_car(get_cdr(retval), ctx->r);
5013
8288
  ctx->flags = (uint32_t)flags;
5014
8288
  ctx->r = retval;
5015
8288
  ctx->app_cont = true;
5016
8288
}
5017
5018
// cont_recv_to:
5019
//
5020
// s[sp-1] = patterns
5021
//
5022
// ctx->r = timeout value
5023
196
static void cont_recv_to(eval_context_t *ctx) {
5024
196
  if (lbm_is_number(ctx->r)) {
5025
196
    lbm_value *sptr = get_stack_ptr(ctx, 1); // patterns at sptr[0]
5026
196
    float timeout_time = lbm_dec_as_float(ctx->r);
5027
196
    if (timeout_time < 0.0) timeout_time = 0.0; // clamp.
5028
196
    if (ctx->num_mail > 0) {
5029
      lbm_value e;
5030
56
      lbm_value new_env = ctx->curr_env;
5031
#ifdef LBM_ALWAYS_GC
5032
      gc();
5033
#endif
5034
56
      int n = find_match(sptr[0], ctx->mailbox, ctx->num_mail, &e, &new_env);
5035
56
      if (n == FM_NEED_GC) {
5036
        gc();
5037
        new_env = ctx->curr_env;
5038
        n = find_match(sptr[0], ctx->mailbox, ctx->num_mail, &e, &new_env);
5039
        if (n == FM_NEED_GC) error_ctx(ENC_SYM_MERROR);
5040
      }
5041
56
      if (n == FM_PATTERN_ERROR) {
5042
        lbm_set_error_reason("Incorrect pattern format for recv");
5043
        error_at_ctx(ENC_SYM_EERROR, sptr[0]);
5044
56
      } else if (n >= 0) { // match
5045
56
        mailbox_remove_mail(ctx, (lbm_uint)n);
5046
56
        ctx->curr_env = new_env;
5047
56
        ctx->curr_exp = e;
5048
56
        lbm_stack_drop(&ctx->K, 1);
5049
56
        return;
5050
      }
5051
    }
5052
    // If no mail or no match, go to sleep
5053
140
    lbm_uint *rptr = stack_reserve(ctx,2);
5054
140
    rptr[0] = ctx->r;
5055
140
    rptr[1] = RECV_TO_RETRY;
5056
140
    block_current_ctx(LBM_THREAD_STATE_RECV_TO,S_TO_US(timeout_time),true);
5057
  } else {
5058
    error_ctx(ENC_SYM_TERROR);
5059
  }
5060
}
5061
5062
// cont_recv_to_retry
5063
//
5064
// s[sp-2] = patterns
5065
// s[sp-1] = timeout value
5066
//
5067
// ctx->r = nonsense | timeout symbol
5068
140
static void cont_recv_to_retry(eval_context_t *ctx) {
5069
140
  lbm_value *sptr = get_stack_ptr(ctx, 2); //sptr[0] = patterns, sptr[1] = timeout
5070
5071
140
  if (ctx->num_mail > 0) {
5072
    lbm_value e;
5073
140
    lbm_value new_env = ctx->curr_env;
5074
#ifdef LBM_ALWAYS_GC
5075
    gc();
5076
#endif
5077
140
    int n = find_match(sptr[0], ctx->mailbox, ctx->num_mail, &e, &new_env);
5078
140
    if (n == FM_NEED_GC) {
5079
      gc();
5080
      new_env = ctx->curr_env;
5081
      n = find_match(sptr[0], ctx->mailbox, ctx->num_mail, &e, &new_env);
5082
      if (n == FM_NEED_GC) error_ctx(ENC_SYM_MERROR);
5083
    }
5084
140
    if (n == FM_PATTERN_ERROR) {
5085
      lbm_set_error_reason("Incorrect pattern format for recv");
5086
      error_at_ctx(ENC_SYM_EERROR, sptr[0]);
5087
140
    } else if (n >= 0) { // match
5088
56
      mailbox_remove_mail(ctx, (lbm_uint)n);
5089
56
      ctx->curr_env = new_env;
5090
56
      ctx->curr_exp = e;
5091
56
      lbm_stack_drop(&ctx->K, 2);
5092
56
      return;
5093
    }
5094
  }
5095
5096
  // No message matched but the timeout was reached.
5097
  // This is like having a recv-to with no case that matches
5098
  // the timeout symbol.
5099
84
  if (ctx->r == ENC_SYM_TIMEOUT) {
5100
84
    lbm_stack_drop(&ctx->K, 2);
5101
84
    ctx->app_cont = true;
5102
84
    return;
5103
  }
5104
5105
  stack_reserve(ctx,1)[0] = RECV_TO_RETRY;
5106
  reblock_current_ctx(LBM_THREAD_STATE_RECV_TO,true);
5107
}
5108
5109
/*********************************************************/
5110
/* Continuations table                                   */
5111
typedef void (*cont_fun)(eval_context_t *);
5112
5113
static const cont_fun continuations[NUM_CONTINUATIONS] =
5114
  { advance_ctx,  // CONT_DONE
5115
    cont_set_global_env,
5116
    cont_bind_to_key_rest,
5117
    cont_if,
5118
    cont_progn_rest,
5119
    cont_application_args,
5120
    cont_and,
5121
    cont_or,
5122
    cont_wait,
5123
    cont_match,
5124
    cont_application_start,
5125
    cont_eval_r,
5126
    cont_resume,
5127
    cont_closure_application_args,
5128
    cont_exit_atomic,
5129
    cont_read_next_token,
5130
    cont_read_append_continue,
5131
    cont_read_eval_continue,
5132
    cont_read_expect_closepar,
5133
    cont_read_dot_terminate,
5134
    cont_read_done,
5135
    cont_read_start_array,
5136
    cont_read_append_array,
5137
    cont_map,
5138
    cont_match_guard,
5139
    cont_terminate,
5140
    cont_progn_var,
5141
    cont_setq,
5142
    cont_move_to_flash,
5143
    cont_move_val_to_flash_dispatch,
5144
    cont_move_list_to_flash,
5145
    cont_close_list_in_flash,
5146
    cont_qq_expand_start,
5147
    cont_qq_expand,
5148
    cont_qq_append,
5149
    cont_qq_expand_list,
5150
    cont_qq_list,
5151
    cont_kill,
5152
    cont_loop,
5153
    cont_loop_condition,
5154
    cont_merge_rest,
5155
    cont_merge_layer,
5156
    cont_closure_args_rest,
5157
    cont_move_array_elts_to_flash,
5158
    cont_pop_reader_flags,
5159
    cont_exception_handler,
5160
    cont_recv_to,
5161
    cont_wrap_result,
5162
    cont_recv_to_retry
5163
  };
5164
5165
/*********************************************************/
5166
/* Evaluators lookup table (special forms)               */
5167
typedef void (*evaluator_fun)(eval_context_t *);
5168
5169
static const evaluator_fun evaluators[] =
5170
  {
5171
   eval_quote,
5172
   eval_define,
5173
   eval_progn,
5174
   eval_lambda,
5175
   eval_if,
5176
   eval_let,
5177
   eval_and,
5178
   eval_or,
5179
   eval_match,
5180
   eval_receive,
5181
   eval_receive_timeout,
5182
   eval_callcc,
5183
   eval_atomic,
5184
   eval_selfevaluating, // macro
5185
   eval_selfevaluating, // cont
5186
   eval_selfevaluating, // closure
5187
   eval_cond,
5188
   eval_app_cont,
5189
   eval_var,
5190
   eval_setq,
5191
   eval_move_to_flash,
5192
   eval_loop,
5193
   eval_trap
5194
  };
5195
5196
5197
/*********************************************************/
5198
/* Evaluator step function                               */
5199
5200
912134918
static void evaluation_step(void){
5201
912134918
  eval_context_t *ctx = ctx_running;
5202
#ifdef VISUALIZE_HEAP
5203
  heap_vis_gen_image();
5204
#endif
5205
5206
912134918
  if (ctx->app_cont) {
5207
    lbm_value k;
5208
424285381
    lbm_pop(&ctx->K, &k);
5209
424285381
    ctx->app_cont = false;
5210
5211
424285381
    lbm_uint decoded_k = DEC_CONTINUATION(k);
5212
    // If app_cont is true, then top of stack must be a valid continuation!
5213
424285381
    if (decoded_k < NUM_CONTINUATIONS) {
5214
424285381
      continuations[decoded_k](ctx);
5215
    } else {
5216
      error_ctx(ENC_SYM_FATAL_ERROR);
5217
    }
5218
424277197
    return;
5219
  }
5220
5221
487849537
  if (lbm_is_symbol(ctx->curr_exp)) {
5222
224405517
    eval_symbol(ctx);
5223
224405461
    return;
5224
  }
5225
263444020
  if (lbm_is_cons(ctx->curr_exp)) {
5226
168915242
    lbm_cons_t *cell = lbm_ref_cell(ctx->curr_exp);
5227
168915242
    lbm_value h = cell->car;
5228

168915242
    if (lbm_is_symbol(h) && ((h & ENC_SPECIAL_FORMS_MASK) == ENC_SPECIAL_FORMS_BIT)) {
5229
63829124
      lbm_uint eval_index = lbm_dec_sym(h) & SPECIAL_FORMS_INDEX_MASK;
5230
63829124
      evaluators[eval_index](ctx);
5231
63829040
      return;
5232
    }
5233
    /*
5234
     * At this point head can be anything. It should evaluate
5235
     * into a form that can be applied (closure, symbol, ...) though.
5236
     */
5237
105086118
    lbm_value *reserved = stack_reserve(ctx, 3);
5238
105086118
    reserved[0] = ctx->curr_env;
5239
105086118
    reserved[1] = cell->cdr;
5240
105086118
    reserved[2] = APPLICATION_START;
5241
105086118
    ctx->curr_exp = h; // evaluate the function
5242
105086118
    return;
5243
  }
5244
5245
94528778
  eval_selfevaluating(ctx);
5246
94528778
  return;
5247
}
5248
5249
5250
// Reset has a built in pause.
5251
// so after reset, continue.
5252
void lbm_reset_eval(void) {
5253
  eval_cps_next_state_arg = 0;
5254
  eval_cps_next_state = EVAL_CPS_STATE_RESET;
5255
  if (eval_cps_next_state != eval_cps_run_state) eval_cps_state_changed = true;
5256
}
5257
5258
21748
void lbm_pause_eval(void ) {
5259
21748
  eval_cps_next_state_arg = 0;
5260
21748
  eval_cps_next_state = EVAL_CPS_STATE_PAUSED;
5261
21748
  if (eval_cps_next_state != eval_cps_run_state) eval_cps_state_changed = true;
5262
21748
}
5263
5264
21756
void lbm_pause_eval_with_gc(uint32_t num_free) {
5265
21756
  eval_cps_next_state_arg = num_free;
5266
21756
  eval_cps_next_state = EVAL_CPS_STATE_PAUSED;
5267
21756
  if (eval_cps_next_state != eval_cps_run_state) eval_cps_state_changed = true;
5268
21756
}
5269
5270
21756
void lbm_continue_eval(void) {
5271
21756
  eval_cps_next_state = EVAL_CPS_STATE_RUNNING;
5272
21756
  if (eval_cps_next_state != eval_cps_run_state) eval_cps_state_changed = true;
5273
21756
}
5274
5275
void lbm_kill_eval(void) {
5276
  eval_cps_next_state = EVAL_CPS_STATE_KILL;
5277
  if (eval_cps_next_state != eval_cps_run_state) eval_cps_state_changed = true;
5278
}
5279
5280
149474
uint32_t lbm_get_eval_state(void) {
5281
149474
  return eval_cps_run_state;
5282
}
5283
5284
// Only unblocks threads that are unblockable.
5285
// A sleeping thread is not unblockable.
5286
84
static void handle_event_unblock_ctx(lbm_cid cid, lbm_value v) {
5287
84
  eval_context_t *found = NULL;
5288
84
  mutex_lock(&qmutex);
5289
5290
84
  found = lookup_ctx_nm(&blocked, cid);
5291

84
  if (found && LBM_IS_STATE_UNBLOCKABLE(found->state)){
5292
84
    drop_ctx_nm(&blocked,found);
5293
84
    if (lbm_is_error(v)) {
5294
28
      get_stack_ptr(found, 1)[0] = TERMINATE; // replace TOS
5295
28
      found->app_cont = true;
5296
    }
5297
84
    found->r = v;
5298
84
    found->state = LBM_THREAD_STATE_READY;
5299
84
    enqueue_ctx_nm(&queue,found);
5300
  }
5301
84
  mutex_unlock(&qmutex);
5302
84
}
5303
5304
static void handle_event_define(lbm_value key, lbm_value val) {
5305
  lbm_uint dec_key = lbm_dec_sym(key);
5306
  lbm_uint ix_key  = dec_key & GLOBAL_ENV_MASK;
5307
  lbm_value *global_env = lbm_get_global_env();
5308
  lbm_uint orig_env = global_env[ix_key];
5309
  lbm_value new_env;
5310
  // A key is a symbol and should not need to be remembered.
5311
  WITH_GC(new_env, lbm_env_set(orig_env,key,val));
5312
5313
  global_env[ix_key] = new_env;
5314
}
5315
5316
6766
static lbm_value get_event_value(lbm_event_t *e) {
5317
  lbm_value v;
5318
6766
  if (e->buf_len > 0) {
5319
    lbm_flat_value_t fv;
5320
6766
    fv.buf = (uint8_t*)e->buf_ptr;
5321
6766
    fv.buf_size = e->buf_len;
5322
6766
    fv.buf_pos = 0;
5323
6766
    if (!lbm_unflatten_value(&fv, &v)) {
5324
      lbm_set_flags(LBM_FLAG_HANDLER_EVENT_DELIVERY_FAILED);
5325
      v = ENC_SYM_EERROR;
5326
    }
5327
    // Free the flat value buffer. GC is unaware of its existence.
5328
6766
    lbm_free(fv.buf);
5329
  } else {
5330
    v = (lbm_value)e->buf_ptr;
5331
  }
5332
6766
  return v;
5333
}
5334
5335
93326619
static void process_events(void) {
5336
5337
93326619
  if (!lbm_events) {
5338
    return;
5339
  }
5340
5341
  lbm_event_t e;
5342
186660004
  while (lbm_event_pop(&e)) {
5343
6766
    lbm_value event_val = get_event_value(&e);
5344

6766
    switch(e.type) {
5345
84
    case LBM_EVENT_UNBLOCK_CTX:
5346
84
      handle_event_unblock_ctx((lbm_cid)e.parameter, event_val);
5347
84
      break;
5348
    case LBM_EVENT_DEFINE:
5349
      handle_event_define((lbm_value)e.parameter, event_val);
5350
      break;
5351
6682
    case LBM_EVENT_FOR_HANDLER:
5352
6682
      if (lbm_event_handler_pid >= 0) {
5353
6682
        lbm_find_receiver_and_send(lbm_event_handler_pid, event_val);
5354
      }
5355
6682
      break;
5356
    case LBM_EVENT_RUN_USER_CALLBACK:
5357
      user_callback((void*)e.parameter);
5358
      break;
5359
    }
5360
93333385
  }
5361
}
5362
5363
/* eval_cps_run can be paused
5364
   I think it would be better use a mailbox for
5365
   communication between other threads and the run_eval
5366
   but for now a set of variables will be used. */
5367
21756
void lbm_run_eval(void){
5368
5369
21756
  if (setjmp(critical_error_jmp_buf) > 0) {
5370
    printf_callback("GC stack overflow!\n");
5371
    critical_error_callback();
5372
    // terminate evaluation thread.
5373
    return;
5374
  }
5375
5376
21756
  setjmp(error_jmp_buf);
5377
5378
104895
  while (eval_running) {
5379

111800
    if (eval_cps_state_changed  || eval_cps_run_state == EVAL_CPS_STATE_PAUSED) {
5380
81738
      eval_cps_state_changed = false;
5381

81738
      switch (eval_cps_next_state) {
5382
      case EVAL_CPS_STATE_RESET:
5383
        if (eval_cps_run_state != EVAL_CPS_STATE_RESET) {
5384
          is_atomic = false;
5385
          blocked.first = NULL;
5386
          blocked.last = NULL;
5387
          queue.first = NULL;
5388
          queue.last = NULL;
5389
          ctx_running = NULL;
5390
          eval_steps_quota = eval_steps_refill;
5391
          eval_cps_run_state = EVAL_CPS_STATE_RESET;
5392
          if (blocking_extension) {
5393
            blocking_extension = false;
5394
            mutex_unlock(&blocking_extension_mutex);
5395
          }
5396
        }
5397
        usleep_callback(EVAL_CPS_MIN_SLEEP);
5398
        continue;
5399
59982
      case EVAL_CPS_STATE_PAUSED:
5400
59982
        if (eval_cps_run_state != EVAL_CPS_STATE_PAUSED) {
5401
43504
          if (lbm_heap_num_free() < eval_cps_next_state_arg) {
5402
            gc();
5403
          }
5404
43504
          eval_cps_next_state_arg = 0;
5405
43504
          eval_cps_run_state = EVAL_CPS_STATE_PAUSED;
5406
        }
5407
59982
        usleep_callback(EVAL_CPS_MIN_SLEEP);
5408
31329
        continue;
5409
      case EVAL_CPS_STATE_KILL:
5410
        eval_cps_run_state = EVAL_CPS_STATE_DEAD;
5411
        eval_running = false;
5412
        continue;
5413
21756
      default: // running state
5414
21756
        eval_cps_run_state = eval_cps_next_state;
5415
21756
        break;
5416
      }
5417
30062
    }
5418
    while (true) {
5419

1005505723
      if (eval_steps_quota && ctx_running) {
5420
912134918
        eval_steps_quota--;
5421
912134918
        evaluation_step();
5422
      } else {
5423
93370805
        if (eval_cps_state_changed) break;
5424
93327319
        eval_steps_quota = eval_steps_refill;
5425
93327319
        if (!is_atomic) {
5426
93326619
          if (gc_requested) {
5427
96
            gc();
5428
          }
5429
93326619
          process_events();
5430
93326619
          mutex_lock(&qmutex);
5431
93326619
          if (ctx_running) {
5432
91168063
            enqueue_ctx_nm(&queue, ctx_running);
5433
91168063
            ctx_running = NULL;
5434
          }
5435
93326619
          wake_up_ctxs_nm();
5436
93326619
          ctx_running = dequeue_ctx_nm(&queue);
5437
93326619
          mutex_unlock(&qmutex);
5438
93326619
          if (!ctx_running) {
5439
2101311
            lbm_system_sleeping = true;
5440
            //Fixed sleep interval to poll events regularly.
5441
2101311
            usleep_callback(EVAL_CPS_MIN_SLEEP);
5442
2101303
            lbm_system_sleeping = false;
5443
          }
5444
        }
5445
      }
5446
    }
5447
  }
5448
}
5449
5450
lbm_cid lbm_eval_program(lbm_value lisp) {
5451
  return lbm_create_ctx(lisp, ENC_SYM_NIL, 256, NULL);
5452
}
5453
5454
lbm_cid lbm_eval_program_ext(lbm_value lisp, unsigned int stack_size) {
5455
  return lbm_create_ctx(lisp, ENC_SYM_NIL, stack_size, NULL);
5456
}
5457
5458
21756
int lbm_eval_init() {
5459
21756
  if (!qmutex_initialized) {
5460
21756
    mutex_init(&qmutex);
5461
21756
    qmutex_initialized = true;
5462
  }
5463
21756
  if (!lbm_events_mutex_initialized) {
5464
21756
    mutex_init(&lbm_events_mutex);
5465
21756
    lbm_events_mutex_initialized = true;
5466
  }
5467
21756
  if (!blocking_extension_mutex_initialized) {
5468
21756
    mutex_init(&blocking_extension_mutex);
5469
21756
    blocking_extension_mutex_initialized = true;
5470
  }
5471
5472
21756
  mutex_lock(&qmutex);
5473
21756
  mutex_lock(&lbm_events_mutex);
5474
5475
21756
  blocked.first = NULL;
5476
21756
  blocked.last = NULL;
5477
21756
  queue.first = NULL;
5478
21756
  queue.last = NULL;
5479
21756
  ctx_running = NULL;
5480
5481
21756
  eval_cps_run_state = EVAL_CPS_STATE_RUNNING;
5482
5483
21756
  mutex_unlock(&lbm_events_mutex);
5484
21756
  mutex_unlock(&qmutex);
5485
5486
21756
  if (!lbm_init_env()) return 0;
5487
21756
  eval_running = true;
5488
21756
  return 1;
5489
}
5490
5491
21756
bool lbm_eval_init_events(unsigned int num_events) {
5492
5493
21756
  mutex_lock(&lbm_events_mutex);
5494
21756
  lbm_events = (lbm_event_t*)lbm_malloc(num_events * sizeof(lbm_event_t));
5495
21756
  bool r = false;
5496
21756
  if (lbm_events) {
5497
21756
    lbm_events_max = num_events;
5498
21756
    lbm_events_head = 0;
5499
21756
    lbm_events_tail = 0;
5500
21756
    lbm_events_full = false;
5501
21756
    lbm_event_handler_pid = -1;
5502
21756
    r = true;
5503
  }
5504
21756
  mutex_unlock(&lbm_events_mutex);
5505
21756
  return r;
5506
}