Let working, unit tested.

This commit is contained in:
Simon Brooke 2021-09-08 15:01:48 +01:00
parent 3abebe937c
commit 78d2395d60
No known key found for this signature in database
GPG key ID: A7A4F18D1D4DF987
4 changed files with 78 additions and 5 deletions

View file

@ -270,6 +270,7 @@ int main( int argc, char *argv[] ) {
bind_special( L"cond", &lisp_cond );
bind_special( L"lambda", &lisp_lambda );
bind_special( L"\u03bb", &lisp_lambda ); // λ
bind_special(L"let", &lisp_let);
bind_special( L"nlambda", &lisp_nlambda );
bind_special( L"n\u03bb", &lisp_nlambda );
bind_special( L"progn", &lisp_progn );

View file

@ -593,7 +593,7 @@ lisp_set( struct stack_frame *frame, struct cons_pointer frame_pointer,
result = frame->arg[1];
} else {
result =
make_exception( make_cons
throw_exception( make_cons
( c_string_to_lisp_string
( L"The first argument to `set` is not a symbol: " ),
make_cons( frame->arg[0], NIL ) ),
@ -632,7 +632,7 @@ lisp_set_shriek( struct stack_frame *frame, struct cons_pointer frame_pointer,
result = val;
} else {
result =
make_exception( make_cons
throw_exception( make_cons
( c_string_to_lisp_string
( L"The first argument to `set!` is not a symbol: " ),
make_cons( frame->arg[0], NIL ) ),
@ -1212,7 +1212,7 @@ struct cons_pointer
lisp_exception( struct stack_frame *frame, struct cons_pointer frame_pointer,
struct cons_pointer env ) {
struct cons_pointer message = frame->arg[0];
return exceptionp( message ) ? message : make_exception( message,
return exceptionp( message ) ? message : throw_exception( message,
frame->previous );
}
@ -1408,9 +1408,14 @@ struct cons_pointer c_append( struct cons_pointer l1, struct cons_pointer l2 ) {
struct cons_pointer lisp_append( struct stack_frame *frame,
struct cons_pointer frame_pointer,
struct cons_pointer env ) {
return c_append( frame->arg[0], frame->arg[1] );
}
struct cons_pointer result = fetch_arg(frame, (frame->args - 1));
for (int a = frame->args - 2; a >= 0; a--) {
result = c_append(fetch_arg(frame, a), result);
}
return result;
}
struct cons_pointer lisp_mapcar( struct stack_frame *frame,
struct cons_pointer frame_pointer,
@ -1466,6 +1471,45 @@ struct cons_pointer lisp_list( struct stack_frame *frame,
return result;
}
/**
* Special form: evaluate a series of forms in an environment in which
* these bindings are bound.
* This is `let*` in Common Lisp parlance; `let` in Clojure parlance.
*/
struct cons_pointer lisp_let( struct stack_frame *frame,
struct cons_pointer frame_pointer,
struct cons_pointer env) {
struct cons_pointer bindings = env;
struct cons_pointer result = NIL;
for (struct cons_pointer cursor = frame->arg[0];
truep(cursor);
cursor = c_cdr(cursor)) {
struct cons_pointer pair = c_car(cursor);
struct cons_pointer symbol = c_car(pair);
if (symbolp(symbol)) {
bindings = make_cons(
make_cons(symbol, eval_form(frame, frame_pointer, c_cdr(pair), bindings)),
bindings);
} else {
result = throw_exception(
c_string_to_lisp_string(L"Let: cannot bind, not a symbol"),
frame_pointer);
break;
}
}
/* i.e., no exception yet */
for (int form = 1; !exceptionp(result) && form < frame->args; form++) {
result = eval_form(frame, frame_pointer, fetch_arg(frame, form), bindings);
}
return result;
}
// /**
// * Function; print the internal representation of the object indicated by `frame->arg[0]` to the
// * (optional, defaults to the value of `*out*` in the environment) stream indicated by `frame->arg[1]`.

View file

@ -215,4 +215,8 @@ struct cons_pointer lisp_mapcar( struct stack_frame *frame,
struct cons_pointer lisp_list( struct stack_frame *frame,
struct cons_pointer frame_pointer,
struct cons_pointer env );
struct cons_pointer lisp_let( struct stack_frame *frame,
struct cons_pointer frame_pointer,
struct cons_pointer env);
#endif

24
unit-tests/let.sh Executable file
View file

@ -0,0 +1,24 @@
#!/bin/bash
expected='11'
actual=`echo "(let ((a . 5)(b . 6)) (+ a b))" | target/psse | tail -1`
if [ "${expected}" = "${actual}" ]
then
echo "OK"
else
echo "Fail: expected '$expected', got '$actual'"
exit 1
fi
expected='1'
actual=`echo "(let ((a . 5)(b . 6)) (+ a b) (- b a))" | target/psse | tail -1`
if [ "${expected}" = "${actual}" ]
then
echo "OK"
exit 0
else
echo "Fail: expected '$expected', got '$actual'"
exit 1
fi