2022-04-21 19:15:20 +00:00
|
|
|
#include <assert.h>
|
2021-12-10 20:22:16 +00:00
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <stddef.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "apfl.h"
|
|
|
|
|
|
2022-01-02 16:21:16 +00:00
|
|
|
enum repl_mode {
|
|
|
|
|
REPL_TOKENIZER,
|
|
|
|
|
REPL_PARSER,
|
|
|
|
|
REPL_EVAL,
|
|
|
|
|
};
|
|
|
|
|
|
2021-12-10 20:22:16 +00:00
|
|
|
static bool
|
2022-04-15 20:35:36 +00:00
|
|
|
repl_source_reader_cb(void *context, char *buf, size_t *len, bool need)
|
2021-12-10 20:22:16 +00:00
|
|
|
{
|
|
|
|
|
(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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-15 20:35:36 +00:00
|
|
|
static struct apfl_source_reader
|
|
|
|
|
repl_source_reader()
|
|
|
|
|
{
|
|
|
|
|
return (struct apfl_source_reader) {
|
|
|
|
|
.callback = repl_source_reader_cb,
|
|
|
|
|
.opaque = NULL,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-02 16:21:16 +00:00
|
|
|
static int
|
2022-02-08 21:53:13 +00:00
|
|
|
repl_tokenizer(struct apfl_allocator allocator, apfl_tokenizer_ptr tokenizer)
|
2021-12-10 20:22:16 +00:00
|
|
|
{
|
2022-01-02 16:21:16 +00:00
|
|
|
while (true) {
|
|
|
|
|
struct apfl_error err;
|
|
|
|
|
struct apfl_token token;
|
2021-12-10 20:22:16 +00:00
|
|
|
|
2022-01-02 16:21:16 +00:00
|
|
|
switch (apfl_tokenizer_next(tokenizer, false)) {
|
|
|
|
|
case APFL_PARSE_OK:
|
|
|
|
|
token = apfl_tokenizer_get_token(tokenizer);
|
|
|
|
|
apfl_token_print(token, stdout);
|
2022-02-08 21:53:13 +00:00
|
|
|
apfl_token_deinit(allocator, &token);
|
2021-12-15 20:28:44 +00:00
|
|
|
|
2022-01-02 16:21:16 +00:00
|
|
|
break;
|
|
|
|
|
case APFL_PARSE_EOF:
|
|
|
|
|
return 0;
|
|
|
|
|
case APFL_PARSE_ERROR:
|
|
|
|
|
err = apfl_tokenizer_get_error(tokenizer);
|
|
|
|
|
apfl_error_print(err, stderr);
|
2021-12-10 20:22:16 +00:00
|
|
|
|
2022-01-02 16:21:16 +00:00
|
|
|
if (APFL_ERROR_IS_FATAL(err)) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-12-15 20:28:44 +00:00
|
|
|
}
|
2022-01-02 16:21:16 +00:00
|
|
|
}
|
2021-12-15 20:28:44 +00:00
|
|
|
|
2022-04-21 19:15:20 +00:00
|
|
|
static int
|
|
|
|
|
repl_parser(struct apfl_allocator allocator, apfl_parser_ptr parser)
|
2022-01-02 16:21:16 +00:00
|
|
|
{
|
2021-12-10 20:22:16 +00:00
|
|
|
while (true) {
|
2022-04-21 19:15:20 +00:00
|
|
|
struct apfl_expr expr;
|
2021-12-10 20:22:16 +00:00
|
|
|
struct apfl_error err;
|
|
|
|
|
|
2021-12-15 20:28:44 +00:00
|
|
|
switch (apfl_parser_next(parser)) {
|
2021-12-10 20:22:16 +00:00
|
|
|
case APFL_PARSE_OK:
|
2022-04-21 19:15:20 +00:00
|
|
|
expr = apfl_parser_get_expr(parser);
|
2022-04-22 20:52:53 +00:00
|
|
|
assert(apfl_expr_print(expr, stdout));
|
2022-04-21 19:15:20 +00:00
|
|
|
apfl_expr_deinit(allocator, &expr);
|
|
|
|
|
break;
|
2021-12-10 20:22:16 +00:00
|
|
|
case APFL_PARSE_EOF:
|
2022-04-21 19:15:20 +00:00
|
|
|
return 0;
|
2021-12-10 20:22:16 +00:00
|
|
|
case APFL_PARSE_ERROR:
|
2021-12-15 20:28:44 +00:00
|
|
|
err = apfl_parser_get_error(parser);
|
2021-12-10 20:22:16 +00:00
|
|
|
apfl_error_print(err, stderr);
|
|
|
|
|
|
|
|
|
|
if (APFL_ERROR_IS_FATAL(err)) {
|
2022-04-21 19:15:20 +00:00
|
|
|
return 1;
|
2021-12-10 20:22:16 +00:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-02 16:21:16 +00:00
|
|
|
}
|
|
|
|
|
|
2022-04-21 19:15:20 +00:00
|
|
|
static int repl_parser_or_tokenizer(enum repl_mode mode)
|
2022-01-02 16:21:16 +00:00
|
|
|
{
|
2022-04-21 19:15:20 +00:00
|
|
|
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 */);
|
2022-01-02 16:21:16 +00:00
|
|
|
}
|
2022-04-21 19:15:20 +00:00
|
|
|
|
|
|
|
|
exit:
|
|
|
|
|
apfl_parser_destroy(parser);
|
|
|
|
|
apfl_tokenizer_destroy(tokenizer);
|
|
|
|
|
|
2022-01-02 16:21:16 +00:00
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-24 21:13:44 +00:00
|
|
|
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)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-02 16:21:16 +00:00
|
|
|
static int
|
2022-04-21 19:15:20 +00:00
|
|
|
repl_eval(void)
|
2022-01-02 16:21:16 +00:00
|
|
|
{
|
2022-04-21 19:15:20 +00:00
|
|
|
int rv = 0;
|
|
|
|
|
|
|
|
|
|
apfl_ctx ctx = apfl_ctx_new(apfl_allocator_default());
|
|
|
|
|
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)) {
|
2022-04-21 20:40:27 +00:00
|
|
|
case APFL_RESULT_OK :
|
2022-06-05 20:06:33 +00:00
|
|
|
assert(apfl_debug_print_val(ctx, -1, apfl_format_file_writer(stdout)));
|
2022-01-02 16:21:16 +00:00
|
|
|
break;
|
|
|
|
|
case APFL_RESULT_ERR:
|
2022-06-24 21:13:44 +00:00
|
|
|
dump_stack_error(ctx, runner);
|
2022-01-02 16:21:16 +00:00
|
|
|
fprintf(stderr, "Error occurred during evaluation.\n");
|
|
|
|
|
break;
|
|
|
|
|
case APFL_RESULT_ERR_FATAL:
|
2022-06-24 21:13:44 +00:00
|
|
|
dump_stack_error(ctx, runner);
|
2022-01-02 16:21:16 +00:00
|
|
|
fprintf(stderr, "Fatal error occurred during evaluation.\n");
|
2022-04-21 19:15:20 +00:00
|
|
|
rv = 1;
|
|
|
|
|
goto exit;
|
2022-01-02 16:21:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
2022-04-21 19:15:20 +00:00
|
|
|
|
|
|
|
|
exit:
|
|
|
|
|
apfl_iterative_runner_destroy(runner);
|
|
|
|
|
apfl_ctx_destroy(ctx);
|
2022-01-02 16:21:16 +00:00
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main(int argc, const char **argv)
|
|
|
|
|
{
|
2022-07-15 19:57:35 +00:00
|
|
|
enum repl_mode mode = REPL_EVAL;
|
2022-01-02 16:21:16 +00:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-21 19:15:20 +00:00
|
|
|
if (mode == REPL_EVAL) {
|
|
|
|
|
return repl_eval();
|
|
|
|
|
} else {
|
|
|
|
|
return repl_parser_or_tokenizer(mode);
|
2022-01-02 16:21:16 +00:00
|
|
|
}
|
2021-12-10 20:22:16 +00:00
|
|
|
}
|