Redo source reader interface

The callback and the opaque data are now grouped together in a struct
instead of being passed individually into the tokenizer.

This also exposes the string source reader struct and therefore removes
the need of heap allocating it. Neat!
This commit is contained in:
Laria 2022-04-15 22:35:36 +02:00
parent 70c3d6e3e4
commit b7c88635d9
6 changed files with 75 additions and 67 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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);
}

View file

@ -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,
};
}

View file

@ -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;
}

View file

@ -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);
}