Post Scarcity 0.0.6
A prototype for a post scarcity programming environment
Loading...
Searching...
No Matches
lispops.c
Go to the documentation of this file.
1/*
2 * lispops.c
3 *
4 * List processing operations.
5 *
6 * The general idea here is that a list processing operation is a
7 * function which takes two arguments, both cons_pointers:
8 *
9 * 1. args, the argument list to this function;
10 * 2. env, the environment in which this function should be evaluated;
11 *
12 * and returns a cons_pointer, the result.
13 *
14 * They must all have the same signature so that I can call them as
15 * function pointers.
16 *
17 * (c) 2017 Simon Brooke <simon@journeyman.cc>
18 * Licensed under GPL version 2.0, or, at your option, any later version.
19 */
20
21#include <ctype.h>
22#include <stdbool.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include "arith/integer.h"
28#include "arith/peano.h"
29#include "debug.h"
30#include "io/io.h"
31#include "io/print.h"
32#include "io/read.h"
33#include "memory/conspage.h"
35#include "memory/stack.h"
36#include "memory/vectorspace.h"
37#include "memory/dump.h"
38#include "ops/equal.h"
39#include "ops/intern.h"
40#include "ops/lispops.h"
41
42/**
43 * @brief the name of the symbol to which the prompt is bound;
44 *
45 * Set in init to `*prompt*`
46 */
48
49/*
50 * also to create in this section:
51 * struct cons_pointer lisp_let( struct cons_pointer args, struct cons_pointer env,
52 * struct stack_frame* frame);
53 *
54 * and others I haven't thought of yet.
55 */
56
57/**
58 * Useful building block; evaluate this single form in the context of this
59 * parent stack frame and this environment.
60 * @param parent the parent stack frame.
61 * @param form the form to be evaluated.
62 * @param env the evaluation environment.
63 * @return the result of evaluating the form.
64 */
65struct cons_pointer eval_form( struct stack_frame *parent,
66 struct cons_pointer parent_pointer,
67 struct cons_pointer form,
68 struct cons_pointer env ) {
69 debug_print( L"eval_form: ", DEBUG_EVAL );
72
73 struct cons_pointer result = form;
74 switch ( pointer2cell( form ).tag.value ) {
75 /* things which evaluate to themselves */
76 case EXCEPTIONTV:
77 case FREETV: // shouldn't happen, but anyway...
78 case INTEGERTV:
79 case KEYTV:
80 case LOOPTV: // don't think this should happen...
81 case NILTV:
82 case RATIOTV:
83 case REALTV:
84 case READTV:
85 case STRINGTV:
86 case TIMETV:
87 case TRUETV:
88 case WRITETV:
89 break;
90 default:
91 {
92 struct cons_pointer next_pointer =
93 make_empty_frame( parent_pointer );
94
95 if ( exceptionp( next_pointer ) ) {
96 result = next_pointer;
97 } else {
98 struct stack_frame *next = get_stack_frame( next_pointer );
99 set_reg( next, 0, form );
100 next->args = 1;
101
102 result = lisp_eval( next, next_pointer, env );
103
104 if ( !exceptionp( result ) ) {
105 /* if we're returning an exception, we should NOT free the
106 * stack frame. Corollary is, when we free an exception, we
107 * should free all the frames it's holding on to. */
108 dec_ref( next_pointer );
109 }
110 }
111 }
112 break;
113 }
114
115 debug_print( L"eval_form ", DEBUG_EVAL );
117 debug_print( L" returning: ", DEBUG_EVAL );
120
121 return result;
122}
123
124/**
125 * Evaluate all the forms in this `list` in the context of this stack `frame`
126 * and this `env`, and return a list of their values. If the arg passed as
127 * `list` is not in fact a list, return NIL.
128 * @param frame the stack frame.
129 * @param list the list of forms to be evaluated.
130 * @param env the evaluation environment.
131 * @return a list of the the results of evaluating the forms.
132 */
133struct cons_pointer eval_forms( struct stack_frame *frame,
134 struct cons_pointer frame_pointer,
135 struct cons_pointer list,
136 struct cons_pointer env ) {
137 struct cons_pointer result = NIL;
138
139 while ( consp( list ) ) {
140 result =
141 make_cons( eval_form( frame, frame_pointer, c_car( list ), env ),
142 result );
143 list = c_cdr( list );
144 }
145
146 return c_reverse( result );
147}
148
149/**
150 * OK, the idea here (and I know this is less than perfect) is that the basic `try`
151 * special form in PSSE takes two arguments, the first, `body`, being a list of forms,
152 * and the second, `catch`, being a catch handler (which is also a list of forms).
153 * Forms from `body` are evaluated in turn until one returns an exception object,
154 * or until the list is exhausted. If the list was exhausted, then the value of
155 * evaluating the last form in `body` is returned. If an exception was encountered,
156 * then each of the forms in `catch` is evaluated and the value of the last of
157 * those is returned.
158 *
159 * This is experimental. It almost certainly WILL change.
160 */
161struct cons_pointer lisp_try( struct stack_frame *frame,
162 struct cons_pointer frame_pointer,
163 struct cons_pointer env ) {
164 struct cons_pointer result =
165 c_progn( frame, frame_pointer, frame->arg[0], env );
166
167 if ( exceptionp( result ) ) {
168 // TODO: need to put the exception into the environment!
169 result = c_progn( frame, frame_pointer, frame->arg[1],
172 ( L"*exception*" ), result ), env ) );
173 }
174
175 return result;
176}
177
178
179/**
180 * Return the object list (root namespace).
181 *
182 * * (oblist)
183 *
184 * @param frame the stack frame in which the expression is to be interpreted;
185 * @param frame_pointer a pointer to my stack_frame.
186 * @param env my environment (ignored).
187 * @return the root namespace.
188 */
189struct cons_pointer
190lisp_oblist( struct stack_frame *frame, struct cons_pointer frame_pointer,
191 struct cons_pointer env ) {
192 return oblist;
193}
194
195/**
196 * Used to construct the body for `lambda` and `nlambda` expressions.
197 */
198struct cons_pointer compose_body( struct stack_frame *frame ) {
199 struct cons_pointer body = frame->more;
200
201 for ( int i = args_in_frame - 1; i > 0; i-- ) {
202 if ( !nilp( body ) ) {
203 body = make_cons( frame->arg[i], body );
204 } else if ( !nilp( frame->arg[i] ) ) {
205 body = make_cons( frame->arg[i], body );
206 }
207 }
208
209 debug_print( L"compose_body returning ", DEBUG_LAMBDA );
211
212 return body;
213}
214
215/**
216 * Construct an interpretable function. *NOTE* that if `args` is a single symbol
217 * rather than a list, a varargs function will be created.
218 *
219 * (lambda args body)
220 *
221 * @param frame the stack frame in which the expression is to be interpreted;
222 * @param frame_pointer a pointer to my stack_frame.
223 * @param env the environment in which it is to be intepreted.
224 * @return an interpretable function with these `args` and this `body`.
225 */
226struct cons_pointer
227lisp_lambda( struct stack_frame *frame, struct cons_pointer frame_pointer,
228 struct cons_pointer env ) {
229 return make_lambda( frame->arg[0], compose_body( frame ) );
230}
231
232/**
233 * Construct an interpretable special form. *NOTE* that if `args` is a single symbol
234 * rather than a list, a varargs special form will be created.
235 *
236 * (nlambda args body)
237 *
238 * @param frame the stack frame in which the expression is to be interpreted;
239 * @param frame_pointer a pointer to my stack_frame.
240 * @param env the environment in which it is to be intepreted.
241 * @return an interpretable special form with these `args` and this `body`.
242 */
243struct cons_pointer
244lisp_nlambda( struct stack_frame *frame, struct cons_pointer frame_pointer,
245 struct cons_pointer env ) {
246 return make_nlambda( frame->arg[0], compose_body( frame ) );
247}
248
249
250/**
251 * Evaluate a lambda or nlambda expression.
252 */
253struct cons_pointer
254eval_lambda( struct cons_space_object *cell, struct stack_frame *frame,
255 struct cons_pointer frame_pointer, struct cons_pointer env ) {
256 struct cons_pointer result = NIL;
257#ifdef DEBUG
258 debug_print( L"eval_lambda called\n", DEBUG_LAMBDA );
260#endif
261
262 struct cons_pointer new_env = env;
263 struct cons_pointer names = cell->payload.lambda.args;
264 struct cons_pointer body = cell->payload.lambda.body;
265
266 if ( consp( names ) ) {
267 /* if `names` is a list, bind successive items from that list
268 * to values of arguments */
269 for ( int i = 0; i < frame->args && consp( names ); i++ ) {
270 struct cons_pointer name = c_car( names );
271 struct cons_pointer val = frame->arg[i];
272
273 new_env = set( name, val, new_env );
274 debug_print_binding( name, val, false, DEBUG_BIND );
275
276 names = c_cdr( names );
277 }
278
279 /* \todo if there's more than `args_in_frame` arguments, bind those too. */
280 } else if ( symbolp( names ) ) {
281 /* if `names` is a symbol, rather than a list of symbols,
282 * then bind a list of the values of args to that symbol. */
283 /* \todo eval all the things in frame->more */
284 struct cons_pointer vals =
285 eval_forms( frame, frame_pointer, frame->more, env );
286
287 for ( int i = args_in_frame - 1; i >= 0; i-- ) {
288 struct cons_pointer val =
289 eval_form( frame, frame_pointer, frame->arg[i], env );
290
291 if ( nilp( val ) && nilp( vals ) ) { /* nothing */
292 } else {
293 vals = make_cons( val, vals );
294 }
295 }
296
297 new_env = set( names, vals, new_env );
298 }
299
300 while ( !nilp( body ) ) {
301 struct cons_pointer sexpr = c_car( body );
302 body = c_cdr( body );
303
304 debug_print( L"In lambda: evaluating ", DEBUG_LAMBDA );
306 // debug_print( L"\t env is: ", DEBUG_LAMBDA );
307 // debug_print_object( new_env, DEBUG_LAMBDA );
309
310 /* if a result is not the terminal result in the lambda, it's a
311 * side effect, and needs to be GCed */
312 dec_ref( result );
313
314 result = eval_form( frame, frame_pointer, sexpr, new_env );
315
316 if ( exceptionp( result ) ) {
317 break;
318 }
319 }
320
321 // TODO: I think we do need to dec_ref everything on new_env back to env
322 // dec_ref( new_env );
323
324 debug_print( L"eval_lambda returning: \n", DEBUG_LAMBDA );
327
328 return result;
329}
330
331/**
332 * if `r` is an exception, and it doesn't have a location, fix up its location from
333 * the name associated with this fn_pointer, if any.
334 */
336 struct cons_pointer
337 fn_pointer ) {
338 struct cons_pointer result = r;
339
340 if ( exceptionp( result )
341 && ( functionp( fn_pointer ) || specialp( fn_pointer ) ) ) {
342 struct cons_space_object *fn_cell = &pointer2cell( fn_pointer );
343
344 struct cons_pointer payload =
345 pointer2cell( result ).payload.exception.payload;
346
347 switch ( get_tag_value( payload ) ) {
348 case NILTV:
349 case CONSTV:
350 case HASHTV:
351 {
353 payload ) ) ) {
354 pointer2cell( result ).payload.exception.payload =
357 fn_cell->payload.function.meta ),
358 payload );
359 }
360 }
361 break;
362 default:
363 pointer2cell( result ).payload.exception.payload =
366 fn_cell->payload.function.
367 meta ) ),
370 payload ), NIL ) );
371 }
372 }
373
374 return result;
375}
376
377
378/**
379 * Internal guts of apply.
380 * @param frame the stack frame, expected to have only one argument, a list
381 * comprising something that evaluates to a function and its arguments.
382 * @param env The evaluation environment.
383 * @return the result of evaluating the function with its arguments.
384 */
385struct cons_pointer
386c_apply( struct stack_frame *frame, struct cons_pointer frame_pointer,
387 struct cons_pointer env ) {
388 debug_print( L"Entering c_apply\n", DEBUG_EVAL );
389 struct cons_pointer result = NIL;
390
391 struct cons_pointer fn_pointer =
392 eval_form( frame, frame_pointer, c_car( frame->arg[0] ), env );
393
394 if ( exceptionp( fn_pointer ) ) {
395 result = fn_pointer;
396 } else {
397 struct cons_space_object *fn_cell = &pointer2cell( fn_pointer );
398 struct cons_pointer args = c_cdr( frame->arg[0] );
399
400 switch ( get_tag_value( fn_pointer ) ) {
401 case EXCEPTIONTV:
402 /* just pass exceptions straight back */
403 result = fn_pointer;
404 break;
405
406 case FUNCTIONTV:
407 {
408 struct cons_pointer exep = NIL;
409 struct cons_pointer next_pointer =
410 make_stack_frame( frame_pointer, args, env );
411
412 if ( exceptionp( next_pointer ) ) {
413 result = next_pointer;
414 } else {
415 struct stack_frame *next =
416 get_stack_frame( next_pointer );
417
419 ( fn_cell->payload.function.executable ) )
420 ( next,
421 next_pointer,
422 env ),
423 fn_pointer );
424 dec_ref( next_pointer );
425 }
426 }
427 break;
428
429 case KEYTV:
430 result = c_assoc( fn_pointer,
431 eval_form( frame,
432 frame_pointer,
433 c_car( c_cdr( frame->arg[0] ) ),
434 env ) );
435 break;
436
437 case LAMBDATV:
438 {
439 struct cons_pointer exep = NIL;
440 struct cons_pointer next_pointer =
441 make_stack_frame( frame_pointer, args, env );
442
443 if ( exceptionp( next_pointer ) ) {
444 result = next_pointer;
445 } else {
446 struct stack_frame *next =
447 get_stack_frame( next_pointer );
448 result =
449 eval_lambda( fn_cell, next, next_pointer, env );
450 if ( !exceptionp( result ) ) {
451 dec_ref( next_pointer );
452 }
453 }
454 }
455 break;
456
457 case HASHTV:
458 /* \todo: if arg[0] is a CONS, treat it as a path */
459 result = c_assoc( eval_form( frame,
460 frame_pointer,
461 c_car( c_cdr
462 ( frame->arg
463 [0] ) ), env ),
464 fn_pointer );
465 break;
466
467 case NLAMBDATV:
468 {
469 struct cons_pointer next_pointer =
470 make_special_frame( frame_pointer, args, env );
471
472 if ( exceptionp( next_pointer ) ) {
473 result = next_pointer;
474 } else {
475 struct stack_frame *next =
476 get_stack_frame( next_pointer );
477 result =
478 eval_lambda( fn_cell, next, next_pointer, env );
479 dec_ref( next_pointer );
480 }
481 }
482 break;
483
484 case SPECIALTV:
485 {
486 struct cons_pointer next_pointer =
487 make_special_frame( frame_pointer, args, env );
488
489 if ( exceptionp( next_pointer ) ) {
490 result = next_pointer;
491 } else {
493 ( fn_cell->payload.special.executable ) )
494 ( get_stack_frame( next_pointer ), next_pointer, env ), fn_pointer );
495 debug_print( L"Special form returning: ", DEBUG_EVAL );
498 dec_ref( next_pointer );
499 }
500 }
501 break;
502
503 default:
504 {
505 int bs = sizeof( wchar_t ) * 1024;
506 wchar_t *buffer = malloc( bs );
507 memset( buffer, '\0', bs );
508 swprintf( buffer, bs,
509 L"Unexpected cell with tag %d (%4.4s) in function position",
510 fn_cell->tag.value, &( fn_cell->tag.bytes[0] ) );
511 struct cons_pointer message =
512 c_string_to_lisp_string( buffer );
513 free( buffer );
514 result =
516 message, frame_pointer );
517 }
518 }
519
520 }
521
522 debug_print( L"c_apply: returning: ", DEBUG_EVAL );
525
526 return result;
527}
528
529/**
530 * Function; evaluate the expression which is the first argument in the frame;
531 * further arguments are ignored.
532 *
533 * * (eval expression)
534 *
535 * @param frame my stack_frame.
536 * @param frame_pointer a pointer to my stack_frame.
537 * @param env my environment.
538 * @return
539 * * If `expression` is a number, string, `nil`, or `t`, returns `expression`.
540 * * If `expression` is a symbol, returns the value that expression is bound
541 * to in the evaluation environment (`env`).
542 * * If `expression` is a list, expects the car to be something that evaluates to a
543 * function or special form:
544 * * If a function, evaluates all the other top level elements in `expression` and
545 * passes them in a stack frame as arguments to the function;
546 * * If a special form, passes the cdr of expression to the special form as argument.
547 * @exception if `expression` is a symbol which is not bound in `env`.
548 */
549struct cons_pointer
550lisp_eval( struct stack_frame *frame, struct cons_pointer frame_pointer,
551 struct cons_pointer env ) {
552 debug_print( L"Eval: ", DEBUG_EVAL );
553 debug_dump_object( frame_pointer, DEBUG_EVAL );
554
555 struct cons_pointer result = frame->arg[0];
556 struct cons_space_object *cell = &pointer2cell( frame->arg[0] );
557
558 switch ( cell->tag.value ) {
559 case CONSTV:
560 result = c_apply( frame, frame_pointer, env );
561 break;
562
563 case SYMBOLTV:
564 {
565 struct cons_pointer canonical = interned( frame->arg[0], env );
566 if ( nilp( canonical ) ) {
567 struct cons_pointer message =
569 ( L"Attempt to take value of unbound symbol." ),
570 frame->arg[0] );
571 result =
573 message, frame_pointer );
574 } else {
575 result = c_assoc( canonical, env );
576// inc_ref( result );
577 }
578 }
579 break;
580 /*
581 * \todo
582 * the Clojure practice of having a map serve in the function place of
583 * an s-expression is a good one and I should adopt it;
584 * H'mmm... this is working, but it isn't here. Where is it?
585 */
586 default:
587 result = frame->arg[0];
588 break;
589 }
590
591 debug_print( L"Eval returning ", DEBUG_EVAL );
592 debug_dump_object( result, DEBUG_EVAL );
593
594 return result;
595}
596
597
598/**
599 * Function; apply the function which is the result of evaluating the
600 * first argument to the list of values which is the result of evaluating
601 * the second argument
602 *
603 * * (apply fn args)
604 *
605 * @param frame my stack_frame.
606 * @param frame_pointer a pointer to my stack_frame.
607 * @param env my environment.
608 * @return the result of applying `fn` to `args`.
609 */
610struct cons_pointer
611lisp_apply( struct stack_frame *frame, struct cons_pointer frame_pointer,
612 struct cons_pointer env ) {
613 debug_print( L"Apply: ", DEBUG_EVAL );
614 debug_dump_object( frame_pointer, DEBUG_EVAL );
615
616 set_reg( frame, 0, make_cons( frame->arg[0], frame->arg[1] ) );
617 set_reg( frame, 1, NIL );
618
619 struct cons_pointer result = c_apply( frame, frame_pointer, env );
620
621 debug_print( L"Apply returning ", DEBUG_EVAL );
622 debug_dump_object( result, DEBUG_EVAL );
623
624 return result;
625}
626
627
628/**
629 * Special form;
630 * returns its argument (strictly first argument - only one is expected but
631 * this isn't at this stage checked) unevaluated.
632 *
633 * * (quote a)
634 *
635 * @param frame my stack_frame.
636 * @param frame_pointer a pointer to my stack_frame.
637 * @param env my environment (ignored).
638 * @return `a`, unevaluated,
639 */
640struct cons_pointer
641lisp_quote( struct stack_frame *frame, struct cons_pointer frame_pointer,
642 struct cons_pointer env ) {
643 return frame->arg[0];
644}
645
646
647/**
648 * Function;
649 * binds the value of `name` in the `namespace` to value of `value`, altering
650 * the namespace in so doing. Retuns `value`.
651 * `namespace` defaults to the oblist.
652 * \todo doesn't actually work yet for namespaces which are not the oblist.
653 *
654 * * (set name value)
655 * * (set name value namespace)
656 *
657 * @param frame my stack_frame.
658 * @param frame_pointer a pointer to my stack_frame.
659 * @param env my environment (ignored).
660 * @return `value`
661 */
662struct cons_pointer
663lisp_set( struct stack_frame *frame, struct cons_pointer frame_pointer,
664 struct cons_pointer env ) {
665 struct cons_pointer result = NIL;
666 struct cons_pointer namespace =
667 nilp( frame->arg[2] ) ? oblist : frame->arg[2];
668
669 if ( symbolp( frame->arg[0] ) ) {
670 deep_bind( frame->arg[0], frame->arg[1] );
671 result = frame->arg[1];
672 } else {
673 result =
677 ( L"The first argument to `set` is not a symbol: " ),
678 make_cons( frame->arg[0], NIL ) ),
679 frame_pointer );
680 }
681
682 return result;
683}
684
685
686/**
687 * Special form;
688 * binds `symbol` in the `namespace` to value of `value`, altering
689 * the namespace in so doing, and returns value. `namespace` defaults to
690 * the value of `oblist`.
691 * \todo doesn't actually work yet for namespaces which are not the oblist.
692 *
693 * * (set! symbol value)
694 * * (set! symbol value namespace)
695 *
696 * @param frame my stack_frame.
697 * @param frame_pointer a pointer to my stack_frame.
698 * @param env my environment (ignored).
699 * @return `value`
700 */
701struct cons_pointer
702lisp_set_shriek( struct stack_frame *frame, struct cons_pointer frame_pointer,
703 struct cons_pointer env ) {
704 struct cons_pointer result = NIL;
705 struct cons_pointer namespace = frame->arg[2];
706
707 if ( symbolp( frame->arg[0] ) ) {
708 struct cons_pointer val =
709 eval_form( frame, frame_pointer, frame->arg[1], env );
710 deep_bind( frame->arg[0], val );
711 result = val;
712 } else {
713 result =
717 ( L"The first argument to `set!` is not a symbol: " ),
718 make_cons( frame->arg[0], NIL ) ),
719 frame_pointer );
720 }
721
722 return result;
723}
724
725/**
726 * @return true if `arg` represents an end of string, else false.
727 * \todo candidate for moving to a memory/string.c file
728 */
729bool end_of_stringp( struct cons_pointer arg ) {
730 return nilp( arg ) ||
731 ( stringp( arg ) &&
732 pointer2cell( arg ).payload.string.character == ( wint_t ) '\0' );
733}
734
735/**
736 * Function;
737 * returns a cell constructed from a and b. If a is of type string but its
738 * cdr is nill, and b is of type string, then returns a new string cell;
739 * otherwise returns a new cons cell.
740 *
741 * Thus: `(cons "a" "bcd") -> "abcd"`, but `(cons "ab" "cd") -> ("ab" . "cd")`
742 *
743 * * (cons a b)
744 *
745 * @param frame my stack_frame.
746 * @param frame_pointer a pointer to my stack_frame.
747 * @param env my environment (ignored).
748 * @return a new cons cell whose `car` is `a` and whose `cdr` is `b`.
749 */
750struct cons_pointer
751lisp_cons( struct stack_frame *frame, struct cons_pointer frame_pointer,
752 struct cons_pointer env ) {
753 struct cons_pointer car = frame->arg[0];
754 struct cons_pointer cdr = frame->arg[1];
755 struct cons_pointer result;
756
757 if ( nilp( car ) && nilp( cdr ) ) {
758 return NIL;
759 } else if ( stringp( car ) && stringp( cdr ) &&
760 end_of_stringp( c_cdr( car ) ) ) {
761 result =
762 make_string( pointer2cell( car ).payload.string.character, cdr );
763 } else {
764 result = make_cons( car, cdr );
765 }
766
767 return result;
768}
769
770/**
771 * Function;
772 * returns the first item (head) of a sequence. Valid for cons cells,
773 * strings, read streams and TODO other things which can be considered as sequences.
774 *
775 * * (car expression)
776 *
777 * @param frame my stack_frame.
778 * @param frame_pointer a pointer to my stack_frame.
779 * @param env my environment (ignored).
780 * @return the first item (head) of `expression`.
781 * @exception if `expression` is not a sequence.
782 */
783struct cons_pointer
784lisp_car( struct stack_frame *frame, struct cons_pointer frame_pointer,
785 struct cons_pointer env ) {
786 struct cons_pointer result = NIL;
787 struct cons_space_object *cell = &pointer2cell( frame->arg[0] );
788
789 switch ( cell->tag.value ) {
790 case CONSTV:
791 result = cell->payload.cons.car;
792 break;
793 case NILTV:
794 break;
795 case READTV:
796 result =
797 make_string( url_fgetwc( cell->payload.stream.stream ), NIL );
798 break;
799 case STRINGTV:
800 result = make_string( cell->payload.string.character, NIL );
801 break;
802 default:
803 result =
806 ( L"Attempt to take CAR of non sequence" ),
807 frame_pointer );
808 }
809
810 return result;
811}
812
813/**
814 * Function;
815 * returns the remainder of a sequence when the head is removed. Valid for cons cells,
816 * strings, read streams and TODO other things which can be considered as sequences.
817 * *NOTE* that if the argument is an input stream, the first character is removed AND
818 * DISCARDED.
819 *
820 * * (cdr expression)
821 *
822 * @param frame my stack_frame.
823 * @param frame_pointer a pointer to my stack_frame.
824 * @param env my environment (ignored).
825 * @return the remainder of `expression` when the head is removed.
826 * @exception if `expression` is not a sequence.
827 */
828struct cons_pointer
829lisp_cdr( struct stack_frame *frame, struct cons_pointer frame_pointer,
830 struct cons_pointer env ) {
831 struct cons_pointer result = NIL;
832 struct cons_space_object *cell = &pointer2cell( frame->arg[0] );
833
834 switch ( cell->tag.value ) {
835 case CONSTV:
836 result = cell->payload.cons.cdr;
837 break;
838 case NILTV:
839 break;
840 case READTV:
841 url_fgetwc( cell->payload.stream.stream );
842 result = frame->arg[0];
843 break;
844 case STRINGTV:
845 result = cell->payload.string.cdr;
846 break;
847 default:
848 result =
851 ( L"Attempt to take CDR of non sequence" ),
852 frame_pointer );
853 }
854
855 return result;
856}
857
858/**
859 * Function: return, as an integer, the length of the sequence indicated by
860 * the first argument, or zero if it is not a sequence.
861 *
862 * * (length any)
863 *
864 * @param frame my stack_frame.
865 * @param frame_pointer a pointer to my stack_frame.
866 * @param env my environment (ignored).
867 * @return the length of `any`, if it is a sequence, or zero otherwise.
868 */
870 struct cons_pointer frame_pointer,
871 struct cons_pointer env ) {
872 return make_integer( c_length( frame->arg[0] ), NIL );
873}
874
875/**
876 * Function; look up the value of a `key` in a `store`.
877 *
878 * * (assoc key store)
879 *
880 * @param frame my stack_frame.
881 * @param frame_pointer a pointer to my stack_frame.
882 * @param env my environment (ignored).
883 * @return the value associated with `key` in `store`, or `nil` if not found.
884 */
885struct cons_pointer
886lisp_assoc( struct stack_frame *frame, struct cons_pointer frame_pointer,
887 struct cons_pointer env ) {
888 return c_assoc( frame->arg[0],
889 nilp( frame->arg[1] ) ? oblist : frame->arg[1] );
890}
891
892/**
893 * @brief `(interned? key store)`: Return `t` if the symbol or keyword `key` is bound in this `store`, else `nil`.
894 *
895 * @param frame
896 * @param frame_pointer
897 * @param env
898 * @return struct cons_pointer
899 */
900struct cons_pointer
901lisp_internedp( struct stack_frame *frame, struct cons_pointer frame_pointer,
902 struct cons_pointer env ) {
903 struct cons_pointer result = internedp( frame->arg[0],
904 nilp( frame->arg[1] ) ? oblist :
905 frame->arg[1] );
906
907 if ( exceptionp( result ) ) {
908 struct cons_pointer old = result;
909 struct cons_space_object *cell = &( pointer2cell( result ) );
910 result =
912 cell->payload.exception.payload, frame_pointer );
913 dec_ref( old );
914 }
915
916 return result;
917}
918
919struct cons_pointer c_keys( struct cons_pointer store ) {
920 struct cons_pointer result = NIL;
921
922 if ( consp( store ) ) {
923 for ( struct cons_pointer pair = c_car( store ); !nilp( pair );
924 pair = c_car( store ) ) {
925 if ( consp( pair ) ) {
926 result = make_cons( c_car( pair ), result );
927 } else if ( hashmapp( pair ) ) {
928 result = c_append( hashmap_keys( pair ), result );
929 }
930
931 store = c_cdr( store );
932 }
933 } else if ( hashmapp( store ) ) {
934 result = hashmap_keys( store );
935 }
936
937 return result;
938}
939
940
941
942struct cons_pointer lisp_keys( struct stack_frame *frame,
943 struct cons_pointer frame_pointer,
944 struct cons_pointer env ) {
945 return c_keys( frame->arg[0] );
946}
947
948/**
949 * Function; are these two objects the same object? Shallow, cheap equality.
950 *
951 * * (eq a b)
952 *
953 * @param frame my stack_frame.
954 * @param frame_pointer a pointer to my stack_frame.
955 * @param env my environment (ignored).
956 * @return `t` if `a` and `b` are pointers to the same object, else `nil`;
957 */
958struct cons_pointer lisp_eq( struct stack_frame *frame,
959 struct cons_pointer frame_pointer,
960 struct cons_pointer env ) {
961 struct cons_pointer result = TRUE;
962
963 if ( frame->args > 1 ) {
964 for ( int b = 1; ( truep( result ) ) && ( b < frame->args ); b++ ) {
965 result = eq( frame->arg[0], fetch_arg( frame, b ) ) ? TRUE : NIL;
966 }
967 }
968
969 return result;
970}
971
972/**
973 * Function; are these two arguments identical? Deep, expensive equality.
974 *
975 * * (equal a b)
976 *
977 * @param frame my stack_frame.
978 * @param frame_pointer a pointer to my stack_frame.
979 * @param env my environment (ignored).
980 * @return `t` if `a` and `b` are recursively identical, else `nil`.
981 */
982struct cons_pointer
983lisp_equal( struct stack_frame *frame, struct cons_pointer frame_pointer,
984 struct cons_pointer env ) {
985 struct cons_pointer result = TRUE;
986
987 if ( frame->args > 1 ) {
988 for ( int b = 1; ( truep( result ) ) && ( b < frame->args ); b++ ) {
989 result =
990 equal( frame->arg[0], fetch_arg( frame, b ) ) ? TRUE : NIL;
991 }
992 }
993
994 return result;
995}
996
997long int c_count( struct cons_pointer p ) {
998 struct cons_space_object *cell = &pointer2cell( p );
999 int result = 0;
1000
1001 switch ( cell->tag.value ) {
1002 case CONSTV:
1003 case STRINGTV:
1004 /* I think doctrine is that you cannot treat symbols or keywords as
1005 * sequences, although internally, of course, they are. Integers are
1006 * also internally sequences, but also should not be treated as such.
1007 */
1008 for ( p; !nilp( p ); p = c_cdr( p ) ) {
1009 result++;
1010 }
1011 }
1012
1013 return result;
1014}
1015
1016/**
1017 * Function: return the number of top level forms in the object which is
1018 * the first (and only) argument, if it is a sequence (which for current
1019 * purposes means a list or a string)
1020 *
1021 * * (count l)
1022 *
1023 * @param frame my stack_frame.
1024 * @param frame_pointer a pointer to my stack_frame.
1025 * @param env my environment (ignored).
1026 * @return the number of top level forms in a list, or characters in a
1027 * string, else 0.
1028 */
1029struct cons_pointer
1030lisp_count( struct stack_frame *frame, struct cons_pointer frame_pointer,
1031 struct cons_pointer env ) {
1032 return acquire_integer( c_count( frame->arg[0] ), NIL );
1033}
1034
1035/**
1036 * Function; read one complete lisp form and return it. If read-stream is specified and
1037 * is a read stream, then read from that stream, else the stream which is the value of
1038 * `*in*` in the environment.
1039 *
1040 * * (read)
1041 * * (read read-stream)
1042 *
1043 * @param frame my stack_frame.
1044 * @param frame_pointer a pointer to my stack_frame.
1045 * @param env my environment.
1046 * @return the expression read.
1047 */
1048struct cons_pointer
1049lisp_read( struct stack_frame *frame, struct cons_pointer frame_pointer,
1050 struct cons_pointer env ) {
1051#ifdef DEBUG
1052 debug_print( L"entering lisp_read\n", DEBUG_IO );
1053#endif
1054 URL_FILE *input;
1055
1056 struct cons_pointer in_stream = readp( frame->arg[0] ) ?
1057 frame->arg[0] : get_default_stream( true, env );
1058
1059 if ( readp( in_stream ) ) {
1060 debug_print( L"lisp_read: setting input stream\n",
1061 DEBUG_IO | DEBUG_REPL );
1062 debug_dump_object( in_stream, DEBUG_IO );
1063 input = pointer2cell( in_stream ).payload.stream.stream;
1064 inc_ref( in_stream );
1065 } else {
1066 /* should not happen, but has done. */
1067 debug_print( L"WARNING: invalid input stream; defaulting!\n",
1068 DEBUG_IO | DEBUG_REPL );
1069 input = file_to_url_file( stdin );
1070 }
1071
1072 struct cons_pointer result = read( frame, frame_pointer, env, input );
1073 debug_print( L"lisp_read returning\n", DEBUG_IO );
1074 debug_dump_object( result, DEBUG_IO );
1075
1076 if ( readp( in_stream ) ) {
1077 dec_ref( in_stream );
1078 } else {
1079 free( input );
1080 }
1081
1082
1083 return result;
1084}
1085
1086
1087/**
1088 * reverse a sequence (if it is a sequence); else return it unchanged.
1089 */
1091 struct cons_pointer result = NIL;
1092
1093 if ( sequencep( arg ) ) {
1094 for ( struct cons_pointer p = arg; sequencep( p ); p = c_cdr( p ) ) {
1095 struct cons_space_object o = pointer2cell( p );
1096 switch ( o.tag.value ) {
1097 case CONSTV:
1098 result = make_cons( o.payload.cons.car, result );
1099 break;
1100 case STRINGTV:
1101 result = make_string( o.payload.string.character, result );
1102 break;
1103 case SYMBOLTV:
1104 result =
1105 make_symbol_or_key( o.payload.string.character, result,
1106 SYMBOLTV );
1107 break;
1108 }
1109 }
1110 } else {
1111 result = arg;
1112 }
1113
1114 return result;
1115}
1116
1117
1118/**
1119 * Function; reverse the order of members in s sequence.
1120 *
1121 * * (reverse sequence)
1122 *
1123 * @param frame my stack_frame.
1124 * @param frame_pointer a pointer to my stack_frame.
1125 * @param env my environment (ignored).
1126 * @return a sequence like this `sequence` but with the members in the reverse order.
1127 */
1129 struct cons_pointer frame_pointer,
1130 struct cons_pointer env ) {
1131 return c_reverse( frame->arg[0] );
1132}
1133
1134/**
1135 * Function: dump/inspect one complete lisp expression and return NIL. If
1136 * write-stream is specified and is a write stream, then print to that stream,
1137 * else the stream which is the value of
1138 * `*out*` in the environment.
1139 *
1140 * * (inspect expr)
1141 * * (inspect expr write-stream)
1142 *
1143 * @param frame my stack_frame.
1144 * @param frame_pointer a pointer to my stack_frame.
1145 * @param env my environment (from which the stream may be extracted).
1146 * @return NIL.
1147 */
1149 struct cons_pointer frame_pointer,
1150 struct cons_pointer env ) {
1151 debug_print( L"Entering lisp_inspect\n", DEBUG_IO );
1152 struct cons_pointer result = NIL;
1153 struct cons_pointer out_stream = writep( frame->arg[1] )
1154 ? frame->arg[1]
1155 : get_default_stream( false, env );
1156 URL_FILE *output;
1157
1158 if ( writep( out_stream ) ) {
1159 debug_print( L"lisp_inspect: setting output stream\n", DEBUG_IO );
1160 debug_dump_object( out_stream, DEBUG_IO );
1161 output = pointer2cell( out_stream ).payload.stream.stream;
1162 } else {
1163 output = file_to_url_file( stderr );
1164 }
1165
1166 dump_object( output, frame->arg[0] );
1167
1168 debug_print( L"Leaving lisp_inspect", DEBUG_IO );
1169
1170 return result;
1171}
1172
1173
1174/**
1175 * Function: get the Lisp type of the single argument.
1176 *
1177 * * (type expression)
1178 *
1179 * @param frame my stack frame.
1180 * @param frame_pointer a pointer to my stack_frame.
1181 * @param env my environment (ignored).
1182 * @return As a Lisp string, the tag of `expression`.
1183 */
1184struct cons_pointer
1185lisp_type( struct stack_frame *frame, struct cons_pointer frame_pointer,
1186 struct cons_pointer env ) {
1187 return c_type( frame->arg[0] );
1188}
1189
1190/**
1191 * Evaluate each of these expressions in this `env`ironment over this `frame`,
1192 * returning only the value of the last.
1193 */
1194struct cons_pointer
1195c_progn( struct stack_frame *frame, struct cons_pointer frame_pointer,
1196 struct cons_pointer expressions, struct cons_pointer env ) {
1197 struct cons_pointer result = NIL;
1198
1199 while ( consp( expressions ) ) {
1200 struct cons_pointer r = result;
1201
1202 result = eval_form( frame, frame_pointer, c_car( expressions ), env );
1203 dec_ref( r );
1204
1205 expressions = exceptionp( result ) ? NIL : c_cdr( expressions );
1206 }
1207
1208 return result;
1209}
1210
1211
1212/**
1213 * Special form; evaluate the expressions which are listed in my arguments
1214 * sequentially and return the value of the last. This function is called 'do'
1215 * in some dialects of Lisp.
1216 *
1217 * * (progn expressions...)
1218 *
1219 * @param frame my stack frame.
1220 * @param frame_pointer a pointer to my stack_frame.
1221 * @param env the environment in which expressions are evaluated.
1222 * @return the value of the last `expression` of the sequence which is my single
1223 * argument.
1224 */
1225struct cons_pointer
1226lisp_progn( struct stack_frame *frame, struct cons_pointer frame_pointer,
1227 struct cons_pointer env ) {
1228 struct cons_pointer result = NIL;
1229
1230 for ( int i = 0; i < args_in_frame && !nilp( frame->arg[i] ); i++ ) {
1231 struct cons_pointer r = result;
1232
1233 result = eval_form( frame, frame_pointer, frame->arg[i], env );
1234
1235 dec_ref( r );
1236 }
1237
1238 if ( consp( frame->more ) ) {
1239 result = c_progn( frame, frame_pointer, frame->more, env );
1240 }
1241
1242 return result;
1243}
1244
1245/**
1246 * @brief evaluate a single cond clause; if the test part succeeds return a
1247 * pair whose car is TRUE and whose cdr is the value of the action part
1248 */
1250 struct stack_frame *frame,
1251 struct cons_pointer frame_pointer,
1252 struct cons_pointer env ) {
1253 struct cons_pointer result = NIL;
1254
1255#ifdef DEBUG
1256 debug_print( L"\n\tCond clause: ", DEBUG_EVAL );
1257 debug_print_object( clause, DEBUG_EVAL );
1259#endif
1260
1261 if ( consp( clause ) ) {
1262 struct cons_pointer val =
1263 eval_form( frame, frame_pointer, c_car( clause ),
1264 env );
1265
1266 if ( !nilp( val ) ) {
1267 result =
1268 make_cons( TRUE,
1269 c_progn( frame, frame_pointer, c_cdr( clause ),
1270 env ) );
1271
1272#ifdef DEBUG
1273 debug_print( L"\n\t\tCond clause ", DEBUG_EVAL );
1274 debug_print_object( clause, DEBUG_EVAL );
1275 debug_print( L" succeeded; returning: ", DEBUG_EVAL );
1276 debug_print_object( result, DEBUG_EVAL );
1278 } else {
1279 debug_print( L"\n\t\tCond clause ", DEBUG_EVAL );
1280 debug_print_object( clause, DEBUG_EVAL );
1281 debug_print( L" failed.\n", DEBUG_EVAL );
1282#endif
1283 }
1284 } else {
1285 result = throw_exception( c_string_to_lisp_symbol( L"cond" ),
1287 ( L"Arguments to `cond` must be lists" ),
1288 frame_pointer );
1289 }
1290
1291 return result;
1292}
1293
1294/**
1295 * Special form: conditional. Each `clause` is expected to be a list; if the first
1296 * item in such a list evaluates to non-NIL, the remaining items in that list
1297 * are evaluated in turn and the value of the last returned. If no arg `clause`
1298 * has a first element which evaluates to non NIL, then NIL is returned.
1299 *
1300 * * (cond clauses...)
1301 *
1302 * @param frame my stack frame.
1303 * @param frame_pointer a pointer to my stack_frame.
1304 * @param env the environment in which arguments will be evaluated.
1305 * @return the value of the last expression of the first successful `clause`.
1306 */
1307struct cons_pointer
1308lisp_cond( struct stack_frame *frame, struct cons_pointer frame_pointer,
1309 struct cons_pointer env ) {
1310 struct cons_pointer result = NIL;
1311 bool done = false;
1312
1313 for ( int i = 0; ( i < frame->args ) && !done; i++ ) {
1314 struct cons_pointer clause_pointer = fetch_arg( frame, i );
1315
1316 result = eval_cond_clause( clause_pointer, frame, frame_pointer, env );
1317
1318 if ( !nilp( result ) && truep( c_car( result ) ) ) {
1319 result = c_cdr( result );
1320 done = true;
1321 break;
1322 }
1323 }
1324#ifdef DEBUG
1325 debug_print( L"\tCond returning: ", DEBUG_EVAL );
1326 debug_print_object( result, DEBUG_EVAL );
1328#endif
1329
1330 return result;
1331}
1332
1333/**
1334 * Throw an exception with a cause.
1335 * `throw_exception` is a misnomer, because it doesn't obey the calling signature of a
1336 * lisp function; but it is nevertheless to be preferred to make_exception. A
1337 * real `throw_exception`, which does, will be needed.
1338 * object pointing to it. Then this should become a normal lisp function
1339 * which expects a normally bound frame and environment, such that
1340 * frame->arg[0] is the payload, frame->arg[1] is the cause, and frame->arg[2] is the cons-space
1341 * pointer to the frame in which the exception occurred.
1342 */
1344 struct cons_pointer message,
1345 struct cons_pointer cause,
1346 struct cons_pointer
1347 frame_pointer ) {
1348 struct cons_pointer result = NIL;
1349
1350#ifdef DEBUG
1351 debug_print( L"\nERROR: `", 511 );
1352 debug_print_object( message, 511 );
1353 debug_print( L"` at `", 511 );
1354 debug_print_object( location, 511 );
1355 debug_print( L"`\n", 511 );
1356 if ( !nilp( cause ) ) {
1357 debug_print( L"\tCaused by: ", 511 );
1358 debug_print_object( cause, 511 );
1359 debug_print( L"`\n", 511 );
1360 }
1361#endif
1362 struct cons_space_object *cell = &pointer2cell( message );
1363
1364 if ( cell->tag.value == EXCEPTIONTV ) {
1365 result = message;
1366 } else {
1367 result =
1370 location ),
1373 message ),
1374 ( nilp( cause ) ? NIL :
1377 cause ), NIL ) ) ) ),
1378 frame_pointer );
1379 }
1380
1381 return result;
1382
1383}
1384
1385/**
1386 * Throw an exception.
1387 * `throw_exception` is a misnomer, because it doesn't obey the calling signature of a
1388 * lisp function; but it is nevertheless to be preferred to make_exception. A
1389 * real `throw_exception`, which does, will be needed.
1390 * object pointing to it. Then this should become a normal lisp function
1391 * which expects a normally bound frame and environment, such that
1392 * frame->arg[0] is the payload, frame->arg[1] is the cause, and frame->arg[2] is the cons-space
1393 * pointer to the frame in which the exception occurred.
1394 */
1395struct cons_pointer
1397 struct cons_pointer payload,
1398 struct cons_pointer frame_pointer ) {
1399 return throw_exception_with_cause( location, payload, NIL, frame_pointer );
1400}
1401
1402/**
1403 * Function; create an exception. Exceptions are special in as much as if an
1404 * exception is created in the binding of the arguments of any function, the
1405 * function will return the exception rather than whatever else it would
1406 * normally return. A function which detects a problem it cannot resolve
1407 * *should* return an exception.
1408 *
1409 * * (exception message location)
1410 *
1411 * @param frame my stack frame.
1412 * @param frame_pointer a pointer to my stack_frame.
1413 * @param env the environment in which arguments will be evaluated.
1414 * @return areturns an exception whose message is this `message`, and whose
1415 * stack frame is the parent stack frame when the function is invoked.
1416 * `message` does not have to be a string but should be something intelligible
1417 * which can be read.
1418 * If `message` is itself an exception, returns that instead.
1419 */
1420struct cons_pointer
1421lisp_exception( struct stack_frame *frame, struct cons_pointer frame_pointer,
1422 struct cons_pointer env ) {
1423 struct cons_pointer message = frame->arg[0];
1424
1425 return exceptionp( message ) ? message :
1426 throw_exception_with_cause( message, frame->arg[1], frame->arg[2],
1427 frame->previous );
1428}
1429
1430/**
1431 * Function: the read/eval/print loop.
1432 *
1433 * * (repl)
1434 * * (repl prompt)
1435 * * (repl prompt input_stream output_stream)
1436 *
1437 * @param frame my stack frame.
1438 * @param frame_pointer a pointer to my stack_frame.
1439 * @param env the environment in which epressions will be evaluated.
1440 * @return the value of the last expression read.
1441 */
1442struct cons_pointer lisp_repl( struct stack_frame *frame,
1443 struct cons_pointer frame_pointer,
1444 struct cons_pointer env ) {
1445 struct cons_pointer expr = NIL;
1446
1447#ifdef DEBUG
1448 debug_print( L"Entering new inner REPL\n\tenv is `", DEBUG_REPL );
1450 debug_print( L"`\n", DEBUG_REPL );
1451#endif
1452
1453 struct cons_pointer input = get_default_stream( true, env );
1454 struct cons_pointer output = get_default_stream( false, env );
1455 struct cons_pointer old_oblist = oblist;
1456 struct cons_pointer new_env = env;
1457
1458 if ( truep( frame->arg[0] ) ) {
1459 new_env = set( prompt_name, frame->arg[0], new_env );
1460 }
1461 if ( readp( frame->arg[1] ) ) {
1462 new_env =
1463 set( c_string_to_lisp_symbol( L"*in*" ), frame->arg[1], new_env );
1464 input = frame->arg[1];
1465 }
1466 if ( writep( frame->arg[2] ) ) {
1467 new_env =
1468 set( c_string_to_lisp_symbol( L"*out*" ), frame->arg[2], new_env );
1469 output = frame->arg[2];
1470 }
1471
1472 inc_ref( input );
1473 inc_ref( output );
1475
1476 /* output should NEVER BE nil; but during development it has happened.
1477 * To allow debugging under such circumstances, we need an emergency
1478 * default. */
1479 URL_FILE *os =
1480 !writep( output ) ? file_to_url_file( stdout ) :
1481 pointer2cell( output ).payload.stream.stream;
1482 if ( !writep( output ) ) {
1483 debug_print( L"WARNING: invalid output; defaulting!\n",
1484 DEBUG_IO | DEBUG_REPL );
1485 }
1486
1487 /* \todo this is subtly wrong. If we were evaluating
1488 * (print (eval (read)))
1489 * then the stack frame for read would have the stack frame for
1490 * eval as parent, and it in turn would have the stack frame for
1491 * print as parent.
1492 */
1493 while ( readp( input ) && writep( output )
1494 && !url_feof( pointer2cell( input ).payload.stream.stream ) ) {
1495 /* OK, here's a really subtle problem: because lists are immutable, anything
1496 * bound in the oblist subsequent to this function being invoked isn't in the
1497 * environment. So, for example, changes to *prompt* or *log* made in the oblist
1498 * are not visible. So copy changes made in the oblist into the enviroment.
1499 * \todo the whole process of resolving symbol values needs to be revisited
1500 * when we get onto namespaces. */
1501 /* OK, there's something even more subtle here if the root namespace is a map.
1502 * H'mmmm...
1503 * I think that now the oblist is a hashmap masquerading as a namespace,
1504 * we should no longer have to do this. TODO: test, and if so, delete this
1505 * statement. */
1506 if ( !eq( oblist, old_oblist ) ) {
1507 struct cons_pointer cursor = oblist;
1508
1509 while ( !nilp( cursor ) && !eq( cursor, old_oblist ) ) {
1510 struct cons_pointer old_new_env = new_env;
1512 ( L"lisp_repl: copying new oblist binding into REPL environment:\n",
1513 DEBUG_REPL );
1514 debug_print_object( c_car( cursor ), DEBUG_REPL );
1516
1517 new_env = make_cons( c_car( cursor ), new_env );
1518 inc_ref( new_env );
1519 dec_ref( old_new_env );
1520 cursor = c_cdr( cursor );
1521 }
1522 old_oblist = oblist;
1523 }
1524
1525 println( os );
1526
1527 struct cons_pointer prompt = c_assoc( prompt_name, new_env );
1528 if ( !nilp( prompt ) ) {
1529 print( os, prompt );
1530 }
1531
1532 expr = lisp_read( get_stack_frame( frame_pointer ), frame_pointer,
1533 new_env );
1534
1535 if ( exceptionp( expr )
1536 && url_feof( pointer2cell( input ).payload.stream.stream ) ) {
1537 /* suppress printing end of stream exception */
1538 dec_ref( expr );
1539 break;
1540 }
1541
1542 println( os );
1543
1544 print( os, eval_form( frame, frame_pointer, expr, new_env ) );
1545
1546 dec_ref( expr );
1547 }
1548
1549 if ( nilp( output ) ) {
1550 free( os );
1551 }
1552 dec_ref( input );
1553 dec_ref( output );
1555 dec_ref( new_env );
1556
1557 debug_printf( DEBUG_REPL, L"Leaving inner repl\n" );
1558
1559 return expr;
1560}
1561
1562/**
1563 * Function. return the source code of the object which is its first argument,
1564 * if it is an executable and has source code.
1565 *
1566 * * (source object)
1567 *
1568 * @param frame my stack frame.
1569 * @param frame_pointer a pointer to my stack_frame.
1570 * @param env the environment (ignored).
1571 * @return the source of the `object` indicated, if it is a function, a lambda,
1572 * an nlambda, or a spcial form; else `nil`.
1573 */
1575 struct cons_pointer frame_pointer,
1576 struct cons_pointer env ) {
1577 struct cons_pointer result = NIL;
1578 struct cons_space_object *cell = &pointer2cell( frame->arg[0] );
1579 struct cons_pointer source_key = c_string_to_lisp_keyword( L"source" );
1580 switch ( cell->tag.value ) {
1581 case FUNCTIONTV:
1582 result = c_assoc( source_key, cell->payload.function.meta );
1583 break;
1584 case SPECIALTV:
1585 result = c_assoc( source_key, cell->payload.special.meta );
1586 break;
1587 case LAMBDATV:
1588 result = make_cons( c_string_to_lisp_symbol( L"lambda" ),
1589 make_cons( cell->payload.lambda.args,
1590 cell->payload.lambda.body ) );
1591 break;
1592 case NLAMBDATV:
1593 result = make_cons( c_string_to_lisp_symbol( L"nlambda" ),
1594 make_cons( cell->payload.lambda.args,
1595 cell->payload.lambda.body ) );
1596 break;
1597 }
1598 // \todo suffers from premature GC, and I can't see why!
1599 inc_ref( result );
1600
1601 return result;
1602}
1603
1604/**
1605 * A version of append which can conveniently be called from C.
1606 */
1607struct cons_pointer c_append( struct cons_pointer l1, struct cons_pointer l2 ) {
1608 switch ( pointer2cell( l1 ).tag.value ) {
1609 case CONSTV:
1610 if ( pointer2cell( l1 ).tag.value == pointer2cell( l2 ).tag.value ) {
1611 if ( nilp( c_cdr( l1 ) ) ) {
1612 return make_cons( c_car( l1 ), l2 );
1613 } else {
1614 return make_cons( c_car( l1 ),
1615 c_append( c_cdr( l1 ), l2 ) );
1616 }
1617 } else {
1620 ( L"Can't append: not same type" ), NIL );
1621 }
1622 break;
1623 case KEYTV:
1624 case STRINGTV:
1625 case SYMBOLTV:
1626 if ( pointer2cell( l1 ).tag.value == pointer2cell( l2 ).tag.value ) {
1627 if ( nilp( c_cdr( l1 ) ) ) {
1628 return
1630 payload.string.character ),
1631 l2,
1632 pointer2cell( l1 ).tag.value );
1633 } else {
1634 return
1636 payload.string.character ),
1637 c_append( c_cdr( l1 ), l2 ),
1638 pointer2cell( l1 ).tag.value );
1639 }
1640 } else {
1643 ( L"Can't append: not same type" ), NIL );
1644 }
1645 break;
1646 default:
1649 ( L"Can't append: not a sequence" ), NIL );
1650 break;
1651 }
1652}
1653
1654/**
1655 * should really be overwritten with a version in Lisp, since this is much easier to write in Lisp
1656 */
1658 struct cons_pointer frame_pointer,
1659 struct cons_pointer env ) {
1660 struct cons_pointer result = fetch_arg( frame, ( frame->args - 1 ) );
1661
1662 for ( int a = frame->args - 2; a >= 0; a-- ) {
1663 result = c_append( fetch_arg( frame, a ), result );
1664 }
1665
1666 return result;
1667}
1668
1670 struct cons_pointer frame_pointer,
1671 struct cons_pointer env ) {
1672 struct cons_pointer result = NIL;
1673 debug_print( L"Mapcar: ", DEBUG_EVAL );
1674 debug_dump_object( frame_pointer, DEBUG_EVAL );
1675 int i = 0;
1676
1677 for ( struct cons_pointer c = frame->arg[1]; truep( c ); c = c_cdr( c ) ) {
1678 struct cons_pointer expr =
1679 make_cons( frame->arg[0], make_cons( c_car( c ), NIL ) );
1680
1681 debug_printf( DEBUG_EVAL, L"Mapcar %d, evaluating ", i );
1684
1685 struct cons_pointer r = eval_form( frame, frame_pointer, expr, env );
1686
1687 if ( exceptionp( r ) ) {
1688 result = r;
1689 inc_ref( expr ); // to protect exception from the later dec_ref
1690 break;
1691 } else {
1692 result = make_cons( r, result );
1693 }
1694 debug_printf( DEBUG_EVAL, L"Mapcar %d, result is ", i++ );
1695 debug_print_object( result, DEBUG_EVAL );
1697
1698 dec_ref( expr );
1699 }
1700
1701 result = consp( result ) ? c_reverse( result ) : result;
1702
1703 debug_print( L"Mapcar returning: ", DEBUG_EVAL );
1704 debug_print_object( result, DEBUG_EVAL );
1706
1707 return result;
1708}
1709
1710/**
1711 * @brief construct and return a list of arbitrarily many arguments.
1712 *
1713 * @param frame The stack frame.
1714 * @param frame_pointer A pointer to the stack frame.
1715 * @param env The evaluation environment.
1716 * @return struct cons_pointer a pointer to the result
1717 */
1718struct cons_pointer lisp_list( struct stack_frame *frame,
1719 struct cons_pointer frame_pointer,
1720 struct cons_pointer env ) {
1721 struct cons_pointer result = frame->more;
1722
1723 for ( int a = nilp( result ) ? frame->args - 1 : args_in_frame - 1;
1724 a >= 0; a-- ) {
1725 result = make_cons( fetch_arg( frame, a ), result );
1726 }
1727
1728 return result;
1729}
1730
1731
1732
1733/**
1734 * Special form: evaluate a series of forms in an environment in which
1735 * these bindings are bound.
1736 * This is `let*` in Common Lisp parlance; `let` in Clojure parlance.
1737 */
1738struct cons_pointer lisp_let( struct stack_frame *frame,
1739 struct cons_pointer frame_pointer,
1740 struct cons_pointer env ) {
1741 struct cons_pointer bindings = env;
1742 struct cons_pointer result = NIL;
1743
1744 for ( struct cons_pointer cursor = frame->arg[0];
1745 truep( cursor ); cursor = c_cdr( cursor ) ) {
1746 struct cons_pointer pair = c_car( cursor );
1747 struct cons_pointer symbol = c_car( pair );
1748
1749 if ( symbolp( symbol ) ) {
1750 struct cons_pointer val =
1751 eval_form( frame, frame_pointer, c_cdr( pair ),
1752 bindings );
1753
1754 debug_print_binding( symbol, val, false, DEBUG_BIND );
1755
1756 bindings = make_cons( make_cons( symbol, val ), bindings );
1757 } else {
1758 result =
1761 ( L"Let: cannot bind, not a symbol" ),
1762 frame_pointer );
1763 break;
1764 }
1765 }
1766
1767 debug_print( L"\nlet: bindings complete.\n", DEBUG_BIND );
1768
1769 /* i.e., no exception yet */
1770 for ( int form = 1; !exceptionp( result ) && form < frame->args; form++ ) {
1771 result =
1772 eval_form( frame, frame_pointer, fetch_arg( frame, form ),
1773 bindings );
1774 }
1775
1776 /* release the local bindings as they go out of scope! **BUT**
1777 * bindings were consed onto the front of env, so caution... */
1778 // for (struct cons_pointer cursor = bindings; !eq( cursor, env); cursor = c_cdr(cursor)) {
1779 // dec_ref( cursor);
1780 // }
1781
1782 return result;
1783
1784}
1785
1786/**
1787 * @brief Boolean `and` of arbitrarily many arguments.
1788 *
1789 * @param frame The stack frame.
1790 * @param frame_pointer A pointer to the stack frame.
1791 * @param env The evaluation environment.
1792 * @return struct cons_pointer a pointer to the result
1793 */
1794struct cons_pointer lisp_and( struct stack_frame *frame,
1795 struct cons_pointer frame_pointer,
1796 struct cons_pointer env ) {
1797 bool accumulator = true;
1798 struct cons_pointer result = frame->more;
1799
1800 for ( int a = 0; accumulator == true && a < frame->args; a++ ) {
1801 accumulator = truthy( fetch_arg( frame, a ) );
1802 }
1803#
1804 return accumulator ? TRUE : NIL;
1805}
1806
1807/**
1808 * @brief Boolean `or` of arbitrarily many arguments.
1809 *
1810 * @param frame The stack frame.
1811 * @param frame_pointer A pointer to the stack frame.
1812 * @param env The evaluation environment.
1813 * @return struct cons_pointer a pointer to the result
1814 */
1815struct cons_pointer lisp_or( struct stack_frame *frame,
1816 struct cons_pointer frame_pointer,
1817 struct cons_pointer env ) {
1818 bool accumulator = false;
1819 struct cons_pointer result = frame->more;
1820
1821 for ( int a = 0; accumulator == false && a < frame->args; a++ ) {
1822 accumulator = truthy( fetch_arg( frame, a ) );
1823 }
1824
1825 return accumulator ? TRUE : NIL;
1826}
1827
1828/**
1829 * @brief Logical inverese: if the first argument is `nil`, return `t`, else `nil`.
1830 *
1831 * @param frame The stack frame.
1832 * @param frame_pointer A pointer to the stack frame.
1833 * @param env The evaluation environment.
1834 * @return struct cons_pointer `t` if the first argument is `nil`, else `nil`.
1835 */
1836struct cons_pointer lisp_not( struct stack_frame *frame,
1837 struct cons_pointer frame_pointer,
1838 struct cons_pointer env ) {
1839 return nilp( frame->arg[0] ) ? TRUE : NIL;
1840}
struct cons_pointer c_cdr(struct cons_pointer arg)
Implementation of cdr in C.
struct cons_pointer make_cons(struct cons_pointer car, struct cons_pointer cdr)
Construct a cons cell from this pair of pointers.
#define KEYTV
The string KEYW, considered as an unsigned int.
#define SPECIALTV
The string SPFM, considered as an unsigned int.
#define exceptionp(conspoint)
true if conspoint points to an exception, else false
#define writep(conspoint)
true if conspoint points to a write stream cell, else false.
int args
the number of arguments provided.
#define truep(conspoint)
true if conspoint points to something that is truthy, i.e.
#define SYMBOLTV
The string SYMB, considered as an unsigned int.
#define functionp(conspoint)
true if conspoint points to a function cell, else false
#define args_in_frame
union cons_space_object::@2 tag
union cons_space_object::@3 payload
#define NIL
a cons pointer which points to the special NIL cell
#define FUNCTIONTV
The string FUNC, considered as an unsigned int.
struct cons_pointer make_exception(struct cons_pointer message, struct cons_pointer frame_pointer)
Construct an exception cell.
struct cons_pointer make_lambda(struct cons_pointer args, struct cons_pointer body)
Construct a lambda (interpretable source) cell.
struct cons_pointer make_symbol_or_key(wint_t c, struct cons_pointer tail, uint32_t tag)
Construct a symbol or keyword from the character c and this tail.
struct cons_pointer c_string_to_lisp_keyword(wchar_t *symbol)
Return a lisp keyword representation of this wide character string.
struct cons_pointer c_cdr(struct cons_pointer arg)
Implementation of cdr in C.
#define STRINGTV
The string STRG, considered as an unsigned int.
struct cons_pointer make_string_like_thing(wint_t c, struct cons_pointer tail, uint32_t tag)
Construct a string from this character (which later will be UTF) and this tail.
#define TIMETV
The string TIME, considered as an unsigned int.
#define INTEGERTV
The string INTR, considered as an unsigned int.
#define FREETV
The string FREE, considered as an unsigned int.
#define readp(conspoint)
true if conspoint points to a read stream cell, else false
int c_length(struct cons_pointer arg)
Implementation of length in C.
struct cons_pointer privileged_keyword_cause
Keywords used when constructing exceptions: :cause.
#define RATIOTV
The string RTIO, considered as an unsigned int.
#define consp(conspoint)
true if conspoint points to a cons cell, else false
#define CONSTV
The string CONS, considered as an unsigned int.
#define LOOPTV
The string LOOX, considered as an unsigned int.
struct cons_pointer make_string(wint_t c, struct cons_pointer tail)
Construct a string from the character c and this tail.
#define specialp(conspoint)
true if conspoint points to a special form cell, else false
#define nilp(conspoint)
true if conspoint points to the special cell NIL, else false (there should only be one of these so it...
#define NLAMBDATV
The string NLMD, considered as an unsigned int.
struct cons_pointer privileged_keyword_name
keywords used in documentation: :name.
#define TRUETV
The string TRUE, considered as an unsigned int.
#define symbolp(conspoint)
true if conspoint points to a symbol cell, else false
#define REALTV
The string REAL, considered as an unsigned int.
uint32_t get_tag_value(struct cons_pointer pointer)
given a cons_pointer as argument, return the tag.
struct cons_pointer c_string_to_lisp_string(wchar_t *string)
Return a lisp string representation of this wide character string.
struct cons_pointer inc_ref(struct cons_pointer pointer)
increment the reference count of the object at this cons pointer.
#define NILTV
The string NIL, considered as an unsigned int.
#define EXCEPTIONTV
The string EXEP, considered as an unsigned int.
#define TRUE
a cons pointer which points to the special T cell
#define sequencep(conspoint)
true if conspoint points to a sequence (list, string or, later, vector), else false.
#define stringp(conspoint)
true if conspoint points to a string cell, else false
struct cons_pointer privileged_keyword_payload
Keywords used when constructing exceptions: :payload.
struct cons_pointer c_string_to_lisp_symbol(wchar_t *symbol)
Return a lisp symbol representation of this wide character string.
struct cons_pointer c_car(struct cons_pointer arg)
Implementation of car in C.
#define LAMBDATV
The string LMDA, considered as an unsigned int.
#define WRITETV
The string WRIT, considered as an unsigned int.
struct cons_pointer c_type(struct cons_pointer pointer)
Get the Lisp type of the single argument.
struct cons_pointer make_nlambda(struct cons_pointer args, struct cons_pointer body)
Construct an nlambda (interpretable source) cell; to a lambda as a special form is to a function.
#define READTV
The string READ, considered as an unsigned int.
struct cons_pointer dec_ref(struct cons_pointer pointer)
Decrement the reference count of the object at this cons pointer.
struct cons_pointer privileged_keyword_location
Keywords used when constructing exceptions: :location.
#define pointer2cell(pointer)
given a cons_pointer as argument, return the cell.
struct cons_pointer make_cons(struct cons_pointer car, struct cons_pointer cdr)
Construct a cons cell from this pair of pointers.
An indirect pointer to a cons cell.
an object in cons space.
A stack frame.
void debug_print_binding(struct cons_pointer key, struct cons_pointer val, bool deep, int level)
Standardise printing of binding trace messages.
Definition debug.c:169
void debug_println(int level)
print a line feed to stderr, if verbosity matches level.
Definition debug.c:104
void debug_dump_object(struct cons_pointer pointer, int level)
Like dump_object, q.v., but protected by the verbosity mechanism.
Definition debug.c:155
void debug_printf(int level, wchar_t *format,...)
wprintf adapted for the debug logging system.
Definition debug.c:120
void debug_print(wchar_t *message, int level)
print this debug message to stderr, if verbosity matches level.
Definition debug.c:60
void debug_print_object(struct cons_pointer pointer, int level)
print the object indicated by this pointer to stderr, if verbosity matches level.
Definition debug.c:138
#define DEBUG_BIND
Print messages debugging symbol binding.
Definition debug.h:38
#define DEBUG_LAMBDA
Print messages debugging lambda functions (interpretation).
Definition debug.h:66
#define DEBUG_REPL
Print messages debugging the read eval print loop.
Definition debug.h:73
#define DEBUG_IO
Print messages debugging input/output operations.
Definition debug.h:59
#define DEBUG_EVAL
Print messages debugging evaluation.
Definition debug.h:52
void dump_object(URL_FILE *output, struct cons_pointer pointer)
dump the object at this cons_pointer to this output stream.
Definition dump.c:59
bool equal(struct cons_pointer a, struct cons_pointer b)
Deep, and thus expensive, equality: true if these two objects have identical structure,...
Definition equal.c:334
bool eq(struct cons_pointer a, struct cons_pointer b)
Shallow, and thus cheap, equality: true if these two objects are the same object, else false.
Definition equal.c:28
int url_feof(URL_FILE *file)
Definition fopen.c:286
struct cons_pointer acquire_integer(int64_t value, struct cons_pointer more)
Supply small valued integers from the small integer cache, if available.
Definition integer.c:129
struct cons_pointer make_integer(int64_t value, struct cons_pointer more)
Allocate an integer cell representing this value and return a cons_pointer to it.
Definition integer.c:89
struct cons_pointer hashmap_keys(struct cons_pointer mapp)
return a flat list of all the keys in the hashmap indicated by map.
Definition intern.c:163
struct cons_pointer internedp(struct cons_pointer key, struct cons_pointer store)
Implementation of interned? in C.
Definition intern.c:436
struct cons_pointer c_assoc(struct cons_pointer key, struct cons_pointer store)
Implementation of assoc in C.
Definition intern.c:478
struct cons_pointer interned(struct cons_pointer key, struct cons_pointer store)
Definition intern.c:424
struct cons_pointer oblist
The global object list/or, to put it differently, the root namespace.
Definition intern.c:49
struct cons_pointer deep_bind(struct cons_pointer key, struct cons_pointer value)
Binds this key to this value in the global oblist, and returns the key.
Definition intern.c:545
struct cons_pointer set(struct cons_pointer key, struct cons_pointer value, struct cons_pointer store)
If this store is modifiable, add this key value pair to it.
Definition intern.c:519
wint_t url_fgetwc(URL_FILE *input)
get one wide character from the buffer.
Definition io.c:151
URL_FILE * file_to_url_file(FILE *f)
given this file handle f, return a new url_file handle wrapping it.
Definition io.c:134
struct cons_pointer get_default_stream(bool inputp, struct cons_pointer env)
Resutn the current default input, or of inputp is false, output stream from this environment.
Definition io.c:411
struct cons_pointer lisp_nlambda(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Construct an interpretable special form.
Definition lispops.c:244
struct cons_pointer lisp_assoc(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function; look up the value of a key in a store.
Definition lispops.c:886
struct cons_pointer c_apply(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Internal guts of apply.
Definition lispops.c:386
struct cons_pointer lisp_source(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function.
Definition lispops.c:1574
struct cons_pointer lisp_mapcar(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Definition lispops.c:1669
struct cons_pointer lisp_cons(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function; returns a cell constructed from a and b.
Definition lispops.c:751
struct cons_pointer lisp_eq(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function; are these two objects the same object? Shallow, cheap equality.
Definition lispops.c:958
struct cons_pointer lisp_read(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function; read one complete lisp form and return it.
Definition lispops.c:1049
struct cons_pointer lisp_exception(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function; create an exception.
Definition lispops.c:1421
struct cons_pointer c_reverse(struct cons_pointer arg)
reverse a sequence (if it is a sequence); else return it unchanged.
Definition lispops.c:1090
struct cons_pointer lisp_car(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function; returns the first item (head) of a sequence.
Definition lispops.c:784
struct cons_pointer compose_body(struct stack_frame *frame)
Used to construct the body for lambda and nlambda expressions.
Definition lispops.c:198
struct cons_pointer eval_form(struct stack_frame *parent, struct cons_pointer parent_pointer, struct cons_pointer form, struct cons_pointer env)
Useful building block; evaluate this single form in the context of this parent stack frame and this e...
Definition lispops.c:65
struct cons_pointer lisp_count(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function: return the number of top level forms in the object which is the first (and only) argument,...
Definition lispops.c:1030
struct cons_pointer throw_exception(struct cons_pointer location, struct cons_pointer payload, struct cons_pointer frame_pointer)
Throw an exception.
Definition lispops.c:1396
struct cons_pointer lisp_let(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Special form: evaluate a series of forms in an environment in which these bindings are bound.
Definition lispops.c:1738
struct cons_pointer lisp_inspect(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function: dump/inspect one complete lisp expression and return NIL.
Definition lispops.c:1148
struct cons_pointer lisp_or(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Boolean or of arbitrarily many arguments.
Definition lispops.c:1815
struct cons_pointer lisp_length(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function: return, as an integer, the length of the sequence indicated by the first argument,...
Definition lispops.c:869
struct cons_pointer lisp_try(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
OK, the idea here (and I know this is less than perfect) is that the basic try special form in PSSE t...
Definition lispops.c:161
struct cons_pointer lisp_apply(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function; apply the function which is the result of evaluating the first argument to the list of valu...
Definition lispops.c:611
long int c_count(struct cons_pointer p)
Definition lispops.c:997
struct cons_pointer c_progn(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer expressions, struct cons_pointer env)
Evaluate each of these expressions in this environment over this frame, returning only the value of t...
Definition lispops.c:1195
struct cons_pointer lisp_eval(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function; evaluate the expression which is the first argument in the frame; further arguments are ign...
Definition lispops.c:550
struct cons_pointer eval_forms(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer list, struct cons_pointer env)
Evaluate all the forms in this list in the context of this stack frame and this env,...
Definition lispops.c:133
struct cons_pointer lisp_type(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function: get the Lisp type of the single argument.
Definition lispops.c:1185
struct cons_pointer lisp_internedp(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
(interned? key store): Return t if the symbol or keyword key is bound in this store,...
Definition lispops.c:901
struct cons_pointer eval_cond_clause(struct cons_pointer clause, struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
evaluate a single cond clause; if the test part succeeds return a pair whose car is TRUE and whose cd...
Definition lispops.c:1249
struct cons_pointer c_keys(struct cons_pointer store)
Definition lispops.c:919
struct cons_pointer lisp_progn(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Special form; evaluate the expressions which are listed in my arguments sequentially and return the v...
Definition lispops.c:1226
bool end_of_stringp(struct cons_pointer arg)
Definition lispops.c:729
struct cons_pointer lisp_keys(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Definition lispops.c:942
struct cons_pointer throw_exception_with_cause(struct cons_pointer location, struct cons_pointer message, struct cons_pointer cause, struct cons_pointer frame_pointer)
Throw an exception with a cause.
Definition lispops.c:1343
struct cons_pointer lisp_equal(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function; are these two arguments identical? Deep, expensive equality.
Definition lispops.c:983
struct cons_pointer lisp_repl(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function: the read/eval/print loop.
Definition lispops.c:1442
struct cons_pointer lisp_set_shriek(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Special form; binds symbol in the namespace to value of value, altering the namespace in so doing,...
Definition lispops.c:702
struct cons_pointer lisp_append(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
should really be overwritten with a version in Lisp, since this is much easier to write in Lisp
Definition lispops.c:1657
struct cons_pointer lisp_not(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Logical inverese: if the first argument is nil, return t, else nil.
Definition lispops.c:1836
struct cons_pointer lisp_quote(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Special form; returns its argument (strictly first argument - only one is expected but this isn't at ...
Definition lispops.c:641
struct cons_pointer lisp_set(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function; binds the value of name in the namespace to value of value, altering the namespace in so do...
Definition lispops.c:663
struct cons_pointer lisp_lambda(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Construct an interpretable function.
Definition lispops.c:227
struct cons_pointer lisp_cdr(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function; returns the remainder of a sequence when the head is removed.
Definition lispops.c:829
struct cons_pointer lisp_list(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
construct and return a list of arbitrarily many arguments.
Definition lispops.c:1718
struct cons_pointer c_append(struct cons_pointer l1, struct cons_pointer l2)
A version of append which can conveniently be called from C.
Definition lispops.c:1607
struct cons_pointer lisp_oblist(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Return the object list (root namespace).
Definition lispops.c:190
struct cons_pointer lisp_cond(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Special form: conditional.
Definition lispops.c:1308
struct cons_pointer lisp_reverse(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Function; reverse the order of members in s sequence.
Definition lispops.c:1128
struct cons_pointer eval_lambda(struct cons_space_object *cell, struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Evaluate a lambda or nlambda expression.
Definition lispops.c:254
struct cons_pointer prompt_name
the name of the symbol to which the prompt is bound;
Definition lispops.c:47
struct cons_pointer maybe_fixup_exception_location(struct cons_pointer r, struct cons_pointer fn_pointer)
if r is an exception, and it doesn't have a location, fix up its location from the name associated wi...
Definition lispops.c:335
struct cons_pointer lisp_and(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env)
Boolean and of arbitrarily many arguments.
Definition lispops.c:1794
#define truthy(arg)
return true if arg is nil, else false.
Definition peano.h:45
void println(URL_FILE *output)
Definition print.c:329
struct cons_pointer print(URL_FILE *output, struct cons_pointer pointer)
Print the cons-space object indicated by pointer to the stream indicated by output.
Definition print.c:156
struct cons_pointer read(struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env, URL_FILE *input)
Read the next object on this input stream and return a cons_pointer to it.
Definition read.c:564
struct cons_pointer make_special_frame(struct cons_pointer previous, struct cons_pointer args, struct cons_pointer env)
A 'special' frame is exactly like a normal stack frame except that the arguments are unevaluated.
Definition stack.c:227
struct cons_pointer fetch_arg(struct stack_frame *frame, unsigned int index)
Fetch a pointer to the value of the local variable at this index.
Definition stack.c:364
void set_reg(struct stack_frame *frame, int reg, struct cons_pointer value)
set a register in a stack frame.
Definition stack.c:39
struct stack_frame * get_stack_frame(struct cons_pointer pointer)
get the actual stackframe object from this pointer, or NULL if pointer is not a stackframe pointer.
Definition stack.c:59
struct cons_pointer make_empty_frame(struct cons_pointer previous)
Make an empty stack frame, and return it.
Definition stack.c:129
struct cons_pointer make_stack_frame(struct cons_pointer previous, struct cons_pointer args, struct cons_pointer env)
Allocate a new stack frame with its previous pointer set to this value, its arguments set up from the...
Definition stack.c:161
#define HASHTV
Definition vectorspace.h:30
#define hashmapp(conspoint)
Definition vectorspace.h:32