GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/joels/Current/lispbm/src/eval_cps.c Lines: 2798 3242 86.3 %
Date: 2024-12-05 14:36:58 Branches: 874 1328 65.8 %

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
21672
void lbm_set_critical_error_callback(void (*fptr)(void)) {
275
21672
  if (fptr == NULL) critical_error_callback = critical_nonsense;
276
21672
  else critical_error_callback = fptr;
277
21672
}
278
279
21672
void lbm_set_usleep_callback(void (*fptr)(uint32_t)) {
280
21672
  if (fptr == NULL) usleep_callback = usleep_nonsense;
281
21672
  else usleep_callback = fptr;
282
21672
}
283
284
21672
void lbm_set_timestamp_us_callback(uint32_t (*fptr)(void)) {
285
21672
  if (fptr == NULL) timestamp_us_callback = timestamp_nonsense;
286
21672
  else timestamp_us_callback = fptr;
287
21672
}
288
289
21672
void lbm_set_ctx_done_callback(void (*fptr)(eval_context_t *)) {
290
21672
  if (fptr == NULL) ctx_done_callback = ctx_done_nonsense;
291
21672
  else ctx_done_callback = fptr;
292
21672
}
293
294
21672
void lbm_set_printf_callback(int (*fptr)(const char*, ...)){
295
21672
  if (fptr == NULL) printf_callback = printf_nonsense;
296
21672
  else printf_callback = fptr;
297
21672
}
298
299
21672
void lbm_set_dynamic_load_callback(bool (*fptr)(const char *, const char **)) {
300
21672
  if (fptr == NULL) dynamic_load_callback = dynamic_load_nonsense;
301
21672
  else  dynamic_load_callback = fptr;
302
21672
}
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
7651
static bool event_internal(lbm_event_type_t event_type, lbm_uint parameter, lbm_uint buf_ptr, lbm_uint buf_len) {
327
7651
  bool r = false;
328
7651
  if (lbm_events) {
329
7651
    mutex_lock(&lbm_events_mutex);
330
7651
    if (!lbm_events_full) {
331
      lbm_event_t event;
332
7651
      event.type = event_type;
333
7651
      event.parameter = parameter;
334
7651
      event.buf_ptr = buf_ptr;
335
7651
      event.buf_len = buf_len;
336
7651
      lbm_events[lbm_events_head] = event;
337
7651
      lbm_events_head = (lbm_events_head + 1) % lbm_events_max;
338
7651
      lbm_events_full = lbm_events_head == lbm_events_tail;
339
7651
      r = true;
340
    }
341
7651
    mutex_unlock(&lbm_events_mutex);
342
  }
343
7651
  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
7567
bool lbm_event(lbm_flat_value_t *fv) {
368
7567
  if (lbm_event_handler_pid > 0) {
369
7567
    return event_internal(LBM_EVENT_FOR_HANDLER, 0, (lbm_uint)fv->buf, fv->buf_size);
370
  }
371
  return false;
372
}
373
374
93342686
static bool lbm_event_pop(lbm_event_t *event) {
375
93342686
  mutex_lock(&lbm_events_mutex);
376

93342686
  if (lbm_events_head == lbm_events_tail && !lbm_events_full) {
377
93335043
    mutex_unlock(&lbm_events_mutex);
378
93335043
    return false;
379
  }
380
7643
  *event = lbm_events[lbm_events_tail];
381
7643
  lbm_events_tail = (lbm_events_tail + 1) % lbm_events_max;
382
7643
  lbm_events_full = false;
383
7643
  mutex_unlock(&lbm_events_mutex);
384
7643
  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
21672
void lbm_set_verbose(bool verbose) {
423
21672
  lbm_verbose = verbose;
424
21672
}
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
4394362
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
4394362
  lbm_value res = lbm_heap_state.freelist;
451
4394362
  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
4394362
  lbm_uint heap_ix = lbm_dec_ptr(res);
461
4394362
  lbm_heap_state.freelist = lbm_heap_state.heap[heap_ix].cdr;
462
4394362
  lbm_heap_state.num_alloc++;
463
4394362
  lbm_heap_state.heap[heap_ix].car = head;
464
4394362
  lbm_heap_state.heap[heap_ix].cdr = tail;
465
4394362
  res = lbm_set_ptr_type(res, LBM_TYPE_CONS);
466
4394362
  return res;
467
}
468
469
469464333
static lbm_uint *get_stack_ptr(eval_context_t *ctx, unsigned int n) {
470
469464333
  if (n <= ctx->K.sp) {
471
469464333
    lbm_uint index = ctx->K.sp - n;
472
469464333
    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
21771776
static lbm_uint *pop_stack_ptr(eval_context_t *ctx, unsigned int n) {
481
21771776
  if (n <= ctx->K.sp) {
482
21771776
    ctx->K.sp -= n;
483
21771776
    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
493991408
static inline lbm_uint *stack_reserve(eval_context_t *ctx, unsigned int n) {
490
493991408
  if (ctx->K.sp + n < ctx->K.size) {
491
493991408
    lbm_uint *ptr = &ctx->K.data[ctx->K.sp];
492
493991408
    ctx->K.sp += n;
493
493991408
    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
119724057
static void get_car_and_cdr(lbm_value a, lbm_value *a_car, lbm_value *a_cdr) {
525
119724057
  if (lbm_is_ptr(a)) {
526
119406397
    lbm_cons_t *cell = lbm_ref_cell(a);
527
119406397
    *a_car = cell->car;
528
119406397
    *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
119724057
}
536
537
/* car cdr caar cadr replacements that are evaluator safe. */
538
114797088
static lbm_value get_car(lbm_value a) {
539
114797088
  if (lbm_is_ptr(a)) {
540
114797088
    lbm_cons_t *cell = lbm_ref_cell(a);
541
114797088
    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
139614548
static lbm_value get_cdr(lbm_value a) {
550
139614548
  if (lbm_is_ptr(a)) {
551
139614520
    lbm_cons_t *cell = lbm_ref_cell(a);
552
139614520
    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
27383891
static lbm_value get_cadr(lbm_value a) {
561
27383891
  if (lbm_is_ptr(a)) {
562
27383891
    lbm_cons_t *cell = lbm_ref_cell(a);
563
27383891
    lbm_value tmp = cell->cdr;
564
27383891
    if (lbm_is_ptr(tmp)) {
565
27373531
      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
12012
static lbm_value allocate_closure(lbm_value params, lbm_value body, lbm_value env) {
577
578
#ifdef LBM_ALWAYS_GC
579
  gc();
580
  if (lbm_heap_num_free() < 4) {
581
    error_ctx(ENC_SYM_MERROR);
582
  }
583
#else
584
12012
  if (lbm_heap_num_free() < 4) {
585
    gc();
586
    if (lbm_heap_num_free() < 4) {
587
      error_ctx(ENC_SYM_MERROR);
588
    }
589
  }
590
#endif
591
  // The freelist will always contain just plain heap-cells.
592
  // So dec_ptr is sufficient.
593
12012
  lbm_value res = lbm_heap_state.freelist;
594
12012
  if (lbm_type_of(res) == LBM_TYPE_CONS) {
595
12012
    lbm_cons_t *heap = lbm_heap_state.heap;
596
12012
    lbm_uint ix = lbm_dec_ptr(res);
597
12012
    heap[ix].car = ENC_SYM_CLOSURE;
598
12012
    ix = lbm_dec_ptr(heap[ix].cdr);
599
12012
    heap[ix].car = params;
600
12012
    ix = lbm_dec_ptr(heap[ix].cdr);
601
12012
    heap[ix].car = body;
602
12012
    ix = lbm_dec_ptr(heap[ix].cdr);
603
12012
    heap[ix].car = env;
604
12012
    lbm_heap_state.freelist = heap[ix].cdr;
605
12012
    heap[ix].cdr = ENC_SYM_NIL;
606
12012
    lbm_heap_state.num_alloc+=4;
607
  } else {
608
    error_ctx(ENC_SYM_FATAL_ERROR);
609
  }
610
12012
  return res;
611
}
612
613
// Allocate a binding and attach it to a list (if so desired)
614
60011153
static lbm_value allocate_binding(lbm_value key, lbm_value val, lbm_value the_cdr) {
615
#ifdef LBM_ALWAYS_GC
616
  lbm_gc_mark_phase(key);
617
  lbm_gc_mark_phase(val);
618
  lbm_gc_mark_phase(the_cdr);
619
  gc();
620
  if (lbm_heap_num_free() < 2) {
621
    error_ctx(ENC_SYM_MERROR);
622
  }
623
#else
624
60011153
  if (lbm_heap_num_free() < 2) {
625
83306
    lbm_gc_mark_phase(key);
626
83306
    lbm_gc_mark_phase(val);
627
83306
    lbm_gc_mark_phase(the_cdr);
628
83306
    gc();
629
83306
    if (lbm_heap_num_free() < 2) {
630
28
      error_ctx(ENC_SYM_MERROR);
631
    }
632
  }
633
#endif
634
60011125
  lbm_cons_t* heap = lbm_heap_state.heap;
635
60011125
  lbm_value binding_cell = lbm_heap_state.freelist;
636
60011125
  lbm_uint binding_cell_ix = lbm_dec_ptr(binding_cell);
637
60011125
  lbm_value list_cell = heap[binding_cell_ix].cdr;
638
60011125
  lbm_uint list_cell_ix = lbm_dec_ptr(list_cell);
639
60011125
  lbm_heap_state.freelist = heap[list_cell_ix].cdr;
640
60011125
  lbm_heap_state.num_alloc += 2;
641
60011125
  heap[binding_cell_ix].car = key;
642
60011125
  heap[binding_cell_ix].cdr = val;
643
60011125
  heap[list_cell_ix].car = binding_cell;
644
60011125
  heap[list_cell_ix].cdr = the_cdr;
645
60011125
  return list_cell;
646
}
647
648
#define CLO_PARAMS 0
649
#define CLO_BODY   1
650
#define CLO_ENV    2
651
#define LOOP_BINDS 0
652
#define LOOP_COND  1
653
#define LOOP_BODY  2
654
655
// (a b c) -> [a b c]
656
57804690
static lbm_value extract_n(lbm_value curr, lbm_value *res, unsigned int n) {
657
218973408
  for (unsigned int i = 0; i < n; i ++) {
658
161168718
    if (lbm_is_ptr(curr)) {
659
161168690
      lbm_cons_t *cell = lbm_ref_cell(curr);
660
161168690
      res[i] = cell->car;
661
161168690
      curr = cell->cdr;
662
    } else {
663
28
      res[i] = ENC_SYM_NIL;
664
    }
665
  }
666
57804690
  return curr; // Rest of list is returned here.
667
}
668
669
73278613
static void call_fundamental(lbm_uint fundamental, lbm_value *args, lbm_uint arg_count, eval_context_t *ctx) {
670
  lbm_value res;
671
#ifdef LBM_ALWAYS_GC
672
  gc();
673
#endif
674
73278613
  res = fundamental_table[fundamental](args, arg_count, ctx);
675
73278613
  if (lbm_is_error(res)) {
676
216265
    if (lbm_is_symbol_merror(res)) {
677
211673
      gc();
678
211673
      res = fundamental_table[fundamental](args, arg_count, ctx);
679
    }
680
216265
    if (lbm_is_error(res)) {
681
4656
      error_at_ctx(res, lbm_enc_sym(FUNDAMENTAL_SYMBOLS_START | fundamental));
682
    }
683
  }
684
73273957
  lbm_stack_drop(&ctx->K, arg_count+1);
685
73273957
  ctx->app_cont = true;
686
73273957
  ctx->r = res;
687
73273957
}
688
689
28
static void atomic_error(void) {
690
28
  is_atomic = false;
691
28
  lbm_set_error_reason((char*)lbm_error_str_forbidden_in_atomic);
692
28
  error_ctx(ENC_SYM_EERROR);
693
}
694
695
// block_current_ctx blocks a context until it is
696
// woken up externally or a timeout period of time passes.
697
// Blocking while in an atomic block would have bad consequences.
698
3270
static void block_current_ctx(uint32_t state, lbm_uint sleep_us,  bool do_cont) {
699
3270
  if (is_atomic) atomic_error();
700
3270
  ctx_running->timestamp = timestamp_us_callback();
701
3270
  ctx_running->sleep_us = sleep_us;
702
3270
  ctx_running->state  = state;
703
3270
  ctx_running->app_cont = do_cont;
704
3270
  enqueue_ctx(&blocked, ctx_running);
705
3270
  ctx_running = NULL;
706
3270
}
707
708
126
lbm_flash_status lbm_write_const_array_padded(uint8_t *data, lbm_uint n, lbm_uint *res) {
709
126
  lbm_uint full_words = n / sizeof(lbm_uint);
710
126
  lbm_uint n_mod = n % sizeof(lbm_uint);
711
712
126
  if (n_mod == 0) { // perfect fit.
713
56
    return lbm_write_const_raw((lbm_uint*)data, full_words, res);
714
  } else {
715
70
    lbm_uint last_word = 0;
716
70
    memcpy(&last_word, &data[full_words * sizeof(lbm_uint)], n_mod);
717
70
    if (full_words >= 1) {
718
14
      lbm_flash_status s = lbm_write_const_raw((lbm_uint*)data, full_words, res);
719
14
      if ( s == LBM_FLASH_WRITE_OK) {
720
        lbm_uint dummy;
721
14
        s = lbm_write_const_raw(&last_word, 1, &dummy);
722
      }
723
14
      return s;
724
    } else {
725
56
      return lbm_write_const_raw(&last_word, 1, res);
726
    }
727
  }
728
}
729
730
/****************************************************/
731
/* Error message creation                           */
732
733
#define ERROR_MESSAGE_BUFFER_SIZE_BYTES 256
734
735
8
void print_environments(char *buf, unsigned int size) {
736
737
8
  lbm_value curr_l = ctx_running->curr_env;
738
8
  printf_callback("\tCurrent local environment:\n");
739
12
  while (lbm_type_of(curr_l) == LBM_TYPE_CONS) {
740
4
    lbm_print_value(buf, (size/2) - 1, lbm_caar(curr_l));
741
4
    lbm_print_value(buf + (size/2),size/2, lbm_cdr(lbm_car(curr_l)));
742
4
    printf_callback("\t%s = %s\n", buf, buf+(size/2));
743
4
    curr_l = lbm_cdr(curr_l);
744
  }
745
8
  printf_callback("\n\n");
746
8
  printf_callback("\tCurrent global environment:\n");
747
8
  lbm_value *glob_env = lbm_get_global_env();
748
749
264
  for (int i = 0; i < GLOBAL_ENV_ROOTS; i ++) {
750
256
    lbm_value curr_g = glob_env[i];;
751
264
    while (lbm_type_of(curr_g) == LBM_TYPE_CONS) {
752
753
8
      lbm_print_value(buf, (size/2) - 1, lbm_caar(curr_g));
754
8
      lbm_print_value(buf + (size/2),size/2, lbm_cdr(lbm_car(curr_g)));
755
8
      printf_callback("\t%s = %s\n", buf, buf+(size/2));
756
8
      curr_g = lbm_cdr(curr_g);
757
    }
758
  }
759
8
}
760
761
24
void print_error_value(char *buf, lbm_uint bufsize, char *pre, lbm_value v, bool lookup) {
762
763
24
  lbm_print_value(buf, bufsize, v);
764
24
  printf_callback("%s %s\n",pre, buf);
765
24
  if (lookup) {
766
16
    if (lbm_is_symbol(v)) {
767
12
      if (lbm_dec_sym(v) >= RUNTIME_SYMBOLS_START) {
768
4
	lbm_value res = ENC_SYM_NIL;
769

4
	if (lbm_env_lookup_b(&res, v, ctx_running->curr_env) ||
770
	    lbm_global_env_lookup(&res, v)) {
771
4
	  lbm_print_value(buf, bufsize, res);
772
4
	  printf_callback("      bound to: %s\n", buf);
773
	} else {
774
	  printf_callback("      UNDEFINED\n");
775
	}
776
      }
777
    }
778
  }
779
24
}
780
781
8
void print_error_message(lbm_value error,
782
                         bool has_at,
783
                         lbm_value at,
784
                         unsigned int row,
785
                         unsigned int col,
786
                         lbm_int row0,
787
                         lbm_int row1,
788
                         lbm_int cid,
789
                         char *name) {
790
  /* try to allocate a lbm_print_value buffer on the lbm_memory */
791
8
  char *buf = lbm_malloc_reserve(ERROR_MESSAGE_BUFFER_SIZE_BYTES);
792
8
  if (!buf) {
793
    printf_callback("Error: Not enough free memory to create a human readable error message\n");
794
    return;
795
  }
796
797
8
  print_error_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES,"   Error:", error, false);
798
8
  if (name) {
799
    printf_callback(  "   CTX: %d \"%s\"\n", cid, name);
800
  } else {
801
8
    printf_callback(  "   CTX: %d\n", cid);
802
  }
803
8
  print_error_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES,"   Current:", ctx_running->curr_exp, true);
804
8
  if (lbm_error_has_suspect) {
805
      print_error_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES,"   At:", lbm_error_suspect, true);
806
      lbm_error_has_suspect = false;
807
8
  } else if (has_at) {
808
8
    print_error_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES,"   In:", at, true);
809
  }
810
811
8
  printf_callback("\n");
812
813

8
  if (lbm_is_symbol(error) &&
814
      error == ENC_SYM_RERROR) {
815
    printf_callback("   Line:   %u\n", row);
816
    printf_callback("   Column: %u\n", col);
817
8
  } else if (row0 >= 0) {
818
    if (row1 < 0) printf_callback("   Starting at row: %d\n", row0);
819
    else printf_callback("   Between row %d and %d\n", row0, row1);
820
  }
821
822
8
  printf_callback("\n");
823
824
8
  if (ctx_running->error_reason) {
825
    printf_callback("   Reason: %s\n\n", ctx_running->error_reason);
826
  }
827
8
  if (lbm_verbose) {
828
8
    lbm_print_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES, ctx_running->r);
829
8
    printf_callback("   Current intermediate result: %s\n\n", buf);
830
831
8
    print_environments(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES);
832
8
    printf_callback("\n\n");
833
834
8
    printf_callback("   Stack:\n");
835
192
    for (unsigned int i = 0; i < ctx_running->K.sp; i ++) {
836
184
      lbm_print_value(buf, ERROR_MESSAGE_BUFFER_SIZE_BYTES, ctx_running->K.data[i]);
837
184
      printf_callback("     %s\n", buf);
838
    }
839
  }
840
8
  lbm_free(buf);
841
}
842
843
/****************************************************/
844
/* Tokenizing and parsing                           */
845
846
310042
bool create_string_channel(char *str, lbm_value *res, lbm_value dep) {
847
848
310042
  lbm_char_channel_t *chan = NULL;
849
310042
  lbm_string_channel_state_t *st = NULL;
850
851
310042
  st = (lbm_string_channel_state_t*)lbm_malloc(sizeof(lbm_string_channel_state_t));
852
310042
  if (st == NULL) {
853
1018
    return false;
854
  }
855
309024
  chan = (lbm_char_channel_t*)lbm_malloc(sizeof(lbm_char_channel_t));
856
309024
  if (chan == NULL) {
857
268
    lbm_free(st);
858
268
    return false;
859
  }
860
861
308756
  lbm_create_string_char_channel(st, chan, str);
862
308756
  lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_CHANNEL, (lbm_uint) chan, ENC_SYM_CHANNEL_TYPE);
863
308756
  if (cell == ENC_SYM_MERROR) {
864
    lbm_free(st);
865
    lbm_free(chan);
866
    return false;
867
  }
868
869
308756
  lbm_char_channel_set_dependency(chan, dep);
870
871
308756
  *res = cell;
872
308756
  return true;
873
}
874
875
21672
bool lift_char_channel(lbm_char_channel_t *chan , lbm_value *res) {
876
21672
  lbm_value cell = lbm_heap_allocate_cell(LBM_TYPE_CHANNEL, (lbm_uint) chan, ENC_SYM_CHANNEL_TYPE);
877
21672
  if (cell == ENC_SYM_MERROR) {
878
    return false;
879
  }
880
21672
  *res = cell;
881
21672
  return true;
882
}
883
884
885
/****************************************************/
886
/* Queue functions                                  */
887
888
696006
static void queue_iterator_nm(eval_context_queue_t *q, ctx_fun f, void *arg1, void *arg2) {
889
  eval_context_t *curr;
890
696006
  curr = q->first;
891
892
709332
  while (curr != NULL) {
893
13326
    f(curr, arg1, arg2);
894
13326
    curr = curr->next;
895
  }
896
696006
}
897
898
void lbm_all_ctxs_iterator(ctx_fun f, void *arg1, void *arg2) {
899
  mutex_lock(&qmutex);
900
  queue_iterator_nm(&blocked, f, arg1, arg2);
901
  queue_iterator_nm(&queue, f, arg1, arg2);
902
  if (ctx_running) f(ctx_running, arg1, arg2);
903
  mutex_unlock(&qmutex);
904
}
905
906
84
void lbm_running_iterator(ctx_fun f, void *arg1, void *arg2){
907
84
  mutex_lock(&qmutex);
908
84
  queue_iterator_nm(&queue, f, arg1, arg2);
909
84
  mutex_unlock(&qmutex);
910
84
}
911
912
84
void lbm_blocked_iterator(ctx_fun f, void *arg1, void *arg2){
913
84
  mutex_lock(&qmutex);
914
84
  queue_iterator_nm(&blocked, f, arg1, arg2);
915
84
  mutex_unlock(&qmutex);
916
84
}
917
918
91262765
static void enqueue_ctx_nm(eval_context_queue_t *q, eval_context_t *ctx) {
919
91262765
  if (q->last == NULL) {
920
88258549
    ctx->prev = NULL;
921
88258549
    ctx->next = NULL;
922
88258549
    q->first = ctx;
923
88258549
    q->last  = ctx;
924
  } else {
925
3004216
    ctx->prev = q->last;
926
3004216
    ctx->next = NULL;
927
3004216
    q->last->next = ctx;
928
3004216
    q->last = ctx;
929
  }
930
91262765
}
931
932
57270
static void enqueue_ctx(eval_context_queue_t *q, eval_context_t *ctx) {
933
57270
  mutex_lock(&qmutex);
934
57270
  enqueue_ctx_nm(q,ctx);
935
57270
  mutex_unlock(&qmutex);
936
57270
}
937
938
19730
static eval_context_t *lookup_ctx_nm(eval_context_queue_t *q, lbm_cid cid) {
939
  eval_context_t *curr;
940
19730
  curr = q->first;
941
19730
  while (curr != NULL) {
942
4200
    if (curr->id == cid) {
943
4200
      return curr;
944
    }
945
    curr = curr->next;
946
  }
947
15530
  return NULL;
948
}
949
950
3186
static bool drop_ctx_nm(eval_context_queue_t *q, eval_context_t *ctx) {
951
952
3186
  bool res = false;
953

3186
  if (q->first == NULL || q->last == NULL) {
954
    if (!(q->last == NULL && q->first == NULL)) {
955
      /* error state that should not happen */
956
      return res;
957
    }
958
    /* Queue is empty */
959
    return res;
960
  }
961
962
3186
  eval_context_t *curr = q->first;
963
3186
  while (curr) {
964
3186
    if (curr->id == ctx->id) {
965
3186
      res = true;
966
3186
      eval_context_t *tmp = curr->next;
967
3186
      if (curr->prev == NULL) {
968
3186
        if (curr->next == NULL) {
969
3172
          q->last = NULL;
970
3172
          q->first = NULL;
971
        } else {
972
14
          q->first = tmp;
973
14
          tmp->prev = NULL;
974
        }
975
      } else { /* curr->prev != NULL */
976
        if (curr->next == NULL) {
977
          q->last = curr->prev;
978
          q->last->next = NULL;
979
        } else {
980
          curr->prev->next = tmp;
981
          tmp->prev = curr->prev;
982
        }
983
      }
984
3186
      break;
985
    }
986
    curr = curr->next;
987
  }
988
3186
  return res;
989
}
990
991
/* End execution of the running context. */
992
22483
static void finish_ctx(void) {
993
994
22483
  if (!ctx_running) {
995
    return;
996
  }
997
  /* Drop the continuation stack immediately to free up lbm_memory */
998
22483
  lbm_stack_free(&ctx_running->K);
999
22483
  ctx_done_callback(ctx_running);
1000
1001
22483
  lbm_free(ctx_running->name); //free name if in LBM_MEM
1002
22483
  lbm_memory_free((lbm_uint*)ctx_running->error_reason); //free error_reason if in LBM_MEM
1003
1004
22483
  lbm_memory_free((lbm_uint*)ctx_running->mailbox);
1005
22483
  lbm_memory_free((lbm_uint*)ctx_running);
1006
22483
  ctx_running = NULL;
1007
}
1008
1009
140
static void context_exists(eval_context_t *ctx, void *cid, void *b) {
1010
140
  if (ctx->id == *(lbm_cid*)cid) {
1011
28
    *(bool*)b = true;
1012
  }
1013
140
}
1014
1015
1232
void lbm_set_error_suspect(lbm_value suspect) {
1016
1232
  lbm_error_suspect = suspect;
1017
1232
  lbm_error_has_suspect = true;
1018
1232
}
1019
1020
1316
void lbm_set_error_reason(char *error_str) {
1021
1316
  if (ctx_running != NULL) {
1022
1316
    ctx_running->error_reason = error_str;
1023
  }
1024
1316
}
1025
1026
// Not possible to CONS_WITH_GC in error_ctx_base (potential loop)
1027
8324
static void error_ctx_base(lbm_value err_val, bool has_at, lbm_value at, unsigned int row, unsigned int column) {
1028
1029
8324
  if (ctx_running->flags & EVAL_CPS_CONTEXT_FLAG_TRAP) {
1030
196
    if (lbm_heap_num_free() < 3) {
1031
      gc();
1032
    }
1033
1034
196
    if (lbm_heap_num_free() >= 3) {
1035
196
      lbm_value msg = lbm_cons(err_val, ENC_SYM_NIL);
1036
196
      msg = lbm_cons(lbm_enc_i(ctx_running->id), msg);
1037
196
      msg = lbm_cons(ENC_SYM_EXIT_ERROR, msg);
1038
196
      if (!lbm_is_symbol_merror(msg)) {
1039
196
        lbm_find_receiver_and_send(ctx_running->parent, msg);
1040
196
        goto error_ctx_base_done;
1041
      }
1042
    }
1043
  }
1044

8128
  if ((ctx_running->flags & EVAL_CPS_CONTEXT_FLAG_TRAP_UNROLL_RETURN) &&
1045
      (err_val != ENC_SYM_FATAL_ERROR)) {
1046
    lbm_uint v;
1047
28896
    while (ctx_running->K.sp > 0) {
1048
28896
      lbm_pop(&ctx_running->K, &v);
1049
28896
      if (v == EXCEPTION_HANDLER) {
1050
8120
        lbm_value *sptr = get_stack_ptr(ctx_running, 2);
1051
8120
        lbm_set_car(sptr[0], ENC_SYM_EXIT_ERROR);
1052
8120
        stack_reserve(ctx_running, 1)[0] = EXCEPTION_HANDLER;
1053
8120
        ctx_running->app_cont = true;
1054
8120
        ctx_running->r = err_val;
1055
8120
        longjmp(error_jmp_buf, 1);
1056
      }
1057
    }
1058
    err_val = ENC_SYM_FATAL_ERROR;
1059
  }
1060
8
  print_error_message(err_val,
1061
                      has_at,
1062
                      at,
1063
                      row,
1064
                      column,
1065
8
                      ctx_running->row0,
1066
8
                      ctx_running->row1,
1067
8
                      ctx_running->id,
1068
8
                      ctx_running->name);
1069
204
 error_ctx_base_done:
1070
204
  ctx_running->r = err_val;
1071
204
  finish_ctx();
1072
204
  longjmp(error_jmp_buf, 1);
1073
}
1074
1075
8072
static void error_at_ctx(lbm_value err_val, lbm_value at) {
1076
8072
  error_ctx_base(err_val, true, at, 0, 0);
1077
}
1078
1079
252
static void error_ctx(lbm_value err_val) {
1080
252
  error_ctx_base(err_val, false, 0, 0, 0);
1081
}
1082
1083
static void read_error_ctx(unsigned int row, unsigned int column) {
1084
  error_ctx_base(ENC_SYM_RERROR, false, 0, row, column);
1085
}
1086
1087
void lbm_critical_error(void) {
1088
  longjmp(critical_error_jmp_buf, 1);
1089
}
1090
1091
// successfully finish a context
1092
22279
static void ok_ctx(void) {
1093
22279
  if (ctx_running->flags & EVAL_CPS_CONTEXT_FLAG_TRAP) {
1094
    lbm_value msg;
1095

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

28
  if (found && (LBM_IS_STATE_UNBLOCKABLE(found->state))) {
1406
28
    drop_ctx_nm(&blocked,found);
1407
28
    found->state = LBM_THREAD_STATE_READY;
1408
28
    enqueue_ctx_nm(&queue,found);
1409
28
    r = true;
1410
  }
1411
28
  mutex_unlock(&qmutex);
1412
28
  mutex_unlock(&blocking_extension_mutex);
1413
28
  return r;
1414
}
1415
1416
// unblock unboxed is also safe for rmbr:ed things.
1417
bool lbm_unblock_ctx_unboxed(lbm_cid cid, lbm_value unboxed) {
1418
  mutex_lock(&blocking_extension_mutex);
1419
  bool r = false;
1420
  eval_context_t *found = NULL;
1421
  mutex_lock(&qmutex);
1422
  found = lookup_ctx_nm(&blocked, cid);
1423
  if (found && (LBM_IS_STATE_UNBLOCKABLE(found->state))) {
1424
    drop_ctx_nm(&blocked,found);
1425
    found->r = unboxed;
1426
    if (lbm_is_error(unboxed)) {
1427
      get_stack_ptr(found, 1)[0] = TERMINATE; // replace TOS
1428
      found->app_cont = true;
1429
    }
1430
    found->state = LBM_THREAD_STATE_READY;
1431
    enqueue_ctx_nm(&queue,found);
1432
    r = true;
1433
  }
1434
  mutex_unlock(&qmutex);
1435
  mutex_unlock(&blocking_extension_mutex);
1436
  return r;
1437
}
1438
1439
112
static bool lbm_block_ctx_base(bool timeout, float t_s) {
1440
112
  mutex_lock(&blocking_extension_mutex);
1441
112
  blocking_extension = true;
1442
112
  if (timeout) {
1443
    blocking_extension_timeout_us = S_TO_US(t_s);
1444
    blocking_extension_timeout = true;
1445
  } else {
1446
112
    blocking_extension_timeout = false;
1447
  }
1448
112
  return true;
1449
}
1450
1451
void lbm_block_ctx_from_extension_timeout(float s) {
1452
  lbm_block_ctx_base(true, s);
1453
}
1454
1455
112
void lbm_block_ctx_from_extension(void) {
1456
112
  lbm_block_ctx_base(false, 0);
1457
112
}
1458
1459
// todo: May need to pop rmbrs from stack, if present.
1460
// Suspect that the letting the discard cont run is really not a problem.
1461
// Either way will be quite confusing what happens to allocated things when undoing block.
1462
void lbm_undo_block_ctx_from_extension(void) {
1463
  blocking_extension = false;
1464
  blocking_extension_timeout_us = 0;
1465
  blocking_extension_timeout = false;
1466
  mutex_unlock(&blocking_extension_mutex);
1467
}
1468
1469
#define LBM_RECEIVER_FOUND 0
1470
#define LBM_RECEIVER_FOUND_MAIL_DELIVERY_FAILED -1
1471
#define LBM_RECEIVER_NOT_FOUND -2
1472
1473
11227
int lbm_find_receiver_and_send(lbm_cid cid, lbm_value msg) {
1474
11227
  mutex_lock(&qmutex);
1475
11227
  eval_context_t *found = NULL;
1476
1477
11227
  found = lookup_ctx_nm(&blocked, cid);
1478
11227
  if (found) {
1479
3004
    if (LBM_IS_STATE_RECV(found->state)) { // only if unblock receivers here.
1480
2990
      drop_ctx_nm(&blocked,found);
1481
2990
      found->state = LBM_THREAD_STATE_READY;
1482
2990
      enqueue_ctx_nm(&queue,found);
1483
    }
1484
3004
    if (!mailbox_add_mail(found, msg)) {
1485
      mutex_unlock(&qmutex);
1486
      return LBM_RECEIVER_FOUND_MAIL_DELIVERY_FAILED;
1487
    }
1488
3004
    mutex_unlock(&qmutex);
1489
3004
    return LBM_RECEIVER_FOUND;
1490
  }
1491
1492
8223
  found = lookup_ctx_nm(&queue, cid);
1493
8223
  if (found) {
1494
1000
    if (!mailbox_add_mail(found, msg)) {
1495
      mutex_unlock(&qmutex);
1496
      return LBM_RECEIVER_FOUND_MAIL_DELIVERY_FAILED;
1497
    }
1498
1000
    mutex_unlock(&qmutex);
1499
1000
    return LBM_RECEIVER_FOUND;
1500
  }
1501
1502
  /* check the current context */
1503

7223
  if (ctx_running && ctx_running->id == cid) {
1504
2996
    if (!mailbox_add_mail(ctx_running, msg)) {
1505
      mutex_unlock(&qmutex);
1506
      return LBM_RECEIVER_FOUND_MAIL_DELIVERY_FAILED;
1507
    }
1508
2996
    mutex_unlock(&qmutex);
1509
2996
    return LBM_RECEIVER_FOUND;
1510
  }
1511
4227
  mutex_unlock(&qmutex);
1512
4227
  return LBM_RECEIVER_NOT_FOUND;
1513
}
1514
1515
// a match binder looks like (? x) or (? _) for example.
1516
// It is a list of two elements where the first is a ? and the second is a symbol.
1517
23420
static inline lbm_value get_match_binder_variable(lbm_value exp) {
1518
23420
  lbm_value var = ENC_SYM_NIL; // 0 false
1519
23420
  if (lbm_is_cons(exp)) {
1520
15552
    lbm_cons_t *e_cell = lbm_ref_cell(exp);
1521
15552
    lbm_value bt = e_cell->car;
1522

15552
    if (bt == ENC_SYM_MATCH_ANY && lbm_is_cons(e_cell->cdr)) {
1523
8804
      var = lbm_ref_cell(e_cell->cdr)->car;
1524
    }
1525
  }
1526
23420
  return var;
1527
}
1528
1529
/* Pattern matching is currently implemented as a recursive
1530
   function and make use of stack relative to the size of
1531
   expressions that are being matched. */
1532
23420
static bool match(lbm_value p, lbm_value e, lbm_value *env, bool *gc) {
1533
23420
  bool r = false;
1534
23420
  lbm_value var = get_match_binder_variable(p);
1535
23420
  if (var) {
1536
8804
    lbm_value binding = lbm_cons(var, e);
1537
8804
    if (lbm_is_cons(binding)) {
1538
8792
      lbm_value new_env = lbm_cons(binding, *env);
1539
8792
      if (lbm_is_cons(new_env)) {
1540
8792
        *env = new_env;
1541
8792
        r = true;
1542
      }
1543
    }
1544
8804
    *gc = !r;
1545
14616
  } else  if (lbm_is_symbol(p)) {
1546
6188
    if (p == ENC_SYM_DONTCARE) r = true;
1547
4816
    else r = (p == e);
1548

8428
  } else if (lbm_is_cons(p) && lbm_is_cons(e) ) {
1549
5628
    lbm_cons_t *p_cell = lbm_ref_cell(p);
1550
5628
    lbm_cons_t *e_cell = lbm_ref_cell(e);
1551
5628
    lbm_value headp = p_cell->car;
1552
5628
    lbm_value tailp = p_cell->cdr;
1553
5628
    lbm_value heade = e_cell->car;
1554
5628
    lbm_value taile = e_cell->cdr;
1555
5628
    r = match(headp, heade, env, gc);
1556

5628
    r = r && match (tailp, taile, env, gc);
1557
  } else {
1558
2800
    r = struct_eq(p, e);
1559
  }
1560
23420
  return r;
1561
}
1562
1563
// Find match is not very picky about syntax.
1564
// A completely malformed recv form is most likely to
1565
// just return no_match.
1566
5630
static int find_match(lbm_value plist, lbm_value *earr, lbm_uint num, lbm_value *e, lbm_value *env) {
1567
1568
  // A pattern list is a list of pattern, expression lists.
1569
  // ( (p1 e1) (p2 e2) ... (pn en))
1570
5630
  lbm_value curr_p = plist;
1571
5630
  int n = 0;
1572
5630
  bool gc = false;
1573
6174
  for (int i = 0; i < (int)num; i ++ ) {
1574
6144
    lbm_value curr_e = earr[i];
1575
7416
    while (!lbm_is_symbol_nil(curr_p)) {
1576
6872
      lbm_value me = get_car(curr_p);
1577
6872
      if (match(get_car(me), curr_e, env, &gc)) {
1578
5600
        if (gc) return FM_NEED_GC;
1579
5600
        *e = get_cadr(me);
1580
1581
5600
        if (!lbm_is_symbol_nil(get_cadr(get_cdr(me)))) {
1582
          return FM_PATTERN_ERROR;
1583
        }
1584
5600
        return n;
1585
      }
1586
1272
      curr_p = get_cdr(curr_p);
1587
    }
1588
544
    curr_p = plist;       /* search all patterns against next exp */
1589
544
    n ++;
1590
  }
1591
1592
30
  return FM_NO_MATCH;
1593
}
1594
1595
/****************************************************/
1596
/* Garbage collection                               */
1597
1598
361077
static void mark_context(eval_context_t *ctx, void *arg1, void *arg2) {
1599
  (void) arg1;
1600
  (void) arg2;
1601
361077
  lbm_value roots[3] = {ctx->curr_exp, ctx->program, ctx->r };
1602
361077
  lbm_gc_mark_env(ctx->curr_env);
1603
361077
  lbm_gc_mark_roots(roots, 3);
1604
361077
  lbm_gc_mark_roots(ctx->mailbox, ctx->num_mail);
1605
361077
  lbm_gc_mark_aux(ctx->K.data, ctx->K.sp);
1606
361077
}
1607
1608
347919
static int gc(void) {
1609
347919
  if (ctx_running) {
1610
347891
    ctx_running->state = ctx_running->state | LBM_THREAD_STATE_GC_BIT;
1611
  }
1612
1613
347919
  gc_requested = false;
1614
347919
  lbm_gc_state_inc();
1615
1616
  // The freelist should generally be NIL when GC runs.
1617
347919
  lbm_nil_freelist();
1618
347919
  lbm_value *env = lbm_get_global_env();
1619
11481327
  for (int i = 0; i < GLOBAL_ENV_ROOTS; i ++) {
1620
11133408
    lbm_gc_mark_env(env[i]);
1621
  }
1622
1623
347919
  mutex_lock(&qmutex); // Lock the queues.
1624
                       // Any concurrent messing with the queues
1625
                       // while doing GC cannot possibly be good.
1626
347919
  queue_iterator_nm(&queue, mark_context, NULL, NULL);
1627
347919
  queue_iterator_nm(&blocked, mark_context, NULL, NULL);
1628
1629
347919
  if (ctx_running) {
1630
347891
    mark_context(ctx_running, NULL, NULL);
1631
  }
1632
347919
  mutex_unlock(&qmutex);
1633
1634
#ifdef VISUALIZE_HEAP
1635
  heap_vis_gen_image();
1636
#endif
1637
1638
347919
  int r = lbm_gc_sweep_phase();
1639
347919
  lbm_heap_new_freelist_length();
1640
347919
  lbm_memory_update_min_free();
1641
1642
347919
  if (ctx_running) {
1643
347891
    ctx_running->state = ctx_running->state & ~LBM_THREAD_STATE_GC_BIT;
1644
  }
1645
347919
  return r;
1646
}
1647
1648
13812
int lbm_perform_gc(void) {
1649
13812
  return gc();
1650
}
1651
1652
/****************************************************/
1653
/* Evaluation functions                             */
1654
1655
1656
224413008
static void eval_symbol(eval_context_t *ctx) {
1657
224413008
  lbm_uint s = lbm_dec_sym(ctx->curr_exp);
1658
224413008
  if (s >= RUNTIME_SYMBOLS_START) {
1659
145531798
    lbm_value res = ENC_SYM_NIL;
1660

171579224
    if (lbm_env_lookup_b(&res, ctx->curr_exp, ctx->curr_env) ||
1661
26047426
        lbm_global_env_lookup(&res, ctx->curr_exp)) {
1662
145526926
      ctx->r =  res;
1663
145526926
      ctx->app_cont = true;
1664
145526926
      return;
1665
    }
1666
    // Dynamic load attempt
1667
    // Only symbols of kind RUNTIME can be dynamically loaded.
1668
4872
    const char *sym_str = lbm_get_name_by_symbol(s);
1669
4872
    const char *code_str = NULL;
1670
4872
    if (!dynamic_load_callback(sym_str, &code_str)) {
1671
56
      error_at_ctx(ENC_SYM_NOT_FOUND, ctx->curr_exp);
1672
    }
1673
4816
    lbm_value *sptr = stack_reserve(ctx, 3);
1674
4816
    sptr[0] = ctx->curr_exp;
1675
4816
    sptr[1] = ctx->curr_env;
1676
4816
    sptr[2] = RESUME;
1677
1678
4816
    lbm_value chan = ENC_SYM_NIL;
1679
#ifdef LBM_ALWAYS_GC
1680
    gc();
1681
#endif
1682
4816
    if (!create_string_channel((char *)code_str, &chan, ENC_SYM_NIL)) {
1683
      gc();
1684
      if (!create_string_channel((char *)code_str, &chan, ENC_SYM_NIL)) {
1685
        error_ctx(ENC_SYM_MERROR);
1686
      }
1687
    }
1688
1689
    // Here, chan has either been assigned or execution has terminated.
1690
1691
    lbm_value loader;
1692

4816
    WITH_GC_RMBR_1(loader, lbm_heap_allocate_list_init(2,
1693
                                                       ENC_SYM_READ,
1694
                                                       chan), chan);
1695
    lbm_value evaluator;
1696

4816
    WITH_GC_RMBR_1(evaluator, lbm_heap_allocate_list_init(2,
1697
                                                          ENC_SYM_EVAL,
1698
                                                          loader), loader);
1699
4816
    ctx->curr_exp = evaluator;
1700
4816
    ctx->curr_env = ENC_SYM_NIL; // dynamics should be evaluable in empty local env
1701
  } else {
1702
    //special symbols and extensions can be handled the same way.
1703
78881210
    ctx->r = ctx->curr_exp;
1704
78881210
    ctx->app_cont = true;
1705
  }
1706
}
1707
1708
// (quote e) => e
1709
4660835
static void eval_quote(eval_context_t *ctx) {
1710
4660835
  ctx->r = get_cadr(ctx->curr_exp);
1711
4660835
  ctx->app_cont = true;
1712
4660835
}
1713
1714
// a => a
1715
96779339
static void eval_selfevaluating(eval_context_t *ctx) {
1716
96779339
  ctx->r = ctx->curr_exp;
1717
96779339
  ctx->app_cont = true;
1718
96779339
}
1719
1720
// (progn e1 ... en)
1721
14310694
static void eval_progn(eval_context_t *ctx) {
1722
14310694
  lbm_value exps = get_cdr(ctx->curr_exp);
1723
1724
14310694
  if (lbm_is_cons(exps)) {
1725
14310666
    lbm_cons_t *cell = lbm_ref_cell(exps); // already checked that it's cons.
1726
14310666
    ctx->curr_exp = cell->car;
1727
14310666
    if (lbm_is_cons(cell->cdr)) { // malformed progn not ending in nil is tolerated
1728
11508482
      lbm_uint *sptr = stack_reserve(ctx, 4);
1729
11508482
      sptr[0] = ctx->curr_env; // env to restore between expressions in progn
1730
11508482
      sptr[1] = lbm_enc_u(0);  // Has env been copied (needed for progn local bindings)
1731
11508482
      sptr[2] = cell->cdr;     // Requirement: sptr[2] is a cons.
1732
11508482
      sptr[3] = PROGN_REST;
1733
    }
1734
28
  } else if (lbm_is_symbol_nil(exps)) { // Empty progn is nil
1735
28
    ctx->r = ENC_SYM_NIL;
1736
28
    ctx->app_cont = true;
1737
  } else {
1738
    error_ctx(ENC_SYM_EERROR);
1739
  }
1740
14310694
}
1741
1742
// (atomic e1 ... en)
1743
252
static void eval_atomic(eval_context_t *ctx) {
1744
252
  if (is_atomic) atomic_error();
1745
252
  stack_reserve(ctx, 1)[0] = EXIT_ATOMIC;
1746
252
  is_atomic = true;
1747
252
  eval_progn(ctx);
1748
252
}
1749
1750
/* (call-cc (lambda (k) .... ))  */
1751
364
static void eval_callcc(eval_context_t *ctx) {
1752
  lbm_value cont_array;
1753
364
  lbm_uint *sptr0 = stack_reserve(ctx, 1);
1754
364
  sptr0[0] = is_atomic ? ENC_SYM_TRUE : ENC_SYM_NIL;
1755
#ifdef LBM_ALWAYS_GC
1756
  gc();
1757
#endif
1758
364
  if (!lbm_heap_allocate_lisp_array(&cont_array, ctx->K.sp)) {
1759
    gc();
1760
    lbm_heap_allocate_lisp_array(&cont_array, ctx->K.sp);
1761
  }
1762
364
  if (lbm_is_ptr(cont_array)) {
1763
364
    lbm_array_header_t *arr = assume_array(cont_array);
1764
364
    memcpy(arr->data, ctx->K.data, ctx->K.sp * sizeof(lbm_uint));
1765
    // The stored stack contains the is_atomic flag.
1766
    // This flag is overwritten in the following execution path.
1767
1768
364
    lbm_value acont = cons_with_gc(ENC_SYM_CONT, cont_array, ENC_SYM_NIL);
1769
364
    lbm_value arg_list = cons_with_gc(acont, ENC_SYM_NIL, ENC_SYM_NIL);
1770
    // Go directly into application evaluation without passing go
1771
364
    lbm_uint *sptr = stack_reserve(ctx, 2);
1772
364
    sptr0[0] = ctx->curr_env;
1773
364
    sptr[0] = arg_list;
1774
364
    sptr[1] = APPLICATION_START;
1775
364
    ctx->curr_exp = get_cadr(ctx->curr_exp);
1776
  } else {
1777
    // failed to create continuation array.
1778
    error_ctx(ENC_SYM_MERROR);
1779
  }
1780
364
}
1781
1782
// (define sym exp)
1783
#define KEY 1
1784
#define VAL 2
1785
4267704
static void eval_define(eval_context_t *ctx) {
1786
  lbm_value parts[3];
1787
4267704
  lbm_value rest = extract_n(ctx->curr_exp, parts, 3);
1788
4267704
  lbm_uint *sptr = stack_reserve(ctx, 2);
1789

4267704
  if (lbm_is_symbol(parts[KEY]) && lbm_is_symbol_nil(rest)) {
1790
4267704
    lbm_uint sym_val = lbm_dec_sym(parts[KEY]);
1791
4267704
    sptr[0] = parts[KEY];
1792
4267704
    if (sym_val >= RUNTIME_SYMBOLS_START) {
1793
4267704
      sptr[1] = SET_GLOBAL_ENV;
1794
4267704
      if (ctx->flags & EVAL_CPS_CONTEXT_FLAG_CONST) {
1795
14
        stack_reserve(ctx, 1)[0] = MOVE_VAL_TO_FLASH_DISPATCH;
1796
      }
1797
4267704
      ctx->curr_exp = parts[VAL];
1798
4267704
      return;
1799
    }
1800
  }
1801
  error_at_ctx(ENC_SYM_EERROR, ctx->curr_exp);
1802
}
1803
1804
1805
/* Eval lambda is cheating, a lot! It does this
1806
   for performance reasons. The cheats are that
1807
   1. When  closure is created, a reference to the local env
1808
   in which the lambda was evaluated is added to the closure.
1809
   Ideally it should have created a list of free variables in the function
1810
   and then looked up the values of these creating a new environment.
1811
   2. The global env is considered global constant. As there is no copying
1812
   of environment bindings into the closure, undefine may break closures.
1813
1814
   Correct closure creation is a lot more expensive than what happens here.
1815
   However, one can try to write programs in such a way that closures are created
1816
   seldomly. If one does that the space-usage benefits of "correct" closures
1817
   may outweigh the performance gain of "incorrect" ones.
1818
1819
   some obscure programs such as test_setq_local_closure.lisp does not
1820
   work properly due to this cheating.
1821
 */
1822
// (lambda param-list body-exp) -> (closure param-list body-exp env)
1823
12012
static void eval_lambda(eval_context_t *ctx) {
1824
  lbm_value vals[3];
1825
12012
  extract_n(ctx->curr_exp, vals, 3);
1826
12012
  ctx->r = allocate_closure(vals[1],vals[2], ctx->curr_env);
1827
#ifdef CLEAN_UP_CLOSURES
1828
  lbm_uint sym_id  = 0;
1829
  if (clean_cl_env_symbol) {
1830
    lbm_value tail = cons_with_gc(ctx->r, ENC_SYM_NIL, ENC_SYM_NIL);
1831
    lbm_value app = cons_with_gc(clean_cl_env_symbol, tail, tail);
1832
    ctx->curr_exp = app;
1833
  } else if (lbm_get_symbol_by_name("clean-cl-env", &sym_id)) {
1834
    clean_cl_env_symbol = lbm_enc_sym(sym_id);
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 {
1839
    ctx->app_cont = true;
1840
  }
1841
#else
1842
12012
  ctx->app_cont = true;
1843
#endif
1844
12012
}
1845
1846
// (if cond-expr then-expr else-expr)
1847
21762204
static void eval_if(eval_context_t *ctx) {
1848
21762204
  lbm_value cdr = get_cdr(ctx->curr_exp);
1849
21762204
  lbm_value *sptr = stack_reserve(ctx, 3);
1850
21762204
  sptr[0] = get_cdr(cdr);
1851
21762204
  sptr[1] = ctx->curr_env;
1852
21762204
  sptr[2] = IF;
1853
21762204
  ctx->curr_exp = get_car(cdr);
1854
21762204
}
1855
1856
// (cond (cond-expr-1 expr-1)
1857
//         ...
1858
//       (cond-expr-N expr-N))
1859
1316
static void eval_cond(eval_context_t *ctx) {
1860
  lbm_value cond1[2];
1861
1316
  lbm_value rest_conds = extract_n(ctx->curr_exp, cond1, 2);
1862
1863
  // end recursion at (cond )
1864
1316
  if (lbm_is_symbol_nil(cond1[1])) {
1865
28
    ctx->r = ENC_SYM_NIL;
1866
28
    ctx->app_cont = true;
1867
  } else {
1868
    // Cond is one of the few places where a bit of syntax checking takes place at runtime..
1869
    // Maybe dont bother?
1870
1288
    lbm_uint len = lbm_list_length(cond1[1]);
1871
1288
    if (len != 2) {
1872
      lbm_set_error_reason("Incorrect syntax in cond");
1873
      error_ctx(ENC_SYM_EERROR);
1874
    }
1875
    lbm_value cond_expr[2];
1876
1288
    extract_n(cond1[1], cond_expr, 2);
1877
    lbm_value rest;
1878

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

26935440
    if (key == ENC_SYM_NIL || key == ENC_SYM_DONTCARE) return BL_OK;
1898
    lbm_value binding;
1899
    lbm_value new_env_tmp;
1900
21325332
    binding = lbm_cons(key, ENC_SYM_PLACEHOLDER);
1901
21325332
    new_env_tmp = lbm_cons(binding, *env);
1902

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

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

643566
    if (IS_CONTINUATION(sv) && (sv == PROGN_REST)) {
1993
643566
      lbm_uint sp = ctx->K.sp;
1994
643566
      uint32_t is_copied = lbm_dec_as_u32(ctx->K.data[sp-3]);
1995
643566
      if (is_copied == 0) {
1996
        lbm_value env;
1997

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

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

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

1775760
    if (lbm_is_symbol(new_env) && new_env == ENC_SYM_NOT_FOUND) {
2321
841372
      lbm_uint ix_key = lbm_dec_sym(key) & GLOBAL_ENV_MASK;
2322
841372
      lbm_value *glob_env = lbm_get_global_env();
2323
841372
      new_env = lbm_env_modify_binding(glob_env[ix_key], key, val);
2324
841372
      glob_env[ix_key] = new_env;
2325
    }
2326

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

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

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

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

330428
    if (!program && !incremental) {
2394
297080
      rptr[0] = READING_EXPRESSION;
2395

33348
    } else if (program && !incremental) {
2396
11228
      rptr[0] = READING_PROGRAM;
2397

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

2128
  if (nargs >= 1 &&
2454
1064
      lbm_is_closure(args[0])) {
2455
840
    closure_pos = 0;
2456

448
  } else if (nargs >= 2 &&
2457
308
      lbm_is_number(args[0]) &&
2458
84
      lbm_is_closure(args[1])) {
2459
84
    stack_size = lbm_dec_as_u32(args[0]);
2460
84
    closure_pos = 1;
2461

280
  } else if (nargs >= 2 &&
2462
280
             lbm_is_array_r(args[0]) &&
2463
140
             lbm_is_closure(args[1])) {
2464
    name = lbm_dec_str(args[0]);
2465
    closure_pos = 1;
2466

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

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

56804
  if (nargs == 1 && lbm_is_number(args[0])) {
2518
28402
    lbm_uint ts = lbm_dec_as_u32(args[0]);
2519
28402
    lbm_stack_drop(&ctx->K, nargs+1);
2520
28402
    yield_ctx(ts);
2521
  } else {
2522
    lbm_set_error_reason((char*)lbm_error_str_no_number);
2523
    error_at_ctx(ENC_SYM_TERROR, ENC_SYM_YIELD);
2524
  }
2525
28402
}
2526
2527
2127
static void apply_sleep(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2528

4226
  if (nargs == 1 && lbm_is_number(args[0])) {
2529
2127
    lbm_uint ts = (lbm_uint)(1000000.0f * lbm_dec_as_float(args[0]));
2530
2127
    lbm_stack_drop(&ctx->K, nargs+1);
2531
2127
    yield_ctx(ts);
2532
  } else {
2533
    lbm_set_error_reason((char*)lbm_error_str_no_number);
2534
    error_at_ctx(ENC_SYM_TERROR, ENC_SYM_SLEEP);
2535
  }
2536
2099
}
2537
2538
56
static void apply_wait(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2539

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

11452
  if (nargs == 1 || nargs == 2) {
2574
11452
    lbm_value prg = args[prg_pos]; // No check that this is a program.
2575
    lbm_value app_cont;
2576
    lbm_value app_cont_prg;
2577
    lbm_value new_prg;
2578
    lbm_value prg_copy;
2579
2580
11452
    int len = -1;
2581

11452
    WITH_GC(prg_copy, lbm_list_copy(&len, prg));
2582
11452
    lbm_stack_drop(&ctx->K, nargs+1);
2583
    // There is always a continuation (DONE).
2584
    // If ctx->program is nil, the stack should contain DONE.
2585
    // after adding an intermediate done for prg, stack becomes DONE, DONE.
2586
11452
    app_cont = cons_with_gc(ENC_SYM_APP_CONT, ENC_SYM_NIL, prg_copy);
2587
11452
    app_cont_prg = cons_with_gc(app_cont, ENC_SYM_NIL, prg_copy);
2588
11452
    new_prg = lbm_list_append(app_cont_prg, ctx->program);
2589
11452
    new_prg = lbm_list_append(prg_copy, new_prg);
2590
    // new_prg is guaranteed to be a cons cell or nil
2591
    // even if the eval-program application is syntactically broken.
2592
11452
    stack_reserve(ctx, 1)[0] = DONE;
2593
11452
    ctx->program = get_cdr(new_prg);
2594
11452
    ctx->curr_exp = get_car(new_prg);
2595
  } else {
2596
    lbm_set_error_reason((char*)lbm_error_str_num_args);
2597
    error_at_ctx(ENC_SYM_EERROR, ENC_SYM_EVAL_PROGRAM);
2598
  }
2599
11452
}
2600
2601
3332
static void apply_send(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2602
3332
  if (nargs == 2) {
2603
3332
    if (lbm_type_of(args[0]) == LBM_TYPE_I) {
2604
3332
      lbm_cid cid = (lbm_cid)lbm_dec_i(args[0]);
2605
3332
      lbm_value msg = args[1];
2606
3332
      int r = lbm_find_receiver_and_send(cid, msg);
2607
      /* return the status */
2608
3332
      lbm_stack_drop(&ctx->K, nargs+1);
2609
3332
      ctx->r = r == 0 ? ENC_SYM_TRUE : ENC_SYM_NIL;
2610
3332
      ctx->app_cont = true;
2611
    } else {
2612
      error_at_ctx(ENC_SYM_TERROR, ENC_SYM_SEND);
2613
    }
2614
  } else {
2615
    lbm_set_error_reason((char*)lbm_error_str_num_args);
2616
    error_at_ctx(ENC_SYM_EERROR, ENC_SYM_SEND);
2617
  }
2618
3332
}
2619
2620
static void apply_ok(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2621
  lbm_value ok_val = ENC_SYM_TRUE;
2622
  if (nargs >= 1) {
2623
    ok_val = args[0];
2624
  }
2625
  ctx->r = ok_val;
2626
  ok_ctx();
2627
}
2628
2629
28
static void apply_error(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2630
  (void) ctx;
2631
28
  lbm_value err_val = ENC_SYM_EERROR;
2632
28
  if (nargs >= 1) {
2633
28
    err_val = args[0];
2634
  }
2635
28
  error_at_ctx(err_val, ENC_SYM_EXIT_ERROR);
2636
}
2637
2638
// (map f arg-list)
2639
728
static void apply_map(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2640

728
  if (nargs == 2 && lbm_is_cons(args[1])) {
2641
616
    lbm_value *sptr = get_stack_ptr(ctx, 3);
2642
2643
616
    lbm_value f = args[0];
2644
616
    lbm_cons_t *args1_cell = lbm_ref_cell(args[1]);
2645
616
    lbm_value h = args1_cell->car;
2646
616
    lbm_value t = args1_cell->cdr;
2647
2648
    lbm_value appli_1;
2649
    lbm_value appli;
2650

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

616
    WITH_GC_RMBR_1(appli, lbm_heap_allocate_list(2), appli_1);
2652
2653
616
    lbm_value appli_0 = get_cdr(appli_1);
2654
2655
616
    lbm_set_car_and_cdr(appli_0, h, ENC_SYM_NIL);
2656
616
    lbm_set_car(appli_1, ENC_SYM_QUOTE);
2657
2658
616
    lbm_set_car_and_cdr(get_cdr(appli), appli_1, ENC_SYM_NIL);
2659
616
    lbm_set_car(appli, f);
2660
2661
616
    lbm_value elt = cons_with_gc(ctx->r, ENC_SYM_NIL, appli);
2662
616
    sptr[0] = t;     // reuse stack space
2663
616
    sptr[1] = ctx->curr_env;
2664
616
    sptr[2] = elt;
2665
616
    lbm_value *rptr = stack_reserve(ctx,4);
2666
616
    rptr[0] = elt;
2667
616
    rptr[1] = appli;
2668
616
    rptr[2] = appli_0;
2669
616
    rptr[3] = MAP;
2670
616
    ctx->curr_exp = appli;
2671

112
  } else if (nargs == 2 && lbm_is_symbol_nil(args[1])) {
2672
112
    lbm_stack_drop(&ctx->K, 3);
2673
112
    ctx->r = ENC_SYM_NIL;
2674
112
    ctx->app_cont = true;
2675
  } else {
2676
    lbm_set_error_reason((char*)lbm_error_str_num_args);
2677
    error_at_ctx(ENC_SYM_EERROR, ENC_SYM_MAP);
2678
  }
2679
728
}
2680
2681
140
static void apply_reverse(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2682

140
  if (nargs == 1 && lbm_is_list(args[0])) {
2683
140
    lbm_value curr = args[0];
2684
2685
140
    lbm_value new_list = ENC_SYM_NIL;
2686
3332
    while (lbm_is_cons(curr)) {
2687
3192
      lbm_cons_t *curr_cell = lbm_ref_cell(curr); // known cons.
2688
3192
      lbm_value tmp = cons_with_gc(curr_cell->car, new_list, ENC_SYM_NIL);
2689
3192
      new_list = tmp;
2690
3192
      curr = curr_cell->cdr;
2691
    }
2692
140
    lbm_stack_drop(&ctx->K, 2);
2693
140
    ctx->r = new_list;
2694
140
    ctx->app_cont = true;
2695
  } else {
2696
    lbm_set_error_reason("Reverse requires a list argument");
2697
    error_at_ctx(ENC_SYM_EERROR, ENC_SYM_REVERSE);
2698
  }
2699
140
}
2700
2701
34622
static void apply_flatten(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2702
34622
  if (nargs == 1) {
2703
#ifdef LBM_ALWAYS_GC
2704
    gc();
2705
#endif
2706
34594
    lbm_value v = flatten_value(args[0]);
2707
34594
    if ( v == ENC_SYM_MERROR) {
2708
2
      gc();
2709
2
      v = flatten_value(args[0]);
2710
    }
2711
2712
34594
    if (lbm_is_symbol(v)) {
2713
56
      error_at_ctx(v, ENC_SYM_FLATTEN);
2714
    } else {
2715
34538
      lbm_stack_drop(&ctx->K, 2);
2716
34538
      ctx->r = v;
2717
34538
      ctx->app_cont = true;
2718
    }
2719
34538
    return;
2720
  }
2721
28
  error_at_ctx(ENC_SYM_TERROR, ENC_SYM_FLATTEN);
2722
}
2723
2724
34510
static void apply_unflatten(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2725

34510
  if(nargs == 1 && lbm_type_of(args[0]) == LBM_TYPE_ARRAY) {
2726
    lbm_array_header_t *array;
2727
34510
    array = (lbm_array_header_t *)get_car(args[0]);
2728
2729
    lbm_flat_value_t fv;
2730
34510
    fv.buf = (uint8_t*)array->data;
2731
34510
    fv.buf_size = array->size;
2732
34510
    fv.buf_pos = 0;
2733
2734
    lbm_value res;
2735
2736
34510
    ctx->r = ENC_SYM_NIL;
2737
34510
    if (lbm_unflatten_value(&fv, &res)) {
2738
34510
      ctx->r =  res;
2739
    }
2740
34510
    lbm_stack_drop(&ctx->K, 2);
2741
34510
    ctx->app_cont = true;
2742
34510
    return;
2743
  }
2744
  error_at_ctx(ENC_SYM_TERROR, ENC_SYM_UNFLATTEN);
2745
}
2746
2747
84
static void apply_kill(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2748

84
  if (nargs == 2 && lbm_is_number(args[0])) {
2749
84
    lbm_cid cid = lbm_dec_as_i32(args[0]);
2750
2751
84
    if (ctx->id == cid) {
2752
      ctx->r = args[1];
2753
      finish_ctx();
2754
      return;
2755
    }
2756
84
    mutex_lock(&qmutex);
2757
84
    eval_context_t *found = NULL;
2758
84
    found = lookup_ctx_nm(&blocked, cid);
2759
84
    if (found)
2760
      drop_ctx_nm(&blocked, found);
2761
    else
2762
84
      found = lookup_ctx_nm(&queue, cid);
2763
84
    if (found)
2764
84
      drop_ctx_nm(&queue, found);
2765
2766
84
    if (found) {
2767
84
      found->K.data[found->K.sp - 1] = KILL;
2768
84
      found->r = args[1];
2769
84
      found->app_cont = true;
2770
84
      found->state = LBM_THREAD_STATE_READY;
2771
84
      enqueue_ctx_nm(&queue,found);
2772
84
      ctx->r = ENC_SYM_TRUE;
2773
    } else {
2774
      ctx->r = ENC_SYM_NIL;
2775
    }
2776
84
    lbm_stack_drop(&ctx->K, 3);
2777
84
    ctx->app_cont = true;
2778
84
    mutex_unlock(&qmutex);
2779
84
    return;
2780
  }
2781
  error_at_ctx(ENC_SYM_TERROR, ENC_SYM_KILL);
2782
}
2783
2784
282828
static lbm_value cmp_to_clo(lbm_value cmp) {
2785
  lbm_value closure;
2786

282828
  WITH_GC(closure, lbm_heap_allocate_list(4));
2787
282828
  lbm_set_car(closure, ENC_SYM_CLOSURE);
2788
282828
  lbm_value cl1 = lbm_cdr(closure);
2789
  lbm_value par;
2790

282828
  WITH_GC_RMBR_1(par, lbm_heap_allocate_list_init(2, symbol_x, symbol_y), closure);
2791
282828
  lbm_set_car(cl1, par);
2792
282828
  lbm_value cl2 = lbm_cdr(cl1);
2793
  lbm_value body;
2794

282828
  WITH_GC_RMBR_1(body, lbm_heap_allocate_list_init(3, cmp, symbol_x, symbol_y), closure);
2795
282828
  lbm_set_car(cl2, body);
2796
282828
  lbm_value cl3 = lbm_cdr(cl2);
2797
282828
  lbm_set_car(cl3, ENC_SYM_NIL);
2798
282828
  return closure;
2799
}
2800
2801
// (merge comparator list1 list2)
2802
420
static void apply_merge(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2803

420
  if (nargs == 3 && lbm_is_list(args[1]) && lbm_is_list(args[2])) {
2804
2805
420
    if (!lbm_is_closure(args[0])) {
2806
28
      args[0] = cmp_to_clo(args[0]);
2807
    }
2808
2809
    // Copy input lists for functional behaviour at top-level
2810
    // merge itself is in-place in the copied lists.
2811
    lbm_value a;
2812
    lbm_value b;
2813
420
    int len_a = -1;
2814
420
    int len_b = -1;
2815

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

420
    WITH_GC_RMBR_1(b, lbm_list_copy(&len_b, args[2]), a);
2817
2818
420
    if (len_a == 0) {
2819
56
      ctx->r = b;
2820
56
      lbm_stack_drop(&ctx->K, 4);
2821
56
      ctx->app_cont = true;
2822
56
      return;
2823
    }
2824
364
    if (len_b == 0) {
2825
56
      ctx->r = a;
2826
56
      lbm_stack_drop(&ctx->K, 4);
2827
56
      ctx->app_cont = true;
2828
56
      return;
2829
    }
2830
2831
308
    args[1] = a; // keep safe by replacing the original on stack.
2832
308
    args[2] = b;
2833
2834
308
    lbm_value a_1 = a;
2835
308
    lbm_value a_rest = lbm_cdr(a);
2836
308
    lbm_value b_1 = b;
2837
308
    lbm_value b_rest = lbm_cdr(b);
2838
2839
    lbm_value cl[3]; // Comparator closure
2840
308
    extract_n(lbm_cdr(args[0]), cl, 3);
2841
308
    lbm_value cmp_env = cl[CLO_ENV];
2842
308
    lbm_value par1 = ENC_SYM_NIL;
2843
308
    lbm_value par2 = ENC_SYM_NIL;
2844
308
    lbm_uint len = lbm_list_length(cl[CLO_PARAMS]);
2845
308
    if (len == 2) {
2846
308
      par1 = get_car(cl[CLO_PARAMS]);
2847
308
      par2 = get_cadr(cl[CLO_PARAMS]);
2848
      lbm_value new_env0;
2849
      lbm_value new_env;
2850

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

308
      WITH_GC_RMBR_1(new_env, lbm_env_set(new_env0, par2, lbm_car(b_1)),new_env0);
2852
308
      cmp_env = new_env;
2853
    } else {
2854
      error_at_ctx(ENC_SYM_TERROR, args[0]);
2855
    }
2856
308
    lbm_set_cdr(a_1, b_1);
2857
308
    lbm_set_cdr(b_1, ENC_SYM_NIL);
2858
308
    lbm_value cmp = cl[CLO_BODY];
2859
2860
308
    lbm_stack_drop(&ctx->K, 4); // TODO: Optimize drop 4 alloc 10 into alloc 6
2861
308
    lbm_uint *sptr = stack_reserve(ctx, 10);
2862
308
    sptr[0] = ENC_SYM_NIL; // head of merged list
2863
308
    sptr[1] = ENC_SYM_NIL; // last of merged list
2864
308
    sptr[2] = a_1;
2865
308
    sptr[3] = a_rest;
2866
308
    sptr[4] = b_rest;
2867
308
    sptr[5] = cmp;
2868
308
    sptr[6] = cmp_env;
2869
308
    sptr[7] = par1;
2870
308
    sptr[8] = par2;
2871
308
    sptr[9] = MERGE_REST;
2872
308
    ctx->curr_exp = cl[CLO_BODY];
2873
308
    ctx->curr_env = cmp_env;
2874
308
    return;
2875
  }
2876
  error_at_ctx(ENC_SYM_TERROR, ENC_SYM_MERGE);
2877
}
2878
2879
// (sort comparator list)
2880
283136
static void apply_sort(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2881

283136
  if (nargs == 2 && lbm_is_list(args[1])) {
2882
2883
283136
    if (!lbm_is_closure(args[0])) {
2884
282800
      args[0] = cmp_to_clo(args[0]);
2885
    }
2886
2887
283136
    int len = -1;
2888
    lbm_value list_copy;
2889

283136
    WITH_GC(list_copy, lbm_list_copy(&len, args[1]));
2890
283136
    if (len <= 1) {
2891
28
      lbm_stack_drop(&ctx->K, 3);
2892
28
      ctx->r = list_copy;
2893
28
      ctx->app_cont = true;
2894
28
      return;
2895
    }
2896
2897
283108
    args[1] = list_copy; // Keep safe, original replaced on stack.
2898
2899
    // Take the headmost 2, 1-element sublists.
2900
283108
    lbm_value a = list_copy;
2901
283108
    lbm_value b = lbm_cdr(a);
2902
283108
    lbm_value rest = lbm_cdr(b);
2903
    // Do not terminate b. keep rest of list safe from GC in the following
2904
    // closure extraction.
2905
    //lbm_set_cdr(a, b); // This is void
2906
2907
    lbm_value cl[3]; // Comparator closure
2908
283108
    extract_n(lbm_cdr(args[0]), cl, 3);
2909
283108
    lbm_value cmp_env = cl[CLO_ENV];
2910
283108
    lbm_value par1 = ENC_SYM_NIL;
2911
283108
    lbm_value par2 = ENC_SYM_NIL;
2912
283108
    lbm_uint cl_len = lbm_list_length(cl[CLO_PARAMS]);
2913
283108
    if (cl_len == 2) {
2914
283108
      par1 = get_car(cl[CLO_PARAMS]);
2915
283108
      par2 = get_cadr(cl[CLO_PARAMS]);
2916
      lbm_value new_env0;
2917
      lbm_value new_env;
2918

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

283108
      WITH_GC_RMBR_1(new_env, lbm_env_set(new_env0, par2, lbm_car(b)), new_env0);
2920
283108
      cmp_env = new_env;
2921
    } else {
2922
      error_at_ctx(ENC_SYM_TERROR, args[0]);
2923
    }
2924
283108
    lbm_value cmp = cl[CLO_BODY];
2925
2926
    // Terminate the comparator argument list.
2927
283108
    lbm_set_cdr(b, ENC_SYM_NIL);
2928
2929
283108
    lbm_stack_drop(&ctx->K, 3);  //TODO: optimize drop 3, alloc 20 into alloc 17
2930
283108
    lbm_uint *sptr = stack_reserve(ctx, 20);
2931
283108
    sptr[0] = cmp;
2932
283108
    sptr[1] = cmp_env;
2933
283108
    sptr[2] = par1;
2934
283108
    sptr[3] = par2;
2935
283108
    sptr[4] = ENC_SYM_NIL; // head of merged accumulation of sublists
2936
283108
    sptr[5] = ENC_SYM_NIL; // last of merged accumulation of sublists
2937
283108
    sptr[6] = rest;
2938
283108
    sptr[7] = lbm_enc_i(1);
2939
283108
    sptr[8] = lbm_enc_i(len); //TODO: 28 bit i vs 32 bit i
2940
283108
    sptr[9] = MERGE_LAYER;
2941
283108
    sptr[10] = ENC_SYM_NIL; // head of merged sublist
2942
283108
    sptr[11] = ENC_SYM_NIL; // last of merged sublist
2943
283108
    sptr[12] = a;
2944
283108
    sptr[13] = ENC_SYM_NIL; // no a_rest, 1 element lists in layer 1.
2945
283108
    sptr[14] = ENC_SYM_NIL; // no b_rest, 1 element lists in layer 1.
2946
283108
    sptr[15] = cmp;
2947
283108
    sptr[16] = cmp_env;
2948
283108
    sptr[17] = par1;
2949
283108
    sptr[18] = par2;
2950
283108
    sptr[19] = MERGE_REST;
2951
283108
    ctx->curr_exp = cmp;
2952
283108
    ctx->curr_env = cmp_env;
2953
283108
    return;
2954
  }
2955
  error_ctx(ENC_SYM_TERROR);
2956
}
2957
2958
616308
static void apply_rest_args(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2959
  lbm_value res;
2960
616308
  if (lbm_env_lookup_b(&res, ENC_SYM_REST_ARGS, ctx->curr_env)) {
2961

616280
    if (nargs == 1 && lbm_is_number(args[0])) {
2962
56140
      int32_t ix = lbm_dec_as_i32(args[0]);
2963
56140
      res = lbm_index_list(res, ix);
2964
    }
2965
616280
    ctx->r = res;
2966
  } else {
2967
28
    ctx->r = ENC_SYM_NIL;
2968
  }
2969
616308
  lbm_stack_drop(&ctx->K, nargs+1);
2970
616308
  ctx->app_cont = true;
2971
616308
}
2972
2973
/* (rotate list-expr dist/dir-expr) */
2974
84
static void apply_rotate(lbm_value *args, lbm_uint nargs, eval_context_t *ctx) {
2975

84
  if (nargs == 2 && lbm_is_list(args[0]) && lbm_is_number(args[1])) {
2976
84
    int len = -1;
2977
    lbm_value ls;
2978

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

84
    if (len > 0 && dist != 0) {
2981
56
      int d = dist;
2982
56
      if (dist > 0) {
2983
28
        ls = lbm_list_destructive_reverse(ls);
2984
      } else {
2985
28
        d = -dist;
2986
      }
2987
2988
56
      lbm_value start = ls;
2989
56
      lbm_value end = ENC_SYM_NIL;
2990
56
      lbm_value curr = start;
2991
308
      while (lbm_is_cons(curr)) {
2992
252
        end = curr;
2993
252
        curr = get_cdr(curr);
2994
      }
2995
2996
168
      for (int i = 0; i < d; i ++) {
2997
112
        lbm_value a = start;
2998
112
        start = lbm_cdr(start);
2999
112
        lbm_set_cdr(a, ENC_SYM_NIL);
3000
112
        lbm_set_cdr(end, a);
3001
112
        end = a;
3002
      }
3003
56
      ls = start;
3004
56
      if (dist > 0) {
3005
28
        ls = lbm_list_destructive_reverse(ls);
3006
      }
3007
    }
3008
84
    lbm_stack_drop(&ctx->K, nargs+1);
3009
84
    ctx->app_cont = true;
3010
84
    ctx->r = ls;
3011
84
    return;
3012
  }
3013
  error_ctx(ENC_SYM_EERROR);
3014
}
3015
3016
/***************************************************/
3017
/* Application lookup table                        */
3018
3019
typedef void (*apply_fun)(lbm_value *, lbm_uint, eval_context_t *);
3020
static const apply_fun fun_table[] =
3021
  {
3022
   apply_setvar,
3023
   apply_read,
3024
   apply_read_program,
3025
   apply_read_eval_program,
3026
   apply_spawn,
3027
   apply_spawn_trap,
3028
   apply_yield,
3029
   apply_wait,
3030
   apply_eval,
3031
   apply_eval_program,
3032
   apply_send,
3033
   apply_ok,
3034
   apply_error,
3035
   apply_map,
3036
   apply_reverse,
3037
   apply_flatten,
3038
   apply_unflatten,
3039
   apply_kill,
3040
   apply_sleep,
3041
   apply_merge,
3042
   apply_sort,
3043
   apply_rest_args,
3044
   apply_rotate,
3045
  };
3046
3047
/***************************************************/
3048
/* Application of function that takes arguments    */
3049
/* passed over the stack.                          */
3050
3051
77994101
static void application(eval_context_t *ctx, lbm_value *fun_args, lbm_uint arg_count) {
3052
  /* If arriving here, we know that the fun is a symbol.
3053
   *  and can be a built in operation or an extension.
3054
   */
3055
77994101
  lbm_value fun = fun_args[0];
3056
3057
77994101
  lbm_uint fun_val = lbm_dec_sym(fun);
3058
77994101
  lbm_uint fun_kind = SYMBOL_KIND(fun_val);
3059
3060

77994101
  switch (fun_kind) {
3061
186507
  case SYMBOL_KIND_EXTENSION: {
3062
186507
    extension_fptr f = extension_table[SYMBOL_IX(fun_val)].fptr;
3063
3064
    lbm_value ext_res;
3065

186507
    WITH_GC(ext_res, f(&fun_args[1], arg_count));
3066
186507
    if (lbm_is_error(ext_res)) { //Error other than merror
3067
2996
      error_at_ctx(ext_res, fun);
3068
    }
3069
183511
    lbm_stack_drop(&ctx->K, arg_count + 1);
3070
3071
183511
    ctx->app_cont = true;
3072
183511
    ctx->r = ext_res;
3073
3074
183511
    if (blocking_extension) {
3075
112
      if (is_atomic) {
3076
        // Check atomic_error explicitly so that the mutex
3077
        // can be released if there is an error.
3078
        blocking_extension = false;
3079
        mutex_unlock(&blocking_extension_mutex);
3080
        atomic_error();
3081
      }
3082
112
      blocking_extension = false;
3083
112
      if (blocking_extension_timeout) {
3084
        blocking_extension_timeout = false;
3085
        block_current_ctx(LBM_THREAD_STATE_TIMEOUT, blocking_extension_timeout_us,true);
3086
      } else {
3087
112
        block_current_ctx(LBM_THREAD_STATE_BLOCKED, 0,true);
3088
      }
3089
112
      mutex_unlock(&blocking_extension_mutex);
3090
    }
3091
183511
  }  break;
3092
73278613
  case SYMBOL_KIND_FUNDAMENTAL:
3093
73278613
    call_fundamental(SYMBOL_IX(fun_val), &fun_args[1], arg_count, ctx);
3094
73273957
    break;
3095
4528981
  case SYMBOL_KIND_APPFUN:
3096
4528981
    fun_table[SYMBOL_IX(fun_val)](&fun_args[1], arg_count, ctx);
3097
4528561
    break;
3098
  default:
3099
    // Symbols that are "special" but not in the way caught above
3100
    // ends up here.
3101
    lbm_set_error_reason("Symbol does not represent a function");
3102
    error_at_ctx(ENC_SYM_EERROR,fun_args[0]);
3103
    break;
3104
  }
3105
77986029
}
3106
3107
59422901
static void cont_closure_application_args(eval_context_t *ctx) {
3108
59422901
  lbm_uint* sptr = get_stack_ptr(ctx, 5);
3109
3110
59422901
  lbm_value arg_env = (lbm_value)sptr[0];
3111
59422901
  lbm_value exp     = (lbm_value)sptr[1];
3112
59422901
  lbm_value clo_env = (lbm_value)sptr[2];
3113
59422901
  lbm_value params  = (lbm_value)sptr[3];
3114
59422901
  lbm_value args    = (lbm_value)sptr[4];
3115
3116
  lbm_value car_params, cdr_params;
3117
59422901
  get_car_and_cdr(params, &car_params, &cdr_params);
3118
3119
59422901
  bool a_nil = lbm_is_symbol_nil(args);
3120
59422901
  bool p_nil = lbm_is_symbol_nil(cdr_params);
3121
3122
59422901
  lbm_value binder = allocate_binding(car_params, ctx->r, clo_env);
3123
3124

59422873
  if (!a_nil && !p_nil) {
3125
    lbm_value car_args, cdr_args;
3126
33209876
    get_car_and_cdr(args, &car_args, &cdr_args);
3127
33209876
    sptr[2] = binder;
3128
33209876
    sptr[3] = cdr_params;
3129
33209876
    sptr[4] = cdr_args;
3130
33209876
    stack_reserve(ctx,1)[0] = CLOSURE_ARGS;
3131
33209876
    ctx->curr_exp = car_args;
3132
33209876
    ctx->curr_env = arg_env;
3133

26212997
  } else if (a_nil && p_nil) {
3134
    // Arguments and parameters match up in number
3135
26184773
    lbm_stack_drop(&ctx->K, 5);
3136
26184773
    ctx->curr_env = binder;
3137
26184773
    ctx->curr_exp = exp;
3138
28224
  } else if (p_nil) {
3139
28224
    lbm_value rest_binder = allocate_binding(ENC_SYM_REST_ARGS, ENC_SYM_NIL, binder);
3140
28224
    sptr[2] = rest_binder;
3141
28224
    sptr[3] = get_cdr(args);
3142
28224
    sptr[4] = get_car(rest_binder); // last element of rest_args so far
3143
28224
    stack_reserve(ctx,1)[0] = CLOSURE_ARGS_REST;
3144
28224
    ctx->curr_exp = get_car(args);
3145
28224
    ctx->curr_env = arg_env;
3146
  }  else {
3147
    lbm_set_error_reason((char*)lbm_error_str_num_args);
3148
    error_ctx(ENC_SYM_EERROR);
3149
  }
3150
59422873
}
3151
3152
3153
5797008
static void cont_closure_args_rest(eval_context_t *ctx) {
3154
5797008
  lbm_uint* sptr = get_stack_ptr(ctx, 5);
3155
5797008
  lbm_value arg_env = (lbm_value)sptr[0];
3156
5797008
  lbm_value exp     = (lbm_value)sptr[1];
3157
5797008
  lbm_value clo_env = (lbm_value)sptr[2];
3158
5797008
  lbm_value args    = (lbm_value)sptr[3];
3159
5797008
  lbm_value last    = (lbm_value)sptr[4];
3160
5797008
  lbm_cons_t* heap = lbm_heap_state.heap;
3161
#ifdef LBM_ALWAYS_GC
3162
  gc();
3163
#endif
3164
5797008
  lbm_value binding = lbm_heap_state.freelist;
3165
5797008
  if (binding == ENC_SYM_NIL) {
3166
7498
    gc();
3167
7498
    binding = lbm_heap_state.freelist;
3168
7498
    if (binding == ENC_SYM_NIL) error_ctx(ENC_SYM_MERROR);
3169
  }
3170
5797008
  lbm_uint binding_ix = lbm_dec_ptr(binding);
3171
5797008
  lbm_heap_state.freelist = heap[binding_ix].cdr;
3172
5797008
  lbm_heap_state.num_alloc += 1;
3173
5797008
  heap[binding_ix].car = ctx->r;
3174
5797008
  heap[binding_ix].cdr = ENC_SYM_NIL;
3175
3176
3177
5797008
  lbm_set_cdr(last, binding);
3178
5797008
  sptr[4] = binding;
3179
3180
5797008
  if (args == ENC_SYM_NIL) {
3181
588252
    lbm_stack_drop(&ctx->K, 5);
3182
588252
    ctx->curr_env = clo_env;
3183
588252
    ctx->curr_exp = exp;
3184
  } else {
3185
5208756
    stack_reserve(ctx,1)[0] = CLOSURE_ARGS_REST;
3186
5208756
    sptr[3] = get_cdr(args);
3187
5208756
    ctx->curr_exp = get_car(args);
3188
5208756
    ctx->curr_env = arg_env;
3189
  }
3190
5797008
}
3191
3192
247679113
static void cont_application_args(eval_context_t *ctx) {
3193
247679113
  lbm_uint *sptr = get_stack_ptr(ctx, 3);
3194
3195
247679113
  lbm_value env = sptr[0];
3196
247679113
  lbm_value rest = sptr[1];
3197
247679113
  lbm_value count = sptr[2];
3198
3199
247679113
  ctx->curr_env = env;
3200
247679113
  sptr[0] = ctx->r; // Function 1st then Arguments
3201
247679113
  if (lbm_is_cons(rest)) {
3202
169685012
    lbm_cons_t *cell = lbm_ref_cell(rest);
3203
169685012
    sptr[1] = env;
3204
169685012
    sptr[2] = cell->cdr;
3205
169685012
    lbm_value *rptr = stack_reserve(ctx,2);
3206
169685012
    rptr[0] = count + (1 << LBM_VAL_SHIFT);
3207
169685012
    rptr[1] = APPLICATION_ARGS;
3208
169685012
    ctx->curr_exp = cell->car;
3209
  } else {
3210
    // No more arguments
3211
77994101
    lbm_stack_drop(&ctx->K, 2);
3212
77994101
    lbm_uint nargs = lbm_dec_u(count);
3213
77994101
    lbm_value *args = get_stack_ptr(ctx, (uint32_t)(nargs + 1));
3214
77994101
    application(ctx,args, nargs);
3215
  }
3216
247671041
}
3217
3218
3985884
static void cont_and(eval_context_t *ctx) {
3219
  lbm_value env;
3220
  lbm_value rest;
3221
3985884
  lbm_value arg = ctx->r;
3222
3985884
  lbm_pop_2(&ctx->K, &rest, &env);
3223
3985884
  if (lbm_is_symbol_nil(arg)) {
3224
280056
    ctx->app_cont = true;
3225
280056
    ctx->r = ENC_SYM_NIL;
3226
3705828
  } else if (lbm_is_symbol_nil(rest)) {
3227
1701952
    ctx->app_cont = true;
3228
  } else {
3229
2003876
    lbm_value *sptr = stack_reserve(ctx, 3);
3230
2003876
    sptr[0] = env;
3231
2003876
    sptr[1] = get_cdr(rest);
3232
2003876
    sptr[2] = AND;
3233
2003876
    ctx->curr_env = env;
3234
2003876
    ctx->curr_exp = get_car(rest);
3235
  }
3236
3985884
}
3237
3238
15988
static void cont_or(eval_context_t *ctx) {
3239
  lbm_value env;
3240
  lbm_value rest;
3241
15988
  lbm_value arg = ctx->r;
3242
15988
  lbm_pop_2(&ctx->K, &rest, &env);
3243
15988
  if (!lbm_is_symbol_nil(arg)) {
3244
840
    ctx->app_cont = true;
3245
15148
  } else if (lbm_is_symbol_nil(rest)) {
3246
6356
    ctx->app_cont = true;
3247
6356
    ctx->r = ENC_SYM_NIL;
3248
  } else {
3249
8792
    lbm_value *sptr = stack_reserve(ctx, 3);
3250
8792
    sptr[0] = env;
3251
8792
    sptr[1] = get_cdr(rest);
3252
8792
    sptr[2] = OR;
3253
8792
    ctx->curr_exp = get_car(rest);
3254
8792
    ctx->curr_env = env;
3255
  }
3256
15988
}
3257
3258
40888386
static int fill_binding_location(lbm_value key, lbm_value value, lbm_value env) {
3259
40888386
  if (lbm_type_of(key) == LBM_TYPE_SYMBOL) {
3260
26887350
    if (key == ENC_SYM_DONTCARE) return FB_OK;
3261
24087238
    lbm_env_modify_binding(env,key,value);
3262
24087238
    return FB_OK;
3263

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

5673192
  if (lbm_is_symbol(new_env0) || lbm_is_symbol(new_env)) {
3545
    error_ctx(ENC_SYM_FATAL_ERROR);
3546
  }
3547
5673192
  cmp_env = new_env;
3548
3549
5673192
  stack_reserve(ctx,1)[0] = MERGE_REST;
3550
5673192
  ctx->curr_exp = cmp_body;
3551
5673192
  ctx->curr_env = cmp_env;
3552
}
3553
3554
// merge_layer stack contents
3555
// s[sp-9] = cmp
3556
// s[sp-8] = cmp_env
3557
// s[sp-7] = par1
3558
// s[sp-6] = par2
3559
// s[sp-5] = acc - first cell
3560
// s[sp-4] = acc - last cell
3561
// s[sp-3] = rest;
3562
// s[sp-2] = layer
3563
// s[sp-1] = length or original list
3564
//
3565
// ctx->r merged sublist
3566
3401272
static void cont_merge_layer(eval_context_t *ctx) {
3567
3401272
  lbm_uint *sptr = get_stack_ptr(ctx, 9);
3568
3401272
  lbm_int layer = lbm_dec_i(sptr[7]);
3569
3401272
  lbm_int len = lbm_dec_i(sptr[8]);
3570
3571
3401272
  lbm_value r_curr = ctx->r;
3572
13620600
  while (lbm_is_cons(r_curr)) {
3573
13620600
    lbm_value next = lbm_cdr(r_curr);
3574
13620600
    if (next == ENC_SYM_NIL) {
3575
3401272
      break;
3576
    }
3577
10219328
    r_curr = next;
3578
  }
3579
3580
3401272
  if (sptr[4] == ENC_SYM_NIL) {
3581
1132348
    sptr[4] = ctx->r;
3582
1132348
    sptr[5] = r_curr;
3583
  } else {
3584
2268924
    lbm_set_cdr(sptr[5], ctx->r); // accumulate merged sublists.
3585
2268924
    sptr[5] = r_curr;
3586
  }
3587
3588
3401272
  lbm_value layer_rest = sptr[6];
3589
  // switch layer or done ?
3590
3401272
  if (layer_rest == ENC_SYM_NIL) {
3591
1132348
    if (layer * 2 >= len) {
3592
283108
      ctx->r = sptr[4];
3593
283108
      ctx->app_cont = true;
3594
283108
      lbm_stack_drop(&ctx->K, 9);
3595
283108
      return;
3596
    } else {
3597
      // Setup for merges of the next layer
3598
849240
      layer = layer * 2;
3599
849240
      sptr[7] = lbm_enc_i(layer);
3600
849240
      layer_rest = sptr[4]; // continue on the accumulation of all sublists.
3601
849240
      sptr[5] = ENC_SYM_NIL;
3602
849240
      sptr[4] = ENC_SYM_NIL;
3603
    }
3604
  }
3605
  // merge another sublist based on current layer.
3606
3118164
  lbm_value a_list = layer_rest;
3607
  // build sublist a
3608
3118164
  lbm_value curr = layer_rest;
3609
7661080
  for (int i = 0; i < layer-1; i ++) {
3610
4543028
    if (lbm_is_cons(curr)) {
3611
4542916
      curr = lbm_cdr(curr);
3612
    } else {
3613
112
      break;
3614
    }
3615
  }
3616
3118164
  layer_rest = lbm_cdr(curr);
3617
3118164
  lbm_set_cdr(curr, ENC_SYM_NIL); //terminate sublist.
3618
3619
3118164
  lbm_value b_list = layer_rest;
3620
  // build sublist b
3621
3118164
  curr = layer_rest;
3622
5959800
  for (int i = 0; i < layer-1; i ++) {
3623
3407796
    if (lbm_is_cons(curr)) {
3624
2841636
      curr = lbm_cdr(curr);
3625
    } else {
3626
566160
      break;
3627
    }
3628
  }
3629
3118164
  layer_rest = lbm_cdr(curr);
3630
3118164
  lbm_set_cdr(curr, ENC_SYM_NIL); //terminate sublist.
3631
3632
3118164
  sptr[6] = layer_rest;
3633
3634
3118164
  if (b_list == ENC_SYM_NIL) {
3635
283192
    stack_reserve(ctx,1)[0] = MERGE_LAYER;
3636
283192
    ctx->r = a_list;
3637
283192
    ctx->app_cont = true;
3638
283192
    return;
3639
  }
3640
  // Set up for a merge of sublists.
3641
3642
2834972
  lbm_value a_rest = lbm_cdr(a_list);
3643
2834972
  lbm_value b_rest = lbm_cdr(b_list);
3644
2834972
  lbm_value a = a_list;
3645
2834972
  lbm_value b = b_list;
3646
2834972
  lbm_set_cdr(a, b);
3647
  // Terminating the b list would be incorrect here
3648
  // if there was any chance that the environment update below
3649
  // performs GC.
3650
2834972
  lbm_set_cdr(b, ENC_SYM_NIL);
3651
3652
2834972
  lbm_value cmp_body = sptr[0];
3653
2834972
  lbm_value cmp_env = sptr[1];
3654
2834972
  lbm_value par1 = sptr[2];
3655
2834972
  lbm_value par2 = sptr[3];
3656
  // Environment should be preallocated already at this point
3657
  // and the operations below should never need GC.
3658
2834972
  lbm_value new_env0 = lbm_env_set(cmp_env, par1, lbm_car(a));
3659
2834972
  lbm_value new_env = lbm_env_set(cmp_env, par2, lbm_car(b));
3660

2834972
  if (lbm_is_symbol(new_env0) || lbm_is_symbol(new_env)) {
3661
    error_ctx(ENC_SYM_FATAL_ERROR);
3662
  }
3663
2834972
  cmp_env = new_env;
3664
3665
2834972
  lbm_uint *merge_cont = stack_reserve(ctx, 11);
3666
2834972
  merge_cont[0] = MERGE_LAYER;
3667
2834972
  merge_cont[1] = ENC_SYM_NIL;
3668
2834972
  merge_cont[2] = ENC_SYM_NIL;
3669
2834972
  merge_cont[3] = a;
3670
2834972
  merge_cont[4] = a_rest;
3671
2834972
  merge_cont[5] = b_rest;
3672
2834972
  merge_cont[6] = cmp_body;
3673
2834972
  merge_cont[7] = cmp_env;
3674
2834972
  merge_cont[8] = par1;
3675
2834972
  merge_cont[9] = par2;
3676
2834972
  merge_cont[10] = MERGE_REST;
3677
2834972
  ctx->curr_exp = cmp_body;
3678
2834972
  ctx->curr_env = cmp_env;
3679
2834972
  return;
3680
}
3681
3682
/****************************************************/
3683
/*   READER                                         */
3684
3685
33337
static void read_finish(lbm_char_channel_t *str, eval_context_t *ctx) {
3686
3687
  /* Tokenizer reached "end of file"
3688
     The parser could be in a state where it needs
3689
     more tokens to correctly finish an expression.
3690
3691
     Four cases
3692
     1. The program / expression is malformed and the context should die.
3693
     2. We are finished reading a program and should close off the
3694
     internal representation with a closing parenthesis. Then
3695
     apply continuation.
3696
     3. We are finished reading an expression and should
3697
     apply the continuation
3698
     4. We are finished read-and-evaluating
3699
3700
     In case 2, we should find the READ_DONE at sp - 5.
3701
     In case 3, we should find the READ_DONE at sp - 1.
3702
     In case 4, we should find the READ_DONE at sp - 4.
3703
3704
     case 3 should not end up here, but rather end up in
3705
     cont_read_done.
3706
  */
3707
3708
33337
  if (lbm_is_symbol(ctx->r)) {
3709
10757
    lbm_uint sym_val = lbm_dec_sym(ctx->r);
3710

10757
    if (sym_val >= TOKENIZER_SYMBOLS_START &&
3711
        sym_val <= TOKENIZER_SYMBOLS_END) {
3712
      read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
3713
    }
3714
  }
3715
3716

33337
  if (ctx->K.sp > 4  && (ctx->K.data[ctx->K.sp - 4] == READ_DONE) &&
3717
22109
      (ctx->K.data[ctx->K.sp - 5] == READING_PROGRAM_INCREMENTALLY)) {
3718
    /* read and evaluate is done */
3719
    lbm_value env;
3720
    lbm_value s;
3721
    lbm_value sym;
3722
22109
    lbm_pop_3(&ctx->K, &sym, &env, &s);
3723
22109
    ctx->curr_env = env;
3724
22109
    ctx->app_cont = true; // Program evaluated and result is in ctx->r.
3725

11228
  } else if (ctx->K.sp > 5 && (ctx->K.data[ctx->K.sp - 5] == READ_DONE) &&
3726
11228
             (ctx->K.data[ctx->K.sp - 6] == READING_PROGRAM)) {
3727
    /* successfully finished reading a program  (CASE 2) */
3728
11228
    ctx->r = ENC_SYM_CLOSEPAR;
3729
11228
    ctx->app_cont = true;
3730
  } else {
3731
    if (lbm_channel_row(str) == 1 && lbm_channel_column(str) == 1) {
3732
      // (read "") evaluates to nil.
3733
      ctx->r = ENC_SYM_NIL;
3734
      ctx->app_cont = true;
3735
    } else {
3736
      lbm_channel_reader_close(str);
3737
      lbm_set_error_reason((char*)lbm_error_str_parse_eof);
3738
      read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
3739
    }
3740
  }
3741
33337
}
3742
3743
/* cont_read_next_token
3744
   sp-2 : Stream
3745
   sp-1 : Grab row
3746
*/
3747
5706032
static void cont_read_next_token(eval_context_t *ctx) {
3748
5706032
  lbm_value *sptr = get_stack_ptr(ctx, 2);
3749
5706032
  lbm_value stream = sptr[0];
3750
5706032
  lbm_value grab_row0 = sptr[1];
3751
3752
5706032
  lbm_char_channel_t *chan = lbm_dec_channel(stream);
3753

5706032
  if (chan == NULL || chan->state == NULL) {
3754
    error_ctx(ENC_SYM_FATAL_ERROR);
3755
  }
3756
3757

5706032
  if (!lbm_channel_more(chan) && lbm_channel_is_empty(chan)) {
3758
11872
    lbm_stack_drop(&ctx->K, 2);
3759
11872
    read_finish(chan, ctx);
3760
5706032
    return;
3761
  }
3762
  /* Eat whitespace and comments */
3763
5694160
  if (!tok_clean_whitespace(chan)) {
3764
697
    sptr[0] = stream;
3765
697
    sptr[1] = lbm_enc_u(0);
3766
697
    stack_reserve(ctx,1)[0] = READ_NEXT_TOKEN;
3767
697
    yield_ctx(EVAL_CPS_MIN_SLEEP);
3768
697
    return;
3769
  }
3770
  /* After eating whitespace we may be at end of file/stream */
3771

5693463
  if (!lbm_channel_more(chan) && lbm_channel_is_empty(chan)) {
3772
21465
    lbm_stack_drop(&ctx->K, 2);
3773
21465
    read_finish(chan, ctx);
3774
21465
    return;
3775
  }
3776
3777
5671998
  if (lbm_dec_u(grab_row0)) {
3778
378344
    ctx->row0 = (int32_t)lbm_channel_row(chan);
3779
378344
    ctx->row1 = -1; // a new start, end is unknown
3780
  }
3781
3782
  /* Attempt to extract tokens from the character stream */
3783
5671998
  int n = 0;
3784
5671998
  lbm_value res = ENC_SYM_NIL;
3785
5671998
  unsigned int string_len = 0;
3786
3787
  /*
3788
   * SYNTAX
3789
   */
3790
  uint32_t match;
3791
5671998
  n = tok_syntax(chan, &match);
3792
5671998
  if (n > 0) {
3793
1407056
    if (!lbm_channel_drop(chan, (unsigned int)n)) {
3794
      error_ctx(ENC_SYM_FATAL_ERROR);
3795
    }
3796
1407056
    ctx->app_cont = true;
3797



1407056
    switch(match) {
3798
667660
    case TOKOPENPAR: {
3799
667660
      sptr[0] = ENC_SYM_NIL;
3800
667660
      sptr[1] = ENC_SYM_NIL;
3801
667660
      lbm_value *rptr = stack_reserve(ctx,5);
3802
667660
      rptr[0] = stream;
3803
667660
      rptr[1] = READ_APPEND_CONTINUE;
3804
667660
      rptr[2] = stream;
3805
667660
      rptr[3] = lbm_enc_u(0);
3806
667660
      rptr[4] = READ_NEXT_TOKEN;
3807
667660
      ctx->r = ENC_SYM_OPENPAR;
3808
667660
    } return;
3809
667660
    case TOKCLOSEPAR: {
3810
667660
      lbm_stack_drop(&ctx->K, 2);
3811
667660
      ctx->r = ENC_SYM_CLOSEPAR;
3812
667660
    } return;
3813
3304
    case TOKOPENBRACK: {
3814
3304
      sptr[0] = stream;
3815
3304
      sptr[1] = READ_START_ARRAY;
3816
3304
      lbm_value *rptr = stack_reserve(ctx, 3);
3817
3304
      rptr[0] = stream;
3818
3304
      rptr[1] = lbm_enc_u(0);
3819
3304
      rptr[2] = READ_NEXT_TOKEN;
3820
3304
      ctx->r = ENC_SYM_OPENBRACK;
3821
3304
    } return;
3822
3304
    case TOKCLOSEBRACK:
3823
3304
      lbm_stack_drop(&ctx->K, 2);
3824
3304
      ctx->r = ENC_SYM_CLOSEBRACK;
3825
3304
      return;
3826
6216
    case TOKDOT:
3827
6216
      lbm_stack_drop(&ctx->K, 2);
3828
6216
      ctx->r = ENC_SYM_DOT;
3829
6216
      return;
3830
1036
    case TOKDONTCARE:
3831
1036
      lbm_stack_drop(&ctx->K, 2);
3832
1036
      ctx->r = ENC_SYM_DONTCARE;
3833
1036
      return;
3834
27356
    case TOKQUOTE:
3835
27356
      sptr[0] = ENC_SYM_QUOTE;
3836
27356
      sptr[1] = WRAP_RESULT;
3837
27356
      break;
3838
5040
    case TOKBACKQUOTE: {
3839
5040
      sptr[0] = QQ_EXPAND_START;
3840
5040
      sptr[1] = stream;
3841
5040
      lbm_value *rptr = stack_reserve(ctx, 2);
3842
5040
      rptr[0] = lbm_enc_u(0);
3843
5040
      rptr[1] = READ_NEXT_TOKEN;
3844
5040
      ctx->app_cont = true;
3845
5040
    } return;
3846
56
    case TOKCOMMAAT:
3847
56
      sptr[0] = ENC_SYM_COMMAAT;
3848
56
      sptr[1] = WRAP_RESULT;
3849
56
      break;
3850
13944
    case TOKCOMMA:
3851
13944
      sptr[0] = ENC_SYM_COMMA;
3852
13944
      sptr[1] = WRAP_RESULT;
3853
13944
      break;
3854
6832
    case TOKMATCHANY:
3855
6832
      lbm_stack_drop(&ctx->K, 2);
3856
6832
      ctx->r = ENC_SYM_MATCH_ANY;
3857
6832
      return;
3858
2296
    case TOKOPENCURL: {
3859
2296
      sptr[0] = ENC_SYM_NIL;
3860
2296
      sptr[1] = ENC_SYM_NIL;
3861
2296
      lbm_value *rptr = stack_reserve(ctx,2);
3862
2296
      rptr[0] = stream;
3863
2296
      rptr[1] = READ_APPEND_CONTINUE;
3864
2296
      ctx->r = ENC_SYM_PROGN;
3865
2296
    } return;
3866
2296
    case TOKCLOSECURL:
3867
2296
      lbm_stack_drop(&ctx->K, 2);
3868
2296
      ctx->r = ENC_SYM_CLOSEPAR;
3869
2296
      return;
3870
56
    case TOKCONSTSTART: /* fall through */
3871
    case TOKCONSTEND: {
3872
56
      if (match == TOKCONSTSTART)  ctx->flags |= EVAL_CPS_CONTEXT_FLAG_CONST;
3873
56
      if (match == TOKCONSTEND)    ctx->flags &= ~EVAL_CPS_CONTEXT_FLAG_CONST;
3874
56
      sptr[0] = stream;
3875
56
      sptr[1] = lbm_enc_u(0);
3876
56
      stack_reserve(ctx,1)[0] = READ_NEXT_TOKEN;
3877
56
      ctx->app_cont = true;
3878
56
    } return;
3879
    default:
3880
      read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
3881
    }
3882
    // read next token
3883
41356
    lbm_value *rptr = stack_reserve(ctx, 3);
3884
41356
    rptr[0] = stream;
3885
41356
    rptr[1] = lbm_enc_u(0);
3886
41356
    rptr[2] = READ_NEXT_TOKEN;
3887
41356
    ctx->app_cont = true;
3888
41356
    return;
3889
4264942
  } else if (n < 0) goto retry_token;
3890
3891
  /*
3892
   *  STRING
3893
   */
3894
4264942
  n = tok_string(chan, &string_len);
3895
4264942
  if (n >= 2) {
3896
9380
    lbm_channel_drop(chan, (unsigned int)n);
3897
#ifdef LBM_ALWAYS_GC
3898
    gc();
3899
#endif
3900
9380
    if (!lbm_heap_allocate_array(&res, (unsigned int)(string_len+1))) {
3901
      gc();
3902
      lbm_heap_allocate_array(&res, (unsigned int)(string_len+1));
3903
    }
3904
9380
    if (lbm_is_ptr(res)) {
3905
9380
      lbm_array_header_t *arr = assume_array(res);
3906
9380
      char *data = (char*)arr->data;
3907
9380
      memset(data,0, string_len + 1);
3908
9380
      memcpy(data, tokpar_sym_str, string_len);
3909
9380
      lbm_stack_drop(&ctx->K, 2);
3910
9380
      ctx->r = res;
3911
9380
      ctx->app_cont = true;
3912
9380
      return;
3913
    } else {
3914
      error_ctx(ENC_SYM_MERROR);
3915
    }
3916
4255562
  } else if (n < 0) goto retry_token;
3917
3918
  /*
3919
   * FLOAT
3920
   */
3921
  token_float f_val;
3922
4255562
  n = tok_double(chan, &f_val);
3923
4255562
  if (n > 0) {
3924
13132
    lbm_channel_drop(chan, (unsigned int) n);
3925
13132
    switch(f_val.type) {
3926
10108
    case TOKTYPEF32:
3927

10108
      WITH_GC(res, lbm_enc_float((float)f_val.value));
3928
10108
      break;
3929
3024
    case TOKTYPEF64:
3930
3024
      res = lbm_enc_double(f_val.value);
3931
3024
      break;
3932
    default:
3933
      read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
3934
    }
3935
13132
    lbm_stack_drop(&ctx->K, 2);
3936
13132
    ctx->r = res;
3937
13132
    ctx->app_cont = true;
3938
13132
    return;
3939
4242430
  } else if (n < 0) goto retry_token;
3940
3941
  /*
3942
   * INTEGER
3943
   */
3944
  token_int int_result;
3945
4242429
  n = tok_integer(chan, &int_result);
3946
4242429
  if (n > 0) {
3947
3356976
    lbm_channel_drop(chan, (unsigned int)n);
3948


3356976
    switch(int_result.type) {
3949
2212
    case TOKTYPEBYTE:
3950
2212
      res = lbm_enc_char((uint8_t)(int_result.negative ? -int_result.value : int_result.value));
3951
2212
      break;
3952
3335920
    case TOKTYPEI:
3953
3335920
      res = lbm_enc_i((lbm_int)(int_result.negative ? -int_result.value : int_result.value));
3954
3335920
      break;
3955
3500
    case TOKTYPEU:
3956
3500
      res = lbm_enc_u((lbm_uint)(int_result.negative ? -int_result.value : int_result.value));
3957
3500
      break;
3958
3668
    case TOKTYPEI32:
3959


3668
      WITH_GC(res, lbm_enc_i32((int32_t)(int_result.negative ? -int_result.value : int_result.value)));
3960
3668
      break;
3961
4480
    case TOKTYPEU32:
3962


4480
      WITH_GC(res,lbm_enc_u32((uint32_t)(int_result.negative ? -int_result.value : int_result.value)));
3963
4480
      break;
3964
3780
    case TOKTYPEI64:
3965


3780
      WITH_GC(res,lbm_enc_i64((int64_t)(int_result.negative ? -int_result.value : int_result.value)));
3966
3780
      break;
3967
3416
    case TOKTYPEU64:
3968


3416
      WITH_GC(res,lbm_enc_u64((uint64_t)(int_result.negative ? -int_result.value : int_result.value)));
3969
3416
      break;
3970
    default:
3971
      read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
3972
    }
3973
3356976
    lbm_stack_drop(&ctx->K, 2);
3974
3356976
    ctx->r = res;
3975
3356976
    ctx->app_cont = true;
3976
3356976
    return;
3977
885453
  } else if (n < 0) goto retry_token;
3978
3979
  /*
3980
   * SYMBOL
3981
   */
3982
885450
  n = tok_symbol(chan);
3983
885450
  if (n > 0) {
3984
885276
    lbm_channel_drop(chan, (unsigned int) n);
3985
    lbm_uint symbol_id;
3986
885276
    if (!lbm_get_symbol_by_name(tokpar_sym_str, &symbol_id)) {
3987
99862
      int r = 0;
3988
99862
      if (n > 4 &&
3989
23758
          tokpar_sym_str[0] == 'e' &&
3990
406
          tokpar_sym_str[1] == 'x' &&
3991
42
          tokpar_sym_str[2] == 't' &&
3992
56
          tokpar_sym_str[3] == '-') {
3993
        lbm_uint ext_id;
3994
14
        lbm_uint ext_name_len = (lbm_uint)n + 1;
3995
#ifdef LBM_ALWAYS_GC
3996
        gc();
3997
#endif
3998
14
        char *ext_name = lbm_malloc(ext_name_len);
3999
14
        if (!ext_name) {
4000
          gc();
4001
          ext_name = lbm_malloc(ext_name_len);
4002
        }
4003
14
        if (ext_name) {
4004
14
          memcpy(ext_name, tokpar_sym_str, ext_name_len);
4005
14
          r = lbm_add_extension(ext_name, lbm_extensions_default);
4006
14
          if (!lbm_lookup_extension_id(ext_name, &ext_id)) {
4007
            error_ctx(ENC_SYM_FATAL_ERROR);
4008
          }
4009
14
          symbol_id = ext_id;
4010
        } else {
4011
          error_ctx(ENC_SYM_MERROR);
4012
        }
4013
      } else {
4014
99848
        if (ctx->flags & EVAL_CPS_CONTEXT_FLAG_CONST &&
4015
140
            ctx->flags & EVAL_CPS_CONTEXT_FLAG_INCREMENTAL_READ) {
4016
70
          r = lbm_add_symbol_base(tokpar_sym_str, &symbol_id, true); //flash
4017
70
          if (!r) {
4018
            lbm_set_error_reason((char*)lbm_error_str_flash_error);
4019
            error_ctx(ENC_SYM_FATAL_ERROR);
4020
          }
4021
        } else {
4022
#ifdef LBM_ALWAYS_GC
4023
          gc();
4024
#endif
4025
99778
          r = lbm_add_symbol_base(tokpar_sym_str, &symbol_id,false); //ram
4026
99778
          if (!r) {
4027
            gc();
4028
            r = lbm_add_symbol_base(tokpar_sym_str, &symbol_id,false); //ram
4029
          }
4030
        }
4031
      }
4032
99862
      if (!r) {
4033
        read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
4034
      }
4035
    }
4036
885276
    lbm_stack_drop(&ctx->K, 2);
4037
885276
    ctx->r = lbm_enc_sym(symbol_id);
4038
885276
    ctx->app_cont = true;
4039
885276
    return;
4040
174
  } else if (n == TOKENIZER_NEED_MORE) {
4041
6
    goto retry_token;
4042
168
  } else if (n <= TOKENIZER_STRING_ERROR) {
4043
    read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
4044
  }
4045
4046
  /*
4047
   * CHAR
4048
   */
4049
  char c_val;
4050
168
  n = tok_char(chan, &c_val);
4051
168
  if(n > 0) {
4052
168
    lbm_channel_drop(chan,(unsigned int) n);
4053
168
    lbm_stack_drop(&ctx->K, 2);
4054
168
    ctx->r = lbm_enc_char((uint8_t)c_val);
4055
168
    ctx->app_cont = true;
4056
168
    return;
4057
  }else if (n < 0) goto retry_token;
4058
4059
  read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
4060
4061
10
 retry_token:
4062
10
  if (n == TOKENIZER_NEED_MORE) {
4063
10
    sptr[0] = stream;
4064
10
    sptr[1] = lbm_enc_u(0);
4065
10
    stack_reserve(ctx,1)[0] = READ_NEXT_TOKEN;
4066
10
    yield_ctx(EVAL_CPS_MIN_SLEEP);
4067
10
    return;
4068
  }
4069
  read_error_ctx(lbm_channel_row(chan), lbm_channel_column(chan));
4070
}
4071
4072
3304
static void cont_read_start_array(eval_context_t *ctx) {
4073
3304
  lbm_value *sptr = get_stack_ptr(ctx, 1);
4074
3304
  lbm_value stream = sptr[0];
4075
4076
3304
  lbm_char_channel_t *str = lbm_dec_channel(stream);
4077

3304
  if (str == NULL || str->state == NULL) {
4078
    error_ctx(ENC_SYM_FATAL_ERROR);
4079
  }
4080
3304
  if (ctx->r == ENC_SYM_CLOSEBRACK) {
4081
    lbm_value array;
4082
4083
56
    if (!lbm_heap_allocate_array(&array, 0)) {
4084
      gc();
4085
      if (!lbm_heap_allocate_array(&array, 0)) {
4086
        lbm_set_error_reason((char*)lbm_error_str_read_no_mem);
4087
        lbm_channel_reader_close(str);
4088
        error_ctx(ENC_SYM_FATAL_ERROR); // Terminates ctx
4089
      }
4090
    }
4091
56
    lbm_stack_drop(&ctx->K, 1);
4092
56
    ctx->r = array;
4093
56
    ctx->app_cont = true;
4094
3248
  } else if (lbm_is_number(ctx->r)) {
4095
#ifdef LBM_ALWAYS_GC
4096
    gc();
4097
#endif
4098
3248
    lbm_uint num_free = lbm_memory_longest_free();
4099
3248
    lbm_uint initial_size = (lbm_uint)((float)num_free * 0.9);
4100
3248
    if (initial_size == 0) {
4101
      gc();
4102
      num_free = lbm_memory_longest_free();
4103
      initial_size = (lbm_uint)((float)num_free * 0.9);
4104
      if (initial_size == 0) {
4105
        lbm_channel_reader_close(str);
4106
        error_ctx(ENC_SYM_MERROR);
4107
      }
4108
    }
4109
    lbm_value array;
4110
3248
    initial_size = sizeof(lbm_uint) * initial_size;
4111
4112
    // Keep in mind that this allocation can fail for both
4113
    // lbm_memory and heap reasons.
4114
3248
    if (!lbm_heap_allocate_array(&array, initial_size)) {
4115
      gc();
4116
      if (!lbm_heap_allocate_array(&array, initial_size)) {
4117
        lbm_set_error_reason((char*)lbm_error_str_read_no_mem);
4118
        lbm_channel_reader_close(str);
4119
        error_ctx(ENC_SYM_FATAL_ERROR);
4120
        // NOTE: If array is not created evaluation ends here.
4121
        // Static analysis seems unaware.
4122
      }
4123
    }
4124
4125
3248
    sptr[0] = array;
4126
3248
    lbm_value *rptr = stack_reserve(ctx, 4);
4127
3248
    rptr[0] = lbm_enc_u(initial_size);
4128
3248
    rptr[1] = lbm_enc_u(0);
4129
3248
    rptr[2] = stream;
4130
3248
    rptr[3] = READ_APPEND_ARRAY;
4131
3248
    ctx->app_cont = true;
4132
  } else {
4133
    lbm_channel_reader_close(str);
4134
    read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
4135
  }
4136
3304
}
4137
4138
371000
static void cont_read_append_array(eval_context_t *ctx) {
4139
371000
  lbm_uint *sptr = get_stack_ptr(ctx, 4);
4140
4141
371000
  lbm_value array  = sptr[0];
4142
371000
  lbm_value size   = lbm_dec_as_u32(sptr[1]);
4143
371000
  lbm_value ix     = lbm_dec_as_u32(sptr[2]);
4144
371000
  lbm_value stream = sptr[3];
4145
4146
371000
  if (ix >= (size - 1)) {
4147
    error_ctx(ENC_SYM_MERROR);
4148
  }
4149
4150
  // if sptr[0] is not an array something is very very wrong.
4151
  // Not robust against a garbage on stack. But how would garbage get onto stack?
4152
371000
  lbm_array_header_t *arr = assume_array(array);
4153
371000
  if (lbm_is_number(ctx->r)) {
4154
367752
    ((uint8_t*)arr->data)[ix] = (uint8_t)lbm_dec_as_u32(ctx->r);
4155
4156
367752
    sptr[2] = lbm_enc_u(ix + 1);
4157
367752
    lbm_value *rptr = stack_reserve(ctx, 4);
4158
367752
    rptr[0] = READ_APPEND_ARRAY;
4159
367752
    rptr[1] = stream;
4160
367752
    rptr[2] = lbm_enc_u(0);
4161
367752
    rptr[3] = READ_NEXT_TOKEN;
4162
367752
    ctx->app_cont = true;
4163

3248
  } else if (lbm_is_symbol(ctx->r) && ctx->r == ENC_SYM_CLOSEBRACK) {
4164
3248
    lbm_uint array_size = ix / sizeof(lbm_uint);
4165
4166
3248
    if (ix % sizeof(lbm_uint) != 0) {
4167
2436
      array_size = array_size + 1;
4168
    }
4169
3248
    lbm_memory_shrink((lbm_uint*)arr->data, array_size);
4170
3248
    arr->size = ix;
4171
3248
    lbm_stack_drop(&ctx->K, 4);
4172
3248
    ctx->r = array;
4173
3248
    ctx->app_cont = true;
4174
  } else {
4175
    error_ctx(ENC_SYM_TERROR);
4176
  }
4177
371000
}
4178
4179
4888422
static void cont_read_append_continue(eval_context_t *ctx) {
4180
4888422
  lbm_value *sptr = get_stack_ptr(ctx, 3);
4181
4182
4888422
  lbm_value first_cell = sptr[0];
4183
4888422
  lbm_value last_cell  = sptr[1];
4184
4888422
  lbm_value stream     = sptr[2];
4185
4186
4888422
  lbm_char_channel_t *str = lbm_dec_channel(stream);
4187

4888422
  if (str == NULL || str->state == NULL) {
4188
    error_ctx(ENC_SYM_FATAL_ERROR);
4189
  }
4190
4191
4888422
  if (lbm_type_of(ctx->r) == LBM_TYPE_SYMBOL) {
4192
4193
1531628
    switch(ctx->r) {
4194
674968
    case ENC_SYM_CLOSEPAR:
4195
674968
      if (lbm_type_of(last_cell) == LBM_TYPE_CONS) {
4196
672308
        lbm_set_cdr(last_cell, ENC_SYM_NIL); // terminate the list
4197
672308
        ctx->r = first_cell;
4198
      } else {
4199
2660
        ctx->r = ENC_SYM_NIL;
4200
      }
4201
674968
      lbm_stack_drop(&ctx->K, 3);
4202
      /* Skip reading another token and apply the continuation */
4203
674968
      ctx->app_cont = true;
4204
674968
      return;
4205
6216
    case ENC_SYM_DOT: {
4206
6216
      lbm_value *rptr = stack_reserve(ctx, 4);
4207
6216
      rptr[0] = READ_DOT_TERMINATE;
4208
6216
      rptr[1] = stream;
4209
6216
      rptr[2] = lbm_enc_u(0);
4210
6216
      rptr[3] = READ_NEXT_TOKEN;
4211
6216
      ctx->app_cont = true;
4212
6216
    } return;
4213
    }
4214
  }
4215
4207238
  lbm_value new_cell = cons_with_gc(ctx->r, ENC_SYM_NIL, ENC_SYM_NIL);
4216
4207238
  if (lbm_is_symbol_merror(new_cell)) {
4217
    lbm_channel_reader_close(str);
4218
    read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
4219
    return;
4220
  }
4221
4207238
  if (lbm_type_of(last_cell) == LBM_TYPE_CONS) {
4222
3528714
    lbm_set_cdr(last_cell, new_cell);
4223
3528714
    last_cell = new_cell;
4224
  } else {
4225
678524
    first_cell = last_cell = new_cell;
4226
  }
4227
4207238
  sptr[0] = first_cell;
4228
4207238
  sptr[1] = last_cell;
4229
4207238
  sptr[2] = stream;    // unchanged.
4230
4207238
  lbm_value *rptr = stack_reserve(ctx, 4);
4231
4207238
  rptr[0] = READ_APPEND_CONTINUE;
4232
4207238
  rptr[1] = stream;
4233
4207238
  rptr[2] = lbm_enc_u(0);
4234
4207238
  rptr[3] = READ_NEXT_TOKEN;
4235
4207238
  ctx->app_cont = true;
4236
}
4237
4238
70070
static void cont_read_eval_continue(eval_context_t *ctx) {
4239
  lbm_value env;
4240
  lbm_value stream;
4241
70070
  lbm_pop_2(&ctx->K, &env, &stream);
4242
4243
70070
  lbm_char_channel_t *str = lbm_dec_channel(stream);
4244

70070
  if (str && str->state) {
4245
70070
    ctx->row1 = (lbm_int)str->row(str);
4246
70070
    if (lbm_type_of(ctx->r) == LBM_TYPE_SYMBOL) {
4247
5600
      switch(ctx->r) {
4248
      case ENC_SYM_CLOSEPAR:
4249
        ctx->app_cont = true;
4250
        return;
4251
      case ENC_SYM_DOT:
4252
        // A dot here is a syntax error.
4253
        lbm_set_error_reason((char*)lbm_error_str_parse_dot);
4254
        read_error_ctx(lbm_channel_row(str),lbm_channel_column(str));
4255
        return;
4256
      }
4257
    }
4258
70070
    lbm_value *rptr = stack_reserve(ctx, 8);
4259
70070
    rptr[0] = stream;
4260
70070
    rptr[1] = env;
4261
70070
    rptr[2] = READ_EVAL_CONTINUE;
4262
70070
    rptr[3] = stream;
4263
70070
    rptr[4] = lbm_enc_u(1);
4264
70070
    rptr[5] = READ_NEXT_TOKEN;
4265
70070
    rptr[6] = lbm_enc_u(ctx->flags);
4266
70070
    rptr[7] = POP_READER_FLAGS;
4267
4268
70070
    ctx->curr_env = env;
4269
70070
    ctx->curr_exp = ctx->r;
4270
  } else {
4271
    error_ctx(ENC_SYM_FATAL_ERROR);
4272
  }
4273
}
4274
4275
6216
static void cont_read_expect_closepar(eval_context_t *ctx) {
4276
  lbm_value res;
4277
  lbm_value stream;
4278
4279
6216
  lbm_pop_2(&ctx->K, &res, &stream);
4280
4281
6216
  lbm_char_channel_t *str = lbm_dec_channel(stream);
4282

6216
  if (str == NULL || str->state == NULL) {
4283
    error_ctx(ENC_SYM_FATAL_ERROR);
4284
  }
4285
4286
6216
  if (lbm_type_of(ctx->r) == LBM_TYPE_SYMBOL &&
4287
6216
      ctx->r == ENC_SYM_CLOSEPAR) {
4288
6216
    ctx->r = res;
4289
6216
    ctx->app_cont = true;
4290
  } else {
4291
    lbm_channel_reader_close(str);
4292
    lbm_set_error_reason((char*)lbm_error_str_parse_close);
4293
    read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
4294
  }
4295
6216
}
4296
4297
6216
static void cont_read_dot_terminate(eval_context_t *ctx) {
4298
6216
  lbm_value *sptr = get_stack_ptr(ctx, 3);
4299
4300
6216
  lbm_value last_cell  = sptr[1];
4301
6216
  lbm_value stream = sptr[2];
4302
4303
6216
  lbm_char_channel_t *str = lbm_dec_channel(stream);
4304

6216
  if (str == NULL || str->state == NULL) {
4305
    error_ctx(ENC_SYM_FATAL_ERROR);
4306
  }
4307
4308
6216
  lbm_stack_drop(&ctx->K ,3);
4309
4310
6216
  if (lbm_type_of(ctx->r) == LBM_TYPE_SYMBOL &&
4311
1736
      (ctx->r == ENC_SYM_CLOSEPAR ||
4312
1736
       ctx->r == ENC_SYM_DOT)) {
4313
    lbm_channel_reader_close(str);
4314
    lbm_set_error_reason((char*)lbm_error_str_parse_dot);
4315
    read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
4316
  } else {
4317
6216
    if (lbm_is_cons(last_cell)) {
4318
6216
      lbm_set_cdr(last_cell, ctx->r);
4319
6216
      ctx->r = sptr[0]; // first cell
4320
6216
      lbm_value *rptr = stack_reserve(ctx, 6);
4321
6216
      rptr[0] = stream;
4322
6216
      rptr[1] = ctx->r;
4323
6216
      rptr[2] = READ_EXPECT_CLOSEPAR;
4324
6216
      rptr[3] = stream;
4325
6216
      rptr[4] = lbm_enc_u(0);
4326
6216
      rptr[5] = READ_NEXT_TOKEN;
4327
6216
      ctx->app_cont = true;
4328
    } else {
4329
      lbm_channel_reader_close(str);
4330
      lbm_set_error_reason((char*)lbm_error_str_parse_dot);
4331
      read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
4332
    }
4333
  }
4334
6216
}
4335
4336
330417
static void cont_read_done(eval_context_t *ctx) {
4337
  lbm_value stream;
4338
  lbm_value f_val;
4339
  lbm_value reader_mode;
4340
330417
  lbm_pop_3(&ctx->K, &reader_mode, &stream, &f_val);
4341
4342
330417
  uint32_t flags = lbm_dec_as_u32(f_val);
4343
330417
  ctx->flags &= ~EVAL_CPS_CONTEXT_READER_FLAGS_MASK;
4344
330417
  ctx->flags |= (flags & EVAL_CPS_CONTEXT_READER_FLAGS_MASK);
4345
4346
330417
  lbm_char_channel_t *str = lbm_dec_channel(stream);
4347

330417
  if (str == NULL || str->state == NULL) {
4348
    error_ctx(ENC_SYM_FATAL_ERROR);
4349
  }
4350
4351
330417
  lbm_channel_reader_close(str);
4352
330417
  if (lbm_is_symbol(ctx->r)) {
4353
22417
    lbm_uint sym_val = lbm_dec_sym(ctx->r);
4354

22417
    if (sym_val >= TOKENIZER_SYMBOLS_START &&
4355
        sym_val <= TOKENIZER_SYMBOLS_END) {
4356
      read_error_ctx(lbm_channel_row(str), lbm_channel_column(str));
4357
    }
4358
  }
4359
330417
  ctx->row0 = -1;
4360
330417
  ctx->row1 = -1;
4361
330417
  ctx->app_cont = true;
4362
330417
}
4363
4364
41356
static void cont_wrap_result(eval_context_t *ctx) {
4365
  lbm_value cell;
4366
  lbm_value wrapper;
4367
41356
  lbm_pop(&ctx->K, &wrapper);
4368

41356
  WITH_GC(cell, lbm_heap_allocate_list_init(2,
4369
                                            wrapper,
4370
                                            ctx->r));
4371
41356
  ctx->r = cell;
4372
41356
  ctx->app_cont = true;
4373
41356
}
4374
4375
105091324
static void cont_application_start(eval_context_t *ctx) {
4376
4377
  /* sptr[0] = env
4378
   * sptr[1] = args
4379
   * ctx->r  = function
4380
   */
4381
4382
105091324
  if (lbm_is_symbol(ctx->r)) {
4383
77994136
    stack_reserve(ctx,1)[0] = lbm_enc_u(0);
4384
77994136
    cont_application_args(ctx);
4385
27097188
  } else if (lbm_is_cons(ctx->r)) {
4386
27097188
    lbm_uint *sptr = get_stack_ptr(ctx, 2);
4387
27097188
    lbm_value args = (lbm_value)sptr[1];
4388

27097188
    switch (get_car(ctx->r)) {
4389
27090804
    case ENC_SYM_CLOSURE: {
4390
      lbm_value cl[3];
4391
27090804
      extract_n(get_cdr(ctx->r), cl, 3);
4392
27090804
      lbm_value arg_env = (lbm_value)sptr[0];
4393
      lbm_value arg0, arg_rest;
4394
27090804
      get_car_and_cdr(args, &arg0, &arg_rest);
4395
27090804
      sptr[1] = cl[CLO_BODY];
4396
27090804
      bool a_nil = lbm_is_symbol_nil(args);
4397
27090804
      bool p_nil = lbm_is_symbol_nil(cl[CLO_PARAMS]);
4398
27090804
      lbm_value *reserved = stack_reserve(ctx, 4);
4399
4400

27090804
      if (!a_nil && !p_nil) {
4401
26213116
        reserved[0] = cl[CLO_ENV];
4402
26213116
        reserved[1] = cl[CLO_PARAMS];
4403
26213116
        reserved[2] = arg_rest;
4404
26213116
        reserved[3] = CLOSURE_ARGS;
4405
26213116
        ctx->curr_exp = arg0;
4406
26213116
        ctx->curr_env = arg_env;
4407

877688
      } else if (a_nil && p_nil) {
4408
        // No params, No args
4409
317660
        lbm_stack_drop(&ctx->K, 6);
4410
317660
        ctx->curr_exp = cl[CLO_BODY];
4411
317660
        ctx->curr_env = cl[CLO_ENV];
4412
560028
      } else if (p_nil) {
4413
560028
        reserved[1] = get_cdr(args);      // protect cdr(args) from allocate_binding
4414
560028
        ctx->curr_exp = get_car(args);    // protect car(args) from allocate binding
4415
560028
        ctx->curr_env = arg_env;
4416
560028
        lbm_value rest_binder = allocate_binding(ENC_SYM_REST_ARGS, ENC_SYM_NIL, cl[CLO_ENV]);
4417
560028
        reserved[0] = rest_binder;
4418
560028
        reserved[2] = get_car(rest_binder);
4419
560028
        reserved[3] = CLOSURE_ARGS_REST;
4420
      } else {
4421
        lbm_set_error_reason((char*)lbm_error_str_num_args);
4422
        error_at_ctx(ENC_SYM_EERROR, ctx->r);
4423
      }
4424
27090804
    } break;
4425
196
    case ENC_SYM_CONT:{
4426
      /* Continuation created using call-cc.
4427
       * ((SYM_CONT . cont-array) arg0 )
4428
       */
4429
196
      lbm_value c = get_cdr(ctx->r); /* should be the continuation array*/
4430
4431
196
      if (!lbm_is_lisp_array_r(c)) {
4432
        error_ctx(ENC_SYM_FATAL_ERROR);
4433
      }
4434
4435
196
      lbm_uint arg_count = lbm_list_length(args);
4436
196
      lbm_value arg = ENC_SYM_NIL;
4437
      switch (arg_count) {
4438
56
      case 0:
4439
56
        arg = ENC_SYM_NIL;
4440
56
        break;
4441
140
      case 1:
4442
140
        arg = get_car(args);
4443
140
        break;
4444
      default:
4445
        lbm_set_error_reason((char*)lbm_error_str_num_args);
4446
        error_ctx(ENC_SYM_EERROR);
4447
      }
4448
196
      lbm_stack_clear(&ctx->K);
4449
4450
196
      lbm_array_header_t *arr = assume_array(c);
4451
196
      ctx->K.sp = arr->size / sizeof(lbm_uint);
4452
196
      memcpy(ctx->K.data, arr->data, arr->size);
4453
4454
      lbm_value atomic;
4455
196
      lbm_pop(&ctx->K, &atomic);
4456
196
      is_atomic = atomic ? 1 : 0;
4457
4458
196
      ctx->curr_exp = arg;
4459
196
      break;
4460
    }
4461
6188
    case ENC_SYM_MACRO:{
4462
      /*
4463
       * Perform macro expansion.
4464
       * Macro expansion is really just evaluation in an
4465
       * environment augmented with the unevaluated expressions passed
4466
       * as arguments.
4467
       */
4468
6188
      lbm_value env = (lbm_value)sptr[0];
4469
4470
6188
      lbm_value curr_param = get_cadr(ctx->r);
4471
6188
      lbm_value curr_arg = args;
4472
6188
      lbm_value expand_env = env;
4473

43484
      while (lbm_is_cons(curr_param) &&
4474
18648
             lbm_is_cons(curr_arg)) {
4475
18648
        lbm_cons_t *param_cell = lbm_ref_cell(curr_param); // already checked that cons.
4476
18648
        lbm_cons_t *arg_cell = lbm_ref_cell(curr_arg);
4477
18648
        lbm_value car_curr_param = param_cell->car;
4478
18648
        lbm_value cdr_curr_param = param_cell->cdr;
4479
18648
        lbm_value car_curr_arg = arg_cell->car;
4480
18648
        lbm_value cdr_curr_arg = arg_cell->cdr;
4481
4482
18648
        lbm_value entry = cons_with_gc(car_curr_param, car_curr_arg, expand_env);
4483
18648
        lbm_value aug_env = cons_with_gc(entry, expand_env,ENC_SYM_NIL);
4484
18648
        expand_env = aug_env;
4485
4486
18648
        curr_param = cdr_curr_param;
4487
18648
        curr_arg   = cdr_curr_arg;
4488
      }
4489
      /* Two rounds of evaluation is performed.
4490
       * First to instantiate the arguments into the macro body.
4491
       * Second to evaluate the resulting program.
4492
       */
4493
6188
      sptr[1] = EVAL_R;
4494
6188
      lbm_value exp = get_cadr(get_cdr(ctx->r));
4495
6188
      ctx->curr_exp = exp;
4496
6188
      ctx->curr_env = expand_env;
4497
6188
    } break;
4498
    default:
4499
      error_ctx(ENC_SYM_EERROR);
4500
    }
4501
  } else {
4502
    error_ctx(ENC_SYM_EERROR);
4503
  }
4504
105089756
}
4505
4506
6188
static void cont_eval_r(eval_context_t* ctx) {
4507
  lbm_value env;
4508
6188
  lbm_pop(&ctx->K, &env);
4509
6188
  ctx->curr_exp = ctx->r;
4510
6188
  ctx->curr_env = env;
4511
6188
}
4512
4513
643566
static void cont_progn_var(eval_context_t* ctx) {
4514
4515
  lbm_value key;
4516
  lbm_value env;
4517
4518
643566
  lbm_pop_2(&ctx->K, &key, &env);
4519
4520
643566
  if (fill_binding_location(key, ctx->r, env) < 0) {
4521
    lbm_set_error_reason("Incorrect type of name/key in let-binding");
4522
    error_at_ctx(ENC_SYM_TERROR, key);
4523
  }
4524
4525
643566
  ctx->app_cont = true;
4526
643566
}
4527
4528
1775480
static void cont_setq(eval_context_t *ctx) {
4529
  lbm_value sym;
4530
  lbm_value env;
4531
1775480
  lbm_pop_2(&ctx->K, &sym, &env);
4532
  lbm_value res;
4533

1775480
  WITH_GC(res, perform_setvar(sym, ctx->r, env));
4534
1775424
  ctx->r = res;
4535
1775424
  ctx->app_cont = true;
4536
1775424
}
4537
4538
2408
lbm_flash_status request_flash_storage_cell(lbm_value val, lbm_value *res) {
4539
4540
  lbm_value flash_cell;
4541
2408
  lbm_flash_status s = lbm_allocate_const_cell(&flash_cell);
4542
2408
  if (s != LBM_FLASH_WRITE_OK)
4543
    return s;
4544
2408
  lbm_value new_val = val;
4545
2408
  new_val &= ~LBM_PTR_VAL_MASK; // clear the value part of the ptr
4546
2408
  new_val |= (flash_cell & LBM_PTR_VAL_MASK);
4547
2408
  new_val |= LBM_PTR_TO_CONSTANT_BIT;
4548
2408
  *res = new_val;
4549
2408
  return s;
4550
}
4551
4552
840
static void cont_move_to_flash(eval_context_t *ctx) {
4553
4554
  lbm_value args;
4555
840
  lbm_pop(&ctx->K, &args);
4556
4557
840
  if (lbm_is_symbol_nil(args)) {
4558
    // Done looping over arguments. return true.
4559
364
    ctx->r = ENC_SYM_TRUE;
4560
364
    ctx->app_cont = true;
4561
840
    return;
4562
  }
4563
4564
  lbm_value first_arg, rest;
4565
476
  get_car_and_cdr(args, &first_arg, &rest);
4566
4567
  lbm_value val;
4568

476
  if (lbm_is_symbol(first_arg) && lbm_global_env_lookup(&val, first_arg)) {
4569
    // Prepare to copy the rest of the arguments when done with first.
4570
476
    lbm_value *rptr = stack_reserve(ctx, 2);
4571
476
    rptr[0] = rest;
4572
476
    rptr[1] = MOVE_TO_FLASH;
4573
476
    if (lbm_is_ptr(val) &&
4574
476
        (!(val & LBM_PTR_TO_CONSTANT_BIT))) {
4575
476
      lbm_value * rptr1 = stack_reserve(ctx, 3);
4576
476
      rptr1[0] = first_arg;
4577
476
      rptr1[1] = SET_GLOBAL_ENV;
4578
476
      rptr1[2] = MOVE_VAL_TO_FLASH_DISPATCH;
4579
476
      ctx->r = val;
4580
    }
4581
476
    ctx->app_cont = true;
4582
476
    return;
4583
  }
4584
  error_ctx(ENC_SYM_EERROR);
4585
}
4586
4587
3388
static void cont_move_val_to_flash_dispatch(eval_context_t *ctx) {
4588
4589
3388
  lbm_value val = ctx->r;
4590
4591
3388
  if (lbm_is_cons(val)) {
4592
798
    lbm_value *rptr = stack_reserve(ctx, 5);
4593
798
    rptr[0] = ENC_SYM_NIL; // fst cell of list
4594
798
    rptr[1] = ENC_SYM_NIL; // last cell of list
4595
798
    rptr[2] = get_cdr(val);
4596
798
    rptr[3] = MOVE_LIST_TO_FLASH;
4597
798
    rptr[4] = MOVE_VAL_TO_FLASH_DISPATCH;
4598
798
    ctx->r = get_car(val);
4599
798
    ctx->app_cont = true;
4600
798
    return;
4601
  }
4602
4603

2590
  if (lbm_is_ptr(val) && (val & LBM_PTR_TO_CONSTANT_BIT)) {
4604
    //ctx->r unchanged
4605
    ctx->app_cont = true;
4606
    return;
4607
  }
4608
4609
2590
  if (lbm_is_ptr(val)) {
4610
280
    lbm_cons_t *ref = lbm_ref_cell(val);
4611
280
    if (lbm_type_of(ref->cdr) == LBM_TYPE_SYMBOL) {
4612

280
      switch (ref->cdr) {
4613
140
      case ENC_SYM_RAW_I_TYPE: /* fall through */
4614
      case ENC_SYM_RAW_U_TYPE:
4615
      case ENC_SYM_RAW_F_TYPE: {
4616
140
        lbm_value flash_cell = ENC_SYM_NIL;
4617
140
        handle_flash_status(request_flash_storage_cell(val, &flash_cell));
4618
140
        handle_flash_status(write_const_car(flash_cell, ref->car));
4619
140
        handle_flash_status(write_const_cdr(flash_cell, ref->cdr));
4620
140
        ctx->r = flash_cell;
4621
140
      } break;
4622
56
      case ENC_SYM_IND_I_TYPE: /* fall through */
4623
      case ENC_SYM_IND_U_TYPE:
4624
      case ENC_SYM_IND_F_TYPE: {
4625
#ifndef LBM64
4626
        /* 64 bit values are in lbm mem on 32bit platforms. */
4627
56
        lbm_uint *lbm_mem_ptr = (lbm_uint*)ref->car;
4628
        lbm_uint flash_ptr;
4629
4630
56
        handle_flash_status(lbm_write_const_raw(lbm_mem_ptr, 2, &flash_ptr));
4631
56
        lbm_value flash_cell = ENC_SYM_NIL;
4632
56
        handle_flash_status(request_flash_storage_cell(val, &flash_cell));
4633
56
        handle_flash_status(write_const_car(flash_cell, flash_ptr));
4634
56
        handle_flash_status(write_const_cdr(flash_cell, ref->cdr));
4635
56
        ctx->r = flash_cell;
4636
#else
4637
        // There are no indirect types in LBM64
4638
        error_ctx(ENC_SYM_FATAL_ERROR);
4639
#endif
4640
56
      } break;
4641
28
      case ENC_SYM_LISPARRAY_TYPE: {
4642
28
        lbm_array_header_t *arr = (lbm_array_header_t*)ref->car;
4643
28
        lbm_uint size = arr->size / sizeof(lbm_uint);
4644
28
        lbm_uint flash_addr = 0;
4645
28
        lbm_value *arrdata = (lbm_value *)arr->data;
4646
28
        lbm_value flash_cell = ENC_SYM_NIL;
4647
28
        handle_flash_status(request_flash_storage_cell(val, &flash_cell));
4648
28
        handle_flash_status(lbm_allocate_const_raw(size, &flash_addr));
4649
28
        lift_array_flash(flash_cell,
4650
                         false,
4651
                         (char *)flash_addr,
4652
                         arr->size);
4653
        // Move array contents to flash recursively
4654
28
        lbm_value *rptr = stack_reserve(ctx, 5);
4655
28
        rptr[0] = flash_cell;
4656
28
        rptr[1] = lbm_enc_u(0);
4657
28
        rptr[2] = val;
4658
28
        rptr[3] = MOVE_ARRAY_ELTS_TO_FLASH;
4659
28
        rptr[4] = MOVE_VAL_TO_FLASH_DISPATCH;
4660
28
        ctx->r = arrdata[0];
4661
28
        ctx->app_cont = true;
4662
28
        return;
4663
      }
4664
56
      case ENC_SYM_ARRAY_TYPE: {
4665
56
        lbm_array_header_t *arr = (lbm_array_header_t*)ref->car;
4666
        // arbitrary address: flash_arr.
4667
56
        lbm_uint flash_arr = 0;
4668
56
        handle_flash_status(lbm_write_const_array_padded((uint8_t*)arr->data, arr->size, &flash_arr));
4669
56
        lbm_value flash_cell = ENC_SYM_NIL;
4670
56
        handle_flash_status(request_flash_storage_cell(val, &flash_cell));
4671
56
        lift_array_flash(flash_cell,
4672
                         true,
4673
                         (char *)flash_arr,
4674
                         arr->size);
4675
56
        ctx->r = flash_cell;
4676
56
      } break;
4677
      case ENC_SYM_CHANNEL_TYPE: /* fall through */
4678
      case ENC_SYM_CUSTOM_TYPE:
4679
        lbm_set_error_reason((char *)lbm_error_str_flash_not_possible);
4680
        error_ctx(ENC_SYM_EERROR);
4681
      }
4682
252
    } else {
4683
      error_ctx(ENC_SYM_FATAL_ERROR);
4684
    }
4685
252
    ctx->app_cont = true;
4686
252
    return;
4687
  }
4688
2310
  ctx->r = val;
4689
2310
  ctx->app_cont = true;
4690
}
4691
4692
2016
static void cont_move_list_to_flash(eval_context_t *ctx) {
4693
4694
  // ctx->r holds the value that should go in car
4695
4696
2016
  lbm_value *sptr = get_stack_ptr(ctx, 3);
4697
4698
2016
  lbm_value fst = sptr[0];
4699
2016
  lbm_value lst = sptr[1];
4700
2016
  lbm_value val = sptr[2];
4701
4702
4703
2016
  lbm_value new_lst = ENC_SYM_NIL;
4704
  // Allocate element ptr storage after storing the element to flash.
4705
2016
  handle_flash_status(request_flash_storage_cell(lbm_enc_cons_ptr(LBM_PTR_NULL), &new_lst));
4706
4707
2016
  if (lbm_is_symbol_nil(fst)) {
4708
798
    lst = new_lst;
4709
798
    fst = new_lst;
4710
798
    handle_flash_status(write_const_car(lst, ctx->r));
4711
  } else {
4712
1218
    handle_flash_status(write_const_cdr(lst, new_lst)); // low before high
4713
1218
    handle_flash_status(write_const_car(new_lst, ctx->r));
4714
1218
    lst = new_lst;
4715
  }
4716
4717
2016
  if (lbm_is_cons(val)) {
4718
1218
    sptr[0] = fst;
4719
1218
    sptr[1] = lst;//rest_cell;
4720
1218
    sptr[2] = get_cdr(val);
4721
1218
    lbm_value *rptr = stack_reserve(ctx, 2);
4722
1218
    rptr[0] = MOVE_LIST_TO_FLASH;
4723
1218
    rptr[1] = MOVE_VAL_TO_FLASH_DISPATCH;
4724
1218
    ctx->r = get_car(val);
4725
  } else {
4726
798
    sptr[0] = fst;
4727
798
    sptr[1] = lst;
4728
798
    sptr[2] = CLOSE_LIST_IN_FLASH;
4729
798
    stack_reserve(ctx, 1)[0] = MOVE_VAL_TO_FLASH_DISPATCH;
4730
798
    ctx->r =  val;
4731
  }
4732
2016
  ctx->app_cont = true;
4733
2016
}
4734
4735
798
static void cont_close_list_in_flash(eval_context_t *ctx) {
4736
  lbm_value fst;
4737
  lbm_value lst;
4738
798
  lbm_pop_2(&ctx->K, &lst, &fst);
4739
798
  lbm_value val = ctx->r;
4740
798
  handle_flash_status(write_const_cdr(lst, val));
4741
798
  ctx->r = fst;
4742
798
  ctx->app_cont = true;
4743
798
}
4744
4745
84
static void cont_move_array_elts_to_flash(eval_context_t *ctx) {
4746
84
  lbm_value *sptr = get_stack_ptr(ctx, 3);
4747
  // sptr[2] = source array in RAM
4748
  // sptr[1] = current index
4749
  // sptr[0] = target array in flash
4750
84
  lbm_array_header_t *src_arr = assume_array(sptr[2]);
4751
84
  lbm_uint size = src_arr->size / sizeof(lbm_uint);
4752
84
  lbm_value *srcdata = (lbm_value *)src_arr->data;
4753
4754
84
  lbm_array_header_t *tgt_arr = assume_array(sptr[0]);
4755
84
  lbm_uint *tgtdata = (lbm_value *)tgt_arr->data;
4756
84
  lbm_uint ix = lbm_dec_as_u32(sptr[1]);
4757
84
  handle_flash_status(lbm_const_write(&tgtdata[ix], ctx->r));
4758
84
  if (ix >= size-1) {
4759
28
    ctx->r = sptr[0];
4760
28
    lbm_stack_drop(&ctx->K, 3);
4761
28
    ctx->app_cont = true;
4762
28
    return;
4763
  }
4764
56
  sptr[1] = lbm_enc_u(ix + 1);
4765
56
  lbm_value *rptr = stack_reserve(ctx, 2);
4766
56
  rptr[0] = MOVE_ARRAY_ELTS_TO_FLASH;
4767
56
  rptr[1] = MOVE_VAL_TO_FLASH_DISPATCH;
4768
56
  ctx->r = srcdata[ix+1];
4769
56
  ctx->app_cont = true;
4770
56
  return;
4771
}
4772
4773
5040
static void cont_qq_expand_start(eval_context_t *ctx) {
4774
5040
  lbm_value *rptr = stack_reserve(ctx, 2);
4775
5040
  rptr[0] = ctx->r;
4776
5040
  rptr[1] = QQ_EXPAND;
4777
5040
  ctx->r = ENC_SYM_NIL;
4778
5040
  ctx->app_cont = true;
4779
5040
}
4780
4781
10220
lbm_value quote_it(lbm_value qquoted) {
4782

19992
  if (lbm_is_symbol(qquoted) &&
4783
19544
      lbm_is_special(qquoted)) return qquoted;
4784
4785
448
  lbm_value val = cons_with_gc(qquoted, ENC_SYM_NIL, ENC_SYM_NIL);
4786
448
  return cons_with_gc(ENC_SYM_QUOTE, val, ENC_SYM_NIL);
4787
}
4788
4789
37856
bool is_append(lbm_value a) {
4790
75656
  return (lbm_is_cons(a) &&
4791

75656
          lbm_is_symbol(get_car(a)) &&
4792
37800
          (get_car(a) == ENC_SYM_APPEND));
4793
}
4794
4795
63672
lbm_value append(lbm_value front, lbm_value back) {
4796
63672
  if (lbm_is_symbol_nil(front)) return back;
4797
29344
  if (lbm_is_symbol_nil(back)) return front;
4798
4799

29960
  if (lbm_is_quoted_list(front) &&
4800
10388
      lbm_is_quoted_list(back)) {
4801
448
    lbm_value f = get_cadr(front);
4802
448
    lbm_value b = get_cadr(back);
4803
448
    return quote_it(lbm_list_append(f, b));
4804
  }
4805
4806

28672
  if (is_append(back) &&
4807
9940
      lbm_is_quoted_list(get_cadr(back)) &&
4808
392
       lbm_is_quoted_list(front)) {
4809
392
    lbm_value ql = get_cadr(back);
4810
392
    lbm_value f = get_cadr(front);
4811
392
    lbm_value b = get_cadr(ql);
4812
4813
392
    lbm_value v = lbm_list_append(f, b);
4814
392
    lbm_set_car(get_cdr(ql), v);
4815
392
    return back;
4816
  }
4817
4818
18732
  if (is_append(back)) {
4819
9156
    back  = get_cdr(back);
4820
9156
    lbm_value new = cons_with_gc(front, back, ENC_SYM_NIL);
4821
9156
    return cons_with_gc(ENC_SYM_APPEND, new, ENC_SYM_NIL);
4822
  }
4823
4824
  lbm_value t0, t1;
4825
4826
9576
  t0 = cons_with_gc(back, ENC_SYM_NIL, front);
4827
9576
  t1 = cons_with_gc(front, t0, ENC_SYM_NIL);
4828
9576
  return cons_with_gc(ENC_SYM_APPEND, t1, ENC_SYM_NIL);
4829
}
4830
4831
/* Bawden's qq-expand implementation
4832
(define (qq-expand x)
4833
  (cond ((tag-comma? x)
4834
         (tag-data x))
4835
        ((tag-comma-atsign? x)
4836
         (error "Illegal"))
4837
        ((tag-backquote? x)
4838
         (qq-expand
4839
          (qq-expand (tag-data x))))
4840
        ((pair? x)
4841
         `(append
4842
           ,(qq-expand-list (car x))
4843
           ,(qq-expand (cdr x))))
4844
        (else `',x)))
4845
 */
4846
34384
static void cont_qq_expand(eval_context_t *ctx) {
4847
  lbm_value qquoted;
4848
34384
  lbm_pop(&ctx->K, &qquoted);
4849
4850
34384
  switch(lbm_type_of(qquoted)) {
4851
24612
  case LBM_TYPE_CONS: {
4852
24612
    lbm_value car_val = get_car(qquoted);
4853
24612
    lbm_value cdr_val = get_cdr(qquoted);
4854

24612
    if (lbm_type_of(car_val) == LBM_TYPE_SYMBOL &&
4855
        car_val == ENC_SYM_COMMA) {
4856
28
      ctx->r = append(ctx->r, get_car(cdr_val));
4857
28
      ctx->app_cont = true;
4858

24584
    } else if (lbm_type_of(car_val) == LBM_TYPE_SYMBOL &&
4859
               car_val == ENC_SYM_COMMAAT) {
4860
      error_ctx(ENC_SYM_RERROR);
4861
    } else {
4862
24584
      lbm_value *rptr = stack_reserve(ctx, 6);
4863
24584
      rptr[0] = ctx->r;
4864
24584
      rptr[1] = QQ_APPEND;
4865
24584
      rptr[2] = cdr_val;
4866
24584
      rptr[3] = QQ_EXPAND;
4867
24584
      rptr[4] = car_val;
4868
24584
      rptr[5] = QQ_EXPAND_LIST;
4869
24584
      ctx->app_cont = true;
4870
24584
      ctx->r = ENC_SYM_NIL;
4871
    }
4872
4873
24612
  } break;
4874
9772
  default: {
4875
9772
    lbm_value res = quote_it(qquoted);
4876
9772
    ctx->r = append(ctx->r, res);
4877
9772
    ctx->app_cont = true;
4878
  }
4879
  }
4880
34384
}
4881
4882
29344
static void cont_qq_append(eval_context_t *ctx) {
4883
  lbm_value head;
4884
29344
  lbm_pop(&ctx->K, &head);
4885
29344
  ctx->r = append(head, ctx->r);
4886
29344
  ctx->app_cont = true;
4887
29344
}
4888
4889
/* Bawden's qq-expand-list implementation
4890
(define (qq-expand-list x)
4891
  (cond ((tag-comma? x)
4892
         `(list ,(tag-data x)))
4893
        ((tag-comma-atsign? x)
4894
         (tag-data x))
4895
        ((tag-backquote? x)
4896
         (qq-expand-list
4897
          (qq-expand (tag-data x))))
4898
        ((pair? x)
4899
         `(list
4900
           (append
4901
            ,(qq-expand-list (car x))
4902
            ,(qq-expand (cdr x)))))
4903
        (else `'(,x))))
4904
*/
4905
4906
29344
static void cont_qq_expand_list(eval_context_t* ctx) {
4907
  lbm_value l;
4908
29344
  lbm_pop(&ctx->K, &l);
4909
4910
29344
  ctx->app_cont = true;
4911
29344
  switch(lbm_type_of(l)) {
4912
18732
  case LBM_TYPE_CONS: {
4913
18732
    lbm_value car_val = get_car(l);
4914
18732
    lbm_value cdr_val = get_cdr(l);
4915

18732
    if (lbm_type_of(car_val) == LBM_TYPE_SYMBOL &&
4916
        car_val == ENC_SYM_COMMA) {
4917
13916
      lbm_value tl = cons_with_gc(get_car(cdr_val), ENC_SYM_NIL, ENC_SYM_NIL);
4918
13916
      lbm_value tmp = cons_with_gc(ENC_SYM_LIST, tl, ENC_SYM_NIL);
4919
13916
      ctx->r = append(ctx->r, tmp);
4920
13972
      return;
4921

4816
    } else if (lbm_type_of(car_val) == LBM_TYPE_SYMBOL &&
4922
               car_val == ENC_SYM_COMMAAT) {
4923
56
      ctx->r = get_car(cdr_val);
4924
56
      return;
4925
    } else {
4926
4760
      lbm_value *rptr = stack_reserve(ctx, 7);
4927
4760
      rptr[0] = QQ_LIST;
4928
4760
      rptr[1] = ctx->r;
4929
4760
      rptr[2] = QQ_APPEND;
4930
4760
      rptr[3] = cdr_val;
4931
4760
      rptr[4] = QQ_EXPAND;
4932
4760
      rptr[5] = car_val;
4933
4760
      rptr[6] = QQ_EXPAND_LIST;
4934
4760
      ctx->r = ENC_SYM_NIL;
4935
    }
4936
4937
4760
  } break;
4938
10612
  default: {
4939
10612
    lbm_value a_list = cons_with_gc(l, ENC_SYM_NIL, ENC_SYM_NIL);
4940
10612
    lbm_value tl = cons_with_gc(a_list, ENC_SYM_NIL, ENC_SYM_NIL);
4941
10612
    lbm_value tmp = cons_with_gc(ENC_SYM_QUOTE, tl, ENC_SYM_NIL);
4942
10612
    ctx->r = append(ctx->r, tmp);
4943
  }
4944
  }
4945
}
4946
4947
4760
static void cont_qq_list(eval_context_t *ctx) {
4948
4760
  lbm_value val = ctx->r;
4949
4760
  lbm_value apnd_app = cons_with_gc(val, ENC_SYM_NIL, ENC_SYM_NIL);
4950
4760
  lbm_value tmp = cons_with_gc(ENC_SYM_LIST, apnd_app, ENC_SYM_NIL);
4951
4760
  ctx->r = tmp;
4952
4760
  ctx->app_cont = true;
4953
4760
}
4954
4955
84
static void cont_kill(eval_context_t *ctx) {
4956
  (void) ctx;
4957
84
  ok_ctx();
4958
84
}
4959
4960
70066
static void cont_pop_reader_flags(eval_context_t *ctx) {
4961
  lbm_value flags;
4962
70066
  lbm_pop(&ctx->K, &flags);
4963
70066
  ctx->flags = ctx->flags & ~EVAL_CPS_CONTEXT_READER_FLAGS_MASK;
4964
70066
  ctx->flags |= (lbm_dec_as_u32(flags) & EVAL_CPS_CONTEXT_READER_FLAGS_MASK);
4965
  // r is unchanged.
4966
70066
  ctx->app_cont = true;
4967
70066
}
4968
4969
8288
static void cont_exception_handler(eval_context_t *ctx) {
4970
8288
  lbm_value *sptr = pop_stack_ptr(ctx, 2);
4971
8288
  lbm_value retval = sptr[0];
4972
8288
  lbm_value flags = sptr[1];
4973
8288
  lbm_set_car(get_cdr(retval), ctx->r);
4974
8288
  ctx->flags = (uint32_t)flags;
4975
8288
  ctx->r = retval;
4976
8288
  ctx->app_cont = true;
4977
8288
}
4978
4979
// cont_recv_to:
4980
//
4981
// s[sp-1] = patterns
4982
//
4983
// ctx->r = timeout value
4984
140
static void cont_recv_to(eval_context_t *ctx) {
4985
140
  if (lbm_is_number(ctx->r)) {
4986
140
    lbm_value *sptr = get_stack_ptr(ctx, 1); // patterns at sptr[0]
4987
140
    float timeout_time = lbm_dec_as_float(ctx->r);
4988
4989
140
    if (ctx->num_mail > 0) {
4990
      lbm_value e;
4991
56
      lbm_value new_env = ctx->curr_env;
4992
#ifdef LBM_ALWAYS_GC
4993
      gc();
4994
#endif
4995
56
      int n = find_match(sptr[0], ctx->mailbox, ctx->num_mail, &e, &new_env);
4996
56
      if (n == FM_NEED_GC) {
4997
        gc();
4998
        new_env = ctx->curr_env;
4999
        n = find_match(sptr[0], ctx->mailbox, ctx->num_mail, &e, &new_env);
5000
        if (n == FM_NEED_GC) error_ctx(ENC_SYM_MERROR);
5001
      }
5002
56
      if (n == FM_PATTERN_ERROR) {
5003
        lbm_set_error_reason("Incorrect pattern format for recv");
5004
        error_at_ctx(ENC_SYM_EERROR, sptr[0]);
5005
56
      } else if (n >= 0) { // match
5006
56
        mailbox_remove_mail(ctx, (lbm_uint)n);
5007
56
        ctx->curr_env = new_env;
5008
56
        ctx->curr_exp = e;
5009
56
        lbm_stack_drop(&ctx->K, 1);
5010
56
        return;
5011
      }
5012
    }
5013
    // If no mail or no match, go to sleep
5014
84
    lbm_uint *rptr = stack_reserve(ctx,2);
5015
84
    rptr[0] = ctx->r; // timeout time
5016
84
    rptr[1] = RECV_TO_RETRY;
5017
84
    block_current_ctx(LBM_THREAD_STATE_RECV_TO,S_TO_US(timeout_time),true);
5018
  } else {
5019
    error_ctx(ENC_SYM_TERROR);
5020
  }
5021
}
5022
5023
// cont_recv_to_retry
5024
//
5025
// s[sp-2] = patterns
5026
// s[sp-1] = timeout value
5027
//
5028
// ctx->r = nonsense | timeout symbol
5029
84
static void cont_recv_to_retry(eval_context_t *ctx) {
5030
84
  lbm_value *sptr = get_stack_ptr(ctx, 2); //sptr[0] = patterns, sptr[1] = timeout
5031
5032
  // num_mail should be at least 1 here.
5033
84
  if (ctx->num_mail > 0) {
5034
    lbm_value e;
5035
84
    lbm_value new_env = ctx->curr_env;
5036
#ifdef LBM_ALWAYS_GC
5037
    gc();
5038
#endif
5039
84
    int n = find_match(sptr[0], ctx->mailbox, ctx->num_mail, &e, &new_env);
5040
84
    if (n == FM_NEED_GC) {
5041
      gc();
5042
      new_env = ctx->curr_env;
5043
      n = find_match(sptr[0], ctx->mailbox, ctx->num_mail, &e, &new_env);
5044
      if (n == FM_NEED_GC) error_ctx(ENC_SYM_MERROR);
5045
    }
5046
84
    if (n == FM_PATTERN_ERROR) {
5047
      lbm_set_error_reason("Incorrect pattern format for recv");
5048
      error_at_ctx(ENC_SYM_EERROR, sptr[0]);
5049
84
    } else if (n >= 0) { // match
5050
56
      mailbox_remove_mail(ctx, (lbm_uint)n);
5051
56
      ctx->curr_env = new_env;
5052
56
      ctx->curr_exp = e;
5053
56
      lbm_stack_drop(&ctx->K, 2);
5054
56
      return;
5055
    }
5056
  }
5057
5058
  // No message matched but the timeout was reached.
5059
  // This is like having a recv-to with no case that matches
5060
  // the timeout symbol.
5061
28
  if (ctx->r == ENC_SYM_TIMEOUT) {
5062
28
    lbm_stack_drop(&ctx->K, 2);
5063
28
    ctx->app_cont = true;
5064
28
    return;
5065
  }
5066
5067
  //TODO: Timeout is reset if there is a completely unrelated message.
5068
  //      Don't currently have an easy fix for this.
5069
  stack_reserve(ctx,1)[0] = RECV_TO_RETRY;
5070
  block_current_ctx(LBM_THREAD_STATE_RECV_TO,S_TO_US(sptr[1]),true);
5071
}
5072
5073
/*********************************************************/
5074
/* Continuations table                                   */
5075
typedef void (*cont_fun)(eval_context_t *);
5076
5077
static const cont_fun continuations[NUM_CONTINUATIONS] =
5078
  { advance_ctx,  // CONT_DONE
5079
    cont_set_global_env,
5080
    cont_bind_to_key_rest,
5081
    cont_if,
5082
    cont_progn_rest,
5083
    cont_application_args,
5084
    cont_and,
5085
    cont_or,
5086
    cont_wait,
5087
    cont_match,
5088
    cont_application_start,
5089
    cont_eval_r,
5090
    cont_resume,
5091
    cont_closure_application_args,
5092
    cont_exit_atomic,
5093
    cont_read_next_token,
5094
    cont_read_append_continue,
5095
    cont_read_eval_continue,
5096
    cont_read_expect_closepar,
5097
    cont_read_dot_terminate,
5098
    cont_read_done,
5099
    cont_read_start_array,
5100
    cont_read_append_array,
5101
    cont_map,
5102
    cont_match_guard,
5103
    cont_terminate,
5104
    cont_progn_var,
5105
    cont_setq,
5106
    cont_move_to_flash,
5107
    cont_move_val_to_flash_dispatch,
5108
    cont_move_list_to_flash,
5109
    cont_close_list_in_flash,
5110
    cont_qq_expand_start,
5111
    cont_qq_expand,
5112
    cont_qq_append,
5113
    cont_qq_expand_list,
5114
    cont_qq_list,
5115
    cont_kill,
5116
    cont_loop,
5117
    cont_loop_condition,
5118
    cont_merge_rest,
5119
    cont_merge_layer,
5120
    cont_closure_args_rest,
5121
    cont_move_array_elts_to_flash,
5122
    cont_pop_reader_flags,
5123
    cont_exception_handler,
5124
    cont_recv_to,
5125
    cont_wrap_result,
5126
    cont_recv_to_retry
5127
  };
5128
5129
/*********************************************************/
5130
/* Evaluators lookup table (special forms)               */
5131
typedef void (*evaluator_fun)(eval_context_t *);
5132
5133
static const evaluator_fun evaluators[] =
5134
  {
5135
   eval_quote,
5136
   eval_define,
5137
   eval_progn,
5138
   eval_lambda,
5139
   eval_if,
5140
   eval_let,
5141
   eval_and,
5142
   eval_or,
5143
   eval_match,
5144
   eval_receive,
5145
   eval_receive_timeout,
5146
   eval_callcc,
5147
   eval_atomic,
5148
   eval_selfevaluating, // macro
5149
   eval_selfevaluating, // cont
5150
   eval_selfevaluating, // closure
5151
   eval_cond,
5152
   eval_app_cont,
5153
   eval_var,
5154
   eval_setq,
5155
   eval_move_to_flash,
5156
   eval_loop,
5157
   eval_trap
5158
  };
5159
5160
5161
/*********************************************************/
5162
/* Evaluator step function                               */
5163
5164
912163512
static void evaluation_step(void){
5165
912163512
  eval_context_t *ctx = ctx_running;
5166
#ifdef VISUALIZE_HEAP
5167
  heap_vis_gen_image();
5168
#endif
5169
5170
912163512
  if (ctx->app_cont) {
5171
    lbm_value k;
5172
424295918
    lbm_pop(&ctx->K, &k);
5173
424295918
    ctx->app_cont = false;
5174
5175
424295918
    lbm_uint decoded_k = DEC_CONTINUATION(k);
5176
5177
424295918
    if (decoded_k < NUM_CONTINUATIONS) {
5178
424295918
      continuations[decoded_k](ctx);
5179
    } else {
5180
      error_ctx(ENC_SYM_FATAL_ERROR);
5181
    }
5182
424287734
    return;
5183
  }
5184
5185
487867594
  if (lbm_is_symbol(ctx->curr_exp)) {
5186
224413008
    eval_symbol(ctx);
5187
224412952
    return;
5188
  }
5189
263454586
  if (lbm_is_cons(ctx->curr_exp)) {
5190
168922191
    lbm_cons_t *cell = lbm_ref_cell(ctx->curr_exp);
5191
168922191
    lbm_value h = cell->car;
5192

168922191
    if (lbm_is_symbol(h) && ((h & ENC_SPECIAL_FORMS_MASK) == ENC_SPECIAL_FORMS_BIT)) {
5193
63831175
      lbm_uint eval_index = lbm_dec_sym(h) & SPECIAL_FORMS_INDEX_MASK;
5194
63831175
      evaluators[eval_index](ctx);
5195
63831091
      return;
5196
    }
5197
    /*
5198
     * At this point head can be anything. It should evaluate
5199
     * into a form that can be applied (closure, symbol, ...) though.
5200
     */
5201
105091016
    lbm_value *reserved = stack_reserve(ctx, 3);
5202
105091016
    reserved[0] = ctx->curr_env;
5203
105091016
    reserved[1] = cell->cdr;
5204
105091016
    reserved[2] = APPLICATION_START;
5205
105091016
    ctx->curr_exp = h; // evaluate the function
5206
105091016
    return;
5207
  }
5208
5209
94532395
  eval_selfevaluating(ctx);
5210
94532395
  return;
5211
}
5212
5213
5214
// Reset has a built in pause.
5215
// so after reset, continue.
5216
void lbm_reset_eval(void) {
5217
  eval_cps_next_state_arg = 0;
5218
  eval_cps_next_state = EVAL_CPS_STATE_RESET;
5219
  if (eval_cps_next_state != eval_cps_run_state) eval_cps_state_changed = true;
5220
}
5221
5222
21664
void lbm_pause_eval(void ) {
5223
21664
  eval_cps_next_state_arg = 0;
5224
21664
  eval_cps_next_state = EVAL_CPS_STATE_PAUSED;
5225
21664
  if (eval_cps_next_state != eval_cps_run_state) eval_cps_state_changed = true;
5226
21664
}
5227
5228
21672
void lbm_pause_eval_with_gc(uint32_t num_free) {
5229
21672
  eval_cps_next_state_arg = num_free;
5230
21672
  eval_cps_next_state = EVAL_CPS_STATE_PAUSED;
5231
21672
  if (eval_cps_next_state != eval_cps_run_state) eval_cps_state_changed = true;
5232
21672
}
5233
5234
21672
void lbm_continue_eval(void) {
5235
21672
  eval_cps_next_state = EVAL_CPS_STATE_RUNNING;
5236
21672
  if (eval_cps_next_state != eval_cps_run_state) eval_cps_state_changed = true;
5237
21672
}
5238
5239
void lbm_kill_eval(void) {
5240
  eval_cps_next_state = EVAL_CPS_STATE_KILL;
5241
  if (eval_cps_next_state != eval_cps_run_state) eval_cps_state_changed = true;
5242
}
5243
5244
148973
uint32_t lbm_get_eval_state(void) {
5245
148973
  return eval_cps_run_state;
5246
}
5247
5248
// Only unblocks threads that are unblockable.
5249
// A sleeping thread is not unblockable.
5250
84
static void handle_event_unblock_ctx(lbm_cid cid, lbm_value v) {
5251
84
  eval_context_t *found = NULL;
5252
84
  mutex_lock(&qmutex);
5253
5254
84
  found = lookup_ctx_nm(&blocked, cid);
5255

84
  if (found && LBM_IS_STATE_UNBLOCKABLE(found->state)){
5256
84
    drop_ctx_nm(&blocked,found);
5257
84
    if (lbm_is_error(v)) {
5258
28
      get_stack_ptr(found, 1)[0] = TERMINATE; // replace TOS
5259
28
      found->app_cont = true;
5260
    }
5261
84
    found->r = v;
5262
84
    found->state = LBM_THREAD_STATE_READY;
5263
84
    enqueue_ctx_nm(&queue,found);
5264
  }
5265
84
  mutex_unlock(&qmutex);
5266
84
}
5267
5268
static void handle_event_define(lbm_value key, lbm_value val) {
5269
  lbm_uint dec_key = lbm_dec_sym(key);
5270
  lbm_uint ix_key  = dec_key & GLOBAL_ENV_MASK;
5271
  lbm_value *global_env = lbm_get_global_env();
5272
  lbm_uint orig_env = global_env[ix_key];
5273
  lbm_value new_env;
5274
  // A key is a symbol and should not need to be remembered.
5275
  WITH_GC(new_env, lbm_env_set(orig_env,key,val));
5276
5277
  global_env[ix_key] = new_env;
5278
}
5279
5280
7643
static lbm_value get_event_value(lbm_event_t *e) {
5281
  lbm_value v;
5282
7643
  if (e->buf_len > 0) {
5283
    lbm_flat_value_t fv;
5284
7643
    fv.buf = (uint8_t*)e->buf_ptr;
5285
7643
    fv.buf_size = e->buf_len;
5286
7643
    fv.buf_pos = 0;
5287
7643
    if (!lbm_unflatten_value(&fv, &v)) {
5288
      lbm_set_flags(LBM_FLAG_HANDLER_EVENT_DELIVERY_FAILED);
5289
      v = ENC_SYM_EERROR;
5290
    }
5291
    // Free the flat value buffer. GC is unaware of its existence.
5292
7643
    lbm_free(fv.buf);
5293
  } else {
5294
    v = (lbm_value)e->buf_ptr;
5295
  }
5296
7643
  return v;
5297
}
5298
5299
93335042
static void process_events(void) {
5300
5301
93335042
  if (!lbm_events) {
5302
    return;
5303
  }
5304
5305
  lbm_event_t e;
5306
186677727
  while (lbm_event_pop(&e)) {
5307
7643
    lbm_value event_val = get_event_value(&e);
5308

7643
    switch(e.type) {
5309
84
    case LBM_EVENT_UNBLOCK_CTX:
5310
84
      handle_event_unblock_ctx((lbm_cid)e.parameter, event_val);
5311
84
      break;
5312
    case LBM_EVENT_DEFINE:
5313
      handle_event_define((lbm_value)e.parameter, event_val);
5314
      break;
5315
7559
    case LBM_EVENT_FOR_HANDLER:
5316
7559
      if (lbm_event_handler_pid >= 0) {
5317
7559
        lbm_find_receiver_and_send(lbm_event_handler_pid, event_val);
5318
      }
5319
7559
      break;
5320
    case LBM_EVENT_RUN_USER_CALLBACK:
5321
      user_callback((void*)e.parameter);
5322
      break;
5323
    }
5324
93342685
  }
5325
}
5326
5327
/* eval_cps_run can be paused
5328
   I think it would be better use a mailbox for
5329
   communication between other threads and the run_eval
5330
   but for now a set of variables will be used. */
5331
21672
void lbm_run_eval(void){
5332
5333
21672
  if (setjmp(critical_error_jmp_buf) > 0) {
5334
    printf_callback("GC stack overflow!\n");
5335
    critical_error_callback();
5336
    // terminate evaluation thread.
5337
    return;
5338
  }
5339
5340
21672
  setjmp(error_jmp_buf);
5341
5342
106859
  while (eval_running) {
5343

52612
    if (eval_cps_state_changed  || eval_cps_run_state == EVAL_CPS_STATE_PAUSED) {
5344
22628
      eval_cps_state_changed = false;
5345

22628
      switch (eval_cps_next_state) {
5346
      case EVAL_CPS_STATE_RESET:
5347
        if (eval_cps_run_state != EVAL_CPS_STATE_RESET) {
5348
          is_atomic = false;
5349
          blocked.first = NULL;
5350
          blocked.last = NULL;
5351
          queue.first = NULL;
5352
          queue.last = NULL;
5353
          ctx_running = NULL;
5354
          eval_steps_quota = eval_steps_refill;
5355
          eval_cps_run_state = EVAL_CPS_STATE_RESET;
5356
          if (blocking_extension) {
5357
            blocking_extension = false;
5358
            mutex_unlock(&blocking_extension_mutex);
5359
          }
5360
        }
5361
        usleep_callback(EVAL_CPS_MIN_SLEEP);
5362
        continue;
5363
956
      case EVAL_CPS_STATE_PAUSED:
5364
956
        if (eval_cps_run_state != EVAL_CPS_STATE_PAUSED) {
5365
43336
          if (lbm_heap_num_free() < eval_cps_next_state_arg) {
5366
            gc();
5367
          }
5368
43336
          eval_cps_next_state_arg = 0;
5369
43336
          eval_cps_run_state = EVAL_CPS_STATE_PAUSED;
5370
        }
5371
956
        usleep_callback(EVAL_CPS_MIN_SLEEP);
5372
33539
        continue;
5373
      case EVAL_CPS_STATE_KILL:
5374
        eval_cps_run_state = EVAL_CPS_STATE_DEAD;
5375
        eval_running = false;
5376
        continue;
5377
21672
      default: // running state
5378
21672
        eval_cps_run_state = eval_cps_next_state;
5379
21672
        break;
5380
      }
5381
29984
    }
5382
    while (true) {
5383

1005542578
      if (eval_steps_quota && ctx_running) {
5384
912163512
        eval_steps_quota--;
5385
912163512
        evaluation_step();
5386
      } else {
5387
93379066
        if (eval_cps_state_changed) break;
5388
93335742
        eval_steps_quota = eval_steps_refill;
5389
93335742
        if (!is_atomic) {
5390
93335042
          if (gc_requested) {
5391
96
            gc();
5392
          }
5393
93335042
          process_events();
5394
93335042
          mutex_lock(&qmutex);
5395
93335042
          if (ctx_running) {
5396
91170995
            enqueue_ctx_nm(&queue, ctx_running);
5397
91170995
            ctx_running = NULL;
5398
          }
5399
93335042
          wake_up_ctxs_nm();
5400
93335042
          ctx_running = dequeue_ctx_nm(&queue);
5401
93335042
          mutex_unlock(&qmutex);
5402
93335042
          if (!ctx_running) {
5403
2106924
            lbm_system_sleeping = true;
5404
            //Fixed sleep interval to poll events regularly.
5405
2106924
            usleep_callback(EVAL_CPS_MIN_SLEEP);
5406
2106916
            lbm_system_sleeping = false;
5407
          }
5408
        }
5409
      }
5410
    }
5411
  }
5412
}
5413
5414
lbm_cid lbm_eval_program(lbm_value lisp) {
5415
  return lbm_create_ctx(lisp, ENC_SYM_NIL, 256, NULL);
5416
}
5417
5418
lbm_cid lbm_eval_program_ext(lbm_value lisp, unsigned int stack_size) {
5419
  return lbm_create_ctx(lisp, ENC_SYM_NIL, stack_size, NULL);
5420
}
5421
5422
21672
int lbm_eval_init() {
5423
21672
  if (!qmutex_initialized) {
5424
21672
    mutex_init(&qmutex);
5425
21672
    qmutex_initialized = true;
5426
  }
5427
21672
  if (!lbm_events_mutex_initialized) {
5428
21672
    mutex_init(&lbm_events_mutex);
5429
21672
    lbm_events_mutex_initialized = true;
5430
  }
5431
21672
  if (!blocking_extension_mutex_initialized) {
5432
21672
    mutex_init(&blocking_extension_mutex);
5433
21672
    blocking_extension_mutex_initialized = true;
5434
  }
5435
5436
21672
  mutex_lock(&qmutex);
5437
21672
  mutex_lock(&lbm_events_mutex);
5438
5439
21672
  blocked.first = NULL;
5440
21672
  blocked.last = NULL;
5441
21672
  queue.first = NULL;
5442
21672
  queue.last = NULL;
5443
21672
  ctx_running = NULL;
5444
5445
21672
  eval_cps_run_state = EVAL_CPS_STATE_RUNNING;
5446
5447
21672
  mutex_unlock(&lbm_events_mutex);
5448
21672
  mutex_unlock(&qmutex);
5449
5450
21672
  if (!lbm_init_env()) return 0;
5451
21672
  eval_running = true;
5452
21672
  return 1;
5453
}
5454
5455
21672
bool lbm_eval_init_events(unsigned int num_events) {
5456
5457
21672
  mutex_lock(&lbm_events_mutex);
5458
21672
  lbm_events = (lbm_event_t*)lbm_malloc(num_events * sizeof(lbm_event_t));
5459
21672
  bool r = false;
5460
21672
  if (lbm_events) {
5461
21672
    lbm_events_max = num_events;
5462
21672
    lbm_events_head = 0;
5463
21672
    lbm_events_tail = 0;
5464
21672
    lbm_events_full = false;
5465
21672
    lbm_event_handler_pid = -1;
5466
21672
    r = true;
5467
  }
5468
21672
  mutex_unlock(&lbm_events_mutex);
5469
21672
  return r;
5470
}