/** * repl.c * * Post Scarcity Soctware Environment * * First cut at a top level read-eval-print loop. * * Copyright (c): 17 Apr 2026 Simon Brooke * Licensed under GPL version 2.0, or, at your option, any later version. */ #include #include #include #include "debug.h" #include "io/fopen.h" #include "io/io.h" #include "io/print.h" #include "io/read.h" #include "memory/node.h" #include "memory/pointer.h" #include "memory/pso.h" #include "memory/pso2.h" #include "memory/pso4.h" #include "memory/tags.h" #include "payloads/cons.h" #include "payloads/function.h" #include "payloads/stack.h" #include "ops/assoc.h" #include "ops/eval_apply.h" #include "ops/stack_ops.h" #include "ops/truth.h" /** * @brief Handle an interrupt signal. * * @param dummy */ void interrupt_handler( int dummy ) { wprintf( L"TODO: handle ctrl-C in a more interesting way\n" ); } /** * Very simple read/eval/print loop for bootstrapping. */ void repl( struct pso_pointer frame_pointer ) { struct pso4 *frame = pointer_to_pso4( frame_pointer ); bool show_prompt = c_truep( fetch_arg( frame, 0 ) ); // todo: issue #21: must have stack frame passed in. signal( SIGINT, interrupt_handler ); debug_print( L"Entered repl\n", DEBUG_REPL, 0 ); struct pso_pointer env = fetch_env( frame_pointer ); struct pso_pointer input_stream = c_assoc( lisp_io_in, env ); struct pso_pointer output_stream = c_assoc( lisp_io_out, env ); if ( !readp( input_stream ) ) { debug_print( L"Invalid read stream: ", DEBUG_IO, 0 ); debug_print_object( input_stream, DEBUG_IO, 0 ); input_stream = lisp_stdin; } if ( !writep( output_stream ) ) { debug_print( L"Invalid write stream: ", DEBUG_IO, 0 ); debug_print_object( output_stream, DEBUG_IO, 0 ); output_stream = lisp_stdout; } while ( readp( input_stream ) && !url_feof( stream_get_url_file( input_stream ) ) ) { if ( show_prompt ) { princ( make_frame( 2, frame_pointer, c_assoc( lisp_io_prompt, env ), output_stream ) ); } /* the reason for initialising a new stack for each REPL input is to * be sure the old stack is fully torn down and reclaimed. Once I'm * confident of that, TODO: do not start a new stack base each time! */ struct pso_pointer base_of_stack = inc_ref( make_frame_with_env( 0, nil, consp( oblist ) ? oblist : make_cons( nil, oblist, nil ) ) ); struct pso_pointer next = inc_ref( make_frame( 1, base_of_stack, input_stream ) ); struct pso_pointer read_value = inc_ref( read( next ) ); dec_ref( next ); next = inc_ref( make_frame( 1, base_of_stack, read_value ) ); struct pso_pointer eval_value = inc_ref( eval( next ) ); dec_ref( next ); dec_ref( read_value ); next = inc_ref( make_frame ( 2, base_of_stack, eval_value, output_stream ) ); print( next ); dec_ref( next ); dec_ref( base_of_stack ); } debug_print( L"Leaving repl\n", DEBUG_REPL, 0 ); }