Some changes to how streams work, clean up alisp.org
This commit is contained in:
27
alisp.h
27
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
|
||||
|
||||
31
alisp.org
31
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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
5
main.c
5
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);
|
||||
|
||||
Reference in New Issue
Block a user