diff --git a/Makefile b/Makefile index 98a6bd3..3fc8148 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ test: $(OBJS) $(TESTS) Makefile .PHONY: clean clean: - $(RM) $(TARGET) $(OBJS) $(DEPS) $(SRC_DIRS)/*~ *~ + $(RM) $(TARGET) $(OBJS) $(DEPS) $(SRC_DIRS)/*~ $(SRC_DIRS)/*/*~ *~ repl: $(TARGET) -p 2> psse.log diff --git a/src/arith/peano.c b/src/arith/peano.c index 423bd51..63783f5 100644 --- a/src/arith/peano.c +++ b/src/arith/peano.c @@ -8,11 +8,11 @@ */ #include +#include #include #include #include #include -#include #include "consspaceobject.h" #include "conspage.h" @@ -28,7 +28,7 @@ long double to_long_double( struct cons_pointer arg ); int64_t to_long_int( struct cons_pointer arg ); -struct cons_pointer add_2( struct stack_frame *frame, struct cons_pointer arg1, +struct cons_pointer add_2( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer arg1, struct cons_pointer arg2 ); @@ -119,7 +119,7 @@ int64_t to_long_int( struct cons_pointer arg ) { * return a cons_pointer indicating a number which is the sum of * the numbers indicated by `arg1` and `arg2`. */ -struct cons_pointer add_2( struct stack_frame *frame, struct cons_pointer arg1, +struct cons_pointer add_2( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer arg1, struct cons_pointer arg2 ) { struct cons_pointer result; struct cons_space_object cell1 = pointer2cell( arg1 ); @@ -153,7 +153,7 @@ struct cons_pointer add_2( struct stack_frame *frame, struct cons_pointer arg1, cell2.payload.integer.value ); break; case RATIOTV: - result = add_integer_ratio( frame, arg1, arg2 ); + result = add_integer_ratio( frame_pointer, arg1, arg2 ); break; case REALTV: result = @@ -161,9 +161,9 @@ struct cons_pointer add_2( struct stack_frame *frame, struct cons_pointer arg1, to_long_double( arg2 ) ); break; default: - result = lisp_throw( c_string_to_lisp_string + result = throw_exception( c_string_to_lisp_string ( "Cannot add: not a number" ), - frame ); + frame_pointer ); break; } break; @@ -173,10 +173,10 @@ struct cons_pointer add_2( struct stack_frame *frame, struct cons_pointer arg1, result = arg2; break; case INTEGERTV: - result = add_integer_ratio( frame, arg2, arg1 ); + result = add_integer_ratio( frame_pointer, arg2, arg1 ); break; case RATIOTV: - result = add_ratio_ratio( frame, arg1, arg2 ); + result = add_ratio_ratio( frame_pointer, arg1, arg2 ); break; case REALTV: result = @@ -184,9 +184,9 @@ struct cons_pointer add_2( struct stack_frame *frame, struct cons_pointer arg1, to_long_double( arg2 ) ); break; default: - result = lisp_throw( c_string_to_lisp_string + result = throw_exception( c_string_to_lisp_string ( "Cannot add: not a number" ), - frame ); + frame_pointer ); break; } break; @@ -197,8 +197,8 @@ struct cons_pointer add_2( struct stack_frame *frame, struct cons_pointer arg1, break; default: result = exceptionp( arg2 ) ? arg2 : - lisp_throw( c_string_to_lisp_string - ( "Cannot add: not a number" ), frame ); + throw_exception( c_string_to_lisp_string + ( "Cannot add: not a number" ), frame_pointer ); } } @@ -218,7 +218,7 @@ struct cons_pointer add_2( struct stack_frame *frame, struct cons_pointer arg1, * @return a pointer to an integer or real. */ struct cons_pointer lisp_add( struct stack_frame - *frame, struct + *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { struct cons_pointer result = make_integer( 0 ); struct cons_pointer tmp; @@ -227,7 +227,7 @@ struct cons_pointer lisp_add( struct stack_frame i < args_in_frame && !nilp( frame->arg[i] ) && !exceptionp( result ); i++ ) { tmp = result; - result = add_2( frame, result, frame->arg[i] ); + result = add_2( frame, frame_pointer, result, frame->arg[i] ); if ( !eq( tmp, result ) ) { dec_ref( tmp ); } @@ -236,7 +236,7 @@ struct cons_pointer lisp_add( struct stack_frame struct cons_pointer more = frame->more; while ( consp( more ) && !exceptionp( result ) ) { tmp = result; - result = add_2( frame, result, c_car( more ) ); + result = add_2( frame, frame_pointer, result, c_car( more ) ); if ( !eq( tmp, result ) ) { dec_ref( tmp ); } @@ -252,7 +252,7 @@ struct cons_pointer lisp_add( struct stack_frame * return a cons_pointer indicating a number which is the product of * the numbers indicated by `arg1` and `arg2`. */ -struct cons_pointer multiply_2( struct stack_frame *frame, +struct cons_pointer multiply_2( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer arg1, struct cons_pointer arg2 ) { struct cons_pointer result; @@ -286,7 +286,7 @@ struct cons_pointer multiply_2( struct stack_frame *frame, cell2.payload.integer.value ); break; case RATIOTV: - result = multiply_integer_ratio( frame, arg1, arg2 ); + result = multiply_integer_ratio( frame_pointer, arg1, arg2 ); break; case REALTV: result = @@ -294,9 +294,9 @@ struct cons_pointer multiply_2( struct stack_frame *frame, to_long_double( arg2 ) ); break; default: - result = lisp_throw( c_string_to_lisp_string + result = throw_exception( c_string_to_lisp_string ( "Cannot multiply: not a number" ), - frame ); + frame_pointer ); break; } break; @@ -306,10 +306,10 @@ struct cons_pointer multiply_2( struct stack_frame *frame, result = arg2; break; case INTEGERTV: - result = multiply_integer_ratio( frame, arg2, arg1 ); + result = multiply_integer_ratio( frame_pointer, arg2, arg1 ); break; case RATIOTV: - result = multiply_ratio_ratio( frame, arg1, arg2 ); + result = multiply_ratio_ratio( frame_pointer, arg1, arg2 ); break; case REALTV: result = @@ -317,9 +317,9 @@ struct cons_pointer multiply_2( struct stack_frame *frame, to_long_double( arg2 ) ); break; default: - result = lisp_throw( c_string_to_lisp_string + result = throw_exception( c_string_to_lisp_string ( "Cannot multiply: not a number" ), - frame ); + frame_pointer ); } break; case REALTV: @@ -328,9 +328,9 @@ struct cons_pointer multiply_2( struct stack_frame *frame, to_long_double( arg2 ) ); break; default: - result = lisp_throw( c_string_to_lisp_string + result = throw_exception( c_string_to_lisp_string ( "Cannot multiply: not a number" ), - frame ); + frame_pointer ); break; } } @@ -353,7 +353,7 @@ struct cons_pointer multiply_2( struct stack_frame *frame, */ struct cons_pointer lisp_multiply( struct stack_frame - *frame, struct + *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { struct cons_pointer result = make_integer( 1 ); struct cons_pointer tmp; @@ -361,7 +361,7 @@ struct cons_pointer lisp_multiply( struct for ( int i = 0; i < args_in_frame && !nilp( frame->arg[i] ) && !exceptionp( result ); i++ ) { tmp = result; - result = multiply_2( frame, result, frame->arg[i] ); + result = multiply_2( frame, frame_pointer, result, frame->arg[i] ); if ( !eq( tmp, result ) ) { dec_ref( tmp ); @@ -372,7 +372,7 @@ struct cons_pointer lisp_multiply( struct while ( consp( more ) && !exceptionp( result ) ) { tmp = result; - result = multiply_2( frame, result, c_car( more ) ); + result = multiply_2( frame, frame_pointer, result, c_car( more ) ); if ( !eq( tmp, result ) ) { dec_ref( tmp ); @@ -388,7 +388,7 @@ struct cons_pointer lisp_multiply( struct * return a cons_pointer indicating a number which is the * inverse of the number indicated by `arg`. */ -struct cons_pointer inverse( struct stack_frame *frame, +struct cons_pointer inverse( struct cons_pointer frame, struct cons_pointer arg ) { struct cons_pointer result = NIL; struct cons_space_object cell = pointer2cell( arg ); @@ -430,7 +430,7 @@ struct cons_pointer inverse( struct stack_frame *frame, */ struct cons_pointer lisp_subtract( struct stack_frame - *frame, struct + *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { struct cons_pointer result = NIL; struct cons_space_object cell0 = pointer2cell( frame->arg[0] ); @@ -451,10 +451,11 @@ struct cons_pointer lisp_subtract( struct break; case RATIOTV:{ struct cons_pointer tmp = - make_ratio( frame, frame->arg[0], + make_ratio( frame_pointer, frame->arg[0], make_integer( 1 ) ); + inc_ref(tmp); result = - subtract_ratio_ratio( frame, tmp, frame->arg[1] ); + subtract_ratio_ratio( frame_pointer, tmp, frame->arg[1] ); dec_ref( tmp ); } break; @@ -464,9 +465,9 @@ struct cons_pointer lisp_subtract( struct to_long_double( frame->arg[1] ) ); break; default: - result = lisp_throw( c_string_to_lisp_string - ( "Cannot multiply: not a number" ), - frame ); + result = throw_exception( c_string_to_lisp_string + ( "Cannot subtract: not a number" ), + frame_pointer ); break; } break; @@ -477,16 +478,17 @@ struct cons_pointer lisp_subtract( struct break; case INTEGERTV:{ struct cons_pointer tmp = - make_ratio( frame, frame->arg[1], + make_ratio( frame_pointer, frame->arg[1], make_integer( 1 ) ); + inc_ref(tmp); result = - subtract_ratio_ratio( frame, frame->arg[0], tmp ); + subtract_ratio_ratio( frame_pointer, frame->arg[0], tmp ); dec_ref( tmp ); } break; case RATIOTV: result = - subtract_ratio_ratio( frame, frame->arg[0], + subtract_ratio_ratio( frame_pointer, frame->arg[0], frame->arg[1] ); break; case REALTV: @@ -495,9 +497,9 @@ struct cons_pointer lisp_subtract( struct to_long_double( frame->arg[1] ) ); break; default: - result = lisp_throw( c_string_to_lisp_string - ( "Cannot multiply: not a number" ), - frame ); + result = throw_exception( c_string_to_lisp_string + ( "Cannot subtract: not a number" ), + frame_pointer ); break; } break; @@ -507,8 +509,8 @@ struct cons_pointer lisp_subtract( struct to_long_double( frame->arg[1] ) ); break; default: - result = lisp_throw( c_string_to_lisp_string - ( "Cannot multiply: not a number" ), frame ); + result = throw_exception( c_string_to_lisp_string + ( "Cannot subtract: not a number" ), frame_pointer ); break; } @@ -525,7 +527,7 @@ struct cons_pointer lisp_subtract( struct */ struct cons_pointer lisp_divide( struct stack_frame - *frame, struct + *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { struct cons_pointer result = NIL; struct cons_space_object arg0 = pointer2cell( frame->arg[0] ); @@ -542,8 +544,10 @@ struct cons_pointer lisp_divide( struct break; case INTEGERTV:{ struct cons_pointer unsimplified = - make_ratio( frame, frame->arg[0], frame->arg[1] ); - result = simplify_ratio( frame, unsimplified ); + make_ratio( frame_pointer, frame->arg[0], frame->arg[1] ); + /* OK, if result may be unsimplified, we should not inc_ref it + * - but if not, we should dec_ref it. */ + result = simplify_ratio( frame_pointer, unsimplified ); if ( !eq( unsimplified, result ) ) { dec_ref( unsimplified ); } @@ -552,9 +556,9 @@ struct cons_pointer lisp_divide( struct case RATIOTV:{ struct cons_pointer one = make_integer( 1 ); struct cons_pointer ratio = - make_ratio( frame, frame->arg[0], one ); + make_ratio( frame_pointer, frame->arg[0], one ); result = - divide_ratio_ratio( frame, ratio, frame->arg[1] ); + divide_ratio_ratio( frame_pointer, ratio, frame->arg[1] ); dec_ref( ratio ); } break; @@ -564,9 +568,9 @@ struct cons_pointer lisp_divide( struct to_long_double( frame->arg[1] ) ); break; default: - result = lisp_throw( c_string_to_lisp_string + result = throw_exception( c_string_to_lisp_string ( "Cannot divide: not a number" ), - frame ); + frame_pointer ); break; } break; @@ -577,16 +581,19 @@ struct cons_pointer lisp_divide( struct break; case INTEGERTV:{ struct cons_pointer one = make_integer( 1 ); + inc_ref( one); struct cons_pointer ratio = - make_ratio( frame, frame->arg[1], one ); + make_ratio( frame_pointer, frame->arg[1], one ); + inc_ref(ratio); result = - divide_ratio_ratio( frame, frame->arg[0], ratio ); + divide_ratio_ratio( frame_pointer, frame->arg[0], ratio ); dec_ref( ratio ); + dec_ref(one); } break; case RATIOTV: result = - divide_ratio_ratio( frame, frame->arg[0], + divide_ratio_ratio( frame_pointer, frame->arg[0], frame->arg[1] ); break; case REALTV: @@ -595,9 +602,9 @@ struct cons_pointer lisp_divide( struct to_long_double( frame->arg[1] ) ); break; default: - result = lisp_throw( c_string_to_lisp_string + result = throw_exception( c_string_to_lisp_string ( "Cannot divide: not a number" ), - frame ); + frame_pointer ); break; } break; @@ -607,8 +614,8 @@ struct cons_pointer lisp_divide( struct to_long_double( frame->arg[1] ) ); break; default: - result = lisp_throw( c_string_to_lisp_string - ( "Cannot divide: not a number" ), frame ); + result = throw_exception( c_string_to_lisp_string + ( "Cannot divide: not a number" ), frame_pointer ); break; } diff --git a/src/arith/peano.h b/src/arith/peano.h index 79735c0..46008c2 100644 --- a/src/arith/peano.h +++ b/src/arith/peano.h @@ -23,7 +23,7 @@ extern "C" { * @return a pointer to an integer or real. */ struct cons_pointer - lisp_add( struct stack_frame *frame, struct cons_pointer env ); + lisp_add( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); /** * Multiply an indefinite number of numbers together @@ -32,7 +32,7 @@ extern "C" { * @return a pointer to an integer or real. */ struct cons_pointer - lisp_multiply( struct stack_frame *frame, struct cons_pointer env ); + lisp_multiply( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); /** * Subtract one number from another. @@ -41,7 +41,7 @@ extern "C" { * @return a pointer to an integer or real. */ struct cons_pointer - lisp_subtract( struct stack_frame *frame, struct cons_pointer env ); + lisp_subtract( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); /** * Divide one number by another. @@ -50,7 +50,7 @@ extern "C" { * @return a pointer to an integer or real. */ struct cons_pointer - lisp_divide( struct stack_frame *frame, struct cons_pointer env ); + lisp_divide( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); #ifdef __cplusplus } diff --git a/src/arith/ratio.c b/src/arith/ratio.c index 8a5eec7..042aea1 100644 --- a/src/arith/ratio.c +++ b/src/arith/ratio.c @@ -13,6 +13,7 @@ #include "conspage.h" #include "consspaceobject.h" +#include "dump.h" #include "equal.h" #include "integer.h" #include "lispops.h" @@ -24,7 +25,7 @@ * declared in peano.c, can't include piano.h here because * circularity. TODO: refactor. */ -struct cons_pointer inverse( struct stack_frame *frame, +struct cons_pointer inverse( struct cons_pointer frame_pointer, struct cons_pointer arg ); /** @@ -54,7 +55,7 @@ int64_t least_common_multiple( int64_t m, int64_t n ) { * be in a simplified representation. If `arg` isn't a ratio, * will throw exception. */ -struct cons_pointer simplify_ratio( struct stack_frame *frame, +struct cons_pointer simplify_ratio( struct cons_pointer frame_pointer, struct cons_pointer arg ) { struct cons_pointer result = arg; @@ -70,15 +71,15 @@ struct cons_pointer simplify_ratio( struct stack_frame *frame, result = make_integer( ddrv / gcd ); } else { result = - make_ratio( frame, make_integer( ddrv / gcd ), + make_ratio( frame_pointer, make_integer( ddrv / gcd ), make_integer( drrv / gcd ) ); } } } else { result = - lisp_throw( make_cons( c_string_to_lisp_string + throw_exception( make_cons( c_string_to_lisp_string ( "Shouldn't happen: bad arg to simplify_ratio" ), - arg ), frame ); + arg ), frame_pointer ); } return result; @@ -91,7 +92,7 @@ struct cons_pointer simplify_ratio( struct stack_frame *frame, * the ratios indicated by `arg1` and `arg2`. If you pass non-ratios, * this is going to break horribly. */ -struct cons_pointer add_ratio_ratio( struct stack_frame *frame, +struct cons_pointer add_ratio_ratio( struct cons_pointer frame_pointer, struct cons_pointer arg1, struct cons_pointer arg2 ) { struct cons_pointer r, result; @@ -123,7 +124,7 @@ struct cons_pointer add_ratio_ratio( struct stack_frame *frame, #endif if ( dr1v == dr2v ) { - r = make_ratio( frame, + r = make_ratio( frame_pointer, make_integer( dd1v + dd2v ), cell1.payload.ratio.divisor ); } else { @@ -131,10 +132,10 @@ struct cons_pointer add_ratio_ratio( struct stack_frame *frame, dr1vm = make_integer( dr1v * m1 ), dd2vm = make_integer( dd2v * m2 ), dr2vm = make_integer( dr2v * m2 ), - r1 = make_ratio( frame, dd1vm, dr1vm ), - r2 = make_ratio( frame, dd2vm, dr2vm ); + r1 = make_ratio( frame_pointer, dd1vm, dr1vm ), + r2 = make_ratio( frame_pointer, dd2vm, dr2vm ); - r = add_ratio_ratio( frame, r1, r2 ); + r = add_ratio_ratio( frame_pointer, r1, r2 ); /* because the references on dd1vm, dr1vm, dd2vm and dr2vm were * never incremented except when making r1 and r2, decrementing @@ -143,17 +144,17 @@ struct cons_pointer add_ratio_ratio( struct stack_frame *frame, dec_ref( r2 ); } - result = simplify_ratio( frame, r ); + result = simplify_ratio( frame_pointer, r ); if ( !eq( r, result ) ) { dec_ref( r ); } } else { result = - lisp_throw( make_cons( c_string_to_lisp_string + throw_exception( make_cons( c_string_to_lisp_string ( "Shouldn't happen: bad arg to add_ratio_ratio" ), make_cons( arg1, make_cons( arg2, NIL ) ) ), - frame ); + frame_pointer ); } #ifdef DEBUG @@ -171,26 +172,26 @@ struct cons_pointer add_ratio_ratio( struct stack_frame *frame, * the intger indicated by `intarg` and the ratio indicated by * `ratarg`. If you pass other types, this is going to break horribly. */ -struct cons_pointer add_integer_ratio( struct stack_frame *frame, +struct cons_pointer add_integer_ratio( struct cons_pointer frame_pointer, struct cons_pointer intarg, struct cons_pointer ratarg ) { struct cons_pointer result; if ( integerp( intarg ) && ratiop( ratarg ) ) { struct cons_pointer one = make_integer( 1 ), - ratio = make_ratio( frame, intarg, one ); + ratio = make_ratio( frame_pointer, intarg, one ); - result = add_ratio_ratio( frame, ratio, ratarg ); + result = add_ratio_ratio( frame_pointer, ratio, ratarg ); dec_ref( one ); dec_ref( ratio ); } else { result = - lisp_throw( make_cons( c_string_to_lisp_string + throw_exception( make_cons( c_string_to_lisp_string ( "Shouldn't happen: bad arg to add_integer_ratio" ), make_cons( intarg, make_cons( ratarg, NIL ) ) ), - frame ); + frame_pointer ); } return result; @@ -201,15 +202,15 @@ struct cons_pointer add_integer_ratio( struct stack_frame *frame, * indicated by `arg1` divided by the ratio indicated by `arg2`. If either * of these aren't RTIO cells, something horrid will happen and it is YOUR FAULT. */ -struct cons_pointer divide_ratio_ratio( struct stack_frame *frame, +struct cons_pointer divide_ratio_ratio( struct cons_pointer frame_pointer, struct cons_pointer arg1, struct cons_pointer arg2 ) { - struct cons_pointer i = make_ratio( frame, + struct cons_pointer i = make_ratio( frame_pointer, pointer2cell( arg2 ).payload.ratio. divisor, pointer2cell( arg2 ).payload.ratio. dividend ), result = - multiply_ratio_ratio( frame, arg1, i ); + multiply_ratio_ratio( frame_pointer, arg1, i ); dec_ref( i ); @@ -221,9 +222,7 @@ struct cons_pointer divide_ratio_ratio( struct stack_frame *frame, * the ratios indicated by `arg1` and `arg2`. If you pass non-ratios, * this is going to break horribly. */ -struct cons_pointer multiply_ratio_ratio( struct - stack_frame - *frame, struct +struct cons_pointer multiply_ratio_ratio( struct cons_pointer frame_pointer, struct cons_pointer arg1, struct cons_pointer arg2 ) { struct cons_pointer result; @@ -249,18 +248,18 @@ struct cons_pointer multiply_ratio_ratio( struct ddrv = dd1v * dd2v, drrv = dr1v * dr2v; struct cons_pointer unsimplified = - make_ratio( frame, make_integer( ddrv ), + make_ratio( frame_pointer, make_integer( ddrv ), make_integer( drrv ) ); - result = simplify_ratio( frame, unsimplified ); + result = simplify_ratio( frame_pointer, unsimplified ); if ( !eq( unsimplified, result ) ) { dec_ref( unsimplified ); } } else { result = - lisp_throw( c_string_to_lisp_string + throw_exception( c_string_to_lisp_string ( "Shouldn't happen: bad arg to multiply_ratio_ratio" ), - frame ); + frame_pointer ); } return result; @@ -271,23 +270,23 @@ struct cons_pointer multiply_ratio_ratio( struct * the intger indicated by `intarg` and the ratio indicated by * `ratarg`. If you pass other types, this is going to break horribly. */ -struct cons_pointer multiply_integer_ratio( struct stack_frame *frame, +struct cons_pointer multiply_integer_ratio( struct cons_pointer frame_pointer, struct cons_pointer intarg, struct cons_pointer ratarg ) { struct cons_pointer result; if ( integerp( intarg ) && ratiop( ratarg ) ) { struct cons_pointer one = make_integer( 1 ), - ratio = make_ratio( frame, intarg, one ); - result = multiply_ratio_ratio( frame, ratio, ratarg ); + ratio = make_ratio( frame_pointer, intarg, one ); + result = multiply_ratio_ratio( frame_pointer, ratio, ratarg ); dec_ref( one ); dec_ref( ratio ); } else { result = - lisp_throw( c_string_to_lisp_string + throw_exception( c_string_to_lisp_string ( "Shouldn't happen: bad arg to multiply_integer_ratio" ), - frame ); + frame_pointer ); } return result; @@ -299,11 +298,11 @@ struct cons_pointer multiply_integer_ratio( struct stack_frame *frame, * the ratios indicated by `arg1` and `arg2`. If you pass non-ratios, * this is going to break horribly. */ -struct cons_pointer subtract_ratio_ratio( struct stack_frame *frame, +struct cons_pointer subtract_ratio_ratio( struct cons_pointer frame_pointer, struct cons_pointer arg1, struct cons_pointer arg2 ) { - struct cons_pointer i = inverse( frame, arg2 ), - result = add_ratio_ratio( frame, arg1, i ); + struct cons_pointer i = inverse( frame_pointer, arg2 ), + result = add_ratio_ratio( frame_pointer, arg1, i ); dec_ref( i ); @@ -315,7 +314,7 @@ struct cons_pointer subtract_ratio_ratio( struct stack_frame *frame, * Construct a ratio frame from these two pointers, expected to be integers * or (later) bignums, in the context of this stack_frame. */ -struct cons_pointer make_ratio( struct stack_frame *frame, +struct cons_pointer make_ratio( struct cons_pointer frame_pointer, struct cons_pointer dividend, struct cons_pointer divisor ) { struct cons_pointer result; @@ -328,9 +327,9 @@ struct cons_pointer make_ratio( struct stack_frame *frame, cell->payload.ratio.divisor = divisor; } else { result = - lisp_throw( c_string_to_lisp_string + throw_exception( c_string_to_lisp_string ( "Dividend and divisor of a ratio must be integers" ), - frame ); + frame_pointer ); } #ifdef DEBUG dump_object( stderr, result ); diff --git a/src/arith/ratio.h b/src/arith/ratio.h index c4e5548..feb8925 100644 --- a/src/arith/ratio.h +++ b/src/arith/ratio.h @@ -11,36 +11,34 @@ #ifndef __ratio_h #define __ratio_h -struct cons_pointer simplify_ratio( struct stack_frame *frame, +struct cons_pointer simplify_ratio( struct cons_pointer frame_pointer, struct cons_pointer arg ); -struct cons_pointer add_ratio_ratio( struct stack_frame *frame, +struct cons_pointer add_ratio_ratio( struct cons_pointer frame_pointer, struct cons_pointer arg1, struct cons_pointer arg2 ); -struct cons_pointer add_integer_ratio( struct stack_frame *frame, +struct cons_pointer add_integer_ratio( struct cons_pointer frame_pointer, struct cons_pointer intarg, struct cons_pointer ratarg ); -struct cons_pointer divide_ratio_ratio( struct stack_frame *frame, +struct cons_pointer divide_ratio_ratio( struct cons_pointer frame_pointer, struct cons_pointer arg1, struct cons_pointer arg2 ); -struct cons_pointer multiply_ratio_ratio( struct - stack_frame - *frame, struct +struct cons_pointer multiply_ratio_ratio( struct cons_pointer frame_pointer, struct cons_pointer arg1, struct cons_pointer arg2 ); -struct cons_pointer multiply_integer_ratio( struct stack_frame *frame, +struct cons_pointer multiply_integer_ratio( struct cons_pointer frame_pointer, struct cons_pointer intarg, struct cons_pointer ratarg ); -struct cons_pointer subtract_ratio_ratio( struct stack_frame *frame, +struct cons_pointer subtract_ratio_ratio( struct cons_pointer frame_pointer, struct cons_pointer arg1, struct cons_pointer arg2 ); -struct cons_pointer make_ratio( struct stack_frame *frame, +struct cons_pointer make_ratio( struct cons_pointer frame_pointer, struct cons_pointer dividend, struct cons_pointer divisor ); diff --git a/src/init.c b/src/init.c index 9716365..48516f6 100644 --- a/src/init.c +++ b/src/init.c @@ -90,6 +90,7 @@ int main( int argc, char *argv[] ) { bind_function( "eq", &lisp_eq ); bind_function( "equal", &lisp_equal ); bind_function( "eval", &lisp_eval ); + bind_function( "exception", &lisp_exception ); bind_function( "multiply", &lisp_multiply ); bind_function( "read", &lisp_read ); bind_function( "oblist", &lisp_oblist ); @@ -98,6 +99,7 @@ int main( int argc, char *argv[] ) { bind_function( "reverse", &lisp_reverse ); bind_function( "set", &lisp_set ); bind_function( "subtract", &lisp_subtract ); + bind_function( "throw", &lisp_exception ); bind_function( "type", &lisp_type ); bind_function( "+", &lisp_add ); diff --git a/src/memory/consspaceobject.c b/src/memory/consspaceobject.c index 39f464a..75a5257 100644 --- a/src/memory/consspaceobject.c +++ b/src/memory/consspaceobject.c @@ -63,98 +63,6 @@ void dec_ref( struct cons_pointer pointer ) { } } -void dump_string_cell( FILE * output, wchar_t *prefix, - struct cons_pointer pointer ) { - struct cons_space_object cell = pointer2cell( pointer ); - if ( cell.payload.string.character == 0 ) { - fwprintf( output, - L"\t\t%ls cell: termination; next at page %d offset %d, count %u\n", - prefix, - cell.payload.string.cdr.page, cell.payload.string.cdr.offset, - cell.count ); - } else { - fwprintf( output, - L"\t\t%ls cell: character '%lc' (%d) next at page %d offset %d, count %u\n", - prefix, - ( wint_t ) cell.payload.string.character, - cell.payload.string.character, - cell.payload.string.cdr.page, - cell.payload.string.cdr.offset, cell.count ); - fwprintf( output, L"\t\t value: " ); - print( output, pointer ); - fwprintf( output, L"\n" ); - } -} - -/** - * dump the object at this cons_pointer to this output stream. - */ -void dump_object( FILE * output, struct cons_pointer pointer ) { - struct cons_space_object cell = pointer2cell( pointer ); - fwprintf( output, - L"\t%c%c%c%c (%d) at page %d, offset %d count %u\n", - cell.tag.bytes[0], - cell.tag.bytes[1], - cell.tag.bytes[2], - cell.tag.bytes[3], - cell.tag.value, pointer.page, pointer.offset, cell.count ); - - switch ( cell.tag.value ) { - case CONSTV: - fwprintf( output, - L"\t\tCons cell: car at page %d offset %d, cdr at page %d offset %d, count %u\n", - cell.payload.cons.car.page, - cell.payload.cons.car.offset, - cell.payload.cons.cdr.page, - cell.payload.cons.cdr.offset, cell.count ); - break; - case EXCEPTIONTV: - fwprintf( output, L"\t\tException cell: " ); - print( output, cell.payload.exception.message ); - fwprintf( output, L"\n" ); - for ( struct stack_frame * frame = cell.payload.exception.frame; - frame != NULL; frame = frame->previous ) { - dump_frame( output, frame ); - } - break; - case FREETV: - fwprintf( output, L"\t\tFree cell: next at page %d offset %d\n", - cell.payload.cons.cdr.page, - cell.payload.cons.cdr.offset ); - break; - case INTEGERTV: - fwprintf( output, - L"\t\tInteger cell: value %ld, count %u\n", - cell.payload.integer.value, cell.count ); - break; - case LAMBDATV: - fwprintf( output, L"\t\tLambda cell; args: " ); - print( output, cell.payload.lambda.args ); - fwprintf( output, L";\n\t\t\tbody: " ); - print( output, cell.payload.lambda.body ); - break; - case RATIOTV: - fwprintf( output, - L"\t\tRational cell: value %ld/%ld, count %u\n", - pointer2cell( cell.payload.ratio.dividend ).payload. - integer.value, - pointer2cell( cell.payload.ratio.divisor ).payload. - integer.value, cell.count ); - break; - case READTV: - fwprintf( output, L"\t\tInput stream\n" ); - case REALTV: - fwprintf( output, L"\t\tReal cell: value %Lf, count %u\n", - cell.payload.real.value, cell.count ); - break; - case STRINGTV: - dump_string_cell( output, L"String", pointer ); - break; - case SYMBOLTV: - dump_string_cell( output, L"Symbol", pointer ); - break; - } -} /** * Construct a cons cell from this pair of pointers. @@ -178,20 +86,24 @@ struct cons_pointer make_cons( struct cons_pointer car, /** * Construct an exception cell. * @param message should be a lisp string describing the problem, but actually any cons pointer will do; - * @param frame should be the frame in which the exception occurred. + * @param frame_pointer should be the pointer to the frame in which the exception occurred. */ struct cons_pointer make_exception( struct cons_pointer message, - struct stack_frame *frame ) { - struct cons_pointer pointer = allocate_cell( EXCEPTIONTAG ); - struct cons_space_object *cell = &pointer2cell( pointer ); + struct cons_pointer frame_pointer ) { + struct cons_pointer result = NIL; + struct cons_pointer pointer = allocate_cell( EXCEPTIONTAG ); + struct cons_space_object *cell = &pointer2cell( pointer ); - inc_ref( pointer ); /* this is a hack; I don't know why it's necessary to do this, but if I don't the cell gets freed */ + inc_ref( pointer ); /* this is a hack; I don't know why it's necessary to do this, but if I don't the cell gets freed */ - inc_ref( message ); - cell->payload.exception.message = message; - cell->payload.exception.frame = frame; + inc_ref( message ); + inc_ref( frame_pointer); + cell->payload.exception.message = message; + cell->payload.exception.frame = frame_pointer; - return pointer; + result = pointer; + + return result; } @@ -200,7 +112,8 @@ struct cons_pointer make_exception( struct cons_pointer message, */ struct cons_pointer make_function( struct cons_pointer src, struct cons_pointer ( *executable ) - ( struct stack_frame *, struct cons_pointer ) ) { + ( struct stack_frame *, + struct cons_pointer, struct cons_pointer ) ) { struct cons_pointer pointer = allocate_cell( FUNCTIONTAG ); struct cons_space_object *cell = &pointer2cell( pointer ); @@ -298,7 +211,8 @@ struct cons_pointer make_symbol( wint_t c, struct cons_pointer tail ) { */ struct cons_pointer make_special( struct cons_pointer src, struct cons_pointer ( *executable ) - ( struct stack_frame * frame, struct cons_pointer env ) ) { + ( struct stack_frame * frame, + struct cons_pointer, struct cons_pointer env ) ) { struct cons_pointer pointer = allocate_cell( SPECIALTAG ); struct cons_space_object *cell = &pointer2cell( pointer ); diff --git a/src/memory/consspaceobject.h b/src/memory/consspaceobject.h index 43bdfe0..b31a0bf 100644 --- a/src/memory/consspaceobject.h +++ b/src/memory/consspaceobject.h @@ -278,13 +278,14 @@ struct cons_pointer { * here to avoid circularity. TODO: refactor. */ struct stack_frame { - struct stack_frame *previous; /* the previous frame */ + struct cons_pointer previous; /* the previous frame */ struct cons_pointer arg[args_in_frame]; /* * first 8 arument bindings */ struct cons_pointer more; /* list of any further argument bindings */ struct cons_pointer function; /* the function to be called */ + int args; }; /** @@ -311,7 +312,7 @@ struct cons_payload { */ struct exception_payload { struct cons_pointer message; - struct stack_frame *frame; + struct cons_pointer frame; }; /** @@ -326,6 +327,7 @@ struct exception_payload { struct function_payload { struct cons_pointer source; struct cons_pointer ( *executable ) ( struct stack_frame *, + struct cons_pointer, struct cons_pointer ); }; @@ -379,13 +381,11 @@ struct real_payload { * its argument list) and a cons pointer (representing its environment) and a * stack frame (representing the previous stack frame) as arguments and returns * a cons pointer (representing its result). - * - * NOTE that this means that special forms do not appear on the lisp stack, - * which may be confusing. TODO: think about this. */ struct special_payload { struct cons_pointer source; struct cons_pointer ( *executable ) ( struct stack_frame *, + struct cons_pointer, struct cons_pointer ); }; @@ -421,7 +421,8 @@ struct vectorp_payload { * tag. */ uint32_t value; /* the tag considered as a number */ } tag; - uint64_t address; /* the address of the actual vector space + struct vector_space_object * address; + /* the address of the actual vector space * object (TODO: will change when I actually * implement vector space) */ }; @@ -514,20 +515,11 @@ void inc_ref( struct cons_pointer pointer ); */ void dec_ref( struct cons_pointer pointer ); -/** - * dump the object at this cons_pointer to this output stream. - */ -void dump_object( FILE * output, struct cons_pointer pointer ); - struct cons_pointer make_cons( struct cons_pointer car, struct cons_pointer cdr ); -/** - * Construct an exception cell. - * @param message should be a lisp string describing the problem, but actually any cons pointer will do; - * @param frame should be the frame in which the exception occurred. - */ + struct cons_pointer make_exception( struct cons_pointer message, - struct stack_frame *frame ); + struct cons_pointer frame_pointer ); /** * Construct a cell which points to an executable Lisp special form. @@ -535,6 +527,7 @@ struct cons_pointer make_exception( struct cons_pointer message, struct cons_pointer make_function( struct cons_pointer src, struct cons_pointer ( *executable ) ( struct stack_frame *, + struct cons_pointer, struct cons_pointer ) ); /** @@ -550,20 +543,13 @@ struct cons_pointer make_lambda( struct cons_pointer args, struct cons_pointer make_nlambda( struct cons_pointer args, struct cons_pointer body ); -/** - * Construct a ratio frame from these two pointers, expected to be integers - * or (later) bignums, in the context of this stack_frame. - */ -struct cons_pointer make_ratio( struct stack_frame *frame, - struct cons_pointer dividend, - struct cons_pointer divisor ); - /** * Construct a cell which points to an executable Lisp special form. */ struct cons_pointer make_special( struct cons_pointer src, struct cons_pointer ( *executable ) ( struct stack_frame *, + struct cons_pointer, struct cons_pointer ) ); /** diff --git a/src/memory/dump.c b/src/memory/dump.c new file mode 100644 index 0000000..5306801 --- /dev/null +++ b/src/memory/dump.c @@ -0,0 +1,120 @@ +/* + * dump.c + * + * Dump representations of both cons space and vector space objects. + * + * + * (c) 2018 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#include +#include +#include +#include +/* + * wide characters + */ +#include +#include + +#include "conspage.h" +#include "consspaceobject.h" +#include "print.h" +#include "stack.h" +#include "vectorspace.h" + + +void dump_string_cell( FILE * output, wchar_t *prefix, + struct cons_pointer pointer ) { + struct cons_space_object cell = pointer2cell( pointer ); + if ( cell.payload.string.character == 0 ) { + fwprintf( output, + L"\t\t%ls cell: termination; next at page %d offset %d, count %u\n", + prefix, + cell.payload.string.cdr.page, cell.payload.string.cdr.offset, + cell.count ); + } else { + fwprintf( output, + L"\t\t%ls cell: character '%lc' (%d) next at page %d offset %d, count %u\n", + prefix, + ( wint_t ) cell.payload.string.character, + cell.payload.string.character, + cell.payload.string.cdr.page, + cell.payload.string.cdr.offset, cell.count ); + fwprintf( output, L"\t\t value: " ); + print( output, pointer ); + fwprintf( output, L"\n" ); + } +} + +/** + * dump the object at this cons_pointer to this output stream. + */ +void dump_object( FILE * output, struct cons_pointer pointer ) { + struct cons_space_object cell = pointer2cell( pointer ); + fwprintf( output, + L"\t%c%c%c%c (%d) at page %d, offset %d count %u\n", + cell.tag.bytes[0], + cell.tag.bytes[1], + cell.tag.bytes[2], + cell.tag.bytes[3], + cell.tag.value, pointer.page, pointer.offset, cell.count ); + + switch ( cell.tag.value ) { + case CONSTV: + fwprintf( output, + L"\t\tCons cell: car at page %d offset %d, cdr at page %d offset %d, count %u\n", + cell.payload.cons.car.page, + cell.payload.cons.car.offset, + cell.payload.cons.cdr.page, + cell.payload.cons.cdr.offset, cell.count ); + break; + case EXCEPTIONTV: + fwprintf( output, L"\t\tException cell: " ); + dump_stack_trace( output, pointer); + break; + case FREETV: + fwprintf( output, L"\t\tFree cell: next at page %d offset %d\n", + cell.payload.cons.cdr.page, + cell.payload.cons.cdr.offset ); + break; + case INTEGERTV: + fwprintf( output, + L"\t\tInteger cell: value %ld, count %u\n", + cell.payload.integer.value, cell.count ); + break; + case LAMBDATV: + fwprintf( output, L"\t\tLambda cell; args: " ); + print( output, cell.payload.lambda.args ); + fwprintf( output, L";\n\t\t\tbody: " ); + print( output, cell.payload.lambda.body ); + break; + case RATIOTV: + fwprintf( output, + L"\t\tRational cell: value %ld/%ld, count %u\n", + pointer2cell( cell.payload.ratio.dividend ).payload. + integer.value, + pointer2cell( cell.payload.ratio.divisor ).payload. + integer.value, cell.count ); + break; + case READTV: + fwprintf( output, L"\t\tInput stream\n" ); + case REALTV: + fwprintf( output, L"\t\tReal cell: value %Lf, count %u\n", + cell.payload.real.value, cell.count ); + break; + case STRINGTV: + dump_string_cell( output, L"String", pointer ); + break; + case SYMBOLTV: + dump_string_cell( output, L"Symbol", pointer ); + break; + case VECTORPOINTTV: { + struct vector_space_object * vso = cell.payload.vectorp.address; + fwprintf( output, L"\t\tVector space object of type %4.4s, payload size %d bytes\n", + vso->header.tag, vso->header.size); + } + break; + } +} diff --git a/src/memory/dump.h b/src/memory/dump.h new file mode 100644 index 0000000..e49f453 --- /dev/null +++ b/src/memory/dump.h @@ -0,0 +1,29 @@ +/** + * dump.h + * + * Dump representations of both cons space and vector space objects. + * + * (c) 2018 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#include +#include +#include +/* + * wide characters + */ +#include +#include + +#ifndef __dump_h +#define __dump_h + + +/** + * dump the object at this cons_pointer to this output stream. + */ +void dump_object( FILE * output, struct cons_pointer pointer ); + + +#endif diff --git a/src/memory/stack.c b/src/memory/stack.c index 1bb8b1b..8fe268e 100644 --- a/src/memory/stack.c +++ b/src/memory/stack.c @@ -11,9 +11,6 @@ * with freelists to a more general 'equal sized object pages', so that * allocating/freeing stack frames can be more efficient. * - * Stack frames are not yet a first class object; they have no VECP pointer - * in cons space. - * * (c) 2017 Simon Brooke * Licensed under GPL version 2.0, or, at your option, any later version. */ @@ -25,87 +22,128 @@ #include "lispops.h" #include "print.h" #include "stack.h" +#include "vectorspace.h" + +/** + * get the actual stackframe object from this `pointer`, or NULL if + * `pointer` is not a stackframe pointer. + */ +struct stack_frame * get_stack_frame(struct cons_pointer pointer) { + struct stack_frame * result = NULL; + struct vector_space_object * vso = + pointer2cell(pointer).payload.vectorp.address; + + if (vectorpointp(pointer) && stackframep(vso)) + { + result = (struct stack_frame *) &(vso->payload); + } + + return result; +} /** * Make an empty stack frame, and return it. * @param previous the current top-of-stack; * @param env the environment in which evaluation happens. - * @return the new frame. + * @return the new frame, or NULL if memory is exhausted. */ -struct stack_frame *make_empty_frame( struct stack_frame *previous, - struct cons_pointer env ) { - struct stack_frame *result = malloc( sizeof( struct stack_frame ) ); +struct cons_pointer make_empty_frame( struct cons_pointer previous ) { + struct cons_pointer result = make_vso(STACKFRAMETAG, sizeof(struct stack_frame)); + if (!nilp(result)) { + struct stack_frame *frame = get_stack_frame(result); /* * TODO: later, pop a frame off a free-list of stack frames */ - result->previous = previous; + frame->previous = previous; + inc_ref(previous); /* * clearing the frame with memset would probably be slightly quicker, but * this is clear. */ - result->more = NIL; - result->function = NIL; + frame->more = NIL; + frame->function = NIL; + frame->args = 0; for ( int i = 0; i < args_in_frame; i++ ) { - set_reg( result, i, NIL ); + set_reg( frame, i, NIL ); } + } return result; } - /** * Allocate a new stack frame with its previous pointer set to this value, * its arguments set up from these args, evaluated in this env. * @param previous the current top-of-stack; * @args the arguments to load into this frame; * @param env the environment in which evaluation happens. - * @return the new frame. + * @return the new frame, or an exception if one occurred while building it. */ -struct stack_frame *make_stack_frame( struct stack_frame *previous, - struct cons_pointer args, - struct cons_pointer env, - struct cons_pointer *exception ) { - struct stack_frame *result = make_empty_frame( previous, env ); +struct cons_pointer make_stack_frame( struct cons_pointer previous, + struct cons_pointer args, + struct cons_pointer env ) { + struct cons_pointer result = make_empty_frame( previous ); - for ( int i = 0; i < args_in_frame && consp( args ); i++ ) { - /* iterate down the arg list filling in the arg slots in the + if (nilp(result)) + { + /* i.e. out of memory */ + result = make_exception(c_string_to_lisp_string( "Memory exhausted."), previous); + } else { + struct stack_frame * frame = get_stack_frame(result); + + for ( frame->args = 0; frame->args < args_in_frame && consp( args ); frame->args++ ) { + /* iterate down the arg list filling in the arg slots in the * frame. When there are no more slots, if there are still args, * stash them on more */ - struct cons_space_object cell = pointer2cell( args ); + struct cons_space_object cell = pointer2cell( args ); - /* + /* * TODO: if we were running on real massively parallel hardware, * each arg except the first should be handed off to another * processor to be evaled in parallel; but see notes here: * https://github.com/simon-brooke/post-scarcity/wiki/parallelism */ - struct stack_frame *arg_frame = make_empty_frame( result, env ); + struct cons_pointer arg_frame_pointer = make_empty_frame( result); + inc_ref(arg_frame_pointer); + + if(nilp(arg_frame_pointer)) { + result = make_exception(c_string_to_lisp_string( "Memory exhausted."), previous); + break; + } else { + struct stack_frame *arg_frame = get_stack_frame( arg_frame_pointer ); set_reg( arg_frame, 0, cell.payload.cons.car ); - struct cons_pointer val = lisp_eval( arg_frame, env ); + struct cons_pointer val = lisp_eval( arg_frame, arg_frame_pointer, env ); if ( exceptionp( val ) ) { - exception = &val; - break; + result = val; + break; } else { - set_reg( result, i, val ); + set_reg( frame, frame->args, val ); } - free_stack_frame( arg_frame ); + dec_ref(arg_frame_pointer); args = cell.payload.cons.cdr; + } } - if ( consp( args ) ) { + if (!exceptionp(result)) { + if ( consp( args ) ) { /* if we still have args, eval them and stick the values on `more` */ - struct cons_pointer more = eval_forms( previous, args, env ); - result->more = more; + struct cons_pointer more = eval_forms( get_stack_frame(previous), previous, args, env ); + frame->more = more; inc_ref( more ); - } + } - dump_frame( stderr, result ); - return result; +#ifdef DEBUG + dump_frame( stderr, result ); +#endif + } + } + + return result; } /** @@ -116,25 +154,39 @@ struct stack_frame *make_stack_frame( struct stack_frame *previous, * @param env the execution environment; * @return a new special frame. */ -struct stack_frame *make_special_frame( struct stack_frame *previous, +struct cons_pointer make_special_frame( struct cons_pointer previous, struct cons_pointer args, struct cons_pointer env ) { - struct stack_frame *result = make_empty_frame( previous, env ); + struct cons_pointer result = make_empty_frame( previous ); - for ( int i = 0; i < args_in_frame && !nilp( args ); i++ ) { + if (nilp(result)) + { + /* i.e. out of memory */ + result = make_exception(c_string_to_lisp_string( "Memory exhausted."), previous); + } else { + struct stack_frame * frame = get_stack_frame(result); + + for ( frame->args = 0; frame->args < args_in_frame && !nilp( args ); frame->args++ ) { /* iterate down the arg list filling in the arg slots in the * frame. When there are no more slots, if there are still args, * stash them on more */ struct cons_space_object cell = pointer2cell( args ); - set_reg( result, i, cell.payload.cons.car ); + set_reg( frame, frame->args, cell.payload.cons.car ); args = cell.payload.cons.cdr; } - if ( consp( args ) ) { - result->more = args; + if (!exceptionp(result)) { + if ( consp( args ) ) { + frame->more = args; inc_ref( args ); + } + +#ifdef DEBUG + dump_frame( stderr, result ); +#endif } + } return result; } @@ -160,26 +212,41 @@ void free_stack_frame( struct stack_frame *frame ) { /** * Dump a stackframe to this stream for debugging * @param output the stream - * @param frame the frame + * @param frame_pointer the pointer to 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++ ) { - struct cons_space_object cell = pointer2cell( frame->arg[arg] ); +void dump_frame( FILE * output, struct cons_pointer frame_pointer ) { + struct stack_frame *frame = get_stack_frame(frame_pointer); - fwprintf( output, L"Arg %d:\t%c%c%c%c\tcount: %10u\tvalue: ", arg, - cell.tag.bytes[0], - cell.tag.bytes[1], cell.tag.bytes[2], cell.tag.bytes[3], - cell.count ); + if (frame != NULL) { + for ( int arg = 0; arg < frame->args; arg++ ) { + struct cons_space_object cell = pointer2cell( frame->arg[arg] ); - print( output, frame->arg[arg] ); - fputws( L"\n", output ); + fwprintf( output, L"Arg %d:\t%c%c%c%c\tcount: %10u\tvalue: ", arg, + cell.tag.bytes[0], + cell.tag.bytes[1], cell.tag.bytes[2], cell.tag.bytes[3], + cell.count ); + + print( output, frame->arg[arg] ); + fputws( L"\n", output ); } fputws( L"More: \t", output ); print( output, frame->more ); fputws( L"\n", output ); + } } +void dump_stack_trace(FILE * output, struct cons_pointer pointer) { + if (exceptionp(pointer)) { + print( output, pointer2cell(pointer).payload.exception.message ); + fwprintf( output, L"\n" ); + dump_stack_trace(output, pointer2cell(pointer).payload.exception.frame); + } else { + while (vectorpointp(pointer) && stackframep(pointer_to_vso(pointer))) { + dump_frame( output, pointer); + pointer = get_stack_frame(pointer)->previous; + } + } +} /** * Fetch a pointer to the value of the local variable at this index. diff --git a/src/memory/stack.h b/src/memory/stack.h index d708b39..df76849 100644 --- a/src/memory/stack.h +++ b/src/memory/stack.h @@ -24,46 +24,40 @@ #ifndef __stack_h #define __stack_h +/** + * macros for the tag of a stack frame. + */ +#define STACKFRAMETAG "STAK" +#define STACKFRAMETV 1262572627 + +/** + * is this vector-space object a stack frame? + */ +#define stackframep(vso)(vso->header.tag.value == STACKFRAMETV) + /** * set a register in a stack frame. Alwaye use this macro to do so, • because that way we can be sure the inc_ref happens! */ #define set_reg(frame,register,value)frame->arg[register]=value; inc_ref(value) +struct stack_frame * get_stack_frame(struct cons_pointer pointer); -/** - * Make an empty stack frame, and return it. - * @param previous the current top-of-stack; - * @param env the environment in which evaluation happens. - * @return the new frame. - */ -struct stack_frame *make_empty_frame( struct stack_frame *previous, - struct cons_pointer env ); +struct cons_pointer make_empty_frame( struct cons_pointer previous ); + +struct cons_pointer make_stack_frame( struct cons_pointer previous, + struct cons_pointer args, + struct cons_pointer env ); -struct stack_frame *make_stack_frame( struct stack_frame *previous, - struct cons_pointer args, - struct cons_pointer env, - struct cons_pointer *exception ); 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 ); +void dump_frame( FILE * output, struct cons_pointer pointer ); + +void dump_stack_trace(FILE * output, struct cons_pointer frame_pointer); struct cons_pointer fetch_arg( struct stack_frame *frame, unsigned int n ); -/** - * A 'special' frame is exactly like a normal stack frame except that the - * arguments are unevaluated. - * @param previous the previous stack frame; - * @param args a list of the arguments to be stored in this stack frame; - * @param env the execution environment; - * @return a new special frame. - */ -struct stack_frame *make_special_frame( struct stack_frame *previous, +struct cons_pointer make_special_frame( struct cons_pointer previous, struct cons_pointer args, struct cons_pointer env ); diff --git a/src/memory/vectorspace.c b/src/memory/vectorspace.c index 4b18b96..c0b6f8d 100644 --- a/src/memory/vectorspace.c +++ b/src/memory/vectorspace.c @@ -8,6 +8,7 @@ * Licensed under GPL version 2.0, or, at your option, any later version. */ +#include #include #include #include @@ -29,7 +30,7 @@ * NOTE that `tag` should be the vector-space tag of the particular type of * vector-space object, NOT `VECTORPOINTTAG`. */ -struct cons_pointer make_vec_pointer( char *tag, uint64_t address ) { +struct cons_pointer make_vec_pointer( char * tag, struct vector_space_object * address ) { struct cons_pointer pointer = allocate_cell( VECTORPOINTTAG ); struct cons_space_object cell = pointer2cell( pointer ); @@ -44,26 +45,33 @@ struct cons_pointer make_vec_pointer( char *tag, uint64_t address ) { * and return a `cons_pointer` which points to an object whigh points to it. * NOTE that `tag` should be the vector-space tag of the particular type of * vector-space object, NOT `VECTORPOINTTAG`. + * Returns NIL if the vector could not be allocated due to memory exhaustion. */ -struct cons_pointer make_vso( char *tag, int64_t payload_size ) { +struct cons_pointer make_vso( char *tag, uint64_t payload_size ) { struct cons_pointer result = NIL; int64_t total_size = sizeof( struct vector_space_header ) + payload_size; - struct vector_space_header *vso = malloc( total_size ); + /* Pad size to 64 bit words. This is intended to promote access efficiancy + * on 64 bit machines but may just be voodoo coding */ + uint64_t padded = ceil((total_size * 8.0) / 8.0); + struct vector_space_object *vso = malloc( padded ); if ( vso != NULL ) { - strncpy( &vso->tag.bytes[0], tag, TAGLENGTH ); - vso->vecp = make_vec_pointer( tag, ( uint64_t ) vso ); - vso->size = payload_size; + strncpy( &vso->header.tag.bytes[0], tag, TAGLENGTH ); + vso->header.vecp = make_vec_pointer( tag, vso ); + vso->header.size = payload_size; #ifdef DEBUG fwprintf( stderr, - L"Allocated vector-space object of type %s, total size %ld, payload size %ld\n", + L"Allocated vector-space object of type %4.4s, total size %ld, payload size %ld\n", tag, total_size, payload_size ); + if (padded != total_size){ + fwprintf(stderr, L"\t\tPadded from %d to %d\n", + total_size, padded); + } #endif - result = vso->vecp; + result = vso->header.vecp; } - return result; } diff --git a/src/memory/vectorspace.h b/src/memory/vectorspace.h index 07a0b91..83fa74c 100644 --- a/src/memory/vectorspace.h +++ b/src/memory/vectorspace.h @@ -34,20 +34,16 @@ #define NAMESPACETAG "NMSP" #define NAMESPACETV 0 -/* - * a stack frame. - */ -#define STACKFRAMETAG "STAK" -#define STACKFRAMETV /* * a vector of cons pointers. */ #define VECTORTAG "VECT" #define VECTORTV 0 -#define pointer_to_vso(pointer)(vectorpointp(pointer)? pointer2cell(pointer).payload.vectorp.address : 0) +#define pointer_to_vso(pointer)((vectorpointp(pointer)? pointer2cell(pointer).payload.vectorp.address : NULL)) +#define vso_get_vecp(vso)((vso->header.vecp)) -struct cons_pointer make_vso( char *tag, int64_t payload_size ); +struct cons_pointer make_vso( char *tag, uint64_t payload_size ); struct vector_space_header { union { @@ -62,8 +58,10 @@ struct vector_space_header { struct cons_pointer vecp; /* back pointer to the vector pointer * which uniquely points to this vso */ uint64_t size; /* the size of my payload, in bytes */ - char mark; /* mark bit for marking/sweeping the - * heap (not in this version) */ +}; + +struct vector_space_object { + struct vector_space_header header; char payload; /* we'll malloc `size` bytes for payload, * `payload` is just the first of these. * TODO: this is almost certainly not diff --git a/src/ops/lispops.c b/src/ops/lispops.c index 9b12faa..825222f 100644 --- a/src/ops/lispops.c +++ b/src/ops/lispops.c @@ -80,6 +80,7 @@ struct cons_pointer c_cdr( struct cons_pointer arg ) { * @return the result of evaluating the form. */ struct cons_pointer eval_form( struct stack_frame *parent, + struct cons_pointer parent_pointer, struct cons_pointer form, struct cons_pointer env ) { fputws( L"eval_form: ", stderr ); @@ -87,15 +88,19 @@ struct cons_pointer eval_form( struct stack_frame *parent, fputws( L"\n", stderr ); struct cons_pointer result = NIL; - struct stack_frame *next = make_empty_frame( parent, env ); + struct cons_pointer next_pointer = make_empty_frame( parent_pointer ); + inc_ref( next_pointer); + + struct stack_frame * next = get_stack_frame(next_pointer); set_reg( next, 0, form ); - result = lisp_eval( next, env ); + + result = lisp_eval( next, next_pointer, env ); if ( !exceptionp( result ) ) { /* if we're returning an exception, we should NOT free the * stack frame. Corollary is, when we free an exception, we * should free all the frames it's holding on to. */ - free_stack_frame( next ); + dec_ref(next_pointer); } return result; @@ -106,12 +111,13 @@ struct cons_pointer eval_form( struct stack_frame *parent, * and this `env`, and return a list of their values. If the arg passed as * `list` is not in fact a list, return nil. */ -struct cons_pointer eval_forms( struct stack_frame *frame, +struct cons_pointer eval_forms( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer list, struct cons_pointer env ) { + /* TODO: refactor. This runs up the C stack. */ return consp( list ) ? - make_cons( eval_form( frame, c_car( list ), env ), - eval_forms( frame, c_cdr( list ), env ) ) : NIL; + make_cons( eval_form( frame, frame_pointer, c_car( list ), env ), + eval_forms( frame, frame_pointer, c_cdr( list ), env ) ) : NIL; } /** @@ -120,7 +126,7 @@ struct cons_pointer eval_forms( struct stack_frame *frame, * (oblist) */ struct cons_pointer -lisp_oblist( struct stack_frame *frame, struct cons_pointer env ) { +lisp_oblist( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { return oblist; } @@ -153,7 +159,7 @@ struct cons_pointer compose_body( struct stack_frame *frame ) { * @param env the environment in which it is to be intepreted. */ struct cons_pointer -lisp_lambda( struct stack_frame *frame, struct cons_pointer env ) { +lisp_lambda( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { return make_lambda( frame->arg[0], compose_body( frame ) ); } @@ -164,7 +170,7 @@ lisp_lambda( struct stack_frame *frame, struct cons_pointer env ) { * @param env the environment in which it is to be intepreted. */ struct cons_pointer -lisp_nlambda( struct stack_frame *frame, struct cons_pointer env ) { +lisp_nlambda( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { return make_nlambda( frame->arg[0], compose_body( frame ) ); } @@ -182,7 +188,7 @@ void log_binding( struct cons_pointer name, struct cons_pointer val ) { * Evaluate a lambda or nlambda expression. */ struct cons_pointer -eval_lambda( struct cons_space_object cell, struct stack_frame *frame, +eval_lambda( struct cons_space_object cell, struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { struct cons_pointer result = NIL; fwprintf( stderr, L"eval_lambda called\n" ); @@ -206,10 +212,11 @@ eval_lambda( struct cons_space_object cell, struct stack_frame *frame, } else if ( symbolp( names ) ) { /* if `names` is a symbol, rather than a list of symbols, * then bind a list of the values of args to that symbol. */ + /* TODO: eval all the things in frame->more */ struct cons_pointer vals = frame->more; for ( int i = args_in_frame - 1; i >= 0; i-- ) { - struct cons_pointer val = eval_form( frame, frame->arg[i], env ); + struct cons_pointer val = eval_form( frame, frame_pointer, frame->arg[i], env ); if ( nilp( val ) && nilp( vals ) ) { /* nothing */ } else { @@ -223,8 +230,10 @@ eval_lambda( struct cons_space_object cell, struct stack_frame *frame, while ( !nilp( body ) ) { struct cons_pointer sexpr = c_car( body ); body = c_cdr( body ); +#ifdef DEBUG fputws( L"In lambda: ", stderr ); - result = eval_form( frame, sexpr, new_env ); +#endif + result = eval_form( frame, frame_pointer, sexpr, new_env ); } return result; @@ -239,17 +248,23 @@ eval_lambda( struct cons_space_object cell, struct stack_frame *frame, * @return the result of evaluating the function with its arguments. */ struct cons_pointer -c_apply( struct stack_frame *frame, struct cons_pointer env ) { +c_apply( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { struct cons_pointer result = NIL; - struct stack_frame *fn_frame = make_empty_frame( frame, env ); + + /* construct a child frame and within it evaluate the first argument - the + * argument in the function position. */ + struct cons_pointer fn_frame_pointer = make_empty_frame( frame_pointer ); + inc_ref( fn_frame_pointer); + struct stack_frame *fn_frame = get_stack_frame(fn_frame_pointer); + set_reg( fn_frame, 0, c_car( frame->arg[0] ) ); - struct cons_pointer fn_pointer = lisp_eval( fn_frame, env ); + struct cons_pointer fn_pointer = lisp_eval( fn_frame, fn_frame_pointer, env ); if ( !exceptionp( result ) ) { /* if we're returning an exception, we should NOT free the * stack frame. Corollary is, when we free an exception, we * should free all the frames it's holding on to. */ - free_stack_frame( fn_frame ); + dec_ref(fn_frame_pointer); } struct cons_space_object fn_cell = pointer2cell( fn_pointer ); @@ -263,67 +278,66 @@ c_apply( struct stack_frame *frame, struct cons_pointer env ) { case FUNCTIONTV: { struct cons_pointer exep = NIL; - struct stack_frame *next = - make_stack_frame( frame, args, env, &exep ); - result = ( *fn_cell.payload.special.executable ) ( next, env ); - if ( exceptionp( exep ) ) { - /* if we're returning an exception, we should NOT free the - * stack frame. Corollary is, when we free an exception, we - * should free all the frames it's holding on to. */ - result = exep; + struct cons_pointer next_pointer = + make_stack_frame( frame_pointer, args, env ); + inc_ref(next_pointer); + if ( exceptionp( next_pointer ) ) { + result = next_pointer; } else { - free_stack_frame( next ); + struct stack_frame *next = get_stack_frame(next_pointer); + + result = ( *fn_cell.payload.function.executable ) ( next, next_pointer, env ); + dec_ref(next_pointer); } } break; case LAMBDATV: { struct cons_pointer exep = NIL; - struct stack_frame *next = - make_stack_frame( frame, args, env, &exep ); -#ifdef DEBUG - fputws( L"Stack frame for lambda\n", stderr ); - dump_frame( stderr, next ); -#endif - result = eval_lambda( fn_cell, next, env ); - if ( exceptionp( result ) ) { - /* if we're returning an exception, we should NOT free the - * stack frame. Corollary is, when we free an exception, we - * should free all the frames it's holding on to. */ - result = exep; + struct cons_pointer next_pointer = + make_stack_frame( frame_pointer, args, env ); + inc_ref(next_pointer); + if ( exceptionp( next_pointer ) ) { + result = next_pointer; } else { - free_stack_frame( next ); + struct stack_frame *next = get_stack_frame(next_pointer); + result = eval_lambda( fn_cell, next, next_pointer, env ); + if ( !exceptionp( result ) ) { + dec_ref(next_pointer); } + } } break; case NLAMBDATV: { - struct stack_frame *next = - make_special_frame( frame, args, env ); -#ifdef DEBUG - fputws( L"Stack frame for nlambda\n", stderr ); - dump_frame( stderr, next ); -#endif - result = eval_lambda( fn_cell, next, env ); + struct cons_pointer next_pointer = + make_special_frame( frame_pointer, args, env ); + inc_ref(next_pointer); + if ( exceptionp( next_pointer ) ) { + result = next_pointer; + } else { + struct stack_frame *next = get_stack_frame(frame_pointer); + result = eval_lambda( fn_cell, next, next_pointer, env ); if ( !exceptionp( result ) ) { - /* if we're returning an exception, we should NOT free the - * stack frame. Corollary is, when we free an exception, we - * should free all the frames it's holding on to. */ - free_stack_frame( next ); + dec_ref(next_pointer); } + } } break; case SPECIALTV: { - struct stack_frame *next = - make_special_frame( frame, args, env ); - result = ( *fn_cell.payload.special.executable ) ( next, env ); + struct cons_pointer next_pointer = + make_special_frame( frame_pointer, args, env ); + inc_ref(next_pointer); + if ( exceptionp( next_pointer ) ) { + result = next_pointer; + } else { + struct stack_frame *next = get_stack_frame(frame_pointer); + result = ( *fn_cell.payload.special.executable ) ( next, next_pointer, env ); if ( !exceptionp( result ) ) { - /* if we're returning an exception, we should NOT free the - * stack frame. Corollary is, when we free an exception, we - * should free all the frames it's holding on to. */ - free_stack_frame( next ); + dec_ref(next_pointer); } + } } break; default: @@ -338,9 +352,10 @@ c_apply( struct stack_frame *frame, struct cons_pointer env ) { struct cons_pointer message = c_string_to_lisp_string( buffer ); free( buffer ); - result = lisp_throw( message, frame ); + result = throw_exception( message, frame_pointer ); } } + dec_ref(fn_frame_pointer); return result; } @@ -378,19 +393,19 @@ struct cons_pointer c_type( struct cons_pointer pointer ) { * If a special form, passes the cdr of s_expr to the special form as argument. */ struct cons_pointer -lisp_eval( struct stack_frame *frame, struct cons_pointer env ) { +lisp_eval( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { struct cons_pointer result = frame->arg[0]; struct cons_space_object cell = pointer2cell( frame->arg[0] ); #ifdef DEBUG fputws( L"Eval: ", stderr ); - dump_frame( stderr, frame ); + dump_frame( stderr, frame_pointer ); #endif switch ( cell.tag.value ) { case CONSTV: { - result = c_apply( frame, env ); + result = c_apply( frame, frame_pointer, env ); } break; @@ -403,7 +418,7 @@ lisp_eval( struct stack_frame *frame, struct cons_pointer env ) { make_cons( c_string_to_lisp_string ( "Attempt to take value of unbound symbol." ), frame->arg[0] ); - result = lisp_throw( message, frame ); + result = throw_exception( message, frame_pointer ); } else { result = c_assoc( canonical, env ); inc_ref( result ); @@ -441,15 +456,15 @@ lisp_eval( struct stack_frame *frame, struct cons_pointer env ) { * the second argument */ struct cons_pointer -lisp_apply( struct stack_frame *frame, struct cons_pointer env ) { +lisp_apply( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { #ifdef DEBUG fputws( L"Apply: ", stderr ); - dump_frame( stderr, frame ); + dump_frame( stderr, frame_pointer ); #endif set_reg( frame, 0, make_cons( frame->arg[0], frame->arg[1] ) ); set_reg( frame, 1, NIL ); - struct cons_pointer result = c_apply( frame, env ); + struct cons_pointer result = c_apply( frame, frame_pointer, env ); #ifdef DEBUG fputws( L"Apply returning ", stderr ); @@ -469,7 +484,7 @@ lisp_apply( struct stack_frame *frame, struct cons_pointer env ) { * this isn't at this stage checked) unevaluated. */ struct cons_pointer -lisp_quote( struct stack_frame *frame, struct cons_pointer env ) { +lisp_quote( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { return frame->arg[0]; } @@ -484,7 +499,7 @@ lisp_quote( struct stack_frame *frame, struct cons_pointer env ) { * the namespace in so doing. `namespace` defaults to the value of `oblist`. */ struct cons_pointer -lisp_set( struct stack_frame *frame, struct cons_pointer env ) { +lisp_set( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { struct cons_pointer result = NIL; struct cons_pointer namespace = nilp( frame->arg[2] ) ? oblist : frame->arg[2]; @@ -497,7 +512,7 @@ lisp_set( struct stack_frame *frame, struct cons_pointer env ) { make_exception( make_cons ( c_string_to_lisp_string ( "The first argument to `set!` is not a symbol: " ), - make_cons( frame->arg[0], NIL ) ), frame ); + make_cons( frame->arg[0], NIL ) ), frame_pointer ); } return result; @@ -514,13 +529,13 @@ lisp_set( struct stack_frame *frame, struct cons_pointer env ) { * the namespace in so doing. `namespace` defaults to the value of `oblist`. */ struct cons_pointer -lisp_set_shriek( struct stack_frame *frame, struct cons_pointer env ) { +lisp_set_shriek( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { struct cons_pointer result = NIL; struct cons_pointer namespace = nilp( frame->arg[2] ) ? oblist : frame->arg[2]; if ( symbolp( frame->arg[0] ) ) { - struct cons_pointer val = eval_form( frame, frame->arg[1], env ); + struct cons_pointer val = eval_form( frame, frame_pointer, frame->arg[1], env ); deep_bind( frame->arg[0], val ); result = val; } else { @@ -528,7 +543,7 @@ lisp_set_shriek( struct stack_frame *frame, struct cons_pointer env ) { make_exception( make_cons ( c_string_to_lisp_string ( "The first argument to `set!` is not a symbol: " ), - make_cons( frame->arg[0], NIL ) ), frame ); + make_cons( frame->arg[0], NIL ) ), frame_pointer ); } return result; @@ -543,7 +558,7 @@ lisp_set_shriek( struct stack_frame *frame, struct cons_pointer env ) { * otherwise returns a new cons cell. */ struct cons_pointer -lisp_cons( struct stack_frame *frame, struct cons_pointer env ) { +lisp_cons( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { struct cons_pointer car = frame->arg[0]; struct cons_pointer cdr = frame->arg[1]; struct cons_pointer result; @@ -567,7 +582,7 @@ lisp_cons( struct stack_frame *frame, struct cons_pointer env ) { * strings, and TODO read streams and other things which can be considered as sequences. */ struct cons_pointer -lisp_car( struct stack_frame *frame, struct cons_pointer env ) { +lisp_car( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { struct cons_pointer result = NIL; if ( consp( frame->arg[0] ) ) { @@ -579,7 +594,7 @@ lisp_car( struct stack_frame *frame, struct cons_pointer env ) { } else { struct cons_pointer message = c_string_to_lisp_string( "Attempt to take CAR of non sequence" ); - result = lisp_throw( message, frame ); + result = throw_exception( message, frame_pointer ); } return result; @@ -591,7 +606,7 @@ lisp_car( struct stack_frame *frame, struct cons_pointer env ) { * strings, and TODO read streams and other things which can be considered as sequences. */ struct cons_pointer -lisp_cdr( struct stack_frame *frame, struct cons_pointer env ) { +lisp_cdr( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { struct cons_pointer result = NIL; if ( consp( frame->arg[0] ) ) { @@ -603,7 +618,7 @@ lisp_cdr( struct stack_frame *frame, struct cons_pointer env ) { } else { struct cons_pointer message = c_string_to_lisp_string( "Attempt to take CDR of non sequence" ); - result = lisp_throw( message, frame ); + result = throw_exception( message, frame_pointer ); } return result; @@ -614,7 +629,7 @@ lisp_cdr( struct stack_frame *frame, struct cons_pointer env ) { * Returns the value associated with key in store, or NIL if not found. */ struct cons_pointer -lisp_assoc( struct stack_frame *frame, struct cons_pointer env ) { +lisp_assoc( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { return c_assoc( frame->arg[0], frame->arg[1] ); } @@ -622,7 +637,7 @@ lisp_assoc( struct stack_frame *frame, struct cons_pointer env ) { * (eq a b) * Returns T if a and b are pointers to the same object, else NIL */ -struct cons_pointer lisp_eq( struct stack_frame *frame, +struct cons_pointer lisp_eq( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { return eq( frame->arg[0], frame->arg[1] ) ? TRUE : NIL; } @@ -632,7 +647,7 @@ struct cons_pointer lisp_eq( struct stack_frame *frame, * Returns T if a and b are pointers to structurally identical objects, else NIL */ struct cons_pointer -lisp_equal( struct stack_frame *frame, struct cons_pointer env ) { +lisp_equal( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { return equal( frame->arg[0], frame->arg[1] ) ? TRUE : NIL; } @@ -643,14 +658,14 @@ lisp_equal( struct stack_frame *frame, struct cons_pointer env ) { * is a read stream, then read from that stream, else stdin. */ struct cons_pointer -lisp_read( struct stack_frame *frame, struct cons_pointer env ) { +lisp_read( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { FILE *input = stdin; if ( readp( frame->arg[0] ) ) { input = pointer2cell( frame->arg[0] ).payload.stream.stream; } - return read( frame, input ); + return read( frame, frame_pointer, input ); } @@ -683,7 +698,7 @@ struct cons_pointer c_reverse( struct cons_pointer arg ) { * (reverse sequence) * Return a sequence like this sequence but with the members in the reverse order. */ -struct cons_pointer lisp_reverse( struct stack_frame *frame, +struct cons_pointer lisp_reverse( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { return c_reverse( frame->arg[0] ); } @@ -696,7 +711,10 @@ struct cons_pointer lisp_reverse( struct stack_frame *frame, * is a write stream, then print to that stream, else stdout. */ struct cons_pointer -lisp_print( struct stack_frame *frame, struct cons_pointer env ) { +lisp_print( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { +#ifdef DEBUG + fputws(L"Entering print\n", stderr); +#endif struct cons_pointer result = NIL; FILE *output = stdout; @@ -706,9 +724,11 @@ lisp_print( struct stack_frame *frame, struct cons_pointer env ) { result = print( output, frame->arg[0] ); +#ifdef DEBUG fputws( L"Print returning ", stderr ); - print( stderr, result ); + // print( stderr, result ); fputws( L"\n", stderr ); +#endif return result; } @@ -721,7 +741,7 @@ lisp_print( struct stack_frame *frame, struct cons_pointer env ) { * @return As a Lisp string, the tag of the object which is the argument. */ struct cons_pointer -lisp_type( struct stack_frame *frame, struct cons_pointer env ) { +lisp_type( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { return c_type( frame->arg[0] ); } @@ -739,16 +759,16 @@ lisp_type( struct stack_frame *frame, struct cons_pointer env ) { * argument. */ struct cons_pointer -lisp_progn( struct stack_frame *frame, struct cons_pointer env ) { +lisp_progn( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { struct cons_pointer remaining = frame->more; struct cons_pointer result = NIL; for ( int i = 0; i < args_in_frame && !nilp( frame->arg[i] ); i++ ) { - result = eval_form( frame, frame->arg[i], env ); + result = eval_form( frame, frame_pointer, frame->arg[i], env ); } while ( consp( remaining ) ) { - result = eval_form( frame, c_car( remaining ), env ); + result = eval_form( frame, frame_pointer, c_car( remaining ), env ); remaining = c_cdr( remaining ); } @@ -766,7 +786,7 @@ lisp_progn( struct stack_frame *frame, struct cons_pointer env ) { * @return the value of the last form of the first successful clause. */ struct cons_pointer -lisp_cond( struct stack_frame *frame, struct cons_pointer env ) { +lisp_cond( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ) { struct cons_pointer result = NIL; bool done = false; @@ -777,11 +797,11 @@ lisp_cond( struct stack_frame *frame, struct cons_pointer env ) { if ( consp( clause_pointer ) ) { struct cons_space_object cell = pointer2cell( clause_pointer ); - result = eval_form( frame, c_car( clause_pointer ), env ); + result = eval_form( frame, frame_pointer, c_car( clause_pointer ), env ); if ( !nilp( result ) ) { struct cons_pointer vals = - eval_forms( frame, c_cdr( clause_pointer ), env ); + eval_forms( frame, frame_pointer,c_cdr( clause_pointer ), env ); while ( consp( vals ) ) { result = c_car( vals ); @@ -793,9 +813,9 @@ lisp_cond( struct stack_frame *frame, struct cons_pointer env ) { } else if ( nilp( clause_pointer ) ) { done = true; } else { - result = lisp_throw( c_string_to_lisp_string + result = throw_exception( c_string_to_lisp_string ( "Arguments to `cond` must be lists" ), - frame ); + frame_pointer); } } /* TODO: if there are more than 8 clauses we need to continue into the @@ -805,15 +825,17 @@ lisp_cond( struct stack_frame *frame, struct cons_pointer env ) { } /** - * TODO: make this do something sensible somehow. - * This requires that a frame be a heap-space object with a cons-space + * Throw an exception. + * `throw_exception` is a misnomer, because it doesn't obey the calling signature of a + * lisp function; but it is nevertheless to be preferred to make_exception. A + * real `throw_exception`, which does, will be needed. * object pointing to it. Then this should become a normal lisp function * which expects a normally bound frame and environment, such that * frame->arg[0] is the message, and frame->arg[1] is the cons-space * pointer to the frame in which the exception occurred. */ struct cons_pointer -lisp_throw( struct cons_pointer message, struct stack_frame *frame ) { +throw_exception( struct cons_pointer message, struct cons_pointer frame_pointer ) { fwprintf( stderr, L"\nERROR: " ); print( stderr, message ); struct cons_pointer result = NIL; @@ -823,8 +845,23 @@ lisp_throw( struct cons_pointer message, struct stack_frame *frame ) { if ( cell.tag.value == EXCEPTIONTV ) { result = message; } else { - result = make_exception( message, frame ); + result = make_exception( message, frame_pointer ); } return result; } + +/** + * (exception ) + * + * Function. Returns an exception whose message is this `message`, and whose + * stack frame is the parent stack frame when the function is invoked. + * `message` does not have to be a string but should be something intelligible + * which can be read. + * If `message` is itself an exception, returns that instead. + */ +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, frame->previous); +} diff --git a/src/ops/lispops.h b/src/ops/lispops.h index 961cf2e..059255d 100644 --- a/src/ops/lispops.h +++ b/src/ops/lispops.h @@ -51,6 +51,7 @@ struct cons_pointer c_reverse( struct cons_pointer arg ); * @return the result of evaluating the form. */ struct cons_pointer eval_form( struct stack_frame *parent, + struct cons_pointer parent_pointer, struct cons_pointer form, struct cons_pointer env ); @@ -59,7 +60,7 @@ struct cons_pointer eval_form( struct stack_frame *parent, * and this `env`, and return a list of their values. If the arg passed as * `list` is not in fact a list, return nil. */ -struct cons_pointer eval_forms( struct stack_frame *frame, +struct cons_pointer eval_forms( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer list, struct cons_pointer env ); @@ -67,19 +68,19 @@ struct cons_pointer eval_forms( struct stack_frame *frame, /* * special forms */ -struct cons_pointer lisp_eval( struct stack_frame *frame, +struct cons_pointer lisp_eval( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); -struct cons_pointer lisp_apply( struct stack_frame *frame, +struct cons_pointer lisp_apply( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); struct cons_pointer -lisp_oblist( struct stack_frame *frame, struct cons_pointer env ); +lisp_oblist( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); struct cons_pointer -lisp_set( struct stack_frame *frame, struct cons_pointer env ); +lisp_set( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); struct cons_pointer -lisp_set_shriek( struct stack_frame *frame, struct cons_pointer env ); +lisp_set_shriek( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); /** * Construct an interpretable function. @@ -88,7 +89,7 @@ lisp_set_shriek( struct stack_frame *frame, struct cons_pointer env ); * @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 lisp_lambda( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); /** @@ -98,31 +99,31 @@ struct cons_pointer lisp_lambda( struct stack_frame *frame, * @param env the environment in which it is to be intepreted. */ struct cons_pointer -lisp_nlambda( struct stack_frame *frame, struct cons_pointer env ); +lisp_nlambda( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); -struct cons_pointer lisp_quote( struct stack_frame *frame, +struct cons_pointer lisp_quote( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); /* * functions */ -struct cons_pointer lisp_cons( struct stack_frame *frame, +struct cons_pointer lisp_cons( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); -struct cons_pointer lisp_car( struct stack_frame *frame, +struct cons_pointer lisp_car( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); -struct cons_pointer lisp_cdr( struct stack_frame *frame, +struct cons_pointer lisp_cdr( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); -struct cons_pointer lisp_assoc( struct stack_frame *frame, +struct cons_pointer lisp_assoc( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); -struct cons_pointer lisp_eq( struct stack_frame *frame, +struct cons_pointer lisp_eq( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); -struct cons_pointer lisp_equal( struct stack_frame *frame, +struct cons_pointer lisp_equal( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); -struct cons_pointer lisp_print( struct stack_frame *frame, +struct cons_pointer lisp_print( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); -struct cons_pointer lisp_read( struct stack_frame *frame, +struct cons_pointer lisp_read( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); -struct cons_pointer lisp_reverse( struct stack_frame *frame, +struct cons_pointer lisp_reverse( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); /** * Function: Get the Lisp type of the single argument. @@ -131,7 +132,7 @@ struct cons_pointer lisp_reverse( struct stack_frame *frame, * @return As a Lisp string, the tag of the object which is the argument. */ struct cons_pointer -lisp_type( struct stack_frame *frame, struct cons_pointer env ); +lisp_type( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); /** @@ -145,7 +146,7 @@ lisp_type( struct stack_frame *frame, struct cons_pointer env ); * argument. */ struct cons_pointer -lisp_progn( struct stack_frame *frame, struct cons_pointer env ); +lisp_progn( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); /** * Special form: conditional. Each arg is expected to be a list; if the first @@ -157,10 +158,16 @@ lisp_progn( struct stack_frame *frame, struct cons_pointer env ); * @return the value of the last form of the first successful clause. */ struct cons_pointer -lisp_cond( struct stack_frame *frame, struct cons_pointer env ); +lisp_cond( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); -/* - * neither, at this stage, really +/** + * Throw an exception. + * `throw_exception` is a misnomer, because it doesn't obey the calling signature of a + * lisp function; but it is nevertheless to be preferred to make_exception. A + * real `throw_exception`, which does, will be needed. */ -struct cons_pointer lisp_throw( struct cons_pointer message, - struct stack_frame *frame ); +struct cons_pointer throw_exception( struct cons_pointer message, + struct cons_pointer frame_pointer ); + +struct cons_pointer +lisp_exception( struct stack_frame *frame, struct cons_pointer frame_pointer, struct cons_pointer env ); diff --git a/src/ops/print.c b/src/ops/print.c index 4ec5a15..7efd59f 100644 --- a/src/ops/print.c +++ b/src/ops/print.c @@ -20,6 +20,7 @@ #include "conspage.h" #include "consspaceobject.h" #include "integer.h" +#include "stack.h" #include "print.h" /** @@ -118,12 +119,7 @@ struct cons_pointer print( FILE * output, struct cons_pointer pointer ) { case EXCEPTIONTV: fwprintf( output, L"\n%sException: ", print_use_colours ? "\x1B[31m" : "" ); - if ( stringp( cell.payload.exception.message ) ) { - print_string_contents( output, - cell.payload.exception.message ); - } else { - print( output, cell.payload.exception.message ); - } + dump_stack_trace(output, pointer); break; case FUNCTIONTV: fwprintf( output, L"(Function)" ); diff --git a/src/ops/read.c b/src/ops/read.c index bd063b2..1a09700 100644 --- a/src/ops/read.c +++ b/src/ops/read.c @@ -25,6 +25,7 @@ #include "ratio.h" #include "read.h" #include "real.h" +#include "vectorspace.h" /* * for the time being things which may be read are: strings numbers - either @@ -32,9 +33,11 @@ * atoms because I don't yet know what an atom is or how it's stored. */ -struct cons_pointer read_number( struct stack_frame *frame, FILE * input, +struct cons_pointer read_number( struct stack_frame *frame, + struct cons_pointer frame_pointer, FILE * input, wint_t initial, bool seen_period ); -struct cons_pointer read_list( struct stack_frame *frame, FILE * input, +struct cons_pointer read_list( struct stack_frame *frame, + struct cons_pointer frame_pointer, FILE * input, wint_t initial ); struct cons_pointer read_string( FILE * input, wint_t initial ); struct cons_pointer read_symbol( FILE * input, wint_t initial ); @@ -52,7 +55,7 @@ struct cons_pointer c_quote( struct cons_pointer arg ) { * treating this initial character as the first character of the object * representation. */ -struct cons_pointer read_continuation( struct stack_frame *frame, FILE * input, +struct cons_pointer read_continuation( struct stack_frame *frame, struct cons_pointer frame_pointer, FILE * input, wint_t initial ) { struct cons_pointer result = NIL; @@ -64,7 +67,7 @@ struct cons_pointer read_continuation( struct stack_frame *frame, FILE * input, if ( feof( input ) ) { result = make_exception( c_string_to_lisp_string - ( "End of file while reading" ), frame ); + ( "End of file while reading" ), frame_pointer ); } else { switch ( c ) { case ';': @@ -72,16 +75,16 @@ struct cons_pointer read_continuation( struct stack_frame *frame, FILE * input, /* skip all characters from semi-colon to the end of the line */ break; case EOF: - result = lisp_throw( c_string_to_lisp_string - ( "End of input while reading" ), frame ); + result = throw_exception( c_string_to_lisp_string + ( "End of input while reading" ), frame_pointer ); break; case '\'': result = c_quote( read_continuation - ( frame, input, fgetwc( input ) ) ); + ( frame, frame_pointer, input, fgetwc( input ) ) ); break; case '(': - result = read_list( frame, input, fgetwc( input ) ); + result = read_list( frame, frame_pointer, input, fgetwc( input ) ); break; case '"': result = read_string( input, fgetwc( input ) ); @@ -90,7 +93,7 @@ struct cons_pointer read_continuation( struct stack_frame *frame, FILE * input, wint_t next = fgetwc( input ); ungetwc( next, input ); if ( iswdigit( next ) ) { - result = read_number( frame, input, c, false ); + result = read_number( frame, frame_pointer, input, c, false ); } else { result = read_symbol( input, c ); } @@ -101,12 +104,12 @@ struct cons_pointer read_continuation( struct stack_frame *frame, FILE * input, wint_t next = fgetwc( input ); if ( iswdigit( next ) ) { ungetwc( next, input ); - result = read_number( frame, input, c, true ); + result = read_number( frame, frame_pointer, input, c, true ); } else if ( iswblank( next ) ) { /* dotted pair. TODO: this isn't right, we * really need to backtrack up a level. */ result = - read_continuation( frame, input, fgetwc( input ) ); + read_continuation( frame, frame_pointer, input, fgetwc( input ) ); } else { read_symbol( input, c ); } @@ -114,7 +117,7 @@ struct cons_pointer read_continuation( struct stack_frame *frame, FILE * input, break; default: if ( iswdigit( c ) ) { - result = read_number( frame, input, c, false ); + result = read_number( frame, frame_pointer, input, c, false ); } else if ( iswprint( c ) ) { result = read_symbol( input, c ); } else { @@ -122,7 +125,7 @@ struct cons_pointer read_continuation( struct stack_frame *frame, FILE * input, make_exception( make_cons( c_string_to_lisp_string ( "Unrecognised start of input character" ), make_string( c, NIL ) ), - frame ); + frame_pointer ); } break; } @@ -136,7 +139,9 @@ struct cons_pointer read_continuation( struct stack_frame *frame, FILE * input, * TODO: to be able to read bignums, we need to read the number from the * input stream into a Lisp string, and then convert it to a number. */ -struct cons_pointer read_number( struct stack_frame *frame, FILE * input, +struct cons_pointer read_number( struct stack_frame *frame, + struct cons_pointer frame_pointer, + FILE * input, wint_t initial, bool seen_period ) { struct cons_pointer result = NIL; int64_t accumulator = 0; @@ -157,7 +162,7 @@ struct cons_pointer read_number( struct stack_frame *frame, FILE * input, if ( seen_period || dividend != 0 ) { return make_exception( c_string_to_lisp_string ( "Malformed number: too many periods" ), - frame ); + frame_pointer ); } else { seen_period = true; } @@ -165,7 +170,7 @@ struct cons_pointer read_number( struct stack_frame *frame, FILE * input, if ( seen_period || dividend > 0 ) { return make_exception( c_string_to_lisp_string ( "Malformed number: dividend of rational must be integer" ), - frame ); + frame_pointer ); } else { dividend = negative ? 0 - accumulator : accumulator; @@ -200,7 +205,7 @@ struct cons_pointer read_number( struct stack_frame *frame, FILE * input, result = make_real( rv ); } else if ( dividend != 0 ) { result = - make_ratio( frame, make_integer( dividend ), + make_ratio( frame_pointer, make_integer( dividend ), make_integer( accumulator ) ); } else { if ( negative ) { @@ -216,18 +221,18 @@ struct cons_pointer read_number( struct stack_frame *frame, FILE * input, * Read a list from this input stream, which no longer contains the opening * left parenthesis. */ -struct cons_pointer read_list( struct - stack_frame - *frame, FILE * input, wint_t initial ) { +struct cons_pointer read_list( struct stack_frame *frame, + struct cons_pointer frame_pointer, + FILE * input, wint_t initial ) { struct cons_pointer result = NIL; if ( initial != ')' ) { #ifdef DEBUG fwprintf( stderr, L"read_list starting '%C' (%d)\n", initial, initial ); #endif - struct cons_pointer car = read_continuation( frame, input, + struct cons_pointer car = read_continuation( frame, frame_pointer, input, initial ); - result = make_cons( car, read_list( frame, input, fgetwc( input ) ) ); + result = make_cons( car, read_list( frame, frame_pointer, input, fgetwc( input ) ) ); } #ifdef DEBUG else { @@ -318,6 +323,6 @@ struct cons_pointer read_symbol( FILE * input, wint_t initial ) { */ struct cons_pointer read( struct stack_frame - *frame, FILE * input ) { - return read_continuation( frame, input, fgetwc( input ) ); + *frame, struct cons_pointer frame_pointer, FILE * input ) { + return read_continuation( frame, frame_pointer, input, fgetwc( input ) ); } diff --git a/src/ops/read.h b/src/ops/read.h index af7574b..c144699 100644 --- a/src/ops/read.h +++ b/src/ops/read.h @@ -14,6 +14,8 @@ /** * read the next object on this input stream and return a cons_pointer to it. */ -struct cons_pointer read( struct stack_frame *frame, FILE * input ); +struct cons_pointer read( struct stack_frame *frame, + struct cons_pointer frame_pointer, + FILE * input ); #endif diff --git a/src/repl.c b/src/repl.c index f9ca5d5..5dd6567 100644 --- a/src/repl.c +++ b/src/repl.c @@ -31,44 +31,64 @@ * Dummy up a Lisp read call with its own stack frame. */ struct cons_pointer repl_read( struct cons_pointer stream_pointer ) { - struct stack_frame *frame = make_empty_frame( NULL, oblist ); + struct cons_pointer result = NIL; + struct cons_pointer frame_pointer = make_empty_frame( NIL ); + if (!nilp(frame_pointer)) { + inc_ref(frame_pointer); + struct stack_frame *frame = get_stack_frame(frame_pointer); - set_reg( frame, 0, stream_pointer ); - struct cons_pointer result = lisp_read( frame, oblist ); - free_stack_frame( frame ); + if (frame != NULL){ - return result; + set_reg( frame, 0, stream_pointer ); + struct cons_pointer result = lisp_read( frame, frame_pointer, oblist ); + } + dec_ref(frame_pointer); + } + + return result; } /** * Dummy up a Lisp eval call with its own stack frame. */ struct cons_pointer repl_eval( struct cons_pointer input ) { - struct stack_frame *frame = make_empty_frame( NULL, oblist ); + struct cons_pointer result = NIL; + struct cons_pointer frame_pointer = make_empty_frame( NIL ); + if (!nilp(frame_pointer)) { + inc_ref(frame_pointer); + struct stack_frame *frame = get_stack_frame(frame_pointer); - set_reg( frame, 0, input ); - struct cons_pointer result = lisp_eval( frame, oblist ); - - if ( !exceptionp( result ) ) { - free_stack_frame( frame ); + if (frame != NULL){ + set_reg( frame, 0, input ); + result = lisp_eval( frame, frame_pointer, oblist ); } - return result; + dec_ref(frame_pointer); + } + + return result; } /** * Dummy up a Lisp print call with its own stack frame. */ struct cons_pointer repl_print( struct cons_pointer stream_pointer, - struct cons_pointer value ) { - struct stack_frame *frame = make_empty_frame( NULL, oblist ); + struct cons_pointer value ) { + struct cons_pointer result = NIL; + struct cons_pointer frame_pointer = make_empty_frame( NIL ); + if (!nilp(frame_pointer)) { + struct stack_frame *frame = get_stack_frame(frame_pointer); - set_reg( frame, 0, value ); - set_reg( frame, 1, stream_pointer ); - struct cons_pointer result = lisp_print( frame, oblist ); - free_stack_frame( frame ); + if (frame != NULL){ + set_reg( frame, 0, value ); + set_reg( frame, 1, stream_pointer ); + result = lisp_print( frame, frame_pointer, oblist ); + free_stack_frame( frame ); + } + dec_ref(frame_pointer); + } - return result; + return result; } /**