diff --git a/src/apfl.h b/src/apfl.h index 799a20a..fbd6c57 100644 --- a/src/apfl.h +++ b/src/apfl.h @@ -473,9 +473,27 @@ struct apfl_tokenizer; typedef struct apfl_tokenizer *apfl_tokenizer_ptr; -typedef bool (*apfl_source_reader_cb)(void *context, char *buf, size_t *len, bool need); +/* An apfl_source_reader is used to read source code for parsing / evaluation. + */ +struct apfl_source_reader { + /* callback gets called repeatedly to get the source code. + * buf points to a buffer to fill that has a size of *len. + * The callback must set len to the number of read bytes and return true + * on success and false on failure. + * + * Setting len to 0 indicates and end of file. + * + * need is true if more input is required for parsing, this is useful for + * implementing a reader for a REPL to indicate to the user if they need + * to type more code (e.g. by changing the prompt). + */ + bool (*callback)(void *opaque, char *buf, size_t *len, bool need); + + void *opaque; +}; + +apfl_tokenizer_ptr apfl_tokenizer_new(struct apfl_allocator allocator, struct apfl_source_reader); -apfl_tokenizer_ptr apfl_tokenizer_new(struct apfl_allocator allocator, apfl_source_reader_cb, void *context); void apfl_tokenizer_destroy(apfl_tokenizer_ptr); enum apfl_parse_result apfl_tokenizer_next(apfl_tokenizer_ptr, bool need); @@ -492,15 +510,21 @@ struct apfl_token apfl_tokenizer_get_token(apfl_tokenizer_ptr); */ struct apfl_error apfl_tokenizer_get_error(apfl_tokenizer_ptr); - -/* An apfl_source_reader_cb implementation to have a string view as a source. - * Use together with apfl_string_source_reader_new. +/* apfl_string_source_reader_* implements an apfl_source_reader that reads + * source code from a string view. */ -bool apfl_string_source_reader(void *, char *, size_t *len, bool); +struct apfl_string_source_reader_data { + struct apfl_string_view sv; + size_t off; +}; -void *apfl_string_source_reader_new(struct apfl_allocator allocator, struct apfl_string_view); -void apfl_string_source_reader_destroy(void *); +struct apfl_string_source_reader_data apfl_string_source_reader_create(struct apfl_string_view); +/* Creates a source reader for apfl_string_source_reader_data. + * The pointed to apfl_string_source_reader_data and the underlying string view + * must be alive while the reader is in use. + */ +struct apfl_source_reader apfl_string_source_reader(struct apfl_string_source_reader_data *); struct apfl_parser_token_source { enum apfl_parse_result (*next)(void *, bool need); diff --git a/src/main.c b/src/main.c index c3048fc..bd3f6f1 100644 --- a/src/main.c +++ b/src/main.c @@ -12,7 +12,7 @@ enum repl_mode { }; static bool -repl_source_reader(void *context, char *buf, size_t *len, bool need) +repl_source_reader_cb(void *context, char *buf, size_t *len, bool need) { (void)context; @@ -34,6 +34,15 @@ repl_source_reader(void *context, char *buf, size_t *len, bool need) return true; } +static struct apfl_source_reader +repl_source_reader() +{ + return (struct apfl_source_reader) { + .callback = repl_source_reader_cb, + .opaque = NULL, + }; +} + static int repl_tokenizer(struct apfl_allocator allocator, apfl_tokenizer_ptr tokenizer) { @@ -146,7 +155,7 @@ main(int argc, const char **argv) apfl_parser_ptr parser = NULL; apfl_ctx ctx = NULL; - if ((tokenizer = apfl_tokenizer_new(allocator, repl_source_reader, NULL)) == NULL) { + if ((tokenizer = apfl_tokenizer_new(allocator, repl_source_reader())) == NULL) { fprintf(stderr, "Failed initializing tokenizer\n"); rv = 1; goto exit; diff --git a/src/parser_test.c b/src/parser_test.c index c91cb58..e5e36b4 100644 --- a/src/parser_test.c +++ b/src/parser_test.c @@ -9,7 +9,7 @@ struct parser_test { testctx t; struct apfl_allocator allocator; - void *source_reader_ctx; + struct apfl_string_source_reader_data string_source_reader; apfl_tokenizer_ptr tokenizer; apfl_parser_ptr parser; }; @@ -23,11 +23,12 @@ new_parser_test(testctx t, const char *source) pt->t = t; pt->allocator = allocator; - if ((pt->source_reader_ctx = apfl_string_source_reader_new(allocator, apfl_string_view_from(source))) == NULL) { - test_fatalf(t, "Failed initializing source reader"); - } + pt->string_source_reader = apfl_string_source_reader_create(apfl_string_view_from(source)); - if ((pt->tokenizer = apfl_tokenizer_new(allocator, apfl_string_source_reader, pt->source_reader_ctx)) == NULL) { + if ((pt->tokenizer = apfl_tokenizer_new( + allocator, + apfl_string_source_reader(&pt->string_source_reader) + )) == NULL) { test_fatalf(t, "Failed initializing the tokenizer"); } @@ -43,7 +44,6 @@ destroy_parser_test(struct parser_test *pt) { apfl_parser_destroy(pt->parser); apfl_tokenizer_destroy(pt->tokenizer); - apfl_string_source_reader_destroy(pt->source_reader_ctx); free(pt); } diff --git a/src/source_readers.c b/src/source_readers.c index 16195c4..6adcef6 100644 --- a/src/source_readers.c +++ b/src/source_readers.c @@ -3,20 +3,12 @@ #include "apfl.h" -#include "alloc.h" - -struct string_source_reader { - struct apfl_allocator allocator; - struct apfl_string_view sv; - size_t off; -}; - -bool -apfl_string_source_reader(void *opaque, char *buf, size_t *len, bool need) +static bool +reader_callback(void *opaque, char *buf, size_t *len, bool need) { (void)need; - struct string_source_reader *ctx = opaque; + struct apfl_string_source_reader_data *ctx = opaque; size_t maxlen = *len; size_t remain_len = ctx->sv.len - ctx->off; @@ -28,28 +20,19 @@ apfl_string_source_reader(void *opaque, char *buf, size_t *len, bool need) return true; } -void * -apfl_string_source_reader_new(struct apfl_allocator allocator, struct apfl_string_view sv) +struct apfl_string_source_reader_data +apfl_string_source_reader_create(struct apfl_string_view sv) { - struct string_source_reader *ctx = ALLOC_OBJ(allocator, struct string_source_reader); - if (ctx == NULL) { - return NULL; - } - - ctx->allocator = allocator; - ctx->sv = sv; - ctx->off = 0; - - return ctx; + return (struct apfl_string_source_reader_data) { + .sv = sv, + .off = 0, + }; } -void -apfl_string_source_reader_destroy(void *opaque) +struct apfl_source_reader apfl_string_source_reader(struct apfl_string_source_reader_data *data) { - struct string_source_reader *ctx = opaque; - if (ctx == NULL) { - return; - } - - FREE_OBJ(ctx->allocator, ctx); + return (struct apfl_source_reader) { + .callback = reader_callback, + .opaque = data, + }; } diff --git a/src/tokenizer.c b/src/tokenizer.c index 15fd6a5..d445af9 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -16,8 +16,7 @@ static_assert(INT_MAX >= BUFSIZE, "BUFSIZE is too large for type buf_offset"); struct apfl_tokenizer { struct apfl_allocator allocator; - apfl_source_reader_cb source_reader; - void *source_reader_context; + struct apfl_source_reader source_reader; char *buf; buf_offset buf_pos; buf_offset buf_len; @@ -42,7 +41,7 @@ struct apfl_tokenizer { }; apfl_tokenizer_ptr -apfl_tokenizer_new(struct apfl_allocator allocator, apfl_source_reader_cb source_reader, void *context) +apfl_tokenizer_new(struct apfl_allocator allocator, struct apfl_source_reader source_reader) { apfl_tokenizer_ptr tokenizer = ALLOC_OBJ(allocator, struct apfl_tokenizer); if (tokenizer == NULL) { @@ -51,7 +50,6 @@ apfl_tokenizer_new(struct apfl_allocator allocator, apfl_source_reader_cb source tokenizer->allocator = allocator; tokenizer->source_reader = source_reader; - tokenizer->source_reader_context = context; if ((tokenizer->buf = ALLOC_BYTES(allocator, BUFSIZE)) == NULL) { FREE_OBJ(allocator, tokenizer); @@ -110,7 +108,7 @@ read_byte(apfl_tokenizer_ptr tokenizer, char *byte, bool need) tokenizer->buf_pos = 0; tokenizer->buf_len = 0; - if (!tokenizer->source_reader(tokenizer->source_reader_context, tokenizer->buf, &len, need)) { + if (!tokenizer->source_reader.callback(tokenizer->source_reader.opaque, tokenizer->buf, &len, need)) { tokenizer->error.type = APFL_ERR_INPUT_ERROR; return RR_ERR; } diff --git a/src/tokenizer_test.c b/src/tokenizer_test.c index be40829..f4948c0 100644 --- a/src/tokenizer_test.c +++ b/src/tokenizer_test.c @@ -8,7 +8,7 @@ struct tokenizer_test { testctx t; struct apfl_allocator allocator; apfl_tokenizer_ptr tokenizer; - void *ctx; + struct apfl_string_source_reader_data string_source_reader; }; static struct tokenizer_test * @@ -16,25 +16,20 @@ new_tokenizer_test_sv(testctx t, struct apfl_string_view text) { struct apfl_allocator allocator = apfl_allocator_default(); - void *ctx = apfl_string_source_reader_new(allocator, text); - if (ctx == NULL) { - test_fatalf(t, "Failed to initialize the source reader"); - } - - apfl_tokenizer_ptr tokenizer = apfl_tokenizer_new(allocator, apfl_string_source_reader, ctx); - if (tokenizer == NULL) { - test_fatalf(t, "Failed to initialize the tokenizer"); - } - struct tokenizer_test *tt = must_alloc(t, sizeof(struct tokenizer_test)); - *tt = (struct tokenizer_test) { .t = t, .allocator = allocator, - .tokenizer = tokenizer, - .ctx = ctx, + .string_source_reader = apfl_string_source_reader_create(text), }; + if ((tt->tokenizer = apfl_tokenizer_new( + allocator, + apfl_string_source_reader(&tt->string_source_reader) + )) == NULL) { + test_fatalf(t, "Failed to initialize the tokenizer"); + } + return tt; } @@ -48,7 +43,6 @@ new_tokenizer_test(testctx t, const char *text) static void destroy_tokenizer_test(struct tokenizer_test *tt) { - apfl_string_source_reader_destroy(tt->ctx); apfl_tokenizer_destroy(tt->tokenizer); free(tt); }