#include #include #include #include #include #include "apfl.h" enum repl_mode { REPL_TOKENIZER, REPL_PARSER, REPL_EVAL, }; static bool repl_source_reader_cb(void *context, char *buf, size_t *len, bool need) { (void)context; printf(need ? "... " : "> "); fflush(stdout); size_t maxlen = *len; if (fgets(buf, maxlen, stdin) == NULL) { if (feof(stdin)) { *len = 0; return true; } else { return false; } } *len = strlen(buf); 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) { while (true) { struct apfl_error err; struct apfl_token token; switch (apfl_tokenizer_next(tokenizer, false)) { case APFL_PARSE_OK: token = apfl_tokenizer_get_token(tokenizer); apfl_token_print(token, stdout); apfl_token_deinit(allocator, &token); break; case APFL_PARSE_EOF: return 0; case APFL_PARSE_ERROR: err = apfl_tokenizer_get_error(tokenizer); apfl_error_print(err, stderr); if (err.type == APFL_ERR_INPUT_ERROR || err.type == APFL_ERR_MALLOC_FAILED) { return 1; } break; } } } static int repl_parser(struct apfl_allocator allocator, apfl_parser_ptr parser) { while (true) { struct apfl_expr expr; struct apfl_error err; switch (apfl_parser_next(parser)) { case APFL_PARSE_OK: expr = apfl_parser_get_expr(parser); assert(apfl_expr_print(expr, stdout)); apfl_expr_deinit(allocator, &expr); break; case APFL_PARSE_EOF: return 0; case APFL_PARSE_ERROR: err = apfl_parser_get_error(parser); apfl_error_print(err, stderr); if (err.type == APFL_ERR_INPUT_ERROR || err.type == APFL_ERR_MALLOC_FAILED) { return 1; } break; } } } static int repl_parser_or_tokenizer(enum repl_mode mode) { int rv = 0; struct apfl_allocator allocator = apfl_allocator_default(); apfl_tokenizer_ptr tokenizer = NULL; apfl_parser_ptr parser = NULL; if ((tokenizer = apfl_tokenizer_new(allocator, repl_source_reader())) == NULL) { fprintf(stderr, "Failed initializing tokenizer\n"); return 1; } if (mode == REPL_PARSER) { if ((parser = apfl_parser_new(allocator, apfl_tokenizer_as_token_source(tokenizer))) == NULL) { fprintf(stderr, "Failed initializing parser\n"); rv = 1; goto exit; } } switch (mode) { case REPL_TOKENIZER: rv = repl_tokenizer(allocator, tokenizer); break; case REPL_PARSER: rv = repl_parser(allocator, parser); break; default: assert(false /* repl_parser_or_tokenizer called with wrong mode */); } exit: apfl_parser_destroy(parser); apfl_tokenizer_destroy(tokenizer); return rv; } static void dump_stack_error(apfl_ctx ctx, apfl_iterative_runner runner) { if (apfl_iterative_runner_has_error_on_stack(runner)) { assert(apfl_debug_print_val(ctx, -1, apfl_format_file_writer(stderr))); } } static int repl_eval(void) { int rv = 0; apfl_ctx ctx = apfl_ctx_new((struct apfl_config) { .allocator = apfl_allocator_default(), .output_writer = apfl_format_file_writer(stdout), }); if (ctx == NULL) { fprintf(stderr, "Failed to init the context\n"); return 1; } apfl_iterative_runner runner = apfl_iterative_runner_new(ctx, repl_source_reader()); if (runner == NULL) { apfl_ctx_destroy(ctx); fprintf(stderr, "Failed to init runner\n"); return 1; } while (apfl_iterative_runner_next(runner)) { switch (apfl_iterative_runner_get_result(runner)) { case APFL_RESULT_OK : if (apfl_get_type(ctx, -1) == APFL_VALUE_NIL) { apfl_drop(ctx, -1); } else { assert(apfl_debug_print_val(ctx, -1, apfl_format_file_writer(stdout))); } break; case APFL_RESULT_ERR: dump_stack_error(ctx, runner); fprintf(stderr, "Error occurred during evaluation.\n"); break; case APFL_RESULT_ERR_ALLOC: fprintf(stderr, "Fatal: Could not allocate memory.\n"); rv = 1; goto exit; } } if (apfl_iterative_runner_stopped_because_of_error(runner)) { rv = 1; } exit: apfl_iterative_runner_destroy(runner); apfl_ctx_destroy(ctx); return rv; } int main(int argc, const char **argv) { enum repl_mode mode = REPL_EVAL; if (argc > 1) { if (apfl_string_eq(argv[1], "tokenizer")) { mode = REPL_TOKENIZER; } else if (apfl_string_eq(argv[1], "parser")) { mode = REPL_PARSER; } else if (apfl_string_eq(argv[1], "eval")) { mode = REPL_EVAL; } else { fprintf(stderr, "Unknown mode: %s\n", argv[1]); return 1; } } if (mode == REPL_EVAL) { return repl_eval(); } else { return repl_parser_or_tokenizer(mode); } }