Apply works; all unit tests pass.

This commit is contained in:
simon 2017-10-15 18:27:55 +01:00
parent 8e7d1ab913
commit 685790df43
5 changed files with 66 additions and 32 deletions

View file

@ -94,11 +94,11 @@ int main( int argc, char *argv[] ) {
bind_function( "*", &lisp_multiply ); bind_function( "*", &lisp_multiply );
bind_function( "subtract", &lisp_subtract ); bind_function( "subtract", &lisp_subtract );
bind_function( "-", &lisp_subtract ); bind_function( "-", &lisp_subtract );
bind_function( "apply", &lisp_apply );
/* /*
* primitive special forms * primitive special forms
*/ */
bind_special( "apply", &lisp_apply );
bind_special( "eval", &lisp_eval ); bind_special( "eval", &lisp_eval );
bind_special( "quote", &lisp_quote ); bind_special( "quote", &lisp_quote );

View file

@ -73,9 +73,15 @@ struct cons_pointer c_cdr( struct cons_pointer arg ) {
} }
/**
* Internal guts of apply.
* @param frame the stack frame, expected to have only one argument, a list
* comprising something that evaluates to a function and its arguments.
* @param env The evaluation environment.
* @return the result of evaluating the function with its arguments.
*/
struct cons_pointer struct cons_pointer
eval_cons( struct stack_frame *frame, struct cons_pointer env ) { c_apply( struct stack_frame *frame, struct cons_pointer env ) {
struct cons_pointer result = NIL; struct cons_pointer result = NIL;
struct stack_frame *fn_frame = make_empty_frame( frame, env ); struct stack_frame *fn_frame = make_empty_frame( frame, env );
@ -143,9 +149,12 @@ lisp_eval( struct stack_frame *frame, struct cons_pointer env ) {
struct cons_pointer result = frame->arg[0]; struct cons_pointer result = frame->arg[0];
struct cons_space_object cell = pointer2cell( frame->arg[0] ); struct cons_space_object cell = pointer2cell( frame->arg[0] );
fputws( L"Eval: ", stderr );
dump_frame( stderr, frame );
switch ( cell.tag.value ) { switch ( cell.tag.value ) {
case CONSTV: case CONSTV:
result = eval_cons( frame, env ); result = c_apply( frame, env );
break; break;
case SYMBOLTV: case SYMBOLTV:
@ -170,37 +179,35 @@ lisp_eval( struct stack_frame *frame, struct cons_pointer env ) {
*/ */
} }
fputws( L"Eval returning ", stderr );
print( stderr, result );
fputws( L"\n", stderr );
return result; return result;
} }
/** /**
* (apply fn args) * (apply fn args)
* *
* Special form. Apply the function which is the result of evaluating the * function. Apply the function which is the result of evaluating the
* first argoment to the list of arguments which is the result of evaluating * first argoment to the list of arguments which is the result of evaluating
* the second argument * the second argument
*/ */
struct cons_pointer struct cons_pointer
lisp_apply( struct stack_frame *frame, struct cons_pointer env ) { lisp_apply( struct stack_frame *frame, struct cons_pointer env ) {
struct cons_pointer result = NIL; fputws( L"Apply: ", stderr );
dump_frame( stderr, frame );
if ( nilp( frame->arg[1] ) || !nilp( frame->arg[2] ) ) { frame->arg[0] = make_cons( frame->arg[0], frame->arg[1] );
result = inc_ref( frame->arg[0] );
lisp_throw( c_string_to_lisp_string( "(apply <function> <args>" ), frame->arg[1] = NIL;
frame );
}
struct stack_frame *fn_frame = make_empty_frame( frame, env ); struct cons_pointer result = c_apply( frame, env );
fn_frame->arg[0] = frame->arg[0];
inc_ref( fn_frame->arg[0] );
struct cons_pointer fn_pointer = lisp_eval( fn_frame, env );
free_stack_frame( fn_frame );
struct stack_frame *next_frame = fputws( L"Apply returning ", stderr );
make_special_frame( frame, make_cons( fn_pointer, frame->arg[1] ), print( stderr, result );
env ); fputws( L"\n", stderr );
result = eval_cons( next_frame, env );
free_stack_frame( next_frame );
return result; return result;
} }

View file

@ -67,23 +67,25 @@ struct cons_pointer read_continuation( FILE * input, wint_t initial ) {
result = read_string( input, fgetwc( input ) ); result = read_string( input, fgetwc( input ) );
break; break;
default: default:
if ( c == '.' ) { if ( c == '.' ) {
wint_t next = fgetwc( input ); wint_t next = fgetwc( input );
if ( iswdigit( next) ) { if ( iswdigit( next ) ) {
ungetwc( next, input ); ungetwc( next, input );
result = read_number( input, c ); result = read_number( input, c );
} else if ( iswblank( next ) ) { } else if ( iswblank( next ) ) {
result = read_continuation(input, fgetwc( input)); /* dotted pair. TODO: this isn't right, we
* really need to backtrack up a level. */
result = read_continuation( input, fgetwc( input ) );
} else { } else {
read_symbol( input, c ); read_symbol( input, c );
} }
} } else if ( iswdigit( c ) ) {
else if ( iswdigit( c ) ) {
result = read_number( input, c ); result = read_number( input, c );
} else if ( iswprint( c ) ) { } else if ( iswprint( c ) ) {
result = read_symbol( input, c ); result = read_symbol( input, c );
} else { } else {
fwprintf( stderr, L"Unrecognised start of input character %c\n", c ); fwprintf( stderr, L"Unrecognised start of input character %c\n",
c );
} }
} }
@ -206,7 +208,7 @@ struct cons_pointer read_symbol( FILE * input, wint_t initial ) {
ungetwc( initial, input ); ungetwc( initial, input );
break; break;
default: default:
if ( iswprint( initial ) && ! iswblank( initial ) ) { if ( iswprint( initial ) && !iswblank( initial ) ) {
result = result =
make_symbol( initial, read_symbol( input, fgetwc( input ) ) ); make_symbol( initial, read_symbol( input, fgetwc( input ) ) );
} else { } else {
@ -219,9 +221,9 @@ struct cons_pointer read_symbol( FILE * input, wint_t initial ) {
break; break;
} }
fputws(L"Read symbol '", stderr); fputws( L"Read symbol '", stderr );
print(stderr, result); print( stderr, result );
fputws(L"'\n", stderr); fputws( L"'\n", stderr );
return result; return result;
} }

View file

@ -83,6 +83,7 @@ struct stack_frame *make_stack_frame( struct stack_frame *previous,
*/ */
struct stack_frame *arg_frame = make_empty_frame( previous, env ); struct stack_frame *arg_frame = make_empty_frame( previous, env );
arg_frame->arg[0] = cell.payload.cons.car; arg_frame->arg[0] = cell.payload.cons.car;
inc_ref( arg_frame->arg[0] );
result->arg[i] = lisp_eval( arg_frame, env ); result->arg[i] = lisp_eval( arg_frame, env );
inc_ref( result->arg[i] ); inc_ref( result->arg[i] );
free_stack_frame( arg_frame ); free_stack_frame( arg_frame );
@ -143,6 +144,22 @@ void free_stack_frame( struct stack_frame *frame ) {
free( frame ); free( frame );
} }
/**
* Dump a stackframe to this stream for debugging
* @param output the stream
* @param frame the frame
*/
void dump_frame( FILE * output, struct stack_frame *frame ) {
fputws( L"Dumping stack frame\n", output );
for ( int arg = 0; arg < args_in_frame; arg++ ) {
fwprintf( output, L"Arg %d:", arg );
print( output, frame->arg[arg] );
fputws( L"\n", output );
}
}
/** /**
* Fetch a pointer to the value of the local variable at this index. * Fetch a pointer to the value of the local variable at this index.
*/ */

View file

@ -37,6 +37,14 @@ struct stack_frame *make_stack_frame( struct stack_frame *previous,
struct cons_pointer args, struct cons_pointer args,
struct cons_pointer env ); struct cons_pointer env );
void free_stack_frame( struct stack_frame *frame ); void free_stack_frame( struct stack_frame *frame );
/**
* Dump a stackframe to this stream for debugging
* @param output the stream
* @param frame the frame
*/
void dump_frame( FILE * output, struct stack_frame *frame );
struct cons_pointer fetch_arg( struct stack_frame *frame, unsigned int n ); struct cons_pointer fetch_arg( struct stack_frame *frame, unsigned int n );
/** /**