258 lines
5.7 KiB
C
258 lines
5.7 KiB
C
#include "../debug.h"
|
|
#include "../line-ed/line-ed.h"
|
|
#include "cmd.h"
|
|
|
|
#include <blue/cmd.h>
|
|
#include <blue/term.h>
|
|
#include <ivy/lang/ast.h>
|
|
#include <ivy/lang/codegen.h>
|
|
#include <ivy/lang/lex.h>
|
|
#include <mie/convert.h>
|
|
#include <mie/value.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
enum {
|
|
OPT_SHOW_LEX_TOKENS = 100,
|
|
OPT_SHOW_AST_NODES,
|
|
};
|
|
|
|
struct repl {
|
|
bool r_show_lex, r_show_ast;
|
|
struct line_ed *r_ed;
|
|
struct ivy_lexer *r_lex;
|
|
struct ivy_parser *r_parse;
|
|
struct ivy_codegen *r_codegen;
|
|
struct mie_ir_converter *r_converter;
|
|
};
|
|
|
|
static void skip_line(struct ivy_lexer *lex)
|
|
{
|
|
while (ivy_lexer_tokens_available(lex)) {
|
|
struct ivy_token *tok = ivy_lexer_read(lex);
|
|
bool line_end = (tok->t_type == IVY_TOK_LINEFEED);
|
|
|
|
ivy_token_destroy(tok);
|
|
|
|
if (line_end) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static enum ivy_status add_node_to_codegen(
|
|
struct ivy_ast_node *node, enum ivy_ast_iteration_type iteration_type,
|
|
struct ivy_ast_node_iterator *it, void *arg)
|
|
{
|
|
struct repl *repl = arg;
|
|
return ivy_codegen_push_node(repl->r_codegen, node, iteration_type);
|
|
}
|
|
|
|
static int repl_eval_node(struct repl *repl, struct ivy_ast_node *node)
|
|
{
|
|
struct ivy_ast_node_iterator it = {0};
|
|
struct print_ast_node_args args = {
|
|
.indent = true,
|
|
.postorder = false,
|
|
};
|
|
|
|
if (repl->r_show_ast) {
|
|
ivy_ast_node_iterate(node, &it, print_ast_node, &args);
|
|
}
|
|
|
|
enum ivy_status status
|
|
= ivy_ast_node_iterate(node, &it, add_node_to_codegen, repl);
|
|
if (status != IVY_OK) {
|
|
return -1;
|
|
}
|
|
|
|
struct mie_module *mod = ivy_codegen_get_current_module(repl->r_codegen);
|
|
mie_ir_converter_set_src_value(repl->r_converter, MIE_VALUE(mod));
|
|
mie_ir_converter_process(repl->r_converter);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void repl_destroy(struct repl *repl)
|
|
{
|
|
if (repl->r_converter) {
|
|
mie_ir_converter_destroy(repl->r_converter);
|
|
}
|
|
|
|
if (repl->r_codegen) {
|
|
ivy_codegen_destroy(repl->r_codegen);
|
|
}
|
|
|
|
if (repl->r_parse) {
|
|
ivy_parser_destroy(repl->r_parse);
|
|
}
|
|
|
|
if (repl->r_lex) {
|
|
ivy_lexer_destroy(repl->r_lex);
|
|
}
|
|
|
|
if (repl->r_ed) {
|
|
line_ed_destroy(repl->r_ed);
|
|
}
|
|
|
|
free(repl);
|
|
}
|
|
|
|
static enum ivy_status repl_create(struct repl **out)
|
|
{
|
|
struct repl *repl = malloc(sizeof *repl);
|
|
if (!repl) {
|
|
return IVY_ERR_NO_MEMORY;
|
|
}
|
|
|
|
memset(repl, 0x0, sizeof *repl);
|
|
|
|
repl->r_ed = line_ed_create();
|
|
if (!repl->r_ed) {
|
|
repl_destroy(repl);
|
|
return IVY_ERR_NO_MEMORY;
|
|
}
|
|
|
|
line_ed_set_flags(repl->r_ed, LINE_ED_REMOVE_CONTINUATIONS);
|
|
|
|
enum ivy_status status = ivy_lexer_create(&repl->r_lex);
|
|
if (status != IVY_OK) {
|
|
repl_destroy(repl);
|
|
return status;
|
|
}
|
|
|
|
ivy_lexer_set_source(repl->r_lex, &repl->r_ed->l_line_source);
|
|
|
|
status = ivy_parser_create(&repl->r_parse);
|
|
if (status != IVY_OK) {
|
|
repl_destroy(repl);
|
|
return status;
|
|
}
|
|
|
|
status = ivy_codegen_create(&repl->r_codegen);
|
|
if (status != IVY_OK) {
|
|
repl_destroy(repl);
|
|
return status;
|
|
}
|
|
|
|
repl->r_converter = mie_ir_converter_create(MIE_IR_MEM, MIE_IR_TEXT);
|
|
if (!repl->r_converter) {
|
|
repl_destroy(repl);
|
|
return IVY_ERR_NO_MEMORY;
|
|
}
|
|
|
|
mie_ir_converter_set_dest_file(repl->r_converter, stdout);
|
|
|
|
*out = repl;
|
|
return IVY_OK;
|
|
}
|
|
|
|
int repl(const b_command *cmd, const b_arglist *args, const b_array *_)
|
|
{
|
|
#if 0
|
|
b_printf(
|
|
"[bold,bright_red]error[[E0384][reset,bold,white]: cannot "
|
|
"assign twice to immutable variable `i`[reset]\n");
|
|
b_printf("[bold,bright_blue] -->[reset] src/main.rs:7:3\n");
|
|
b_printf("[bold,bright_blue] |[reset]\n");
|
|
b_printf("[bold,bright_blue]4 |[reset] let i = 0;\n");
|
|
b_printf("[bold,bright_blue] | -[reset]\n");
|
|
b_printf("[bold,bright_blue] | |[reset]\n");
|
|
b_printf(
|
|
"[bold,bright_blue] | first assignment to "
|
|
"`i`[reset]\n");
|
|
b_printf(
|
|
"[bold,bright_blue] | help: make this binding "
|
|
"mutable: `mut i`[reset]\n");
|
|
b_printf("[bold,bright_blue]...[reset]\n");
|
|
b_printf("[bold,bright_blue]7 |[reset] i += 1;\n");
|
|
b_printf(
|
|
"[bold,bright_blue] |[bold,bright_red] ^^^^^^ cannot "
|
|
"assign twice to immutable variable[reset]\n");
|
|
#endif
|
|
|
|
struct repl *repl = NULL;
|
|
enum ivy_status status = repl_create(&repl);
|
|
if (status != IVY_OK) {
|
|
return -1;
|
|
}
|
|
|
|
repl->r_show_lex = b_arglist_get_count(
|
|
args, OPT_SHOW_LEX_TOKENS, B_COMMAND_INVALID_ID)
|
|
> 0;
|
|
repl->r_show_ast = b_arglist_get_count(
|
|
args, OPT_SHOW_AST_NODES, B_COMMAND_INVALID_ID)
|
|
> 0;
|
|
|
|
ivy_codegen_start_module(repl->r_codegen);
|
|
|
|
while (true) {
|
|
struct ivy_token *tok = ivy_lexer_read(repl->r_lex);
|
|
status = ivy_lexer_get_status(repl->r_lex);
|
|
if (status == IVY_ERR_EOF) {
|
|
break;
|
|
}
|
|
|
|
if (status != IVY_OK) {
|
|
b_err("lex error (%s)",
|
|
ivy_status_to_string(
|
|
ivy_lexer_get_status(repl->r_lex)));
|
|
continue;
|
|
}
|
|
|
|
if (repl->r_show_lex) {
|
|
print_lex_token(tok);
|
|
}
|
|
|
|
status = ivy_parser_push_token(repl->r_parse, tok);
|
|
|
|
if (status != IVY_OK) {
|
|
b_err("parse error (%s)", ivy_status_to_string(status));
|
|
ivy_token_destroy(tok);
|
|
skip_line(repl->r_lex);
|
|
continue;
|
|
}
|
|
|
|
if (ivy_lexer_tokens_available(repl->r_lex)) {
|
|
continue;
|
|
}
|
|
|
|
struct ivy_ast_node *child = NULL;
|
|
|
|
while ((child = ivy_parser_dequeue_node(repl->r_parse))) {
|
|
repl_eval_node(repl, child);
|
|
ivy_ast_node_destroy(child);
|
|
}
|
|
}
|
|
|
|
repl_destroy(repl);
|
|
return 0;
|
|
}
|
|
|
|
B_COMMAND(CMD_REPL, CMD_ROOT)
|
|
{
|
|
B_COMMAND_NAME("shell");
|
|
B_COMMAND_SHORT_NAME('S');
|
|
B_COMMAND_DESC("start an interactive Ivy shell.");
|
|
B_COMMAND_HELP_OPTION();
|
|
B_COMMAND_FUNCTION(repl);
|
|
|
|
B_COMMAND_OPTION(OPT_SHOW_LEX_TOKENS)
|
|
{
|
|
B_OPTION_LONG_NAME("show-lex");
|
|
B_OPTION_SHORT_NAME('l');
|
|
B_OPTION_DESC(
|
|
"print the lexical tokens generated from the input.");
|
|
}
|
|
|
|
B_COMMAND_OPTION(OPT_SHOW_AST_NODES)
|
|
{
|
|
B_OPTION_LONG_NAME("show-ast");
|
|
B_OPTION_SHORT_NAME('a');
|
|
B_OPTION_DESC(
|
|
"print the abstract syntax tree generated from the "
|
|
"input.");
|
|
}
|
|
}
|