diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..8ae8d15 --- /dev/null +++ b/.clangd @@ -0,0 +1,7 @@ +CompileFlags: {CompilationDatabase: } + +If: + PathMatch: .*\.c + +CompileFlags: + Add: [-std=gnu23, -Wall, -Wextra, -I src/c -I src/c/arith -I src/c/environment -I src/c/io -I src/c/memory -I src/c/ops -I src/c/payloads] \ No newline at end of file diff --git a/Makefile b/Makefile index 701b16b..b6853b9 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ TESTS := $(shell find unit-tests -name *.sh) # INC_DIRS := $(shell find $(SRC_DIRS) -type d) # INC_FLAGS := $(addprefix -I,$(INC_DIRS)) -INC_FLAGS := -I $(SRC_DIRS) +INC_FLAGS := -I $(shell find $(SRC_DIRS) -type d) TMP_DIR ?= ./tmp diff --git a/src/c/io/io.c b/src/c/io/io.c index 2a897f7..61175e8 100644 --- a/src/c/io/io.c +++ b/src/c/io/io.c @@ -15,9 +15,9 @@ #include #include #include -#include #include #include +#include #include #include /* @@ -28,7 +28,7 @@ #include -//#include "arith/integer.h" +// #include "arith/integer.h" #include "debug.h" #include "io/fopen.h" #include "io/io.h" @@ -42,6 +42,8 @@ // #include "ops/intern.h" // #include "ops/lispops.h" +#include "ops/assoc.h" +#include "ops/bind.h" #include "ops/stack_ops.h" #include "ops/string_ops.h" #include "ops/truth.h" @@ -50,7 +52,9 @@ #include "payloads/cons.h" #include "payloads/exception.h" #include "payloads/integer.h" +#include "payloads/read_stream.h" #include "payloads/stack.h" +#include "payloads/write_stream.h" #include "utils.h" @@ -62,21 +66,36 @@ CURLSH *io_share; /** - * @brief bound to the Lisp string representing C_IO_IN in initialisation. + * @brief bound to the Lisp symbol representing C_IO_IN in initialisation. */ struct pso_pointer lisp_io_in; /** - * @brief bound to the Lisp string representing C_IO_OUT in initialisation. + * @brief bound to the Lisp symbol representing C_IO_OUT in initialisation. */ struct pso_pointer lisp_io_out; - /** * Allow a one-character unget facility. This may not be enough - we may need * to allocate a buffer. */ wint_t ungotten = 0; +/** + * given this file handle f, return a new url_file handle wrapping it. + * + * @param f the file to be wrapped; + * @return the new handle, or null if no such handle could be allocated. + */ +URL_FILE *file_to_url_file( FILE *f ) { + URL_FILE *result = ( URL_FILE * ) malloc( sizeof( URL_FILE ) ); + + if ( result != NULL ) { + result->type = CFTYPE_FILE, result->handle.file = f; + } + + return result; +} + /** * Initialise the I/O subsystem. * @@ -99,6 +118,32 @@ int initialise_io( ) { return result; } +struct pso_pointer initialise_default_streams( struct pso_pointer env ) { + lisp_io_in = c_string_to_lisp_symbol( C_IO_IN ); + lisp_io_out = c_string_to_lisp_symbol( C_IO_OUT ); + + env = c_bind( lisp_io_in, + make_read_stream( file_to_url_file( stdin ), + c_cons( c_cons + ( c_string_to_lisp_keyword + ( L"url" ), + c_string_to_lisp_string + ( L"system:standard input" ) ), + nil ) ), env ); + if ( !nilp( env ) && !exceptionp( env ) ) { + env = c_bind( lisp_io_out, + make_write_stream( file_to_url_file( stdout ), + c_cons( c_cons + ( c_string_to_lisp_keyword + ( L"url" ), + c_string_to_lisp_string + ( L"system:standard input" ) ), + nil ) ), env ); + } + + return env; +} + /** * Convert this lisp string-like-thing (also works for symbols, and, later * keywords) into a UTF-8 string. NOTE that the returned value has been @@ -138,24 +183,6 @@ char *lisp_string_to_c_string( struct pso_pointer s ) { return result; } - -/** - * given this file handle f, return a new url_file handle wrapping it. - * - * @param f the file to be wrapped; - * @return the new handle, or null if no such handle could be allocated. - */ -URL_FILE *file_to_url_file( FILE *f ) { - URL_FILE *result = ( URL_FILE * ) malloc( sizeof( URL_FILE ) ); - - if ( result != NULL ) { - result->type = CFTYPE_FILE, result->handle.file = f; - } - - return result; -} - - /** * get one wide character from the buffer. * @@ -193,13 +220,15 @@ wint_t url_fgetwc( URL_FILE *input ) { debug_printf( DEBUG_IO, 0, L"url_fgetwc: cbuff is '%s'; (first) character = %d (%c)\n", cbuff, c, c & 0xf7 ); - /* The value of each individual byte indicates its UTF-8 function, as follows: + /* The value of each individual byte indicates its UTF-8 function, + * as follows: * * 00 to 7F hex (0 to 127): first and only byte of a sequence. - * 80 to BF hex (128 to 191): continuing byte in a multi-byte sequence. - * C2 to DF hex (194 to 223): first byte of a two-byte sequence. - * E0 to EF hex (224 to 239): first byte of a three-byte sequence. - * F0 to FF hex (240 to 255): first byte of a four-byte sequence. + * 80 to BF hex (128 to 191): continuing byte in a multi-byte + * sequence. C2 to DF hex (194 to 223): first byte of a two-byte + * sequence. E0 to EF hex (224 to 239): first byte of a three-byte + * sequence. F0 to FF hex (240 to 255): first byte of a four-byte + * sequence. */ if ( c <= 0xf7 ) { count = 1; @@ -219,8 +248,7 @@ wint_t url_fgetwc( URL_FILE *input ) { free( wbuff ); free( cbuff ); - } - break; + } break; case CFTYPE_NONE: break; } @@ -265,8 +293,8 @@ struct pso_pointer get_character( struct pso_pointer read_stream ) { if ( readp( read_stream ) ) { result = make_character( url_fgetwc - ( pointer_to_object_of_size_class - ( read_stream, 2 )->payload.stream.stream ) ); + ( pointer_to_object_of_size_class( read_stream, 2 ) + ->payload.stream.stream ) ); } return result; @@ -286,8 +314,8 @@ struct pso_pointer push_back_character( struct pso_pointer c, if ( characterp( c ) && readp( r ) ) { if ( url_ungetwc( ( wint_t ) - ( pointer_to_object( c )->payload. - character.character ), + ( pointer_to_object( c )->payload.character. + character ), pointer_to_object( r )->payload.stream.stream ) >= 0 ) { result = t; @@ -308,16 +336,14 @@ struct pso_pointer push_back_character( struct pso_pointer c, * @param env my environment. * @return T if the stream was successfully closed, else nil. */ -struct pso_pointer -lisp_close( struct pso_pointer frame_pointer, struct pso_pointer env ) { +struct pso_pointer lisp_close( struct pso_pointer frame_pointer, + struct pso_pointer env ) { struct pso4 *frame = pointer_to_pso4( frame_pointer ); struct pso_pointer result = nil; if ( readp( fetch_arg( frame, 0 ) ) || writep( fetch_arg( frame, 0 ) ) ) { - if ( url_fclose - ( pointer_to_object( fetch_arg( frame, 0 ) )->payload.stream. - stream ) - == 0 ) { + if ( url_fclose( pointer_to_object( fetch_arg( frame, 0 ) ) + ->payload.stream.stream ) == 0 ) { result = t; } } @@ -328,8 +354,9 @@ lisp_close( struct pso_pointer frame_pointer, struct pso_pointer env ) { struct pso_pointer add_meta_integer( struct pso_pointer meta, wchar_t *key, long int value ) { return - c_cons( c_cons( c_string_to_lisp_keyword( key ), - make_integer( value ) ), meta ); + c_cons( c_cons + ( c_string_to_lisp_keyword( key ), make_integer( value ) ), + meta ); } struct pso_pointer add_meta_string( struct pso_pointer meta, wchar_t *key, @@ -338,8 +365,10 @@ struct pso_pointer add_meta_string( struct pso_pointer meta, wchar_t *key, wchar_t buffer[strlen( value ) + 1]; mbstowcs( buffer, value, strlen( value ) + 1 ); - return c_cons( c_cons( c_string_to_lisp_keyword( key ), - c_string_to_lisp_string( buffer ) ), meta ); + return + c_cons( c_cons + ( c_string_to_lisp_keyword( key ), + c_string_to_lisp_string( buffer ) ), meta ); } struct pso_pointer add_meta_time( struct pso_pointer meta, wchar_t *key, @@ -348,9 +377,8 @@ struct pso_pointer add_meta_time( struct pso_pointer meta, wchar_t *key, * bit of an oversight! */ char datestring[256]; - strftime( datestring, - sizeof( datestring ), - nl_langinfo( D_T_FMT ), localtime( value ) ); + strftime( datestring, sizeof( datestring ), nl_langinfo( D_T_FMT ), + localtime( value ) ); return add_meta_string( meta, key, datestring ); } @@ -386,8 +414,8 @@ static size_t write_meta_callback( char *string, size_t size, size_t nmemb, // add_meta_string( cell->payload.stream.meta, wname, value ); // debug_printf( DEBUG_IO, - // L"write_meta_callback: added header '%s': value '%s'\n", - // name, value ); + // L"write_meta_callback: added header '%s': value + // '%s'\n", name, value ); // } else if ( strncmp( "HTTP", s, 4 ) == 0 ) { // int offset = index_of( ' ', s ); // char *value = trim( &s[offset] ); @@ -400,16 +428,17 @@ static size_t write_meta_callback( char *string, size_t size, size_t nmemb, // 10 ) ); // debug_printf( DEBUG_IO, - // L"write_meta_callback: added header 'status': value '%s'\n", - // value ); + // L"write_meta_callback: added header 'status': value + // '%s'\n", value ); // } else { // debug_printf( DEBUG_IO, - // L"write_meta_callback: header passed with no colon: '%s'\n", - // s ); + // L"write_meta_callback: header passed with no colon: + // '%s'\n", s ); // } // } else { // debug_print - // ( L"Pointer passed to write_meta_callback did not point to a stream: ", + // ( L"Pointer passed to write_meta_callback did not point to a + // stream: ", // DEBUG_IO ); // debug_dump_object( stream, DEBUG_IO ); // } @@ -471,13 +500,28 @@ void collect_meta( struct pso_pointer stream, char *url ) { */ struct pso_pointer get_default_stream( bool inputp, struct pso_pointer env ) { struct pso_pointer result = nil; - // struct pso_pointer stream_name = inputp ? lisp_io_in : lisp_io_out; + struct pso_pointer stream_name = inputp ? lisp_io_in : lisp_io_out; - // result = c_assoc( stream_name, env ); + result = c_assoc( stream_name, env ); return result; } +/** + * @brief if `s` points to either an input or an output stream, return the + * URL_FILE pointer underlying that stream, else NULL. + */ +URL_FILE *stream_get_url_file( struct pso_pointer s ) { + URL_FILE *result = NULL; + + if ( readp( s ) || writep( s ) ) { + struct pso2 *obj = pointer_to_object( s ); + + result = obj->payload.stream.stream; + } + + return result; +} /** * Function: return a stream open on the URL indicated by the first argument; @@ -494,8 +538,8 @@ struct pso_pointer get_default_stream( bool inputp, struct pso_pointer env ) { * @return a string of one character, namely the next available character * on my stream, if any, else nil. */ -struct pso_pointer -lisp_open( struct pso_pointer frame_pointer, struct pso_pointer env ) { +struct pso_pointer lisp_open( struct pso_pointer frame_pointer, + struct pso_pointer env ) { struct pso4 *frame = pointer_to_pso4( frame_pointer ); struct pso_pointer result = nil; @@ -505,10 +549,10 @@ lisp_open( struct pso_pointer frame_pointer, struct pso_pointer env ) { // if ( nilp( fetch_arg( frame, 1) ) ) { // URL_FILE *stream = url_fopen( url, "r" ); - // debug_printf( DEBUG_IO, 0, - // L"lisp_open: stream @ %ld, stream type = %d, stream handle = %ld\n", - // ( long int ) &stream, ( int ) stream->type, - // ( long int ) stream->handle.file ); + // debug_printf( DEBUG_IO, 0, + // L"lisp_open: stream @ %ld, stream type = %d, stream + // handle = %ld\n", ( long int ) &stream, ( int ) + // stream->type, ( long int ) stream->handle.file ); // switch ( stream->type ) { // case CFTYPE_NONE: @@ -561,16 +605,16 @@ lisp_open( struct pso_pointer frame_pointer, struct pso_pointer env ) { * @return a string of one character, namely the next available character * on my stream, if any, else nil. */ -struct pso_pointer -lisp_read_char( struct pso_pointer frame_pointer, struct pso_pointer env ) { +struct pso_pointer lisp_read_char( struct pso_pointer frame_pointer, + struct pso_pointer env ) { struct pso4 *frame = pointer_to_pso4( frame_pointer ); struct pso_pointer result = nil; - if ( readp( fetch_arg( frame, 0 ) ) ) { + struct pso_pointer stream_pointer = fetch_arg( frame, 0 ); + if ( readp( stream_pointer ) ) { result = - make_string( url_fgetwc - ( pointer_to_object( fetch_arg( frame, 0 ) )-> - payload.stream.stream ), nil ); + make_string( url_fgetwc( stream_get_url_file( stream_pointer ) ), + nil ); } return result; @@ -590,14 +634,13 @@ lisp_read_char( struct pso_pointer frame_pointer, struct pso_pointer env ) { * @return a string of one character, namely the next available character * on my stream, if any, else nil. */ -struct pso_pointer -lisp_slurp( struct pso_pointer frame_pointer, struct pso_pointer env ) { +struct pso_pointer lisp_slurp( struct pso_pointer frame_pointer, + struct pso_pointer env ) { struct pso4 *frame = pointer_to_pso4( frame_pointer ); struct pso_pointer result = nil; if ( readp( fetch_arg( frame, 0 ) ) ) { - URL_FILE *stream = - pointer_to_object( fetch_arg( frame, 0 ) )->payload.stream.stream; + URL_FILE *stream = stream_get_url_file( fetch_arg( frame, 0 ) ); struct pso_pointer cursor = make_string( url_fgetwc( stream ), nil ); result = cursor; diff --git a/src/c/io/io.h b/src/c/io/io.h index 703ed2e..995f508 100644 --- a/src/c/io/io.h +++ b/src/c/io/io.h @@ -19,6 +19,7 @@ extern CURLSH *io_share; int initialise_io( ); +struct pso_pointer initialise_default_streams( struct pso_pointer env ); #define C_IO_IN L"*in*" #define C_IO_OUT L"*out*" @@ -37,6 +38,8 @@ struct pso_pointer push_back_character( struct pso_pointer c, struct pso_pointer get_default_stream( bool inputp, struct pso_pointer env ); +URL_FILE *stream_get_url_file( struct pso_pointer s ); + struct pso_pointer lisp_close( struct pso_pointer frame_pointer, struct pso_pointer env ); struct pso_pointer diff --git a/src/c/io/print.h b/src/c/io/print.h index 0a969e0..39b7d41 100644 --- a/src/c/io/print.h +++ b/src/c/io/print.h @@ -14,6 +14,7 @@ #ifndef __psse_io_print_h #define __psse_io_print_h +#include "io/fopen.h" struct pso_pointer c_print( struct pso_pointer p, struct pso_pointer stream ); struct pso_pointer in_print( struct pso_pointer p, URL_FILE * output ); diff --git a/src/c/io/read.c b/src/c/io/read.c index f072a6d..f78e796 100644 --- a/src/c/io/read.c +++ b/src/c/io/read.c @@ -32,6 +32,7 @@ #include "memory/pso2.h" #include "memory/tags.h" +#include "payloads/function.h" #include "payloads/integer.h" #include "payloads/read_stream.h" @@ -41,7 +42,7 @@ #include "ops/string_ops.h" #include "ops/truth.h" -// TODO: what I've copied from 0.0.6 is *wierdly* over-complex for just now. +// TODO: what I've copied from 0.0.6 is *weirdly* over-complex for just now. // I think I'm going to essentially delete all this and start again. We need // to be able to despatch on readttables, and the initial readtable functions // don't need to be written in Lisp. @@ -55,9 +56,9 @@ // the next is the input stream; the next is the readtable, if any. /* - * for the time being things which may be read are: + * for the time being things which may be read are: * * integers - * * lists + * * lists * * atoms * * dotted pairs */ @@ -72,8 +73,12 @@ * 1. The read table currently in use; * 2. The character most recently read from that stream. */ -struct pso_pointer read_example( struct pso_pointer frame_pointer, - struct pso_pointer env ) { +struct pso_pointer read_example( +#ifndef MANAGED_POINTER_ONLY + struct pso4 *frame, +#endif + struct pso_pointer frame_pointer, + struct pso_pointer env ) { struct pso4 *frame = pointer_to_pso4( frame_pointer ); struct pso_pointer stream = fetch_arg( frame, 0 ); struct pso_pointer readtable = fetch_arg( frame, 1 ); @@ -93,8 +98,12 @@ struct pso_pointer read_example( struct pso_pointer frame_pointer, * 1. The read table currently in use; * 2. The character most recently read from that stream. */ -struct pso_pointer read_number( struct pso_pointer frame_pointer, - struct pso_pointer env ) { +struct pso_pointer read_number( +#ifndef MANAGED_POINTER_ONLY + struct pso4 *frame, +#endif + struct pso_pointer frame_pointer, + struct pso_pointer env ) { struct pso4 *frame = pointer_to_pso4( frame_pointer ); struct pso_pointer stream = fetch_arg( frame, 0 ); struct pso_pointer readtable = fetch_arg( frame, 1 ); @@ -109,8 +118,8 @@ struct pso_pointer read_number( struct pso_pointer frame_pointer, if ( nilp( character ) ) { character = get_character( stream ); } - wchar_t c = nilp( character ) ? 0 : - pointer_to_object( character )->payload.character.character; + wchar_t c = nilp( character ) + ? 0 : pointer_to_object( character )->payload.character.character; URL_FILE *input = pointer_to_object( stream )->payload.stream.stream; for ( ; iswdigit( c ); c = url_fgetwc( input ) ) { @@ -124,8 +133,12 @@ struct pso_pointer read_number( struct pso_pointer frame_pointer, return result; } -struct pso_pointer read_symbol( struct pso_pointer frame_pointer, - struct pso_pointer env ) { +struct pso_pointer read_symbol( +#ifndef MANAGED_POINTER_ONLY + struct pso4 *frame, +#endif + struct pso_pointer frame_pointer, + struct pso_pointer env ) { struct pso4 *frame = pointer_to_pso4( frame_pointer ); struct pso_pointer stream = fetch_arg( frame, 0 ); struct pso_pointer readtable = fetch_arg( frame, 1 ); @@ -137,8 +150,8 @@ struct pso_pointer read_symbol( struct pso_pointer frame_pointer, character = get_character( stream ); } - wchar_t c = nilp( character ) ? 0 : - pointer_to_object( character )->payload.character.character; + wchar_t c = nilp( character ) + ? 0 : pointer_to_object( character )->payload.character.character; URL_FILE *input = pointer_to_object( stream )->payload.stream.stream; for ( ; iswalnum( c ); c = url_fgetwc( input ) ) { @@ -163,8 +176,12 @@ struct pso_pointer read_symbol( struct pso_pointer frame_pointer, * 1. The read table currently in use; * 2. The character most recently read from that stream. */ -struct pso_pointer read( struct pso_pointer frame_pointer, - struct pso_pointer env ) { +struct pso_pointer read( +#ifndef MANAGED_POINTER_ONLY + struct pso4 *frame, +#endif + struct pso_pointer frame_pointer, + struct pso_pointer env ) { struct pso4 *frame = pointer_to_pso4( frame_pointer ); struct pso_pointer stream = fetch_arg( frame, 0 ); struct pso_pointer readtable = fetch_arg( frame, 1 ); @@ -201,27 +218,38 @@ struct pso_pointer read( struct pso_pointer frame_pointer, /* skip all characters from semi-colon to the end of the line */ break; case EOF: -// result = throw_exception( c_string_to_lisp_symbol( L"read" ), -// c_string_to_lisp_string -// ( L"End of input while reading" ), -// frame_pointer ); + // result = throw_exception( c_string_to_lisp_symbol( + // L"read" ), + // c_string_to_lisp_string + // ( L"End of input while + // reading" ), + // frame_pointer ); break; default: - struct pso_pointer next = - make_frame( 3, frame_pointer, stream, readtable, - make_character( c ) ); + struct pso_pointer next = make_frame( 3, frame_pointer, stream, + readtable, + make_character( c ) ); inc_ref( next ); if ( iswdigit( c ) ) { result = read_number( next, env ); } else if ( iswalpha( c ) ) { result = read_symbol( next, env ); } else { -// result = -// throw_exception( c_string_to_lisp_symbol( L"read" ), -// make_cons( c_string_to_lisp_string -// ( L"Unrecognised start of input character" ), -// make_string( c, NIL ) ), -// frame_pointer ); + // result = + // throw_exception( + // c_string_to_lisp_symbol( L"read" ), + // make_cons( + // c_string_to_lisp_string + // ( + // L"Unrecognised + // start of + // input + // character" + // ), + // make_string( + // c, NIL ) + // ), + // frame_pointer ); } dec_ref( next ); break; diff --git a/src/c/memory/node.c b/src/c/memory/node.c index 5bac51d..42638a7 100644 --- a/src/c/memory/node.c +++ b/src/c/memory/node.c @@ -8,14 +8,20 @@ * Licensed under GPL version 2.0, or, at your option, any later version. */ -#include "node.h" - #include #include "environment/environment.h" + +#include "io/io.h" + #include "memory/memory.h" #include "memory/pointer.h" +#include "memory/tags.h" + #include "ops/eq.h" +#include "ops/string_ops.h" +#include "ops/truth.h" +#include "payloads/exception.h" /** * @brief Flag to prevent the node being initialised more than once. @@ -63,5 +69,16 @@ struct pso_pointer initialise_node( uint32_t index ) { struct pso_pointer result = initialise_environment( index ); + if ( !nilp( result ) && !exceptionp( result ) ) { + if ( initialise_io( ) == 0 ) { + result = initialise_default_streams( result ); + } else { + result = + make_exception( c_string_to_lisp_string + ( L"Failed to initialise default streams" ), + nil, nil, nil ); + } + } + return result; } diff --git a/src/c/memory/node.h b/src/c/memory/node.h index 5ce48cf..d8559f1 100644 --- a/src/c/memory/node.h +++ b/src/c/memory/node.h @@ -33,6 +33,6 @@ extern struct pso_pointer t; extern struct pso_pointer oblist; -struct pso_pointer initialise_node( uint32_t index ); +struct pso_pointer initialise_node( int node_index ); #endif diff --git a/src/c/ops/bind.c b/src/c/ops/bind.c index ba25834..5d66359 100644 --- a/src/c/ops/bind.c +++ b/src/c/ops/bind.c @@ -19,6 +19,7 @@ #include "ops/stack_ops.h" #include "payloads/cons.h" +#include "payloads/function.h" #include "payloads/stack.h" struct pso_pointer lisp_bind( diff --git a/src/c/ops/bind.h b/src/c/ops/bind.h index 517086a..2682fe8 100644 --- a/src/c/ops/bind.h +++ b/src/c/ops/bind.h @@ -3,7 +3,7 @@ * * Post Scarcity Software Environment: bind. * - * Test for pointer binduality. + * Bind a name to a value in a store. * * (c) 2026 Simon Brooke * Licensed under GPL version 2.0, or, at your option, any later version. diff --git a/src/c/ops/eval_apply.c b/src/c/ops/eval_apply.c index aeb3577..9333a03 100644 --- a/src/c/ops/eval_apply.c +++ b/src/c/ops/eval_apply.c @@ -23,6 +23,7 @@ #include "ops/truth.h" #include "payloads/cons.h" +#include "payloads/function.h" #include "payloads/stack.h" /** diff --git a/src/c/ops/list_ops.h b/src/c/ops/list_ops.h index ae770cd..0121b57 100644 --- a/src/c/ops/list_ops.h +++ b/src/c/ops/list_ops.h @@ -15,6 +15,8 @@ #include "memory/pointer.h" #include "memory/pso4.h" +#include "payloads/function.h" + struct pso_pointer car( #ifndef MANAGED_POINTER_ONLY struct pso4 *frame, diff --git a/src/c/ops/repl.c b/src/c/ops/repl.c new file mode 100644 index 0000000..efc8a3b --- /dev/null +++ b/src/c/ops/repl.c @@ -0,0 +1,90 @@ +/** + * 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/pso2.h" +#include "memory/pso2.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/truth.h" + +/** + * @brief Handle an interrupt signal. + * + * @param dummy + */ +void int_handler( int dummy ) { + wprintf( L"TODO: handle ctrl-C in a more interesting way\n" ); +} + +/** + * Very simple read/eval/print loop for bootstrapping. + */ +void c_repl( ) { + signal( SIGINT, int_handler ); + debug_print( L"Entered repl\n", DEBUG_REPL, 0 ); + + struct pso_pointer env = consp( oblist ) ? oblist : c_cons( oblist, nil ); + struct pso_pointer input_stream = c_assoc( lisp_io_in, env ); + struct pso_pointer output_stream = c_assoc( lisp_io_out, env ); + + while ( readp( input_stream ) + && !url_feof( stream_get_url_file( input_stream ) ) ) { + /* bottom of stack */ + struct pso_pointer frame_pointer = make_frame( 1, nil, input_stream ); + + if ( nilp( frame_pointer ) ) + break; + struct pso_pointer input = read( +#ifndef MANAGED_POINTER_ONLY + pointer_to_pso4( frame_pointer ), +#endif + frame_pointer, env ); + + frame_pointer = make_frame( 1, frame_pointer, input ); + if ( nilp( frame_pointer ) ) + break; + + struct pso_pointer result = eval( +#ifndef MANAGED_POINTER_ONLY + pointer_to_pso4( frame_pointer ), +#endif + frame_pointer, oblist ); + + c_print( result, output_stream ); + + dec_ref( frame_pointer ); + } + + debug_print( L"Leaving repl\n", DEBUG_REPL, 0 ); +} diff --git a/src/c/ops/repl.h b/src/c/ops/repl.h index e5b1a9a..6706539 100644 --- a/src/c/ops/repl.h +++ b/src/c/ops/repl.h @@ -1,15 +1,20 @@ /** - * ops/repl.h + * repl.h * - * The read/eval/print loop. + * Post Scarcity Soctware Environment * - * (c) 2026 Simon Brooke - * Licensed under GPL version 2.0, or, at your option, any later version. + * Read/Eval/Print loop + * + * Copyright (c): 17 Apr 2026 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. */ -#ifndef __psse_ops_repl_h -#define __psse_ops_repl_h +#ifndef SRC_C_OPS_REPL_H_ +#define SRC_C_OPS_REPL_H_ -// struct pso_pointer repl( struct pso_pointer prompt, struct pso_pointer readtable); -#endif + +void c_repl( ); + + +#endif /* SRC_C_OPS_REPL_H_ */ diff --git a/src/c/payloads/read_stream.c b/src/c/payloads/read_stream.c index 995d454..a0b0876 100644 --- a/src/c/payloads/read_stream.c +++ b/src/c/payloads/read_stream.c @@ -1,5 +1,5 @@ /** - * payloads/read_stream.h + * payloads/read_stream.c * * A read stream. * diff --git a/src/c/payloads/write_stream.c b/src/c/payloads/write_stream.c new file mode 100644 index 0000000..371f32c --- /dev/null +++ b/src/c/payloads/write_stream.c @@ -0,0 +1,36 @@ +/** + * payloads/read_stream.c + * + * A read stream. + * + * (c) 2026 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#include + +#include + +#include "io/fopen.h" +#include "memory/pointer.h" +#include "memory/pso.h" +#include "memory/pso2.h" +#include "memory/tags.h" + + +/** + * Construct a cell which points to a stream open for writing. + * @param input the C stream to wrap. + * @param metadata a pointer to an associaton containing metadata on the stream. + * @return a pointer to the new read stream. + */ +struct pso_pointer make_write_stream( URL_FILE *output, + struct pso_pointer metadata ) { + struct pso_pointer pointer = allocate( WRITETAG, 2 ); + struct pso2 *cell = pointer_to_object( pointer ); + + cell->payload.stream.stream = output; + cell->payload.stream.meta = metadata; + + return pointer; +} diff --git a/src/c/payloads/write_stream.h b/src/c/payloads/write_stream.h index d647575..69de8a4 100644 --- a/src/c/payloads/write_stream.h +++ b/src/c/payloads/write_stream.h @@ -11,4 +11,8 @@ #define __psse_payloads_write_stream_h /* write stream shares a payload with /see read_streem.h */ + +#include "io/fopen.h" +struct pso_pointer make_write_stream( URL_FILE * output, + struct pso_pointer metadata ); #endif diff --git a/src/c/psse.c b/src/c/psse.c index 0c36395..cd9b092 100644 --- a/src/c/psse.c +++ b/src/c/psse.c @@ -20,10 +20,12 @@ #include "debug.h" #include "psse.h" #include "io/io.h" + #include "memory/node.h" #include "memory/pso.h" #include "memory/tags.h" +#include "ops/repl.h" #include "ops/stack_ops.h" #include "ops/truth.h" @@ -65,37 +67,8 @@ void print_options( FILE *stream ) { #endif } -/** - * @brief Handle an interrupt signal. - * - * @param dummy - */ -void int_handler( int dummy ) { - wprintf( L"TODO: handle ctrl-C in a more interesting way\n" ); -} /** - * The read/eval/print loop. - */ -void repl( ) { - signal( SIGINT, int_handler ); - debug_print( L"Entered repl\n", DEBUG_REPL, 0 ); - - struct pso_pointer env = consp( oblist ) ? oblist : c_cons( oblist, nil ); - - /* bottom of stack */ - struct pso_pointer frame_pointer = make_frame( 1, nil, nil, env ); - - if ( !nilp( frame_pointer ) ) { -// lisp_repl( get_stack_frame( frame_pointer ), frame_pointer, env ); - - dec_ref( frame_pointer ); - } - - debug_print( L"Leaving repl\n", DEBUG_REPL, 0 ); -} - - /** * main entry point; parse command line arguments, initialise the environment, * and enter the read-eval-print loop. */ @@ -150,7 +123,8 @@ int main( int argc, char *argv[] ) { fputs( "Failed to initialise node\n", stderr ); exit( 1 ); } - // repl( ); + + c_repl( ); exit( 0 ); } diff --git a/src/templates/codetemplates.xml b/src/templates/codetemplates.xml new file mode 100644 index 0000000..7140a04 --- /dev/null +++ b/src/templates/codetemplates.xml @@ -0,0 +1,66 @@ +