From 030a289497db1fcbd22eafb99d7d8827bca94563 Mon Sep 17 00:00:00 2001 From: Aryadev Chavali Date: Mon, 1 Sep 2025 21:47:25 +0100 Subject: Some changes to how streams work, clean up alisp.org --- alisp.h | 27 +++++++++++++++++++++++---- alisp.org | 31 +++++++++++++++---------------- impl/stream.c | 2 +- main.c | 5 ++--- 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/alisp.h b/alisp.h index 41c507c..a1f1748 100644 --- a/alisp.h +++ b/alisp.h @@ -136,19 +136,24 @@ stream_err_t stream_init_string(stream_t *, char *, sv_t); stream_err_t stream_init_file(stream_t *, char *, FILE *); void stream_stop(stream_t *); -// end of stream -bool stream_eos(stream_t *); -// end of cache +// End of Content (i.e. we've consumed all cached content/file) bool stream_eoc(stream_t *); +// size of immediately accessible content u64 stream_size(stream_t *); -bool stream_chunk(stream_t *); +// Return current character, push position by 1 char stream_next(stream_t *); +// Peek current character, do not push position char stream_peek(stream_t *); +// Seek forward or backward in the stream, return success bool stream_seek(stream_t *, i64); bool stream_seek_forward(stream_t *, u64); bool stream_seek_backward(stream_t *, u64); + +// Return a relative substring (using sv_t) of a given size sv_t stream_substr(stream_t *, u64); +// Return an absolutely located substring (using sv_t) at given index and of +// given size. sv_t stream_substr_abs(stream_t *, u64, u64); /// Basic defintions for a Lisp @@ -231,4 +236,18 @@ lisp_t *tag_sym(char *); lisp_t *tag_cons(cons_t *); lisp_t *tag_vec(vec_t *); +/// Reader +typedef enum +{ + READ_OK = 0, +} read_err_t; + +// Attempt to read an expression from the stream, storing it in a pointer, +// returning any errors if failed +read_err_t read(sys_t *, stream_t *, lisp_t **); + +// Attempt to read all expressions from a stream till end of content, storing +// them in the given vector. Return any error at any point during the read. +read_err_t read_all(sys_t *, stream_t *, vec_t *); + #endif diff --git a/alisp.org b/alisp.org index bbeb97d..be27f37 100644 --- a/alisp.org +++ b/alisp.org @@ -38,11 +38,14 @@ seamless in that regard. But we'll need to set a calling convention in order to make calling into this seamless from a runtime perspective. * Tasks -** TODO Potentially optimise symbol table ingress :optimisation:design: +** TODO Capitalise symbols (TBD) :optimisation:design: Should we capitalise symbols? This way, we limit the symbol table's possible options a bit (potentially we could design a better hashing algorithm?) and it would be kinda like an actual Lisp. -** TODO Reader system +** TODO Design Strings +We have ~sv_t~ so our basic C API is done. We just need pluggable +functions to construct and deconstruct strings as lisps. +** WIP Reader system We need to design a reader system. The big idea: given a "stream" of data, we can break out expressions from it. An expression could be either an atomic value or a container. @@ -51,7 +54,7 @@ The natural method is doing this one at a time (the runtime provides a ~read~ function to do this), but we can also convert an entire stream into expressions by consuming it fully. So the principle function here is ~read: stream -> expr~. -*** TODO Design streams +*** DONE Design streams A stream needs to be able to provide characters for us to interpret in our parsing. Lisp is an LL(1) grammar so we only really need one character lookup, but seeking is very useful. @@ -74,21 +77,17 @@ parsing isn't as concerned with the specifics of the underlying data stream. We can use a tagged union of data structures representing the different underlying stream types, then generate abstract functions that provide common functionality. -**** TODO Design the tagged union -**** TODO Design the API -#+begin_src c -bool stream_eos(stream_t *); -char stream_next(stream_t *); -char stream_peek(stream_t *); -sv_t stream_substr(stream_t *, u64, u64); -bool stream_seek(stream_t *, i64); -bool stream_close(stream_t *); -#+end_src -*** TODO Figure out the possible parse errors -*** TODO Design what a "parser function" would look like + +2025-08-29: A really basic interface that makes the parse stage a bit +easier. We're not going to do anything more advanced than the API +i.e. no parsing. +**** DONE Design the tagged union +**** DONE Design the API +*** WIP Figure out the possible parse errors +*** DONE Design what a "parser function" would look like The general function is something like ~stream -> T | Err~. What other state do we need to encode? -*** TODO Write a parser for integers +*** WIP Write a parser for integers *** TODO Write a parser for symbols *** TODO Write a parser for lists *** TODO Write a parser for vectors diff --git a/impl/stream.c b/impl/stream.c index dd264cd..878ca6c 100644 --- a/impl/stream.c +++ b/impl/stream.c @@ -43,7 +43,7 @@ stream_err_t stream_init_file(stream_t *stream, char *name, FILE *pipe) vec_init(&stream->pipe.cache, STREAM_DEFAULT_CHUNK); // try to read an initial chunk - stream_chunk(stream); + // stream_chunk(stream); return STREAM_ERR_OK; } diff --git a/main.c b/main.c index a44a3a6..4db6f68 100644 --- a/main.c +++ b/main.c @@ -33,11 +33,11 @@ int main(void) // stream_init_file(&stream, "stdin", stdin); /// test 1 - while (!stream_eoc(&stream)) + do { printf("%s[%lu]: `%c`\n", stream.name, stream.position, stream_next(&stream)); - } + } while (!stream_eoc(&stream)); printf("%lu/%lu\n", stream.position, stream_size(&stream)); /// test 2 @@ -61,7 +61,6 @@ int main(void) c_.size == d_.size && strncmp(c_.data, d_.data, c_.size) == 0 ? "yes" : "no"); - printf("eos?=%s\n", stream_eos(&stream) ? "yes" : "no"); printf("eoc?=%s\n", stream_eoc(&stream) ? "yes" : "no"); stream_stop(&stream); -- cgit v1.2.3-13-gbd6f