diff --git a/src/conspage.c b/src/conspage.c index a88b62a..e016c86 100644 --- a/src/conspage.c +++ b/src/conspage.c @@ -54,7 +54,7 @@ void make_cons_page( ) { for ( int i = 0; i < CONSPAGESIZE; i++ ) { struct cons_space_object *cell = &conspages[initialised_cons_pages]->cell[i]; - if ( initialised_cons_pages == 0 && i < 3 ) { + if ( initialised_cons_pages == 0 && i < 2 ) { switch ( i ) { case 0: /* @@ -78,16 +78,6 @@ void make_cons_page( ) { 0, 1}; fwprintf( stderr, L"Allocated special cell T\n" ); break; - case 2: - /* - * initialise cell as λ - */ - strncpy( &cell->tag.bytes[0], LAMBDATAG, TAGLENGTH ); - cell->count = MAXREFERENCE; - cell->payload.string.character = ( wint_t ) L'λ'; - cell->payload.free.cdr = NIL; - fwprintf( stderr, L"Allocated special cell LAMBDA\n" ); - break; } } else { /* diff --git a/src/consspaceobject.c b/src/consspaceobject.c index 2d1464e..defc56f 100644 --- a/src/consspaceobject.c +++ b/src/consspaceobject.c @@ -128,6 +128,12 @@ void dump_object( FILE * output, struct cons_pointer pointer ) { L"\t\tInteger cell: value %ld, count %u\n", cell.payload.integer.value, cell.count ); break; + case LAMBDATV: + fwprintf( output, L"Lambda cell; args: " ); + print( output, cell.payload.lambda.args ); + fwprintf( output, L";\n\t\t\tbody: " ); + print( output, cell.payload.lambda.args ); + break; case READTV: fwprintf( output, L"\t\tInput stream\n" ); case REALTV: @@ -152,8 +158,7 @@ struct cons_pointer make_cons( struct cons_pointer car, pointer = allocate_cell( CONSTAG ); - struct cons_space_object *cell = - &conspages[pointer.page]->cell[pointer.offset]; + struct cons_space_object *cell = &pointer2cell( pointer ); inc_ref( car ); inc_ref( cdr ); @@ -195,6 +200,21 @@ make_function( struct cons_pointer src, struct cons_pointer ( *executable ) return pointer; } +/** + * Construct a lambda (interpretable source) cell + */ +struct cons_pointer make_lambda( struct cons_pointer args, + struct cons_pointer body ) { + struct cons_pointer pointer = allocate_cell( LAMBDATAG ); + struct cons_space_object *cell = &pointer2cell( pointer ); + inc_ref( args ); + inc_ref( body ); + cell->payload.lambda.args = args; + cell->payload.lambda.body = body; + + return pointer; +} + /** * Construct a string from this character (which later will be UTF) and * this tail. A string is implemented as a flat list of cells each of which diff --git a/src/consspaceobject.h b/src/consspaceobject.h index 0b50e07..22b7c18 100644 --- a/src/consspaceobject.h +++ b/src/consspaceobject.h @@ -61,8 +61,7 @@ #define INTEGERTV 1381256777 /** - * Lambda is very special, and, like NIL and TRUE, we need to identify it - * quickly and cheaply. So we will give it, too, a special cons cell at {0,2} + * A lambda cell. */ #define LAMBDATAG "LMDA" #define LAMBDATV 1094995276 @@ -134,11 +133,6 @@ */ #define TRUE (struct cons_pointer){ 0, 1} -/** - * a cons pointer which points to the special λ cell - */ -#define LAMBDA (struct cons_pointer){ 0,2} - /** * the maximum possible value of a reference count */ @@ -173,7 +167,7 @@ #define functionp(conspoint) (check_tag(conspoint,FUNCTIONTAG)) /** - * true if conspointer points to the special Lambda cell, else false + * true if conspointer points to a special Lambda cell, else false */ #define lambdap(conspoint) (check_tag(conspoint,LAMBDATAG)) @@ -309,11 +303,15 @@ struct integer_payload { long int value; }; +struct lambda_payload { + struct cons_pointer args; + struct cons_pointer body; +}; + /** * payload for a real number cell. Internals of this liable to change to give 128 bits * precision, but I'm not sure of the detail. - */ -struct real_payload { + */ struct real_payload { long double value; }; @@ -403,6 +401,10 @@ struct cons_space_object { * if tag == INTEGERTAG */ struct integer_payload integer; + /* + * if tag == LAMBDATAG + */ + struct lambda_payload lambda; /* * if tag == NILTAG; we'll treat the special cell NIL as just a cons */ @@ -472,6 +474,12 @@ struct cons_pointer make_function( struct cons_pointer src, ( struct stack_frame *, struct cons_pointer ) ); +/** + * Construct a lambda (interpretable source) cell + */ +struct cons_pointer make_lambda( struct cons_pointer args, + struct cons_pointer body ); + /** * Construct a cell which points to an executable Lisp special form. */ diff --git a/src/equal.c b/src/equal.c index ef0b897..d06903f 100644 --- a/src/equal.c +++ b/src/equal.c @@ -78,8 +78,8 @@ bool equal( struct cons_pointer a, struct cons_pointer b ) { && ( equal( cell_a->payload.string.cdr, cell_b->payload.string.cdr ) || ( end_of_string( cell_a->payload.string.cdr ) - && end_of_string( cell_b->payload. - string.cdr ) ) ); + && end_of_string( cell_b->payload.string. + cdr ) ) ); break; case INTEGERTV: case REALTV: diff --git a/src/init.c b/src/init.c index e4a320f..e782e9a 100644 --- a/src/init.c +++ b/src/init.c @@ -74,8 +74,6 @@ int main( int argc, char *argv[] ) { */ deep_bind( c_string_to_lisp_symbol( "nil" ), NIL ); deep_bind( c_string_to_lisp_symbol( "t" ), TRUE ); - /* lambda is even more privileged than a special form */ - deep_bind( c_string_to_lisp_symbol( "lambda" ), LAMBDA ); /* * primitive function operations @@ -106,6 +104,7 @@ int main( int argc, char *argv[] ) { * primitive special forms */ bind_special( "cond", &lisp_cond ); + bind_special( "lambda", &lisp_lambda ); bind_special( "quote", &lisp_quote ); diff --git a/src/lispops.c b/src/lispops.c index ee59c40..b2f7800 100644 --- a/src/lispops.c +++ b/src/lispops.c @@ -100,58 +100,58 @@ struct cons_pointer eval_form( struct stack_frame *parent, * The Lisp interpreter. * * @param frame the stack frame in which the expression is to be interpreted; - * @param lexpr the lambda expression to be interpreted; * @param env the environment in which it is to be intepreted. */ struct cons_pointer lisp_lambda( struct stack_frame *frame, struct cons_pointer env ) { - struct cons_pointer result = NIL; - struct cons_pointer lexpr = frame->arg[0]; - struct cons_pointer should_be_lambda = - eval_form( frame, c_car( lexpr ), env ); - dump_frame( stderr, frame ); + struct cons_pointer body = + !nilp( frame->arg[args_in_frame - 1] ) ? frame->more : NIL; - if ( lambdap( should_be_lambda ) ) { - struct cons_pointer new_env = env; - struct cons_pointer args = c_car( c_cdr( lexpr ) ); - struct cons_pointer body = c_cdr( c_cdr( lexpr ) ); - - for ( int i = 1; i < args_in_frame && consp( args ); i++ ) { - args = c_cdr( args ); - struct cons_pointer arg = c_car( args ); - print( stderr, c_string_to_lisp_string( "\n\tBinding " ) ); - print( stderr, arg ); - print( stderr, c_string_to_lisp_string( " to " ) ); - print( stderr, frame->arg[i] ); - - new_env = make_cons( make_cons( arg, frame->arg[i] ), new_env ); + for ( int i = args_in_frame - 1; i >= 0; i-- ) { + if ( !nilp( frame->arg[i] ) ) { + body = make_cons( frame->arg[i], body ); } - while ( !nilp( body ) ) { - struct cons_pointer sexpr = c_car( body ); - body = c_cdr( body ); - - result = eval_form( frame, sexpr, new_env ); - } - } else { - if ( exceptionp( should_be_lambda ) ) { - result = should_be_lambda; - } else { - char *buffer = malloc( 1024 ); - struct cons_space_object not_lambda = - pointer2cell( should_be_lambda ); - memset( buffer, '\0', 1024 ); - sprintf( buffer, - "Expected lambda, but found cell with tag %d (%c%c%c%c)", - not_lambda.tag.value, not_lambda.tag.bytes[0], - not_lambda.tag.bytes[1], not_lambda.tag.bytes[2], - not_lambda.tag.bytes[3] ); - struct cons_pointer message = c_string_to_lisp_string( buffer ); - free( buffer ); - result = lisp_throw( message, frame ); - } } + + return make_lambda( frame->arg[0], body ); +} + + +struct cons_pointer +eval_lambda( struct cons_space_object cell, struct stack_frame *frame, + struct cons_pointer env ) { + struct cons_pointer result = NIL; + fwprintf( stderr, L"eval_lambda called" ); + + struct cons_pointer new_env = env; + struct cons_pointer args = cell.payload.lambda.args; + struct cons_pointer body = cell.payload.lambda.body; + struct cons_pointer vals = frame->arg[0]; + + while ( consp( args ) && consp( vals ) ) { + struct cons_pointer arg = c_car( args ); + struct cons_pointer val = c_car( vals ); + print( stderr, c_string_to_lisp_string( "\n\tBinding " ) ); + print( stderr, arg ); + print( stderr, c_string_to_lisp_string( " to " ) ); + print( stderr, val ); + fputws( L"\"\n", stderr ); + + new_env = make_cons( make_cons( arg, val ), new_env ); + args = c_cdr( args ); + vals = c_cdr( vals ); + + } + + while ( !nilp( body ) ) { + struct cons_pointer sexpr = c_car( body ); + body = c_cdr( body ); + fputws( L"In lambda: ", stderr ); + result = eval_form( frame, sexpr, new_env ); + } + return result; } @@ -178,13 +178,9 @@ c_apply( struct stack_frame *frame, struct cons_pointer env ) { struct cons_pointer args = c_cdr( frame->arg[0] ); switch ( fn_cell.tag.value ) { - case SPECIALTV: - { - struct stack_frame *next = - make_special_frame( frame, args, env ); - result = ( *fn_cell.payload.special.executable ) ( next, env ); - free_stack_frame( next ); - } + case EXCEPTIONTV: + /* just pass exceptions straight back */ + result = fn_pointer; break; case FUNCTIONTV: { @@ -194,16 +190,21 @@ c_apply( struct stack_frame *frame, struct cons_pointer env ) { free_stack_frame( next ); } break; - case CONSTV: + case LAMBDATV: { - fwprintf( stdout, - L"Treating cons as lambda expression (apply)\n" ); - result = lisp_lambda( frame, env ); + struct stack_frame *next = + make_stack_frame( frame, args, env ); + result = eval_lambda( fn_cell, next, env ); + free_stack_frame( next ); } break; - case EXCEPTIONTV: - /* just pass exceptions straight back */ - result = fn_pointer; + case SPECIALTV: + { + struct stack_frame *next = + make_special_frame( frame, args, env ); + result = ( *fn_cell.payload.special.executable ) ( next, env ); + free_stack_frame( next ); + } break; default: { @@ -266,12 +267,7 @@ lisp_eval( struct stack_frame *frame, struct cons_pointer env ) { switch ( cell.tag.value ) { case CONSTV: - print( stderr, frame->arg[0] ); - if ( lambdap( c_car( frame->arg[0] ) ) ) { - fwprintf( stdout, - L"Treating cons as lambda expression (eval)\n" ); - result = lisp_lambda( frame, env ); - } else { + { result = c_apply( frame, env ); } break; diff --git a/src/print.c b/src/print.c index d57afc2..d6b966a 100644 --- a/src/print.c +++ b/src/print.c @@ -131,7 +131,11 @@ void print( FILE * output, struct cons_pointer pointer ) { } break; case LAMBDATV: - fwprintf( output, L"lambda" /* "λ" */ ); + fputws( L"(lambda ", output ); + print( output, cell.payload.lambda.args ); + fputws( L" ", output ); + print( output, cell.payload.lambda.body ); + fputws( L")", output ); break; case NILTV: fwprintf( output, L"nil" );