From d69dd0b03ffa30321a1ce4afb84c3a531a04a60d Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Mon, 2 Oct 2023 00:46:12 +0800 Subject: [PATCH] :sparkles: change intg to repl output operand --- src/main.cpp | 2 +- src/nasal_codegen.cpp | 51 ++++++++++++++++++++++++++++++++++++++----- src/nasal_codegen.h | 6 ++++- src/nasal_dbg.h | 2 +- src/nasal_opcode.cpp | 4 ++-- src/nasal_opcode.h | 2 +- src/nasal_vm.cpp | 6 ++--- src/nasal_vm.h | 13 +++++++---- src/repl.cpp | 15 ++++++++----- std/utils.nas | 6 +++++ 10 files changed, 82 insertions(+), 25 deletions(-) create mode 100644 std/utils.nas diff --git a/src/main.cpp b/src/main.cpp index 33bf189..e8ec9b1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -139,7 +139,7 @@ void execute( } // code generator gets parser's ast and import file list to generate code - gen.compile(parse, ld).chkerr(); + gen.compile(parse, ld, false).chkerr(); if (cmd&VM_CODE) { gen.print(std::cout); } diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index afd1729..f93a218 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -79,15 +79,21 @@ void codegen::regist_str(const std::string& str) { void codegen::find_symbol(code_block* node) { auto finder = std::unique_ptr(new symbol_finder); for(const auto& i : finder->do_find(node)) { + // check if symbol conflicts with native function name if (native_function_mapper.count(i.name)) { - die("definition conflicts with native function", i.location); + die("symbol conflicts with native function", i.location); + continue; } + // create new namespace with checking existence of location file if (!experimental_namespace.count(i.location.file)) { experimental_namespace[i.location.file] = {}; } - if (local.empty() && !experimental_namespace.at(i.location.file).count(i.name)) { - experimental_namespace.at(i.location.file).insert(i.name); + // if in global scope, load global symbol into this namespace + auto scope = experimental_namespace.at(i.location.file); + if (local.empty() && !scope.count(i.name)) { + scope.insert(i.name); } + // add symbol for codegen symbol check add_symbol(i.name); } } @@ -477,6 +483,10 @@ void codegen::mcall_hash(call_hash* node) { void codegen::single_def(definition_expr* node) { const auto& str = node->get_variable_name()->get_name(); calc_gen(node->get_value()); + // only generate in repl mode and in global scope + if (need_repl_output && local.empty()) { + emit(op_repl, 0, node->get_location()); + } if (local.empty()) { emit(op_loadg, global_symbol_find(str), node->get_location()); } else { @@ -872,6 +882,10 @@ void codegen::statement_generation(expr* node) { case expr_type::ast_binary: case expr_type::ast_ternary: calc_gen(node); + // only generate in repl mode and in global scope + if (need_repl_output && local.empty()) { + emit(op_repl, 0, node->get_location()); + } emit(op_pop, 0, node->get_location()); break; default: break; @@ -1126,16 +1140,40 @@ void codegen::calc_gen(expr* node) { } } +void codegen::repl_mode_info_output_gen(expr* node) { + switch(node->get_type()) { + case expr_type::ast_id: call_id((identifier*)node); break; + case expr_type::ast_nil: emit(op_pnil, 0, node->get_location()); break; + case expr_type::ast_num: num_gen((number_literal*)node); break; + case expr_type::ast_str: str_gen((string_literal*)node); break; + case expr_type::ast_bool: bool_gen((bool_literal*)node); break; + default: return; + } + // generate repl output operand + emit(op_repl, 0, node->get_location()); + // pop stack + emit(op_pop, 0, node->get_location()); +} + void codegen::block_gen(code_block* node) { for(auto tmp : node->get_expressions()) { switch(tmp->get_type()) { case expr_type::ast_null: break; case expr_type::ast_id: - check_id_exist((identifier*)tmp); break; + if (need_repl_output) { + repl_mode_info_output_gen(tmp); + } else { + check_id_exist((identifier*)tmp); + } + break; case expr_type::ast_nil: case expr_type::ast_num: case expr_type::ast_str: - case expr_type::ast_bool: break; + case expr_type::ast_bool: + if (need_repl_output) { + repl_mode_info_output_gen(tmp); + } + break; case expr_type::ast_cond: cond_gen((condition_expr*)tmp); break; case expr_type::ast_continue: @@ -1177,9 +1215,10 @@ void codegen::ret_gen(return_expr* node) { emit(op_ret, 0, node->get_location()); } -const error& codegen::compile(parse& parse, linker& import) { +const error& codegen::compile(parse& parse, linker& import, bool repl_flag) { init_native_function(); init_file_map(import.get_file_list()); + need_repl_output = repl_flag; in_loop_level.push_back(0); diff --git a/src/nasal_codegen.h b/src/nasal_codegen.h index 0377d1d..05790ed 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -34,6 +34,9 @@ class codegen { private: error err; + // + bool need_repl_output; + // file mapper for file -> index std::unordered_map file_map; void init_file_map(const std::vector&); @@ -121,6 +124,7 @@ private: void binary_gen(binary_operator*); void trino_gen(ternary_operator*); void calc_gen(expr*); + void repl_mode_info_output_gen(expr*); void block_gen(code_block*); void ret_gen(return_expr*); @@ -136,7 +140,7 @@ public: public: codegen() = default; - const error& compile(parse&, linker&); + const error& compile(parse&, linker&, bool); void print(std::ostream&); void symbol_dump(std::ostream&) const; }; diff --git a/src/nasal_dbg.h b/src/nasal_dbg.h index 633d206..397bb7f 100644 --- a/src/nasal_dbg.h +++ b/src/nasal_dbg.h @@ -41,7 +41,7 @@ class dbg:public vm { private: typedef void (dbg::*nasal_vm_func)(); const nasal_vm_func operand_function[op_ret + 1] = { - nullptr, &dbg::o_intg, + nullptr, &dbg::o_repl, &dbg::o_intl, &dbg::o_loadg, &dbg::o_loadl, &dbg::o_loadu, &dbg::o_pnum, &dbg::o_pnil, diff --git a/src/nasal_opcode.cpp b/src/nasal_opcode.cpp index f581997..6977235 100644 --- a/src/nasal_opcode.cpp +++ b/src/nasal_opcode.cpp @@ -3,7 +3,7 @@ namespace nasal { const char* opname[] = { - "exit ", "intg ", "intl ", "loadg ", + "exit ", "repl ", "intl ", "loadg ", "loadl ", "loadu ", "pnum ", "pnil ", "pstr ", "newv ", "newh ", "newf ", "happ ", "para ", "def ", "dyn ", @@ -81,7 +81,7 @@ void codestream::dump(std::ostream& out) const { out << hex << "0x" << num << dec << " (" << nums[num] << ")"; break; case op_callvi: case op_newv: - case op_callfv: case op_intg: + case op_callfv: case op_repl: case op_intl: case op_findex: case op_feach: case op_newf: case op_jmp: case op_jt: diff --git a/src/nasal_opcode.h b/src/nasal_opcode.h index b2cb1ff..98e2459 100644 --- a/src/nasal_opcode.h +++ b/src/nasal_opcode.h @@ -9,7 +9,7 @@ namespace nasal { enum op_code_type:u8 { op_exit, // stop the virtual machine - op_intg, // [deprecated] init global scope + op_repl, // in repl mode: print value on stack top op_intl, // local scope size op_loadg, // load global value op_loadl, // load local value diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index 9a182b4..143e773 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -259,7 +259,7 @@ void vm::run( #ifndef _MSC_VER // using labels as values/computed goto const void* oprs[] = { - &&vmexit, &&intg, &&intl, &&loadg, + &&vmexit, &&repl, &&intl, &&loadg, &&loadl, &&loadu, &&pnum, &&pnil, &&pstr, &&newv, &&newh, &&newf, &&happ, &¶, &&deft, &&dyn, @@ -292,7 +292,7 @@ void vm::run( #else typedef void (vm::*nafunc)(); const nafunc oprs[] = { - nullptr, &vm::o_intg, + nullptr, &vm::o_repl, &vm::o_intl, &vm::o_loadg, &vm::o_loadl, &vm::o_loadu, &vm::o_pnum, &vm::o_pnil, @@ -376,7 +376,7 @@ vmexit: goto *code[++ctx.pc];\ } -intg: exec_nodie(o_intg ); // +imm[pc] (detected at codegen) +repl: exec_nodie(o_repl ); // 0 intl: exec_nodie(o_intl ); // -0 loadg: exec_nodie(o_loadg ); // -1 loadl: exec_nodie(o_loadl ); // -1 diff --git a/src/nasal_vm.h b/src/nasal_vm.h index e69b903..ed7a042 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -41,6 +41,7 @@ protected: /* variables for repl mode */ bool is_repl_mode = false; bool first_exec_flag = true; + bool allow_repl_output = false; /* vm initializing function */ void init( @@ -70,7 +71,7 @@ protected: inline bool cond(var&); /* vm operands */ - inline void o_intg(); + inline void o_repl(); inline void o_intl(); inline void o_loadg(); inline void o_loadl(); @@ -180,6 +181,8 @@ public: void set_detail_report_info(bool flag) {verbose = flag;} /* set repl mode flag */ void set_repl_mode_flag(bool flag) {is_repl_mode = flag;} + /* set repl output flag */ + void set_allow_repl_output_flag(bool flag) {allow_repl_output = flag;} }; inline bool vm::cond(var& val) { @@ -192,9 +195,11 @@ inline bool vm::cond(var& val) { return false; } -inline void vm::o_intg() { - // reserved for another usage - std::cout << "[vm] do nothing\n"; +inline void vm::o_repl() { + // reserved for repl mode stack top value output + if (allow_repl_output) { + std::cout << ctx.top[0] << "\n"; + } } inline void vm::o_intl() { diff --git a/src/repl.cpp b/src/repl.cpp index 602bf81..d749c07 100644 --- a/src/repl.cpp +++ b/src/repl.cpp @@ -96,22 +96,25 @@ bool repl::run() { return false; } - // nasal_opt->do_optimization(nasal_parser->tree()); - if (nasal_codegen->compile(*nasal_parser, *nasal_linker).geterr()) { + nasal_opt->do_optimization(nasal_parser->tree()); + if (nasal_codegen->compile(*nasal_parser, *nasal_linker, true).geterr()) { return false; } - // TODO: gc init stage in this run may cause memory leak, - // because constant strings will be generated again. - // but we could not delete old strings, they maybe still on stack. runtime.run(*nasal_codegen, *nasal_linker, {}); - return true; } void repl::execute() { source = {}; + // mark we are in repl mode info::instance()->in_repl_mode = true; + std::cout << "[nasal-repl] Initializating enviroment...\n"; + // run on pass for initializing basic modules, without output + run(); + // allow output now + runtime.set_allow_repl_output_flag(true); + std::cout << "[nasal-repl] Initialization complete.\n\n"; std::cout << "Nasal REPL interpreter(experimental).\n"; help(); diff --git a/std/utils.nas b/std/utils.nas new file mode 100644 index 0000000..0d2bf41 --- /dev/null +++ b/std/utils.nas @@ -0,0 +1,6 @@ +# utils.nas +# 2023 by ValKmjolnir + +var times_trigger = func(times, count) { + return math.mod(times, count)==0; +} \ No newline at end of file