110 lines
3.3 KiB
C
110 lines
3.3 KiB
C
/**
|
|
* repl.c
|
|
*
|
|
* Post Scarcity Soctware Environment
|
|
*
|
|
* First cut at a top level read-eval-print loop.
|
|
*
|
|
* Copyright (c): 17 Apr 2026 Simon Brooke <simon@journeyman.cc>
|
|
* Licensed under GPL version 2.0, or, at your option, any later version.
|
|
*/
|
|
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <wchar.h>
|
|
|
|
#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 );
|
|
}
|