maug
Quick and dirty C mini-augmentation library.
Loading...
Searching...
No Matches
mlispe.h
Go to the documentation of this file.
1
2#ifndef MLISPE_H
3#define MLISPE_H
4
5#include <mlisps.h>
6
15#ifndef MLISP_TOKEN_SZ_MAX
16# define MLISP_TOKEN_SZ_MAX 4096
17#endif /* !MLISP_TOKEN_SZ_MAX */
18
19#ifndef MLISP_EXEC_TRACE_LVL
20# define MLISP_EXEC_TRACE_LVL 0
21#endif /* !MLISP_EXEC_TRACE_LVL */
22
23#define MLISP_ENV_FLAG_BUILTIN 0x02
24
26#define MLISP_ENV_FLAG_CMP_GT 0x10
27
29#define MLISP_ENV_FLAG_CMP_LT 0x20
30
32#define MLISP_ENV_FLAG_CMP_EQ 0x40
33
35#define MLISP_ENV_FLAG_ARI_ADD 0x10
36
38#define MLISP_ENV_FLAG_ARI_MUL 0x20
39
40#define MLISP_ENV_FLAG_ARI_DIV 0x40
41
42#define MLISP_ENV_FLAG_ARI_MOD 0x80
43
44#define MLISP_ENV_FLAG_ANO_OR 0x10
45
46#define MLISP_ENV_FLAG_ANO_AND 0x20
47
61#define mlisp_stack_push( exec, i, ctype ) \
62 (_mlisp_stack_push_ ## ctype( exec, (ctype)i ))
63
64MERROR_RETVAL mlisp_stack_dump(
65 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec );
66
74 struct MLISP_EXEC_STATE* exec, struct MLISP_STACK_NODE* o );
75
76 /* mlisp_stack */
77
89 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec,
90 const char* strpool, size_t token_strpool_idx, size_t token_strpool_sz );
91
92MERROR_RETVAL mlisp_env_unset(
93 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec,
94 const char* token, size_t token_sz );
95
96MERROR_RETVAL mlisp_env_set(
97 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec,
98 const char* token, size_t token_sz, uint8_t env_type, const void* data,
99 void* cb_data, uint8_t flags );
100
101MERROR_RETVAL mlisp_step(
102 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec );
103
104#define _MLISP_TYPE_TABLE_PUSH_PROTO( idx, ctype, name, const_name, fmt ) \
105 MERROR_RETVAL _mlisp_stack_push_ ## ctype( \
106 struct MLISP_EXEC_STATE* exec, ctype i );
107
108MLISP_TYPE_TABLE( _MLISP_TYPE_TABLE_PUSH_PROTO )
109
110 /* mlisp */
111
112#define mlisp_ast_has_ready_children( exec_child_idx, n ) \
113 ((exec_child_idx) < (n)->ast_idx_children_sz)
114
115#ifdef MLISPE_C
116
117static MERROR_RETVAL _mlisp_preempt(
118 const char* caller, struct MLISP_PARSER* parser,
119 size_t n_idx, struct MLISP_EXEC_STATE* exec, size_t* p_child_idx,
120 size_t new_idx );
121
122static MERROR_RETVAL _mlisp_step_iter(
123 struct MLISP_PARSER* parser,
124 size_t n_idx, struct MLISP_EXEC_STATE* exec );
125
126/* === */
127
128/* Stack Functions */
129
130/* === */
131
132MERROR_RETVAL mlisp_stack_dump(
133 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec
134) {
135 MERROR_RETVAL retval = MERROR_OK;
136 size_t i = 0;
137 char* strpool = NULL;
138 struct MLISP_STACK_NODE* n_stack = NULL;
139
140# define _MLISP_TYPE_TABLE_DUMPS( idx, ctype, name, const_name, fmt ) \
141 } else if( MLISP_TYPE_ ## const_name == n_stack->type ) { \
142 debug_printf( MLISP_EXEC_TRACE_LVL, \
143 MLISP_TRACE_SIGIL " stack " SIZE_T_FMT " (" #const_name "): " fmt, \
144 i, n_stack->value.name );
145
146 mdata_vector_lock( &(exec->stack) );
147 mdata_strpool_lock( &(parser->strpool), strpool ); \
148 while( i < mdata_vector_ct( &(exec->stack) ) ) {
149 n_stack = mdata_vector_get( &(exec->stack), i, struct MLISP_STACK_NODE );
150
151 /* Handle special exceptions. */
152 if( MLISP_TYPE_STR == n_stack->type ) {
153 debug_printf( MLISP_EXEC_TRACE_LVL,
154 MLISP_TRACE_SIGIL " stack " SIZE_T_FMT " (STR): %s",
155 i, &(strpool[n_stack->value.strpool_idx]) );
156
157 } else if( MLISP_TYPE_CB == n_stack->type ) {
158 debug_printf( MLISP_EXEC_TRACE_LVL,
159 MLISP_TRACE_SIGIL " stack " SIZE_T_FMT " (CB): %p",
160 i, n_stack->value.cb );
161
162 } else if( MLISP_TYPE_LAMBDA == n_stack->type ) {
163 debug_printf( MLISP_EXEC_TRACE_LVL,
164 MLISP_TRACE_SIGIL " stack " SIZE_T_FMT " (LAMBDA): " SIZE_T_FMT,
165 i, n_stack->value.lambda );
166
167 } else if( MLISP_TYPE_ARGS_S == n_stack->type ) {
168 debug_printf( MLISP_EXEC_TRACE_LVL,
169 MLISP_TRACE_SIGIL " stack " SIZE_T_FMT " (ARGS_S): " SIZE_T_FMT,
170 i, n_stack->value.args_start );
171
172 } else if( MLISP_TYPE_ARGS_E == n_stack->type ) {
173 debug_printf( MLISP_EXEC_TRACE_LVL,
174 MLISP_TRACE_SIGIL " stack " SIZE_T_FMT " (ARGS_E): " SIZE_T_FMT,
175 i, n_stack->value.args_end );
176
177 } else if( MLISP_TYPE_BEGIN == n_stack->type ) {
178 debug_printf( MLISP_EXEC_TRACE_LVL,
179 MLISP_TRACE_SIGIL " stack " SIZE_T_FMT " (BEGIN): " SIZE_T_FMT,
180 i, n_stack->value.begin );
181
182 /* Handle numeric types. */
183 MLISP_NUM_TYPE_TABLE( _MLISP_TYPE_TABLE_DUMPS );
184 } else {
185 error_printf( "invalid stack type: %u", n_stack->type );
186 }
187 i++;
188 }
189 mdata_strpool_unlock( &(parser->strpool), strpool );
190 mdata_vector_unlock( &(exec->stack) );
191
192cleanup:
193
194 return retval;
195}
196
197/* === */
198
199#define _MLISP_TYPE_TABLE_PUSH( idx, ctype, name, const_name, fmt ) \
200 MERROR_RETVAL _mlisp_stack_push_ ## ctype( \
201 struct MLISP_EXEC_STATE* exec, ctype i \
202 ) { \
203 struct MLISP_STACK_NODE n_stack; \
204 MERROR_RETVAL retval = MERROR_OK; \
205 debug_printf( MLISP_EXEC_TRACE_LVL, \
206 "pushing " #const_name " onto stack: " fmt, i ); \
207 n_stack.type = MLISP_TYPE_ ## const_name; \
208 n_stack.value.name = i; \
209 retval = mdata_vector_append( \
210 &(exec->stack), &n_stack, sizeof( struct MLISP_STACK_NODE ) ); \
211 if( 0 > retval ) { \
212 retval = mdata_retval( retval ); \
213 } else { \
214 retval = 0; \
215 } \
216 return retval; \
217 }
218
219MLISP_TYPE_TABLE( _MLISP_TYPE_TABLE_PUSH );
220
221/* === */
222
224 struct MLISP_EXEC_STATE* exec, struct MLISP_STACK_NODE* o
225) {
226 MERROR_RETVAL retval = MERROR_OK;
227 struct MLISP_STACK_NODE* n_stack = NULL;
228 size_t n_idx = 0;
229
230 /* Check for valid stack pointer. */
231 if( mdata_vector_ct( &(exec->stack) ) == 0 ) {
232 error_printf( "stack underflow!" );
233 retval = MERROR_OVERFLOW;
234 goto cleanup;
235 }
236
237 n_idx = mdata_vector_ct( &(exec->stack) ) - 1;
238
239 /* Perform the pop! */
240 mdata_vector_lock( &(exec->stack) );
241 n_stack = mdata_vector_get(
242 &(exec->stack), n_idx, struct MLISP_STACK_NODE );
243 assert( NULL != n_stack );
244 memcpy( o, n_stack, sizeof( struct MLISP_STACK_NODE ) );
245 n_stack = NULL;
246 mdata_vector_unlock( &(exec->stack) );
247
248# define _MLISP_TYPE_TABLE_POPD( idx, ctype, name, const_name, fmt ) \
249 } else if( MLISP_TYPE_ ## const_name == o->type ) { \
250 debug_printf( MLISP_EXEC_TRACE_LVL, \
251 "popping: " SSIZE_T_FMT ": " fmt, n_idx, o->value.name );
252
253 if( 0 ) {
254 MLISP_TYPE_TABLE( _MLISP_TYPE_TABLE_POPD )
255 }
256
257 retval = mdata_vector_remove( &(exec->stack), n_idx );
258
259cleanup:
260
261 return retval;
262}
263
264/* === */
265
266/* Env Functons */
267
268/* === */
269
270MERROR_RETVAL mlisp_env_dump(
271 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec
272) {
273 MERROR_RETVAL retval = MERROR_OK;
274 size_t i = 0;
275 char* strpool = NULL;
276 struct MLISP_ENV_NODE* e = NULL;
277
278# define _MLISP_TYPE_TABLE_DUMPE( idx, ctype, name, const_name, fmt ) \
279 } else if( MLISP_TYPE_ ## const_name == e->type ) { \
280 debug_printf( MLISP_EXEC_TRACE_LVL, \
281 MLISP_TRACE_SIGIL " env " SIZE_T_FMT \
282 " \"%s\" (" #const_name "): " fmt, \
283 i, &(strpool[e->name_strpool_idx]), e->value.name ); \
284
285 mdata_strpool_lock( &(parser->strpool), strpool );
286 mdata_vector_lock( &(exec->env) );
287 while( i < mdata_vector_ct( &(exec->env) ) ) {
288 assert( mdata_vector_is_locked( &(exec->env) ) );
289 e = mdata_vector_get( &(exec->env), i, struct MLISP_ENV_NODE );
290
291 if( MLISP_ENV_FLAG_BUILTIN == (MLISP_ENV_FLAG_BUILTIN & e->flags) ) {
292 /* Skip builtins. */
293 i++;
294 continue;
295 }
296
297 if( 0 ) {
298 MLISP_NUM_TYPE_TABLE( _MLISP_TYPE_TABLE_DUMPE );
299 /* Handle special exceptions. */
300 } else if( MLISP_TYPE_STR == e->type ) {
301 debug_printf( MLISP_EXEC_TRACE_LVL,
302 MLISP_TRACE_SIGIL " env " SIZE_T_FMT " \"%s\" (STR): %s",
303 i, &(strpool[e->name_strpool_idx]),
304 &(strpool[e->value.strpool_idx]) );
305
306 } else if( MLISP_TYPE_CB == e->type ) {
307 debug_printf( MLISP_EXEC_TRACE_LVL,
308 MLISP_TRACE_SIGIL " env " SIZE_T_FMT " \"%s\" (CB): %p",
309 i, &(strpool[e->name_strpool_idx]), e->value.cb );
310
311 } else if( MLISP_TYPE_LAMBDA == e->type ) {
312 debug_printf( MLISP_EXEC_TRACE_LVL,
313 MLISP_TRACE_SIGIL " env " SIZE_T_FMT
314 " \"%s\" (LAMBDA): " SIZE_T_FMT,
315 i, &(strpool[e->name_strpool_idx]), e->value.lambda );
316
317 } else if( MLISP_TYPE_ARGS_S == e->type ) {
318 debug_printf( MLISP_EXEC_TRACE_LVL,
319 MLISP_TRACE_SIGIL " env " SIZE_T_FMT
320 " \"%s\" (ARGS_S): " SIZE_T_FMT,
321 i, &(strpool[e->name_strpool_idx]), e->value.args_start );
322
323 } else if( MLISP_TYPE_ARGS_E == e->type ) {
324 debug_printf( MLISP_EXEC_TRACE_LVL,
325 MLISP_TRACE_SIGIL " env " SIZE_T_FMT
326 " \"%s\" (ARGS_E): " SIZE_T_FMT,
327 i, &(strpool[e->name_strpool_idx]), e->value.args_end );
328
329 } else {
330 error_printf( MLISP_TRACE_SIGIL " invalid env type: %u", e->type );
331 }
332 i++;
333 }
334 mdata_vector_unlock( &(exec->env) );
335 mdata_strpool_unlock( &(parser->strpool), strpool );
336
337cleanup:
338
339 return retval;
340}
341
342/* === */
343
345 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec,
346 const char* strpool, size_t token_strpool_idx, size_t token_strpool_sz
347) {
348 struct MLISP_ENV_NODE* node_out = NULL;
349 struct MLISP_ENV_NODE* node_test = NULL;
350 ssize_t i = mdata_vector_ct( &(exec->env) ) - 1;
351
352 /* This requires env be locked before entrance! */
353
354 while( 0 <= i ) {
355 assert( mdata_vector_is_locked( &(exec->env) ) );
356 node_test = mdata_vector_get( &(exec->env), i, struct MLISP_ENV_NODE );
357 if( 0 == strncmp(
358 &(strpool[node_test->name_strpool_idx]),
359 &(strpool[token_strpool_idx]),
360 token_strpool_sz + 1
361 ) ) {
362 node_out = node_test;
363 break;
364 }
365 i--;
366 }
367
368 return node_out;
369}
370
371/* === */
372
373MERROR_RETVAL mlisp_env_unset(
374 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec,
375 const char* token, size_t token_sz
376) {
377 MERROR_RETVAL retval = MERROR_OK;
378 ssize_t i = 0;
379 struct MLISP_ENV_NODE* e = NULL;
380 char* strpool = NULL;
381
382 assert( !mdata_vector_is_locked( &(exec->env) ) );
383 mdata_vector_lock( &(exec->env) );
384
385 mdata_strpool_lock( &(parser->strpool), strpool );
386
387 /* Search for the given token in the env. */
388 for( i = mdata_vector_ct( &(exec->env) ) - 1 ; 0 <= i ; i-- ) {
389 assert( mdata_vector_is_locked( &(exec->env) ) );
390 e = mdata_vector_get( &(exec->env), i, struct MLISP_ENV_NODE );
391
392 if( MLISP_TYPE_ARGS_E == e->type ) {
393 debug_printf( MLISP_EXEC_TRACE_LVL,
394 "reached end of env stack frame: " SSIZE_T_FMT, i );
395 goto cleanup;
396 }
397
398 if( 0 != strncmp(
399 token, &(strpool[e->name_strpool_idx]), token_sz + 1 )
400 ) {
401 continue;
402 }
403
404 /* Remove the token. */
405 debug_printf( MLISP_EXEC_TRACE_LVL,
406 "found token %s: %s (" SSIZE_T_FMT "), removing...",
407 token, &(strpool[e->name_strpool_idx]), i );
408 mdata_vector_unlock( &(exec->env) );
409
410 retval = mdata_vector_remove( &(exec->env), i );
411 mdata_vector_lock( &(exec->env) );
412 goto cleanup;
413 }
414
415cleanup:
416
417 assert( mdata_vector_is_locked( &(exec->env) ) );
418 mdata_vector_unlock( &(exec->env) );
419
420 mdata_strpool_unlock( &(parser->strpool), strpool );
421
422 return retval;
423}
424
425/* === */
426
427MERROR_RETVAL mlisp_env_set(
428 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec,
429 const char* token, size_t token_sz, uint8_t env_type, const void* data,
430 void* cb_data, uint8_t flags
431) {
432 MERROR_RETVAL retval = MERROR_OK;
433 struct MLISP_ENV_NODE e;
434 ssize_t new_idx_out = -1;
435
436 if( 0 == token_sz ) {
437 token_sz = maug_strlen( token );
438 }
439 assert( 0 < token_sz );
440
441 /* TODO: Find previous env nodes with same token and change. */
442
443 retval = mlisp_env_unset( parser, exec, token, token_sz );
444 maug_cleanup_if_not_ok();
445
446# define _MLISP_TYPE_TABLE_ASGN( idx, ctype, name, const_name, fmt ) \
447 case idx: \
448 debug_printf( MLISP_EXEC_TRACE_LVL, \
449 "setting env: \"%s\": #" fmt, \
450 token, (ctype)*((ctype*)data) ); \
451 e.value.name = *((ctype*)data); \
452 break;
453
454 /* Setup the new node to copy. */
455 maug_mzero( &e, sizeof( struct MLISP_ENV_NODE ) );
456 e.flags = flags;
457 e.name_strpool_idx =
458 mdata_strpool_append( &(parser->strpool), token, token_sz );
459 if( 0 > e.name_strpool_idx ) {
460 retval = mdata_retval( e.name_strpool_idx );
461 }
462 maug_cleanup_if_not_ok();
463 e.type = env_type;
464 e.cb_data = cb_data;
465 switch( env_type ) {
466 MLISP_NUM_TYPE_TABLE( _MLISP_TYPE_TABLE_ASGN );
467
468 /* Special cases: */
469
470 case 4 /* MLISP_TYPE_STR */:
471 debug_printf( MLISP_EXEC_TRACE_LVL,
472 "setting env: \"%s\": strpool(" SSIZE_T_FMT ")",
473 token, *((ssize_t*)data) );
474 e.value.strpool_idx = *((mdata_strpool_idx_t*)data);
475 break;
476
477 case 5 /* MLISP_TYPE_CB */:
478 debug_printf( MLISP_EXEC_TRACE_LVL,
479 "setting env: \"%s\": 0x%p", token, (mlisp_env_cb_t)data );
480 e.value.cb = (mlisp_env_cb_t)data;
481 break;
482
483 case 6 /* MLISP_TYPE_LAMBDA */:
484 debug_printf( MLISP_EXEC_TRACE_LVL,
485 "setting env: \"%s\": node #" SSIZE_T_FMT,
486 token, *((mlisp_lambda_t*)data) );
487 e.value.lambda = *((mlisp_lambda_t*)data);
488 break;
489
490 case 7: /* MLISP_TYPE_ARGS_S */
491 debug_printf( MLISP_EXEC_TRACE_LVL,
492 "setting env: \"%s\": node #" SSIZE_T_FMT,
493 token, *((mlisp_args_t*)data) );
494 e.value.args_start = *((mlisp_args_t*)data);
495 break;
496
497 case 8: /* MLISP_TYPE_ARGS_E */
498 debug_printf( MLISP_EXEC_TRACE_LVL,
499 "setting env: \"%s\": node #" SSIZE_T_FMT,
500 token, *((mlisp_arge_t*)data) );
501 e.value.args_end = *((mlisp_arge_t*)data);
502 break;
503
504 default:
505 error_printf( "attempted to define invalid type: %d", env_type );
506 retval = MERROR_EXEC;
507 goto cleanup;
508 }
509
510 /* Add the node to the env. */
511 new_idx_out = mdata_vector_append(
512 &(exec->env), &e, sizeof( struct MLISP_ENV_NODE ) );
513 if( 0 > new_idx_out ) {
514 retval = mdata_retval( new_idx_out );
515 }
516 maug_cleanup_if_not_ok();
517
518 debug_printf( MLISP_EXEC_TRACE_LVL, "setup env node " SSIZE_T_FMT ": %s",
519 new_idx_out, token );
520
521cleanup:
522
523 return retval;
524}
525
526/* === */
527
528static ssize_t _mlisp_env_get_env_frame(
529 struct MLISP_EXEC_STATE* exec, struct MLISP_ENV_NODE* e_out
530) {
531 MERROR_RETVAL retval = MERROR_OK;
532 ssize_t ret_idx = 0;
533 struct MLISP_ENV_NODE* e = NULL;
534 ssize_t i = 0;
535 uint8_t autolock = 0;
536
537 if( !mdata_vector_is_locked( &(exec->env) ) ) {
538 mdata_vector_lock( &(exec->env) );
539 autolock = 1;
540 }
541
542 for( i = mdata_vector_ct( &(exec->env) ) - 1; 0 <= i ; i-- ) {
543 /* debug_printf( MLISP_EXEC_TRACE_LVL,
544 "getting frame (trying " SSIZE_T_FMT "...)", i ); */
545 assert( mdata_vector_is_locked( &(exec->env) ) );
546 e = mdata_vector_get( &(exec->env), i, struct MLISP_ENV_NODE );
547 assert( NULL != e );
548
549 if( MLISP_TYPE_ARGS_S != e->type ) {
550 /* Hunt for the initial env arg separator. */
551 continue;
552 }
553
554 debug_printf( MLISP_EXEC_TRACE_LVL,
555 "found initial env arg separator " SSIZE_T_FMT " with ret: "
556 SSIZE_T_FMT,
557 i, e->value.args_start );
558
559 ret_idx = i;
560 if( NULL != e_out ) {
561 memcpy( e_out, e, sizeof( struct MLISP_ENV_NODE ) );
562 }
563 break;
564 }
565
566cleanup:
567
568 if( autolock ) {
569 mdata_vector_unlock( &(exec->env) );
570 }
571
572 if( MERROR_OK != retval ) {
573 ret_idx = retval * -1;
574 }
575
576 return ret_idx;
577}
578
579/* === */
580
581static ssize_t _mlisp_env_prune_args( struct MLISP_EXEC_STATE* exec ) {
582 ssize_t ret_idx = 0;
583 MERROR_RETVAL retval = MERROR_OK;
584 ssize_t i = 0;
585 struct MLISP_ENV_NODE* e = NULL;
586 size_t removed = 0;
587
588 /* This function modifies the env, so existing locks might break. */
589 assert( !mdata_vector_is_locked( &(exec->env) ) );
590
591 assert( 0 < mdata_vector_ct( &(exec->env) ) );
592
593 mdata_vector_lock( &(exec->env) );
594
595 /* Get the most recent start frame in the env. */
596 i = _mlisp_env_get_env_frame( exec, NULL );
597 debug_printf( MLISP_EXEC_TRACE_LVL,
598 "pruning env args starting from env frame " SSIZE_T_FMT "...", i );
599 e = mdata_vector_get( &(exec->env), i, struct MLISP_ENV_NODE );
600 assert( NULL != e );
601
602 while( MLISP_TYPE_ARGS_E != e->type ) {
603 mdata_vector_unlock( &(exec->env) );
604 retval = mdata_vector_remove( &(exec->env), i );
605 maug_cleanup_if_not_ok();
606 mdata_vector_lock( &(exec->env) );
607
608 /* Refresh e based on what i *now* points to. */
609 assert( mdata_vector_is_locked( &(exec->env) ) );
610 e = mdata_vector_get( &(exec->env), i, struct MLISP_ENV_NODE );
611 assert( NULL != e );
612
613 removed++;
614 }
615
616 /* Remove the actual terminal separator. */
617 mdata_vector_unlock( &(exec->env) );
618 retval = mdata_vector_remove( &(exec->env), i );
619 maug_cleanup_if_not_ok();
620 mdata_vector_lock( &(exec->env) );
621
622 debug_printf( MLISP_EXEC_TRACE_LVL,
623 "removed " SIZE_T_FMT " args!", removed );
624
625cleanup:
626
627 mdata_vector_unlock( &(exec->env) );
628
629 if( MERROR_OK != retval ) {
630 ret_idx = retval * -1;
631 }
632
633 return ret_idx;
634}
635
636/* === */
637
638static MERROR_RETVAL _mlisp_env_cb_cmp(
639 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec, size_t n_idx,
640 size_t args_c, void* cb_data, uint8_t flags
641) {
642 MERROR_RETVAL retval = MERROR_OK;
643 struct MLISP_STACK_NODE tmp;
644 char* strpool = NULL;
645 uint8_t truth = 0;
646 int a_int,
647 b_int;
648 int* cur_int = NULL;
649
650# define _MLISP_TYPE_TABLE_CMP( idx, ctype, name, const_name, fmt ) \
651 } else if( MLISP_TYPE_ ## const_name == tmp.type ) { \
652 *cur_int = (int)tmp.value.name; \
653 debug_printf( MLISP_EXEC_TRACE_LVL, \
654 "cmp: pop " fmt " (%d)", tmp.value.name, *cur_int );
655
656 retval = mlisp_stack_pop( exec, &tmp );
657 maug_cleanup_if_not_ok();
658 cur_int = &b_int;
659 if( 0 ) {
660 MLISP_NUM_TYPE_TABLE( _MLISP_TYPE_TABLE_CMP )
661 } else {
662 error_printf( "cmp: invalid type!" );
663 retval = MERROR_EXEC;
664 goto cleanup;
665 }
666
667 retval = mlisp_stack_pop( exec, &tmp );
668 maug_cleanup_if_not_ok();
669 cur_int = &a_int;
670 if( 0 ) {
671 MLISP_NUM_TYPE_TABLE( _MLISP_TYPE_TABLE_CMP )
672 } else {
673 error_printf( "cmp: invalid type!" );
674 retval = MERROR_EXEC;
675 goto cleanup;
676 }
677
678 /* TODO: String comparison? */
679
681 debug_printf( MLISP_EXEC_TRACE_LVL, "cmp %d > %d", a_int, b_int );
682 truth = a_int > b_int;
683 } else if( MLISP_ENV_FLAG_CMP_LT == (MLISP_ENV_FLAG_CMP_LT & flags) ) {
684 debug_printf( MLISP_EXEC_TRACE_LVL, "cmp %d < %d", a_int, b_int );
685 truth = a_int < b_int;
686 } else if( MLISP_ENV_FLAG_CMP_EQ == (MLISP_ENV_FLAG_CMP_EQ & flags) ) {
687 debug_printf( MLISP_EXEC_TRACE_LVL, "cmp %d == %d", a_int, b_int );
688 truth = a_int == b_int;
689 } else {
690 error_printf( "invalid parameter provided to _mlisp_env_cb_cmp()!" );
691 retval = MERROR_EXEC;
692 goto cleanup;
693 }
694
695 retval = mlisp_stack_push( exec, truth, mlisp_bool_t );
696
697cleanup:
698
699 mdata_strpool_unlock( &(parser->strpool), strpool );
700
701
702 return retval;
703}
704
705/* === */
706
707static MERROR_RETVAL _mlisp_env_cb_arithmetic(
708 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec, size_t n_idx,
709 size_t args_c, void* cb_data, uint8_t flags
710) {
711 MERROR_RETVAL retval = MERROR_OK;
712 struct MLISP_STACK_NODE num;
713 char* strpool = NULL;
714 /* TODO: Vary type based on multiplied types. */
715 int16_t num_out = 0;
716 size_t i = 0;
717
718# define _MLISP_TYPE_TABLE_ARI1( idx, ctype, name, const_name, fmt ) \
719 } else if( MLISP_TYPE_ ## const_name == num.type ) { \
720 num_out = num.value.name;
721
722 retval = mlisp_stack_pop( exec, &num );
723 maug_cleanup_if_not_ok();
724
725 if( 0 ) {
726 MLISP_NUM_TYPE_TABLE( _MLISP_TYPE_TABLE_ARI1 )
727 } else {
728 error_printf( "arithmetic: invalid type!" );
729 retval = MERROR_EXEC;
730 goto cleanup;
731 }
732
733# define _MLISP_TYPE_TABLE_ARI2( idx, ctype, name, const_name, fmt ) \
734 } else if( \
735 MLISP_TYPE_ ## const_name == num.type && \
736 MLISP_ENV_FLAG_ARI_ADD == (MLISP_ENV_FLAG_ARI_ADD & flags) \
737 ) { \
738 debug_printf( MLISP_EXEC_TRACE_LVL, \
739 "arithmetic: %d + " fmt, num_out, num.value.name ); \
740 num_out += num.value.name; \
741 } else if( \
742 MLISP_TYPE_ ## const_name == num.type && \
743 MLISP_ENV_FLAG_ARI_MUL == (MLISP_ENV_FLAG_ARI_MUL & flags) \
744 ) { \
745 debug_printf( MLISP_EXEC_TRACE_LVL, \
746 "arithmetic: %d * " fmt, num_out, num.value.name ); \
747 num_out *= num.value.name; \
748 } else if( \
749 MLISP_TYPE_ ## const_name == num.type && \
750 MLISP_ENV_FLAG_ARI_DIV == (MLISP_ENV_FLAG_ARI_DIV & flags) \
751 ) { \
752 debug_printf( MLISP_EXEC_TRACE_LVL, \
753 "arithmetic: %d / " fmt, num_out, num.value.name ); \
754 num_out /= num.value.name; \
755
756 for( i = 0 ; args_c - 1 > i ; i++ ) {
757 retval = mlisp_stack_pop( exec, &num );
758 maug_cleanup_if_not_ok();
759
760 if( 0 ) {
761 MLISP_NUM_TYPE_TABLE( _MLISP_TYPE_TABLE_ARI2 )
762
763 } else if(
764 MLISP_TYPE_INT == num.type &&
765 MLISP_ENV_FLAG_ARI_MOD == (MLISP_ENV_FLAG_ARI_MOD & flags)
766 ) {
767 /* Modulus is a special case, as you can't mod by float. */
768 debug_printf( MLISP_EXEC_TRACE_LVL,
769 "arithmetic: %d %% %d", num_out, num.value.integer );
770 num_out %= num.value.integer;
771 } else {
772 error_printf( "arithmetic: invalid type!" );
773 retval = MERROR_EXEC;
774 goto cleanup;
775 }
776 }
777
778 debug_printf( MLISP_EXEC_TRACE_LVL, "arithmetic result: %d", num_out );
779
780 retval = mlisp_stack_push( exec, num_out, int16_t );
781
782cleanup:
783
784 mdata_strpool_unlock( &(parser->strpool), strpool );
785
786 return retval;
787}
788
789/* === */
790
791static MERROR_RETVAL _mlisp_env_cb_define(
792 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec, size_t n_idx,
793 size_t args_c, void* cb_data, uint8_t flags
794) {
795 MERROR_RETVAL retval = MERROR_OK;
796 struct MLISP_STACK_NODE key;
797 struct MLISP_STACK_NODE val;
798 MAUG_MHANDLE key_tmp_h = NULL;
799 char* key_tmp = NULL;
800
801 retval = mlisp_stack_pop( exec, &val );
802 maug_cleanup_if_not_ok();
803
804 retval = mlisp_stack_pop( exec, &key );
805 maug_cleanup_if_not_ok();
806
807 if( MLISP_TYPE_STR != key.type ) {
808 /* TODO: Do we want to allow defining other types? */
809 /* TODO: We can use _mlisp_eval_token_strpool, maybe? */
810 error_printf( "define: invalid key type: %d", key.type );
811 retval = MERROR_EXEC;
812 goto cleanup;
813 }
814
815 key_tmp_h = mdata_strpool_extract(
816 &(parser->strpool), key.value.strpool_idx );
817 /* TODO: Handle this gracefully. */
818 assert( NULL != key_tmp_h );
819
820 maug_mlock( key_tmp_h, key_tmp );
821 maug_cleanup_if_null_lock( char*, key_tmp );
822
823 debug_printf( MLISP_EXEC_TRACE_LVL,
824 "define \"%s\" (strpool(" SIZE_T_FMT "))...",
825 key_tmp, key.value.strpool_idx );
826
827 retval = mlisp_env_set(
828 parser, exec, key_tmp, 0, val.type, &(val.value), NULL, 0 );
829
830cleanup:
831
832 if( NULL != key_tmp ) {
833 maug_munlock( key_tmp_h, key_tmp );
834 }
835
836 if( NULL != key_tmp_h ) {
837 maug_mfree( key_tmp_h );
838 }
839
840 return retval;
841}
842
843/* === */
844
845static MERROR_RETVAL _mlisp_env_cb_if(
846 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec, size_t n_idx,
847 size_t args_c, void* cb_data, uint8_t flags
848) {
849 MERROR_RETVAL retval = MERROR_OK;
850 size_t* p_if_child_idx = NULL;
851 struct MLISP_STACK_NODE s;
852 struct MLISP_AST_NODE* n = NULL;
853
854 debug_printf( MLISP_EXEC_TRACE_LVL, "qrqrqrqrqr STEP IF qrqrqrqrqr" );
855
856 /* Grab the current exec index for the child vector for this node. */
857 assert( mdata_vector_is_locked( &(exec->per_node_child_idx) ) );
858 p_if_child_idx = mdata_vector_get(
859 &(exec->per_node_child_idx), n_idx, size_t );
860 assert( NULL != p_if_child_idx );
861 debug_printf( MLISP_EXEC_TRACE_LVL,
862 "child idx for if AST node " SIZE_T_FMT ": " SIZE_T_FMT,
863 n_idx, *p_if_child_idx );
864
865 n = mdata_vector_get( &(parser->ast), n_idx, struct MLISP_AST_NODE );
866
867 if( 0 == *p_if_child_idx ) {
868 /* Evaluating if condition. */
869 debug_printf( MLISP_EXEC_TRACE_LVL, "stepping into condition..." );
870 retval = _mlisp_step_iter(
871 parser, n->ast_idx_children[*p_if_child_idx], exec );
872 debug_printf( MLISP_EXEC_TRACE_LVL, "...stepped out of condition" );
873
874 /* Vary the child we jump to based on the boolean val on the stack. */
875 if( MERROR_OK == retval ) {
876 /* Condition evaluation complete. */
877
878 /* Pop the result and check it. */
879 retval = mlisp_stack_pop( exec, &s );
880 maug_cleanup_if_not_ok();
881 if( MLISP_TYPE_BOOLEAN != s.type ) {
882 error_printf( "(if) can only evaluate boolean type!" );
883 retval = MERROR_EXEC;
884 goto cleanup;
885 }
886
887 /* Set the child pointer to 1 if TRUE and 2 if FALSE. */
888 retval = _mlisp_preempt(
889 "if", parser, n_idx, exec, p_if_child_idx,
890 /* Flip boolean and increment. */
891 (1 - s.value.boolean) + 1 );
892 }
893
894 } else if( args_c > *p_if_child_idx ) { /* 3 if else present, else 2. */
895 /* Pursuing TRUE or FALSE clause. */
896
897 debug_printf( MLISP_EXEC_TRACE_LVL,
898 "descending into IF path: " SIZE_T_FMT, *p_if_child_idx );
899
900 /* Prepare for stepping. */
901
902 /* Step and check. */
903 retval = _mlisp_step_iter(
904 parser, n->ast_idx_children[*p_if_child_idx], exec );
905 if( MERROR_OK == retval ) {
906 retval = _mlisp_preempt(
907 "if", parser, n_idx, exec, p_if_child_idx, 3 );
908 }
909 }
910
911cleanup:
912
913 debug_printf( MLISP_EXEC_TRACE_LVL, "qrqrqrqrqr END STEP IF qrqrqrqrqr" );
914
915 return retval;
916}
917
918/* === */
919
920static MERROR_RETVAL _mlisp_env_cb_random(
921 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec, size_t n_idx,
922 size_t args_c, void* cb_data, uint8_t flags
923) {
924 MERROR_RETVAL retval = MERROR_OK;
925 struct MLISP_STACK_NODE mod;
926 int16_t random_int = 0;
927
928 retval = mlisp_stack_pop( exec, &mod );
929 maug_cleanup_if_not_ok();
930
931 if( MLISP_TYPE_INT != mod.type ) {
932 /* TODO: Setup float. */
933 error_printf( "random: invalid modulus type: %d", mod.type );
934 retval = MERROR_EXEC;
935 goto cleanup;
936 }
937
938 random_int = retroflat_get_rand() % mod.value.integer;
939
940 debug_printf( MLISP_EXEC_TRACE_LVL, "random: %d", random_int );
941
942 mlisp_stack_push( exec, random_int, int16_t );
943
944cleanup:
945
946 return retval;
947}
948
949/* === */
950
951static MERROR_RETVAL _mlisp_env_cb_ano(
952 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec, size_t n_idx,
953 size_t args_c, void* cb_data, uint8_t flags
954) {
955 MERROR_RETVAL retval = MERROR_OK;
956 struct MLISP_STACK_NODE val;
957 mlisp_bool_t val_out =
958 MLISP_ENV_FLAG_ANO_OR == (MLISP_ENV_FLAG_ANO_OR & flags) ?
959 0 : 1;
960 size_t i = 0;
961
962 /* TODO: Switch this to a step_or() function so that we can opt not to
963 * evaluate conditions unless prior stepped children are false.
964 */
965
966 for( i = 0 ; args_c > i ; i++ ) {
967 retval = mlisp_stack_pop( exec, &val );
968 maug_cleanup_if_not_ok();
969
970 if( MLISP_TYPE_BOOLEAN != val.type ) {
971 error_printf( "or: invalid boolean type: %d", val.type );
972 }
973
974 if( val.value.boolean ) {
975 debug_printf( MLISP_EXEC_TRACE_LVL, "found TRUE in %s!",
976 MLISP_ENV_FLAG_ANO_OR == (MLISP_ENV_FLAG_ANO_OR & flags) ?
977 "or" : "and" );
978 val_out =
979 MLISP_ENV_FLAG_ANO_OR == (MLISP_ENV_FLAG_ANO_OR & flags) ? 1 : 0;
980 }
981 }
982
983 _mlisp_stack_push_mlisp_bool_t( exec, val_out );
984
985cleanup:
986
987 return retval;
988}
989
990/* === */
991
992/* Execution Functions */
993
994/* === */
995
996static MERROR_RETVAL _mlisp_preempt(
997 const char* caller, struct MLISP_PARSER* parser,
998 size_t n_idx, struct MLISP_EXEC_STATE* exec, size_t* p_child_idx,
999 size_t new_idx
1000) {
1001 /* Could not exec *this* node yet, so don't increment its parent. */
1002 MERROR_RETVAL retval = MERROR_PREEMPT;
1003 char* strpool = NULL;
1004 struct MLISP_AST_NODE* n = NULL;
1005
1006 n = mdata_vector_get( &(parser->ast), n_idx, struct MLISP_AST_NODE );
1007
1008 mdata_strpool_lock( &(parser->strpool), strpool );
1009 assert( 0 < maug_strlen( &(strpool[n->token_idx]) ) );
1010 debug_printf( MLISP_EXEC_TRACE_LVL,
1011 "eval step " SSIZE_T_FMT " under (%s) %s...",
1012 *p_child_idx, caller, &(strpool[n->token_idx]) );
1013 mdata_strpool_unlock( &(parser->strpool), strpool );
1014
1015 /* Increment this node, since the child actually executed. */
1016 (*p_child_idx) = new_idx;
1017 debug_printf( MLISP_EXEC_TRACE_LVL,
1018 "incremented " SIZE_T_FMT " child idx to: " SIZE_T_FMT,
1019 n_idx, *p_child_idx );
1020
1021cleanup:
1022
1023 return retval;
1024}
1025
1026/* === */
1027
1028static MERROR_RETVAL _mlisp_step_iter_children(
1029 struct MLISP_PARSER* parser, size_t n_idx, struct MLISP_EXEC_STATE* exec
1030) {
1031 MERROR_RETVAL retval = MERROR_OK;
1032 size_t* p_child_idx = NULL;
1033 struct MLISP_AST_NODE* n = NULL;
1034
1035 /* Grab the current exec index for the child vector for this node. */
1036 assert( mdata_vector_is_locked( &(exec->per_node_child_idx) ) );
1037 p_child_idx = mdata_vector_get(
1038 &(exec->per_node_child_idx), n_idx, size_t );
1039 assert( NULL != p_child_idx );
1040 debug_printf( MLISP_EXEC_TRACE_LVL,
1041 "child idx for AST node " SIZE_T_FMT ": " SIZE_T_FMT,
1042 n_idx, *p_child_idx );
1043
1044 n = mdata_vector_get( &(parser->ast), n_idx, struct MLISP_AST_NODE );
1045
1046 if(
1047 (
1048 MLISP_AST_FLAG_LAMBDA == (MLISP_AST_FLAG_LAMBDA & n->flags) &&
1049 0 == *p_child_idx
1050 ) ||
1051 MLISP_AST_FLAG_IF == (MLISP_AST_FLAG_IF & n->flags)
1052 ) {
1053 /* A lambda definition was found, and its exec counter is still pointing
1054 * to the arg list. This means the lambda was *not* called on the last
1055 * heartbeat, and we're probably just enountering its definition.
1056 *
1057 * Lambdas are lazily evaluated, so don't pursue it further until it's
1058 * called (stee _mlisp_step_lambda() for more info on this.
1059 */
1060 debug_printf( MLISP_EXEC_TRACE_LVL, "skipping lambda children..." );
1061 goto cleanup;
1062 }
1063
1064 if( mlisp_ast_has_ready_children( *p_child_idx, n ) ) {
1065 /* Call the next uncalled child. */
1066
1067 if(
1068 MLISP_AST_FLAG_DEFINE == (MLISP_AST_FLAG_DEFINE & n->flags) &&
1069 0 == *p_child_idx
1070 ) {
1071 /* The next child is a term to be defined. */
1072 debug_printf( MLISP_EXEC_TRACE_LVL,
1073 "setting MLISP_EXEC_FLAG_DEF_TERM!" );
1074 exec->flags |= MLISP_EXEC_FLAG_DEF_TERM;
1075 } else {
1076 exec->flags &= ~MLISP_EXEC_FLAG_DEF_TERM;
1077 }
1078
1079 /* Step and check. */
1080 retval = _mlisp_step_iter(
1081 parser, n->ast_idx_children[*p_child_idx], exec );
1082 if( MERROR_OK == retval ) {
1083 retval = _mlisp_preempt(
1084 "node", parser, n_idx, exec, p_child_idx, (*p_child_idx) + 1 );
1085 }
1086 goto cleanup;
1087
1088#if 0
1089 } else {
1090 /* Reset the node's child pointer to 0... this will allow it to be
1091 * re-entered later.
1092 */
1093 debug_printf( MDATA_TRACE_LVL,
1094 "resetting node " SIZE_T_FMT " child pointer to 0...",
1095 n_idx );
1096 *p_child_idx = 0;
1097#endif
1098 }
1099
1100cleanup:
1101
1102 return retval;
1103}
1104
1105/* === */
1106
1107static MERROR_RETVAL _mlisp_step_lambda_args(
1108 struct MLISP_PARSER* parser, size_t n_idx, struct MLISP_EXEC_STATE* exec
1109) {
1110 MERROR_RETVAL retval = MERROR_OK;
1111 ssize_t arg_idx = 0;
1112 struct MLISP_STACK_NODE stack_n_arg;
1113 struct MLISP_AST_NODE* ast_n_arg = NULL;
1114 MAUG_MHANDLE key_tmp_h = NULL;
1115 char* key_tmp = NULL;
1116 struct MLISP_AST_NODE* n = NULL;
1117
1118 /* Pop stack into args into the env. These are all the results of previous
1119 * evaluations, before the lambda call, so we can just grab them all in
1120 * one go!
1121 */
1122
1123 /* Get the current args node. */
1124 n = mdata_vector_get( &(parser->ast), n_idx, struct MLISP_AST_NODE );
1125 arg_idx = n->ast_idx_children_sz - 1;
1126
1127 while( 0 <= arg_idx ) {
1128
1129 retval = mlisp_stack_pop( exec, &stack_n_arg );
1130 maug_cleanup_if_not_ok();
1131
1132 ast_n_arg = mdata_vector_get(
1133 &(parser->ast), n->ast_idx_children[arg_idx],
1134 struct MLISP_AST_NODE );
1135
1136 /* Pull out the arg name from the strpool so we can call env_set(). */
1137 key_tmp_h = mdata_strpool_extract(
1138 &(parser->strpool), ast_n_arg->token_idx );
1139 /* TODO: Handle this gracefully. */
1140 assert( NULL != key_tmp_h );
1141
1142 maug_mlock( key_tmp_h, key_tmp );
1143 maug_cleanup_if_null_lock( char*, key_tmp );
1144
1145 retval = mlisp_env_set(
1146 parser, exec, key_tmp, 0, stack_n_arg.type, &(stack_n_arg.value),
1147 NULL, 0 );
1148 maug_cleanup_if_not_ok();
1149
1150 maug_munlock( key_tmp_h, key_tmp );
1151 maug_mfree( key_tmp_h );
1152
1153 arg_idx--;
1154 }
1155
1156cleanup:
1157
1158 if( NULL != key_tmp ) {
1159 maug_munlock( key_tmp_h, key_tmp );
1160 }
1161
1162 if( NULL != key_tmp_h ) {
1163 maug_mfree( key_tmp_h );
1164 }
1165
1166 return retval;
1167}
1168
1169/* === */
1170
1171static MERROR_RETVAL _mlisp_reset_child_pcs(
1172 struct MLISP_PARSER* parser,
1173 size_t n_idx, struct MLISP_EXEC_STATE* exec
1174) {
1175 MERROR_RETVAL retval = MERROR_OK;
1176 size_t* p_child_idx = NULL;
1177 size_t* p_visit_ct = NULL;
1178 struct MLISP_AST_NODE* n = NULL;
1179 size_t i = 0;
1180
1181 assert( mdata_vector_is_locked( &(exec->per_node_child_idx) ) );
1182 assert( mdata_vector_is_locked( &(parser->ast) ) );
1183
1184 /* Perform the actual reset. */
1185 debug_printf( MLISP_TRACE_LVL, "resetting PC on node: " SIZE_T_FMT, n_idx );
1186 p_child_idx = mdata_vector_get( &(exec->per_node_child_idx), n_idx, size_t );
1187 assert( NULL != p_child_idx );
1188 *p_child_idx = 0;
1189
1190 debug_printf( MLISP_TRACE_LVL,
1191 "resetting visit count on node: " SIZE_T_FMT, n_idx );
1192 p_visit_ct = mdata_vector_get( &(exec->per_node_visit_ct), n_idx, size_t );
1193 assert( NULL != p_visit_ct );
1194 *p_visit_ct = 0;
1195
1196 n = mdata_vector_get( &(parser->ast), n_idx, struct MLISP_AST_NODE );
1197
1198 /* Call reset on all children. */
1199 for( i = 0 ; n->ast_idx_children_sz > i ; i++ ) {
1200 retval = _mlisp_reset_child_pcs( parser, n->ast_idx_children[i], exec );
1201 maug_cleanup_if_not_ok();
1202 }
1203
1204cleanup:
1205
1206 return retval;
1207}
1208
1209/* === */
1210
1211static MERROR_RETVAL _mlisp_reset_lambda(
1212 struct MLISP_PARSER* parser,
1213 size_t n_idx, struct MLISP_EXEC_STATE* exec
1214) {
1215 MERROR_RETVAL retval = MERROR_OK;
1216 ssize_t ret_idx = 0;
1217
1218 debug_printf( MLISP_EXEC_TRACE_LVL,
1219 "resetting lambda " SIZE_T_FMT "...", n_idx );
1220
1221 assert( mdata_vector_is_locked( &(exec->per_node_child_idx) ) );
1222 assert( !mdata_vector_is_locked( &(exec->env) ) );
1223
1224 /* Clear off lambda stack args. */
1225 ret_idx = _mlisp_env_prune_args( exec );
1226 if( 0 > ret_idx ) {
1227 retval = ret_idx * -1;
1228 }
1229 maug_cleanup_if_not_ok();
1230
1231 /* Reset per-node program counters. */
1232 retval = _mlisp_reset_child_pcs( parser, n_idx, exec );
1233
1234cleanup:
1235
1236 return retval;
1237}
1238
1239/* === */
1240
1241static MERROR_RETVAL _mlisp_step_lambda(
1242 struct MLISP_PARSER* parser,
1243 size_t n_idx, struct MLISP_EXEC_STATE* exec
1244) {
1245 MERROR_RETVAL retval = MERROR_OK;
1246 size_t* p_lambda_child_idx = NULL;
1247 size_t* p_args_child_idx = NULL;
1248 struct MLISP_AST_NODE* n = NULL;
1249 size_t* p_n_last_lambda = NULL;
1250 ssize_t append_retval = 0;
1251
1252#ifdef MLISP_DEBUG_TRACE
1253 exec->trace[exec->trace_depth++] = n_idx;
1254 assert( exec->trace_depth <= MLISP_DEBUG_TRACE );
1255#endif /* MLISP_DEBUG_TRACE */
1256
1257 /* n_idx is the node of this lambda. */
1258 mdata_vector_lock( &(exec->lambda_trace) );
1259 p_n_last_lambda = mdata_vector_get_last( &(exec->lambda_trace), size_t );
1260 mdata_vector_unlock( &(exec->lambda_trace) );
1261 if( NULL != p_n_last_lambda && n_idx == *p_n_last_lambda ) {
1262 /* This is a recursive call, so get rid of the lambda context so we can
1263 * replace it with a new one afterwards.
1264 */
1265 debug_printf( MLISP_EXEC_TRACE_LVL, "TRACE TAIL TIME!" );
1266 _mlisp_reset_lambda( parser, n_idx, exec );
1267 retval = mdata_vector_remove_last( &(exec->lambda_trace) );
1268 maug_cleanup_if_not_ok();
1269 }
1270
1271 debug_printf( MLISP_EXEC_TRACE_LVL,
1272 "xvxvxvxvxvxvx STEP LAMBDA " SIZE_T_FMT " xvxvxvxvxvx", n_idx );
1273
1274 /* Note that we passed through this lambda to detect tail calls later. */
1275 append_retval = mdata_vector_append(
1276 &(exec->lambda_trace), &n_idx, sizeof( size_t ) );
1277 retval = mdata_retval( append_retval );
1278 maug_cleanup_if_not_ok();
1279
1280 /* Grab the current exec index for the child vector for this node. */
1281 assert( mdata_vector_is_locked( &(exec->per_node_child_idx) ) );
1282 p_lambda_child_idx = mdata_vector_get(
1283 &(exec->per_node_child_idx), n_idx, size_t );
1284 assert( NULL != p_lambda_child_idx );
1285 debug_printf( MLISP_EXEC_TRACE_LVL,
1286 "child idx for lambda AST node " SIZE_T_FMT ": " SIZE_T_FMT,
1287 n_idx, *p_lambda_child_idx );
1288
1289 n = mdata_vector_get( &(parser->ast), n_idx, struct MLISP_AST_NODE );
1290
1291 /* There needs to be an arg node and an exec node. */
1292 /* TODO: Handle this gracefully. */
1293 assert( 1 < n->ast_idx_children_sz );
1294
1295 if( 0 == *p_lambda_child_idx ) {
1296 /* Parse the args passed to this lambda into the env, temporarily. */
1297
1298 /* Get the current args node child index. */
1299 assert( mdata_vector_is_locked( &(exec->per_node_child_idx) ) );
1300 p_args_child_idx = mdata_vector_get(
1301 &(exec->per_node_child_idx),
1302 n->ast_idx_children[*p_lambda_child_idx], size_t );
1303 assert( NULL != p_args_child_idx );
1304 debug_printf( MLISP_EXEC_TRACE_LVL,
1305 "child idx for args AST node " SIZE_T_FMT ": " SIZE_T_FMT,
1306 *p_lambda_child_idx, *p_args_child_idx );
1307
1308 if( 0 == *p_args_child_idx ) {
1309 /* Set return call in env before first arg, in *before-arg* delimiter,
1310 * so the args can be stripped off later when we return. */
1311 retval = mlisp_env_set(
1312 parser, exec, "$ARGS_S$", 0, MLISP_TYPE_ARGS_S, &n_idx, NULL, 0 );
1313 maug_cleanup_if_not_ok();
1314 }
1315
1316 /* Pop stack into args in the env. */
1317 retval = _mlisp_step_lambda_args(
1318 parser, n->ast_idx_children[*p_lambda_child_idx], exec );
1319
1320 if( MERROR_OK == retval ) {
1321 /* Set *after-arg* delimiter in env after last arg. */
1322 retval = mlisp_env_set(
1323 parser, exec, "$ARGS_E$", 0, MLISP_TYPE_ARGS_E, &n_idx, NULL, 0 );
1324 maug_cleanup_if_not_ok();
1325
1326 /* Increment child idx so we call the exec child on next heartbeat. */
1327 (*p_lambda_child_idx)++;
1328 debug_printf( MLISP_EXEC_TRACE_LVL,
1329 "incremented " SIZE_T_FMT " child idx to: " SIZE_T_FMT,
1330 n_idx, *p_lambda_child_idx );
1331 }
1332
1333 /* Set the error to MERROR_PREEMPT so that caller knows this lambda isn't
1334 * finished executing.
1335 */
1336 retval = MERROR_PREEMPT;
1337
1338 } else if( mlisp_ast_has_ready_children( *p_lambda_child_idx, n ) ) {
1339 /* Dive into first lambda child until we no longer can. */
1340
1341 retval = _mlisp_step_iter(
1342 parser, n->ast_idx_children[*p_lambda_child_idx], exec );
1343
1344 if( MERROR_OK == retval ) {
1345 retval = _mlisp_preempt(
1346 "lambda", parser, n_idx, exec, p_lambda_child_idx,
1347 (*p_lambda_child_idx) + 1 );
1348 }
1349
1350 } else {
1351 /* No more children to execute! */
1352 _mlisp_reset_lambda( parser, n_idx, exec );
1353 }
1354
1355 /* TODO: If MERROR_PREEMPT is not returned, remove args_s and args_e? */
1356
1357cleanup:
1358
1359 debug_printf( MLISP_EXEC_TRACE_LVL,
1360 "xvxvxvxvxvxvx END STEP LAMBDA " SIZE_T_FMT " xvxvxvxvxvx", n_idx );
1361
1362 /* Cleanup the passthrough note for this heartbeat. */
1363 mdata_vector_remove_last( &(exec->lambda_trace) );
1364
1365 return retval;
1366}
1367
1368/* === */
1369
1370/* === */
1371
1372static MERROR_RETVAL _mlisp_stack_cleanup(
1373 struct MLISP_PARSER* parser, size_t n_idx, struct MLISP_EXEC_STATE* exec
1374) {
1375 MERROR_RETVAL retval = MERROR_OK;
1376 ssize_t i = 0;
1377 struct MLISP_STACK_NODE o;
1378
1379 /* Pop elements off the stack until we hit the matching begin frame. */
1380 i = mdata_vector_ct( &(exec->stack) ) - 1;
1381 while( 0 <= i ) {
1382
1383 retval = mlisp_stack_pop( exec, &o );
1384 maug_cleanup_if_not_ok();
1385
1386 if( MLISP_TYPE_BEGIN == o.type && n_idx == o.value.begin ) {
1387 break;
1388 }
1389
1390 i--;
1391 }
1392
1393cleanup:
1394
1395 return retval;
1396}
1397
1398/* === */
1399
1400static MERROR_RETVAL _mlisp_eval_token_strpool(
1401 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec,
1402 size_t token_idx, size_t token_sz, struct MLISP_ENV_NODE* e_out
1403) {
1404 uint8_t autolock = 0;
1405 char* strpool = NULL;
1406 MERROR_RETVAL retval = MERROR_OK;
1407 struct MLISP_ENV_NODE* p_e = NULL;
1408
1409 if( !mdata_vector_is_locked( &(exec->env) ) ) {
1410 mdata_vector_lock( &(exec->env) );
1411 autolock = 1;
1412 }
1413
1414 mdata_strpool_lock( &(parser->strpool), strpool );
1415
1416 assert( 0 < maug_strlen( &(strpool[token_idx]) ) );
1417
1418 debug_printf( MLISP_EXEC_TRACE_LVL,
1419 "eval token: \"%s\" (maug_strlen: " SIZE_T_FMT ")",
1420 &(strpool[token_idx]), maug_strlen( &(strpool[token_idx]) ) );
1421 if( 0 == strncmp( &(strpool[token_idx]), "begin", token_sz ) ) {
1422 /* Fake env node e to signal step_iter() to place/cleanup stack frame. */
1423 e_out->type = MLISP_TYPE_BEGIN;
1424
1425 } else if( NULL != (p_e = mlisp_env_get_strpool(
1426 parser, exec, strpool, token_idx, token_sz
1427 ) ) ) {
1428 /* A literal found in the environment. */
1429 debug_printf( MLISP_EXEC_TRACE_LVL, "found %s in env!",
1430 &(strpool[p_e->name_strpool_idx]) );
1431
1432 /* Copy onto native stack so we can unlock env in case this is a
1433 * callback that needs to execute. */
1434 memcpy( e_out, p_e, sizeof( struct MLISP_ENV_NODE ) );
1435 p_e = NULL;
1436
1437 } else if( maug_is_num( &(strpool[token_idx]), token_sz, 10, 1 ) ) {
1438 /* Fake env node e from a numeric literal. */
1439 e_out->value.integer =
1440 maug_atos32( &(strpool[token_idx]), token_sz );
1441 e_out->type = MLISP_TYPE_INT;
1442
1443 } else if( maug_is_float( &(strpool[token_idx]), token_sz ) ) {
1444 /* Fake env node e from a floating point numeric literal. */
1445 e_out->value.floating = maug_atof( &(strpool[token_idx]), token_sz );
1446 e_out->type = MLISP_TYPE_FLOAT;
1447
1448 }
1449
1450cleanup:
1451
1452 if( autolock ) {
1453 mdata_vector_unlock( &(exec->env) );
1454 }
1455
1456 mdata_strpool_unlock( &(parser->strpool), strpool );
1457
1458 return retval;
1459}
1460
1461static MERROR_RETVAL _mlisp_step_iter(
1462 struct MLISP_PARSER* parser,
1463 size_t n_idx, struct MLISP_EXEC_STATE* exec
1464) {
1465 MERROR_RETVAL retval = MERROR_OK;
1466 struct MLISP_ENV_NODE e;
1467 struct MLISP_AST_NODE* n = NULL;
1468 size_t* p_visit_ct = NULL;
1469
1470#ifdef MLISP_DEBUG_TRACE
1471 exec->trace[exec->trace_depth++] = n_idx;
1472 assert( exec->trace_depth <= MLISP_DEBUG_TRACE );
1473#endif /* MLISP_DEBUG_TRACE */
1474
1475 n = mdata_vector_get( &(parser->ast), n_idx, struct MLISP_AST_NODE );
1476
1477 assert( mdata_vector_is_locked( &(exec->per_node_visit_ct) ) );
1478 p_visit_ct = mdata_vector_get(
1479 &(exec->per_node_visit_ct), n_idx, size_t );
1480 assert( NULL != p_visit_ct );
1481 (*p_visit_ct)++;
1482 debug_printf( MLISP_EXEC_TRACE_LVL,
1483 "visit count for AST node " SIZE_T_FMT ": " SIZE_T_FMT,
1484 n_idx, *p_visit_ct );
1485
1486 /* Push a stack frame marker on the first visit to a BEGIN node. */
1487 if(
1488 MLISP_AST_FLAG_BEGIN == (MLISP_AST_FLAG_BEGIN & n->flags) &&
1489 1 == *p_visit_ct
1490 ) {
1491 /* Push a stack frame on first visit. */
1492 _mlisp_stack_push_mlisp_begin_t( exec, n_idx );
1493 }
1494
1495 if(
1496 MERROR_OK !=
1497 (retval = _mlisp_step_iter_children( parser, n_idx, exec ))
1498 ) {
1499 goto cleanup;
1500 }
1501
1502 /* Check for special types like lambda, that are lazily evaluated. */
1503 if( MLISP_AST_FLAG_LAMBDA == (MLISP_AST_FLAG_LAMBDA & n->flags) ) {
1504 /* Push the lambda to the stack so that the "define" above it can
1505 * grab it and associate it with the env.
1506 */
1507 /* TODO: Assert node above it is a define! */
1508 mlisp_stack_push( exec, n_idx, mlisp_lambda_t );
1509 goto cleanup;
1510 }
1511
1512 /* Now that the children have been evaluated above, evaluate this node.
1513 * Assume all the previously called children are now on the stack.
1514 */
1515
1516 /* Grab the token for this node and figure out what it is. */
1517
1518 retval = _mlisp_eval_token_strpool(
1519 parser, exec, n->token_idx, n->token_sz, &e );
1520 maug_cleanup_if_not_ok();
1521
1522 /* Prepare to step. */
1523
1524 /* Put the token or its result (if callable) on the stack. */
1525# define _MLISP_TYPE_TABLE_ENVE( idx, ctype, name, const_name, fmt ) \
1526 } else if( MLISP_TYPE_ ## const_name == e.type ) { \
1527 _mlisp_stack_push_ ## ctype( exec, e.value.name );
1528
1529 if( MLISP_EXEC_FLAG_DEF_TERM == (MLISP_EXEC_FLAG_DEF_TERM & exec->flags) ) {
1530 /* Avoid a deadlock when *re*-assigning terms caused by term being
1531 * evaluated before it is defined.
1532 */
1533 debug_printf( MLISP_EXEC_TRACE_LVL,
1534 "special case! pushing literal to define: " SSIZE_T_FMT,
1535 n->token_idx );
1536 _mlisp_stack_push_mdata_strpool_idx_t( exec, n->token_idx );
1537 } else if( MLISP_TYPE_BEGIN == e.type ) {
1538 /* Cleanup the stack that's been pushed by children since this BEGIN's
1539 * initial visit.
1540 */
1541 retval = _mlisp_stack_cleanup( parser, n_idx, exec );
1542
1543 } else if( MLISP_TYPE_CB == e.type ) {
1544 /* This is a special case... rather than pushing the callback, *execute*
1545 * it and let it push its result to the stack. This will create a
1546 * redundant case below, but that can't be helped...
1547 */
1548 retval = e.value.cb(
1549 parser, exec, n_idx, n->ast_idx_children_sz, e.cb_data, e.flags );
1550
1551 } else if( MLISP_TYPE_LAMBDA == e.type ) {
1552 /* Create a "portal" into the lambda. The execution chain stays pointing
1553 * to this lambda-call node, but _mlisp_step_lambda() returns
1554 * MERROR_PREEMPT up the chain for subsequent heartbeats, until lambda is
1555 * done.
1556 */
1557 retval = _mlisp_step_lambda( parser, e.value.lambda, exec );
1558
1559 MLISP_TYPE_TABLE( _MLISP_TYPE_TABLE_ENVE )
1560 } else {
1561 _mlisp_stack_push_mdata_strpool_idx_t( exec, n->token_idx );
1562 }
1563
1564cleanup:
1565
1566 return retval;
1567}
1568
1569/* === */
1570
1571MERROR_RETVAL mlisp_step(
1572 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec
1573) {
1574 MERROR_RETVAL retval = MERROR_OK;
1575#ifdef MLISP_DEBUG_TRACE
1576 size_t i = 0;
1577 char trace_str[MLISP_DEBUG_TRACE * 5];
1578 maug_ms_t ms_start = 0;
1579 maug_ms_t ms_end = 0;
1580
1581 ms_start = retroflat_get_ms();
1582#endif /* MLISP_DEBUG_TRACE */
1583
1584 debug_printf( MLISP_EXEC_TRACE_LVL, "heartbeat start" );
1585
1586 /* These can remain locked for the whole step, as they're never added or
1587 * removed.
1588 */
1589 assert( !mdata_vector_is_locked( &(exec->per_node_child_idx) ) );
1590 assert( !mdata_vector_is_locked( &(exec->per_node_visit_ct) ) );
1591 assert( !mdata_vector_is_locked( &(parser->ast) ) );
1592 mdata_vector_lock( &(exec->per_node_child_idx) );
1593 mdata_vector_lock( &(exec->per_node_visit_ct) );
1594 mdata_vector_lock( &(parser->ast) );
1595
1596 if( 0 == mdata_vector_ct( &(parser->ast) ) ) {
1597 error_printf( "no valid AST present; could not exec!" );
1598 retval = MERROR_EXEC;
1599 goto cleanup;
1600 }
1601
1602 exec->flags = 0;
1603 assert( 0 == mdata_vector_ct( &(exec->lambda_trace) ) );
1604
1605#ifdef MLISP_DEBUG_TRACE
1606 exec->trace_depth = 0;
1607#endif /* MLISP_DEBUG_TRACE */
1608
1609 /* Find next unevaluated symbol. */
1610 retval = _mlisp_step_iter( parser, 0, exec );
1611 if( MERROR_PREEMPT == retval ) {
1612 /* There's still more to execute. */
1613 retval = MERROR_OK;
1614 } else if( MERROR_OK == retval ) {
1615 /* The last node executed completely. */
1616 debug_printf( MLISP_EXEC_TRACE_LVL, "execution terminated successfully" );
1617 retval = MERROR_EXEC; /* Signal the caller: we're out of instructions! */
1618 } else {
1619 debug_printf( MLISP_EXEC_TRACE_LVL,
1620 "execution terminated with retval: %d", retval );
1621 }
1622
1623#ifdef MLISP_DEBUG_TRACE
1624 ms_end = retroflat_get_ms();
1625
1626 maug_mzero( trace_str, MLISP_DEBUG_TRACE * 5 );
1627 for( i = 0 ; exec->trace_depth > i ; i++ ) {
1628 maug_snprintf(
1629 &(trace_str[maug_strlen( trace_str )]),
1630 (MLISP_DEBUG_TRACE * 5) - maug_strlen( trace_str ),
1631 SIZE_T_FMT ", ", exec->trace[i] );
1632 }
1633 debug_printf( MLISP_EXEC_TRACE_LVL,
1634 MLISP_TRACE_SIGIL " HBEXEC (%u): %s",
1635 ms_end - ms_start, trace_str );
1636#endif /* MLISP_DEBUG_TRACE */
1637
1638cleanup:
1639
1640 debug_printf( MLISP_EXEC_TRACE_LVL, "heartbeat end: %x", retval );
1641
1642 assert( mdata_vector_is_locked( &(parser->ast) ) );
1643 mdata_vector_unlock( &(parser->ast) );
1644 mdata_vector_unlock( &(exec->per_node_visit_ct) );
1645 mdata_vector_unlock( &(exec->per_node_child_idx) );
1646
1647 return retval;
1648}
1649
1650/* === */
1651
1652MERROR_RETVAL mlisp_exec_init(
1653 struct MLISP_PARSER* parser, struct MLISP_EXEC_STATE* exec
1654) {
1655 MERROR_RETVAL retval = MERROR_OK;
1656 ssize_t append_retval = 0;
1657 size_t zero = 0;
1658
1659 maug_mzero( exec, sizeof( struct MLISP_EXEC_STATE ) );
1660
1661 /* Setup lambda visit stack so it can be locked on first step. */
1662 retval = mdata_vector_append(
1663 &(exec->lambda_trace), &zero, sizeof( size_t ) );
1664 if( 0 > append_retval ) {
1665 retval = mdata_retval( append_retval );
1666 }
1667 maug_cleanup_if_not_ok();
1668 mdata_vector_remove_last( &(exec->lambda_trace) );
1669
1670 append_retval = mdata_vector_alloc(
1671 &(exec->env), sizeof( struct MLISP_ENV_NODE ), MDATA_VECTOR_INIT_SZ );
1672 if( 0 > append_retval ) {
1673 retval = mdata_retval( append_retval );
1674 }
1675 maug_cleanup_if_not_ok();
1676
1677 /* Create the node PCs. */
1678 retval = mdata_vector_append(
1679 &(exec->per_node_child_idx), &zero, sizeof( size_t ) );
1680 maug_cleanup_if_not_ok();
1681
1682 /* Make sure there's an exec child node for every AST node. */
1683 while(
1684 mdata_vector_ct( &(exec->per_node_child_idx) ) <=
1685 mdata_vector_ct( &(parser->ast) )
1686 ) {
1687 retval = mdata_vector_append( &(exec->per_node_child_idx), &zero,
1688 sizeof( size_t ) );
1689 }
1690
1691 /* Create the node visit counters. */
1692 retval = mdata_vector_append(
1693 &(exec->per_node_visit_ct), &zero, sizeof( size_t ) );
1694 maug_cleanup_if_not_ok();
1695
1696 /* Make sure there's an exec visit count for every AST node. */
1697 while(
1698 mdata_vector_ct( &(exec->per_node_visit_ct) ) <=
1699 mdata_vector_ct( &(parser->ast) )
1700 ) {
1701 retval = mdata_vector_append( &(exec->per_node_visit_ct), &zero,
1702 sizeof( size_t ) );
1703 }
1704
1705 /* Setup initial env. */
1706
1707 retval = mlisp_env_set(
1708 parser, exec, "and", 2, MLISP_TYPE_CB, _mlisp_env_cb_ano,
1709 NULL, MLISP_ENV_FLAG_BUILTIN | MLISP_ENV_FLAG_ANO_AND );
1710 maug_cleanup_if_not_ok();
1711 retval = mlisp_env_set(
1712 parser, exec, "or", 2, MLISP_TYPE_CB, _mlisp_env_cb_ano,
1713 NULL, MLISP_ENV_FLAG_BUILTIN | MLISP_ENV_FLAG_ANO_OR );
1714 maug_cleanup_if_not_ok();
1715 retval = mlisp_env_set(
1716 parser, exec, "random", 6, MLISP_TYPE_CB, _mlisp_env_cb_random,
1717 NULL, MLISP_ENV_FLAG_BUILTIN );
1718 maug_cleanup_if_not_ok();
1719 retval = mlisp_env_set(
1720 parser, exec, "if", 2, MLISP_TYPE_CB, _mlisp_env_cb_if,
1721 NULL, MLISP_ENV_FLAG_BUILTIN );
1722 maug_cleanup_if_not_ok();
1723 retval = mlisp_env_set(
1724 parser, exec, "define", 6, MLISP_TYPE_CB, _mlisp_env_cb_define,
1725 NULL, MLISP_ENV_FLAG_BUILTIN );
1726 maug_cleanup_if_not_ok();
1727 retval = mlisp_env_set(
1728 parser, exec, "*", 1, MLISP_TYPE_CB, _mlisp_env_cb_arithmetic,
1729 NULL, MLISP_ENV_FLAG_BUILTIN | MLISP_ENV_FLAG_ARI_MUL );
1730 maug_cleanup_if_not_ok();
1731 retval = mlisp_env_set(
1732 parser, exec, "+", 1, MLISP_TYPE_CB, _mlisp_env_cb_arithmetic,
1733 NULL, MLISP_ENV_FLAG_BUILTIN | MLISP_ENV_FLAG_ARI_ADD );
1734 maug_cleanup_if_not_ok();
1735 retval = mlisp_env_set(
1736 parser, exec, "/", 1, MLISP_TYPE_CB, _mlisp_env_cb_arithmetic,
1737 NULL, MLISP_ENV_FLAG_BUILTIN | MLISP_ENV_FLAG_ARI_DIV );
1738 maug_cleanup_if_not_ok();
1739 retval = mlisp_env_set(
1740 parser, exec, "%", 1, MLISP_TYPE_CB, _mlisp_env_cb_arithmetic,
1741 NULL, MLISP_ENV_FLAG_BUILTIN | MLISP_ENV_FLAG_ARI_MOD );
1742 maug_cleanup_if_not_ok();
1743 retval = mlisp_env_set(
1744 parser, exec, "<", 1, MLISP_TYPE_CB, _mlisp_env_cb_cmp,
1745 NULL, MLISP_ENV_FLAG_BUILTIN | MLISP_ENV_FLAG_CMP_LT );
1746 maug_cleanup_if_not_ok();
1747 retval = mlisp_env_set(
1748 parser, exec, ">", 1, MLISP_TYPE_CB, _mlisp_env_cb_cmp,
1749 NULL, MLISP_ENV_FLAG_BUILTIN | MLISP_ENV_FLAG_CMP_GT );
1750 maug_cleanup_if_not_ok();
1751 retval = mlisp_env_set(
1752 parser, exec, "=", 1, MLISP_TYPE_CB, _mlisp_env_cb_cmp,
1753 NULL, MLISP_ENV_FLAG_BUILTIN | MLISP_ENV_FLAG_CMP_EQ );
1754 maug_cleanup_if_not_ok();
1755
1756cleanup:
1757
1758 if( MERROR_OK != retval ) {
1759 error_printf( "mlisp exec initialization failed: %d", retval );
1760 }
1761
1762 return retval;
1763}
1764
1765/* === */
1766
1767void mlisp_exec_free( struct MLISP_EXEC_STATE* exec ) {
1768 mdata_vector_free( &(exec->per_node_child_idx) );
1769 mdata_vector_free( &(exec->per_node_visit_ct) );
1770 mdata_vector_free( &(exec->stack) );
1771 mdata_vector_free( &(exec->env) );
1772 mdata_vector_free( &(exec->lambda_trace) );
1773}
1774
1775#else
1776
1777# define MLISP_PSTATE_TABLE_CONST( name, idx ) \
1778 extern MAUG_CONST uint8_t SEG_MCONST name;
1779
1780MLISP_PARSER_PSTATE_TABLE( MLISP_PSTATE_TABLE_CONST )
1781
1782#ifdef MPARSER_TRACE_NAMES
1783extern MAUG_CONST char* SEG_MCONST gc_mlisp_pstate_names[];
1784#endif /* MPARSER_TRACE_NAMES */
1785
1786#endif /* MLISPE_C */
1787
1788#endif /* !MLISPE_H */
1789
int MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition merror.h:19
#define maug_mzero(ptr, sz)
Zero the block of memory pointed to by ptr.
Definition mmem.h:62
MERROR_RETVAL mlisp_stack_pop(struct MLISP_EXEC_STATE *exec, struct MLISP_STACK_NODE *o)
Pop a value off of (removing from) MLISP_EXEC_STATE::stack and copy it to a provided output.
#define mlisp_stack_push(exec, i, ctype)
Push a value onto MLISP_EXEC_STATE::stack.
Definition mlispe.h:61
#define MLISP_TYPE_TABLE(f)
Table of other types.
Definition mlisps.h:60
#define MLISP_NUM_TYPE_TABLE(f)
Table of numeric types.
Definition mlisps.h:50
#define MLISP_EXEC_FLAG_DEF_TERM
Flag for MLISP_EXEC_STATE::flags indicating next token is a term to be defined.
Definition mlisps.h:29
#define MLISP_ENV_FLAG_CMP_GT
Flag for _mlisp_env_cb_cmp() specifying TRUE if A > B.
Definition mlispe.h:26
#define MLISP_ENV_FLAG_ARI_MUL
Flag for _mlisp_env_cb_arithmetic() specifying to multiply A * B.
Definition mlispe.h:38
#define MLISP_ENV_FLAG_ARI_ADD
Flag for _mlisp_env_cb_arithmetic() specifying to add A + B.
Definition mlispe.h:35
#define MLISP_ENV_FLAG_CMP_EQ
Flag for _mlisp_env_cb_cmp() specifying TRUE if A == B.
Definition mlispe.h:32
#define MLISP_ENV_FLAG_CMP_LT
Flag for _mlisp_env_cb_cmp() specifying TRUE if A < B.
Definition mlispe.h:29
struct MLISP_ENV_NODE * mlisp_env_get_strpool(struct MLISP_PARSER *parser, struct MLISP_EXEC_STATE *exec, const char *strpool, size_t token_strpool_idx, size_t token_strpool_sz)
Get a node from the environment denoted by a string in the strpool.
MLISP Interpreter/Parser Structs.
Definition mlisps.h:98
size_t ast_idx_children_sz
Number of children in MLISP_AST_NODE::ast_idx_children.
Definition mlisps.h:106
Definition mlisps.h:85
Definition mlisps.h:109
struct MDATA_VECTOR lambda_trace
Path through any lambdas the execution has entered during this heartbeat cycle. Used to detect tail c...
Definition mlisps.h:127
struct MDATA_VECTOR per_node_visit_ct
The number of times each node has been visited ever.
Definition mlisps.h:112
struct MDATA_VECTOR stack
A stack of data values resulting from evaluating statements.
Definition mlisps.h:115
struct MDATA_VECTOR env
Environment in which statements are defined.
Definition mlisps.h:122
Definition mlisps.h:135
Definition mlisps.h:93