#include "../debug.h" #include "../line-ed/line-ed.h" #include "cmd.h" #include #include #include #include #include #include #include #include #include #include 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 *_) { 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"); 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."); } }