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 *);
|
stream_err_t stream_init_file(stream_t *, char *, FILE *);
|
||||||
void stream_stop(stream_t *);
|
void stream_stop(stream_t *);
|
||||||
|
|
||||||
// end of stream
|
// End of Content (i.e. we've consumed all cached content/file)
|
||||||
bool stream_eos(stream_t *);
|
|
||||||
// end of cache
|
|
||||||
bool stream_eoc(stream_t *);
|
bool stream_eoc(stream_t *);
|
||||||
|
// size of immediately accessible content
|
||||||
u64 stream_size(stream_t *);
|
u64 stream_size(stream_t *);
|
||||||
|
|
||||||
bool stream_chunk(stream_t *);
|
// Return current character, push position by 1
|
||||||
char stream_next(stream_t *);
|
char stream_next(stream_t *);
|
||||||
|
// Peek current character, do not push position
|
||||||
char stream_peek(stream_t *);
|
char stream_peek(stream_t *);
|
||||||
|
// Seek forward or backward in the stream, return success
|
||||||
bool stream_seek(stream_t *, i64);
|
bool stream_seek(stream_t *, i64);
|
||||||
bool stream_seek_forward(stream_t *, u64);
|
bool stream_seek_forward(stream_t *, u64);
|
||||||
bool stream_seek_backward(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);
|
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);
|
sv_t stream_substr_abs(stream_t *, u64, u64);
|
||||||
|
|
||||||
/// Basic defintions for a Lisp
|
/// Basic defintions for a Lisp
|
||||||
@@ -231,4 +236,18 @@ lisp_t *tag_sym(char *);
|
|||||||
lisp_t *tag_cons(cons_t *);
|
lisp_t *tag_cons(cons_t *);
|
||||||
lisp_t *tag_vec(vec_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
|
#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
|
in order to make calling into this seamless from a runtime
|
||||||
perspective.
|
perspective.
|
||||||
* Tasks
|
* 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
|
Should we capitalise symbols? This way, we limit the symbol table's
|
||||||
possible options a bit (potentially we could design a better hashing
|
possible options a bit (potentially we could design a better hashing
|
||||||
algorithm?) and it would be kinda like an actual Lisp.
|
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
|
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
|
data, we can break out expressions from it. An expression could be
|
||||||
either an atomic value or a container.
|
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
|
~read~ function to do this), but we can also convert an entire stream
|
||||||
into expressions by consuming it fully. So the principle function
|
into expressions by consuming it fully. So the principle function
|
||||||
here is ~read: stream -> expr~.
|
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
|
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
|
our parsing. Lisp is an LL(1) grammar so we only really need one
|
||||||
character lookup, but seeking is very useful.
|
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
|
stream. We can use a tagged union of data structures representing the
|
||||||
different underlying stream types, then generate abstract functions
|
different underlying stream types, then generate abstract functions
|
||||||
that provide common functionality.
|
that provide common functionality.
|
||||||
**** TODO Design the tagged union
|
|
||||||
**** TODO Design the API
|
2025-08-29: A really basic interface that makes the parse stage a bit
|
||||||
#+begin_src c
|
easier. We're not going to do anything more advanced than the API
|
||||||
bool stream_eos(stream_t *);
|
i.e. no parsing.
|
||||||
char stream_next(stream_t *);
|
**** DONE Design the tagged union
|
||||||
char stream_peek(stream_t *);
|
**** DONE Design the API
|
||||||
sv_t stream_substr(stream_t *, u64, u64);
|
*** WIP Figure out the possible parse errors
|
||||||
bool stream_seek(stream_t *, i64);
|
*** DONE Design what a "parser function" would look like
|
||||||
bool stream_close(stream_t *);
|
|
||||||
#+end_src
|
|
||||||
*** TODO Figure out the possible parse errors
|
|
||||||
*** TODO Design what a "parser function" would look like
|
|
||||||
The general function is something like ~stream -> T | Err~. What
|
The general function is something like ~stream -> T | Err~. What
|
||||||
other state do we need to encode?
|
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 symbols
|
||||||
*** TODO Write a parser for lists
|
*** TODO Write a parser for lists
|
||||||
*** TODO Write a parser for vectors
|
*** 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);
|
vec_init(&stream->pipe.cache, STREAM_DEFAULT_CHUNK);
|
||||||
// try to read an initial chunk
|
// try to read an initial chunk
|
||||||
stream_chunk(stream);
|
// stream_chunk(stream);
|
||||||
|
|
||||||
return STREAM_ERR_OK;
|
return STREAM_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
5
main.c
5
main.c
@@ -33,11 +33,11 @@ int main(void)
|
|||||||
// stream_init_file(&stream, "stdin", stdin);
|
// stream_init_file(&stream, "stdin", stdin);
|
||||||
|
|
||||||
/// test 1
|
/// test 1
|
||||||
while (!stream_eoc(&stream))
|
do
|
||||||
{
|
{
|
||||||
printf("%s[%lu]: `%c`\n", stream.name, stream.position,
|
printf("%s[%lu]: `%c`\n", stream.name, stream.position,
|
||||||
stream_next(&stream));
|
stream_next(&stream));
|
||||||
}
|
} while (!stream_eoc(&stream));
|
||||||
printf("%lu/%lu\n", stream.position, stream_size(&stream));
|
printf("%lu/%lu\n", stream.position, stream_size(&stream));
|
||||||
|
|
||||||
/// test 2
|
/// test 2
|
||||||
@@ -61,7 +61,6 @@ int main(void)
|
|||||||
c_.size == d_.size && strncmp(c_.data, d_.data, c_.size) == 0 ? "yes"
|
c_.size == d_.size && strncmp(c_.data, d_.data, c_.size) == 0 ? "yes"
|
||||||
: "no");
|
: "no");
|
||||||
|
|
||||||
printf("eos?=%s\n", stream_eos(&stream) ? "yes" : "no");
|
|
||||||
printf("eoc?=%s\n", stream_eoc(&stream) ? "yes" : "no");
|
printf("eoc?=%s\n", stream_eoc(&stream) ? "yes" : "no");
|
||||||
|
|
||||||
stream_stop(&stream);
|
stream_stop(&stream);
|
||||||
|
|||||||
Reference in New Issue
Block a user