diff --git a/module/keyboard.cpp b/module/keyboard.cpp index 45b54e2..0cdeb72 100644 --- a/module/keyboard.cpp +++ b/module/keyboard.cpp @@ -51,7 +51,7 @@ public: return 1; } int flag = fcntl(0, F_GETFL); - fcntl(0, F_SETFL,flag|O_NONBLOCK); + fcntl(0, F_SETFL, flag|O_NONBLOCK); nread = read(0, &ch, 1); fcntl(0, F_SETFL, flag); if (nread==1) { @@ -83,25 +83,25 @@ public: noecho_input this_window; var nas_getch(var* args, usize size, gc* ngc) { - return var::num((double)this_window.noecho_getch()); + return var::num(static_cast(this_window.noecho_getch())); } var nas_kbhit(var* args, usize size, gc* ngc) { - return var::num((double)this_window.noecho_kbhit()); + return var::num(static_cast(this_window.noecho_kbhit())); } var nas_noblock(var* args, usize size, gc* ngc) { if (this_window.noecho_kbhit()) { - return var::num((double)this_window.noecho_getch()); + return var::num(static_cast(this_window.noecho_getch())); } return nil; } module_func_info func_tbl[] = { - {"nas_getch",nas_getch}, - {"nas_kbhit",nas_kbhit}, - {"nas_noblock",nas_noblock}, - {nullptr,nullptr} + {"nas_getch", nas_getch}, + {"nas_kbhit", nas_kbhit}, + {"nas_noblock", nas_noblock}, + {nullptr, nullptr} }; extern "C" module_func_info* get() { diff --git a/module/nasocket.cpp b/module/nasocket.cpp index a879479..6208321 100644 --- a/module/nasocket.cpp +++ b/module/nasocket.cpp @@ -34,16 +34,16 @@ var nas_socket(var* args, usize size, gc* ngc) { if (args[0].type!=vm_num || args[1].type!=vm_num || args[2].type!=vm_num) return nas_err("socket", "\"af\", \"type\", \"protocol\" should be number"); int sd = socket(args[0].num(), args[1].num(), args[2].num()); - return var::num((double)sd); + return var::num(static_cast(sd)); } var nas_closesocket(var* args, usize size, gc* ngc) { if (args[0].type!=vm_num) return nas_err("closesocket", "\"sd\" should be number"); #ifdef _WIN32 - return var::num((double)closesocket(args[0].num())); + return var::num(static_cast(closesocket(args[0].num()))); #else - return var::num((double)close(args[0].num())); + return var::num(static_cast(close(args[0].num()))); #endif } @@ -52,7 +52,7 @@ var nas_shutdown(var* args, usize size, gc* ngc) { return nas_err("shutdown", "\"sd\" must be a number"); if (args[1].type!=vm_num) return nas_err("shutdown", "\"how\" must be a number"); - return var::num((double)shutdown(args[0].num(), args[1].num())); + return var::num(static_cast(shutdown(args[0].num(), args[1].num()))); } var nas_bind(var* args, usize size, gc* ngc) { @@ -67,7 +67,11 @@ var nas_bind(var* args, usize size, gc* ngc) { server.sin_family = AF_INET; server.sin_addr.s_addr = inet_addr(args[1].str().c_str()); server.sin_port = htons(args[2].num()); - return var::num((double)bind(args[0].num(), (sockaddr*)&server, sizeof(server))); + return var::num(static_cast(bind( + args[0].num(), + (sockaddr*)&server, + sizeof(server) + ))); } var nas_listen(var* args, usize size, gc* ngc) { @@ -75,7 +79,7 @@ var nas_listen(var* args, usize size, gc* ngc) { return nas_err("listen", "\"sd\" must be a number"); if (args[1].type!=vm_num) return nas_err("listen", "\"backlog\" must be a number"); - return var::num((double)listen(args[0].num(), args[1].num())); + return var::num(static_cast(listen(args[0].num(), args[1].num()))); } var nas_connect(var* args, usize size, gc* ngc) { @@ -91,11 +95,11 @@ var nas_connect(var* args, usize size, gc* ngc) { addr.sin_port = htons(args[2].num()); hostent* entry = gethostbyname(args[1].str().c_str()); memcpy(&addr.sin_addr, entry->h_addr, entry->h_length); - return var::num((double)connect( + return var::num(static_cast(connect( args[0].num(), (sockaddr*)&addr, sizeof(sockaddr_in) - )); + ))); } var nas_accept(var* args, usize size, gc* ngc) { @@ -110,7 +114,7 @@ var nas_accept(var* args, usize size, gc* ngc) { #endif var res=ngc->temp = ngc->alloc(vm_hash); auto& hash = res.hash().elems; - hash["sd"] = var::num((double)client_sd); + hash["sd"] = var::num(static_cast(client_sd)); hash["ip"] = ngc->newstr(inet_ntoa(client.sin_addr)); ngc->temp = nil; return res; @@ -123,12 +127,12 @@ var nas_send(var* args, usize size, gc* ngc) { return nas_err("send", "\"buff\" must be a string"); if (args[2].type!=vm_num) return nas_err("send", "\"flags\" muse be a number"); - return var::num((double)send( + return var::num(static_cast(send( args[0].num(), args[1].str().c_str(), args[1].str().length(), args[2].num() - )); + ))); } var nas_sendto(var* args, usize size, gc* ngc) { @@ -148,14 +152,14 @@ var nas_sendto(var* args, usize size, gc* ngc) { addr.sin_port = htons(args[2].num()); hostent* entry = gethostbyname(args[1].str().c_str()); memcpy(&addr.sin_addr, entry->h_addr, entry->h_length); - return var::num((double)sendto( + return var::num(static_cast(sendto( args[0].num(), args[3].str().c_str(), args[3].str().length(), args[4].num(), (sockaddr*)&addr, sizeof(sockaddr_in) - )); + ))); } var nas_recv(var* args, usize size, gc* ngc) { @@ -169,9 +173,9 @@ var nas_recv(var* args, usize size, gc* ngc) { return nas_err("recv", "\"flags\" muse be a number"); var res = ngc->temp = ngc->alloc(vm_hash); auto& hash = res.hash().elems; - char* buf = new char[(int)args[1].num()]; + char* buf = new char[static_cast(args[1].num())]; auto recvsize = recv(args[0].num(), buf,args[1].num(), args[2].num()); - hash["size"] = var::num((double)recvsize); + hash["size"] = var::num(static_cast(recvsize)); buf[recvsize>=0? recvsize:0] = 0; hash["str"] = ngc->newstr(buf); delete[] buf; @@ -192,7 +196,7 @@ var nas_recvfrom(var* args, usize size, gc* ngc) { int socklen = sizeof(sockaddr_in); var res = ngc->temp = ngc->alloc(vm_hash); auto& hash = res.hash().elems; - char* buf = new char[(int)args[1].num()+1]; + char* buf = new char[static_cast(args[1].num()+1)]; #ifdef _WIN32 auto recvsize = recvfrom( args[0].num(), @@ -212,7 +216,7 @@ var nas_recvfrom(var* args, usize size, gc* ngc) { (socklen_t*)&socklen ); #endif - hash["size"] = var::num((double)recvsize); + hash["size"] = var::num(static_cast(recvsize)); buf[recvsize>=0? recvsize:0] = 0; hash["str"] = ngc->newstr(buf); delete[] buf; diff --git a/src/main.cpp b/src/main.cpp index c3d538b..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); } @@ -192,7 +192,7 @@ i32 main(i32 argc, const char* argv[]) { } // execute with arguments - const std::unordered_map cmdlst = { + const std::unordered_map cmdlst = { {"--raw-ast", VM_RAW_AST}, {"--ast", VM_AST}, {"-a", VM_AST}, diff --git a/src/nasal_ast.h b/src/nasal_ast.h index 6e04e84..76ffd6a 100644 --- a/src/nasal_ast.h +++ b/src/nasal_ast.h @@ -62,7 +62,7 @@ protected: public: expr(const span& location, expr_type node_type): nd_loc(location), nd_type(node_type) {} - ~expr() = default; + virtual ~expr() = default; void set_begin(u32 line, u32 column) { nd_loc.begin_line = line; nd_loc.begin_column = column; @@ -81,7 +81,7 @@ class call:public expr { public: call(const span& location, expr_type node_type): expr(location, node_type) {} - ~call() = default; + virtual ~call() = default; virtual void accept(ast_visitor*); }; @@ -89,7 +89,7 @@ class null_expr:public expr { public: null_expr(const span& location): expr(location, expr_type::ast_null) {} - ~null_expr() = default; + ~null_expr() override = default; void accept(ast_visitor*) override; }; @@ -97,7 +97,7 @@ class nil_expr:public expr { public: nil_expr(const span& location): expr(location, expr_type::ast_nil) {} - ~nil_expr() = default; + ~nil_expr() override = default; void accept(ast_visitor*) override; }; @@ -108,7 +108,7 @@ private: public: number_literal(const span& location, const f64 num): expr(location, expr_type::ast_num), number(num) {} - ~number_literal() = default; + ~number_literal() override = default; f64 get_number() const {return number;} void accept(ast_visitor*) override; }; @@ -120,7 +120,7 @@ private: public: string_literal(const span& location, const std::string& str): expr(location, expr_type::ast_str), content(str) {} - ~string_literal() = default; + ~string_literal() override = default; const std::string get_content() const {return content;} void accept(ast_visitor*) override; }; @@ -132,8 +132,8 @@ private: public: identifier(const span& location, const std::string& str): expr(location, expr_type::ast_id), name(str) {} - ~identifier() = default; - const std::string get_name() const {return name;} + ~identifier() override = default; + const std::string& get_name() const {return name;} void accept(ast_visitor*) override; }; @@ -144,7 +144,7 @@ private: public: bool_literal(const span& location, const bool bool_flag): expr(location, expr_type::ast_bool), flag(bool_flag) {} - ~bool_literal() = default; + ~bool_literal() override = default; bool get_flag() const {return flag;} void accept(ast_visitor*) override; }; @@ -156,7 +156,7 @@ private: public: vector_expr(const span& location): expr(location, expr_type::ast_vec) {} - ~vector_expr(); + ~vector_expr() override; void add_element(expr* node) {elements.push_back(node);} std::vector& get_elements() {return elements;} void accept(ast_visitor*) override; @@ -169,7 +169,7 @@ private: public: hash_expr(const span& location): expr(location, expr_type::ast_hash) {} - ~hash_expr(); + ~hash_expr() override; void add_member(hash_pair* node) {members.push_back(node);} std::vector& get_members() {return members;} void accept(ast_visitor*) override; @@ -184,7 +184,7 @@ public: hash_pair(const span& location): expr(location, expr_type::ast_pair), value(nullptr) {} - ~hash_pair(); + ~hash_pair() override; void set_name(const std::string& field_name) {name = field_name;} void set_value(expr* node) {value = node;} const std::string& get_name() const {return name;} @@ -201,7 +201,7 @@ public: function(const span& location): expr(location, expr_type::ast_func), block(nullptr) {} - ~function(); + ~function() override; void add_parameter(parameter* node) {parameter_list.push_back(node);} void set_code_block(code_block* node) {block = node;} std::vector& get_parameter_list() {return parameter_list;} @@ -216,7 +216,7 @@ private: public: code_block(const span& location): expr(location, expr_type::ast_block) {} - ~code_block(); + ~code_block() override; void add_expression(expr* node) {expressions.push_back(node);} std::vector& get_expressions() {return expressions;} void accept(ast_visitor*) override; @@ -239,7 +239,7 @@ public: parameter(const span& location): expr(location, expr_type::ast_param), name(""), default_value(nullptr) {} - ~parameter(); + ~parameter() override; void set_parameter_type(param_type pt) {type = pt;} void set_parameter_name(const std::string& pname) {name = pname;} void set_default_value(expr* node) {default_value = node;} @@ -259,7 +259,7 @@ public: ternary_operator(const span& location): expr(location, expr_type::ast_ternary), condition(nullptr), left(nullptr), right(nullptr) {} - ~ternary_operator(); + ~ternary_operator() override; void set_condition(expr* node) {condition = node;} void set_left(expr* node) {left = node;} void set_right(expr* node) {right = node;} @@ -303,7 +303,7 @@ public: left(nullptr), right(nullptr), optimized_const_number(nullptr), optimized_const_string(nullptr) {} - ~binary_operator(); + ~binary_operator() override; void set_operator_type(binary_type operator_type) {type = operator_type;} void set_left(expr* node) {left = node;} void set_right(expr* node) {right = node;} @@ -334,7 +334,7 @@ public: unary_operator(const span& location): expr(location, expr_type::ast_unary), value(nullptr), optimized_number(nullptr) {} - ~unary_operator(); + ~unary_operator() override; void set_operator_type(unary_type operator_type) {type = operator_type;} void set_value(expr* node) {value = node;} void set_optimized_number(number_literal* node) {optimized_number = node;} @@ -353,7 +353,7 @@ public: call_expr(const span& location): expr(location, expr_type::ast_call), first(nullptr) {} - ~call_expr(); + ~call_expr() override; void set_first(expr* node) {first = node;} void add_call(call* node) {calls.push_back(node);} expr* get_first() {return first;} @@ -369,7 +369,7 @@ public: call_hash(const span& location, const std::string& name): call(location, expr_type::ast_callh), field(name) {} - ~call_hash() = default; + ~call_hash() override = default; const std::string& get_field() const {return field;} void accept(ast_visitor*) override; }; @@ -381,7 +381,7 @@ private: public: call_vector(const span& location): call(location, expr_type::ast_callv) {} - ~call_vector(); + ~call_vector() override; void add_slice(slice_vector* node) {calls.push_back(node);} std::vector& get_slices() {return calls;} void accept(ast_visitor*) override; @@ -394,7 +394,7 @@ private: public: call_function(const span& location): call(location, expr_type::ast_callf) {} - ~call_function(); + ~call_function() override; void add_argument(expr* node) {args.push_back(node);} std::vector& get_argument() {return args;} void accept(ast_visitor*) override; @@ -409,7 +409,7 @@ public: slice_vector(const span& location): expr(location, expr_type::ast_subvec), begin(nullptr), end(nullptr) {} - ~slice_vector(); + ~slice_vector() override; void set_begin(expr* node) {begin = node;} void set_end(expr* node) {end = node;} expr* get_begin() {return begin;} @@ -429,7 +429,7 @@ public: expr(location, expr_type::ast_def), variable_name(nullptr), variables(nullptr), tuple(nullptr), value(nullptr) {} - ~definition_expr(); + ~definition_expr() override; void set_identifier(identifier* node) {variable_name = node;} void set_multi_define(multi_identifier* node) {variables = node;} void set_tuple(tuple_expr* node) {tuple = node;} @@ -464,7 +464,7 @@ public: assignment_expr(const span& location): expr(location, expr_type::ast_assign), left(nullptr), right(nullptr) {} - ~assignment_expr(); + ~assignment_expr() override; void set_assignment_type(assign_type operator_type) {type = operator_type;} void set_left(expr* node) {left = node;} void set_right(expr* node) {right = node;} @@ -481,7 +481,7 @@ private: public: multi_identifier(const span& location): expr(location, expr_type::ast_multi_id) {} - ~multi_identifier(); + ~multi_identifier() override; void add_var(identifier* node) {variables.push_back(node);} std::vector& get_variables() {return variables;} void accept(ast_visitor*) override; @@ -494,7 +494,7 @@ private: public: tuple_expr(const span& location): expr(location, expr_type::ast_tuple) {} - ~tuple_expr(); + ~tuple_expr() override; void add_element(expr* node) {elements.push_back(node);} std::vector& get_elements() {return elements;} void accept(ast_visitor*) override; @@ -509,7 +509,7 @@ public: multi_assign(const span& location): expr(location, expr_type::ast_multi_assign), tuple(nullptr), value(nullptr) {} - ~multi_assign(); + ~multi_assign() override; void set_tuple(tuple_expr* node) {tuple = node;} void set_value(expr* node) {value = node;} tuple_expr* get_tuple() {return tuple;} @@ -526,7 +526,7 @@ public: while_expr(const span& location): expr(location, expr_type::ast_while), condition(nullptr), block(nullptr) {} - ~while_expr(); + ~while_expr() override; void set_condition(expr* node) {condition = node;} void set_code_block (code_block* node) {block = node;} expr* get_condition() {return condition;} @@ -546,7 +546,7 @@ public: expr(location, expr_type::ast_for), initializing(nullptr), condition(nullptr), step(nullptr), block(nullptr) {} - ~for_expr(); + ~for_expr() override; void set_initial(expr* node) {initializing = node;} void set_condition(expr* node) {condition = node;} void set_step(expr* node) {step = node;} @@ -567,7 +567,7 @@ public: iter_expr(const span& location): expr(location, expr_type::ast_iter), name(nullptr), call(nullptr) {} - ~iter_expr(); + ~iter_expr() override; void set_name(identifier* node) {name = node;} void set_call(call_expr* node) {call = node;} identifier* get_name() {return name;} @@ -593,7 +593,7 @@ public: expr(location, expr_type::ast_forei), type(forei_loop_type::foreach), iterator(nullptr), vector_node(nullptr), block(nullptr) {} - ~forei_expr(); + ~forei_expr() override; void set_loop_type(forei_loop_type ft) {type = ft;} void set_iterator(iter_expr* node) {iterator = node;} void set_value(expr* node) {vector_node = node;} @@ -615,7 +615,7 @@ public: condition_expr(const span& location): expr(location, expr_type::ast_cond), if_stmt(nullptr), else_stmt(nullptr) {} - ~condition_expr(); + ~condition_expr() override; void set_if_statement(if_expr* node) {if_stmt = node;} void add_elsif_statement(if_expr* node) {elsif_stmt.push_back(node);} void set_else_statement(if_expr* node) {else_stmt = node;} @@ -634,7 +634,7 @@ public: if_expr(const span& location): expr(location, expr_type::ast_if), condition(nullptr), block(nullptr) {} - ~if_expr(); + ~if_expr() override; void set_condition(expr* node) {condition = node;} void set_code_block(code_block* node) {block = node;} expr* get_condition() {return condition;} @@ -646,7 +646,7 @@ class continue_expr:public expr { public: continue_expr(const span& location): expr(location, expr_type::ast_continue) {} - ~continue_expr() = default; + ~continue_expr() override = default; void accept(ast_visitor*) override; }; @@ -666,7 +666,7 @@ public: return_expr(const span& location): expr(location, expr_type::ast_ret), value(nullptr) {} - ~return_expr(); + ~return_expr() override; void set_value(expr* node) {value = node;} expr* get_value() {return value;} void accept(ast_visitor*) override; diff --git a/src/nasal_builtin.cpp b/src/nasal_builtin.cpp index 8d078d1..11fc253 100644 --- a/src/nasal_builtin.cpp +++ b/src/nasal_builtin.cpp @@ -307,7 +307,9 @@ var builtin_substr(var* local, gc& ngc) { var builtin_streq(var* local, gc& ngc) { var a = local[1]; var b = local[2]; - return var::num(f64((a.type!=vm_str || b.type!=vm_str)? 0:(a.str()==b.str()))); + return var::num(static_cast( + (a.type!=vm_str || b.type!=vm_str)? 0:(a.str()==b.str()) + )); } var builtin_left(var* local, gc& ngc) { @@ -410,9 +412,11 @@ var builtin_sleep(var* local, gc& ngc) { #if defined(_WIN32) && !defined(_GLIBCXX_HAS_GTHREADS) // mingw-w64 win32 thread model has no std::this_thread // also msvc will use this - Sleep(i64(val.num()*1e3)); + Sleep(static_cast(val.num()*1e3)); #else - std::this_thread::sleep_for(std::chrono::microseconds(i64(val.num()*1e6))); + std::this_thread::sleep_for( + std::chrono::microseconds(static_cast(val.num()*1e6)) + ); #endif return nil; } @@ -469,7 +473,7 @@ std::string md5(const std::string& src) { usize buffsize = num<<4; buff.resize(buffsize,0); for(usize i = 0; i>2] |= ((u8)src[i])<<((i&0x3)<<3); + buff[i>>2] |= (static_cast(src[i]))<<((i&0x3)<<3); } buff[src.length()>>2] |= 0x80<<(((src.length()%4))<<3); buff[buffsize-2] = (src.length()<<3)&0xffffffff; diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index 1b3c6d6..f93a218 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -37,23 +37,25 @@ void codegen::check_id_exist(identifier* node) { if (native_function_mapper.count(name)) { if (local.empty()) { die("native function should not be used in global scope", - node->get_location()); + node->get_location() + ); } return; } - if (local_find(name)>=0) { + if (local_symbol_find(name)>=0) { return; } - if (upvalue_find(name)>=0) { + if (upvalue_symbol_find(name)>=0) { return; } - if (global_find(name)>=0) { + if (global_symbol_find(name)>=0) { return; } die("undefined symbol \"" + name + "\", and this symbol is useless here", - node->get_location()); + node->get_location() + ); } void codegen::regist_num(const f64 num) { @@ -77,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); } } @@ -106,18 +114,18 @@ void codegen::add_symbol(const std::string& name) { local.back()[name] = index; } -i32 codegen::local_find(const std::string& name) { +i32 codegen::local_symbol_find(const std::string& name) { if (local.empty()) { return -1; } return local.back().count(name)? local.back().at(name):-1; } -i32 codegen::global_find(const std::string& name) { +i32 codegen::global_symbol_find(const std::string& name) { return global.count(name)? global.at(name):-1; } -i32 codegen::upvalue_find(const std::string& name) { +i32 codegen::upvalue_symbol_find(const std::string& name) { // 32768 level 65536 upvalues i32 index = -1; usize size = local.size(); @@ -133,44 +141,47 @@ i32 codegen::upvalue_find(const std::string& name) { return index; } -void codegen::gen(u8 operation_code, u32 num, const span& loc) { - code.push_back({operation_code, - static_cast(file_map.at(loc.file)), - num, loc.begin_line}); +void codegen::emit(u8 operation_code, u32 immediate_num, const span& location) { + code.push_back({ + operation_code, + static_cast(file_map.at(location.file)), + immediate_num, + location.begin_line + }); } void codegen::num_gen(number_literal* node) { f64 num = node->get_number(); regist_num(num); - gen(op_pnum, const_number_map.at(num), node->get_location()); + emit(op_pnum, const_number_map.at(num), node->get_location()); } void codegen::str_gen(string_literal* node) { const auto& str = node->get_content(); regist_str(str); - gen(op_pstr, const_string_map.at(str), node->get_location()); + emit(op_pstr, const_string_map.at(str), node->get_location()); } void codegen::bool_gen(bool_literal* node) { f64 num = node->get_flag()? 1:0; regist_num(num); - gen(op_pnum, const_number_map.at(num), node->get_location()); + emit(op_pnum, const_number_map.at(num), node->get_location()); } void codegen::vec_gen(vector_expr* node) { for(auto child : node->get_elements()) { calc_gen(child); } - gen(op_newv, node->get_elements().size(), node->get_location()); + emit(op_newv, node->get_elements().size(), node->get_location()); } void codegen::hash_gen(hash_expr* node) { - gen(op_newh, 0, node->get_location()); + emit(op_newh, 0, node->get_location()); for(auto child : node->get_members()) { calc_gen(child->get_value()); const auto& field_name = child->get_name(); regist_str(field_name); - gen(op_happ, const_string_map.at(field_name), child->get_location()); + emit(op_happ, const_string_map.at(field_name), child->get_location()); } } @@ -182,37 +193,40 @@ void codegen::func_gen(function* node) { for(auto tmp : node->get_parameter_list()) { if (tmp->get_parameter_type()== parameter::param_type::default_parameter) { - checked_default=true; + checked_default = true; } else if (tmp->get_parameter_type()== parameter::param_type::dynamic_parameter) { - checked_dynamic=true; + checked_dynamic = true; } // check default parameter and dynamic parameter if (checked_default && tmp->get_parameter_type()!= parameter::param_type::default_parameter) { die("must use default parameter here", - tmp->get_location()); + tmp->get_location() + ); } if (checked_dynamic && tmp!=node->get_parameter_list().back()) { die("dynamic parameter must be the last one", - tmp->get_location()); + tmp->get_location() + ); } // check redefinition const auto& name = tmp->get_parameter_name(); if (argname.count(name)) { die("redefinition of parameter: " + name, - tmp->get_location()); + tmp->get_location() + ); } else { argname[name] = true; } } usize newf=code.size(); - gen(op_newf, 0, node->get_location()); + emit(op_newf, 0, node->get_location()); usize lsize=code.size(); - gen(op_intl, 0, node->get_location()); + emit(op_intl, 0, node->get_location()); // add special keyword 'me' into symbol table // this symbol is only used in local scope(function's scope) @@ -226,19 +240,20 @@ void codegen::func_gen(function* node) { const auto& name = tmp->get_parameter_name(); if (name=="me") { die("\"me\" should not be a parameter", - tmp->get_location()); + tmp->get_location() + ); } regist_str(name); switch(tmp->get_parameter_type()) { case parameter::param_type::normal_parameter: - gen(op_para, const_string_map.at(name), tmp->get_location()); + emit(op_para, const_string_map.at(name), tmp->get_location()); break; case parameter::param_type::default_parameter: calc_gen(tmp->get_default_value()); - gen(op_deft, const_string_map.at(name), tmp->get_location()); + emit(op_deft, const_string_map.at(name), tmp->get_location()); break; case parameter::param_type::dynamic_parameter: - gen(op_dyn, const_string_map.at(name), tmp->get_location()); + emit(op_dyn, const_string_map.at(name), tmp->get_location()); break; } add_symbol(name); @@ -246,12 +261,14 @@ void codegen::func_gen(function* node) { code[newf].num = code.size()+1; // entry usize jmp_ptr = code.size(); - gen(op_jmp, 0, node->get_location()); + emit(op_jmp, 0, node->get_location()); auto block = node->get_code_block(); + // search symbols first, must use after loading parameters // or the location of symbols will change and cause fatal error find_symbol(block); + // add special varibale "arg", which is used to store overflowed args // but if dynamic parameter is declared, this variable will be useless // for example: @@ -262,7 +279,7 @@ void codegen::func_gen(function* node) { // var f = func(a, arg...) {return(arg)} auto arg = std::string("arg"); // this is used to avoid confliction with defined parameter - while(local_find(arg)>=0) { + while(local_symbol_find(arg)>=0) { arg = "0" + arg; } add_symbol(arg); @@ -273,14 +290,15 @@ void codegen::func_gen(function* node) { code[lsize].num = local.back().size(); if (local.back().size()>=STACK_DEPTH) { die("too many local variants: " + - std::to_string(local.back().size()), block->get_location()); + std::to_string(local.back().size()), block->get_location() + ); } local.pop_back(); if (!block->get_expressions().size() || block->get_expressions().back()->get_type()!=expr_type::ast_ret) { - gen(op_pnil, 0, block->get_location()); - gen(op_ret, 0, block->get_location()); + emit(op_pnil, 0, block->get_location()); + emit(op_ret, 0, block->get_location()); } code[jmp_ptr].num = code.size(); } @@ -303,27 +321,29 @@ void codegen::call_gen(call_expr* node) { void codegen::call_id(identifier* node) { const auto& name = node->get_name(); if (native_function_mapper.count(name)) { - gen(op_callb, + emit(op_callb, static_cast(native_function_mapper.at(name)), - node->get_location()); + node->get_location() + ); if (local.empty()) { die("should warp native function in local scope", - node->get_location()); + node->get_location() + ); } return; } i32 index; - if ((index=local_find(name))>=0) { - gen(op_calll, index, node->get_location()); + if ((index = local_symbol_find(name))>=0) { + emit(op_calll, index, node->get_location()); return; } - if ((index=upvalue_find(name))>=0) { - gen(op_upval, index, node->get_location()); + if ((index = upvalue_symbol_find(name))>=0) { + emit(op_upval, index, node->get_location()); return; } - if ((index=global_find(name))>=0) { - gen(op_callg, index, node->get_location()); + if ((index = global_symbol_find(name))>=0) { + emit(op_callg, index, node->get_location()); return; } die("undefined symbol \"" + name + "\"", node->get_location()); @@ -331,7 +351,7 @@ void codegen::call_id(identifier* node) { void codegen::call_hash_gen(call_hash* node) { regist_str(node->get_field()); - gen(op_callh, const_string_map.at(node->get_field()), node->get_location()); + emit(op_callh, const_string_map.at(node->get_field()), node->get_location()); } void codegen::call_vector_gen(call_vector* node) { @@ -339,39 +359,39 @@ void codegen::call_vector_gen(call_vector* node) { if (node->get_slices().size()==1 && !node->get_slices()[0]->get_end()) { calc_gen(node->get_slices()[0]->get_begin()); - gen(op_callv, 0, node->get_slices()[0]->get_location()); + emit(op_callv, 0, node->get_slices()[0]->get_location()); return; } - gen(op_slcbeg, 0, node->get_location()); + emit(op_slcbeg, 0, node->get_location()); for(auto tmp : node->get_slices()) { if (!tmp->get_end()) { calc_gen(tmp->get_begin()); - gen(op_slc, 0, tmp->get_location()); + emit(op_slc, 0, tmp->get_location()); } else { calc_gen(tmp->get_begin()); calc_gen(tmp->get_end()); - gen(op_slc2, 0, tmp->get_location()); + emit(op_slc2, 0, tmp->get_location()); } } - gen(op_slcend, 0, node->get_location()); + emit(op_slcend, 0, node->get_location()); } void codegen::call_func_gen(call_function* node) { if (node->get_argument().size() && node->get_argument()[0]->get_type()==expr_type::ast_pair) { - gen(op_newh, 0, node->get_location()); + emit(op_newh, 0, node->get_location()); for(auto child : node->get_argument()) { calc_gen(((hash_pair*)child)->get_value()); const auto& field_name = ((hash_pair*)child)->get_name(); regist_str(field_name); - gen(op_happ, const_string_map.at(field_name), child->get_location()); + emit(op_happ, const_string_map.at(field_name), child->get_location()); } - gen(op_callfh, 0, node->get_location()); + emit(op_callfh, 0, node->get_location()); } else { for(auto child : node->get_argument()) { calc_gen(child); } - gen(op_callfv, node->get_argument().size(), node->get_location()); + emit(op_callfv, node->get_argument().size(), node->get_location()); } } @@ -386,14 +406,16 @@ void codegen::call_func_gen(call_function* node) { void codegen::mcall(expr* node) { if (node->get_type()!=expr_type::ast_id && node->get_type()!=expr_type::ast_call) { - die("bad left-value", node->get_location()); + die("bad left-value: cannot get memory space", node->get_location()); return; } + // generate symbol call if node is just ast_id and return if (node->get_type()==expr_type::ast_id) { mcall_id((identifier*)node); return; } - auto call_node = (call_expr*)node; + // generate call expression until the last sub-node + auto call_node = static_cast(node); calc_gen(call_node->get_first()); for(usize i = 0; iget_calls().size()-1; ++i) { auto tmp = call_node->get_calls()[i]; @@ -404,15 +426,15 @@ void codegen::mcall(expr* node) { default: break; } } + // the last sub-node will be used to generate memory call expression auto tmp = call_node->get_calls().back(); - if (tmp->get_type()==expr_type::ast_callh) { - mcall_hash((call_hash*)tmp); - } else if (tmp->get_type()==expr_type::ast_callv) { - mcall_vec((call_vector*)tmp); - } else if (tmp->get_type()==expr_type::ast_callf) { - die("bad left-value: function call", tmp->get_location()); - } else { - die("bad left-value: unknown call", tmp->get_location()); + switch(tmp->get_type()) { + case expr_type::ast_callh: mcall_hash((call_hash*)tmp); break; + case expr_type::ast_callv: mcall_vec((call_vector*)tmp); break; + case expr_type::ast_callf: + die("bad left-value: function call", tmp->get_location()); break; + default: + die("bad left-value: unknown call", tmp->get_location()); break; } } @@ -424,16 +446,16 @@ void codegen::mcall_id(identifier* node) { } i32 index; - if ((index=local_find(name))>=0) { - gen(op_mcalll, index, node->get_location()); + if ((index = local_symbol_find(name))>=0) { + emit(op_mcalll, index, node->get_location()); return; } - if ((index=upvalue_find(name))>=0) { - gen(op_mupval, index, node->get_location()); + if ((index = upvalue_symbol_find(name))>=0) { + emit(op_mupval, index, node->get_location()); return; } - if ((index=global_find(name))>=0) { - gen(op_mcallg, index, node->get_location()); + if ((index = global_symbol_find(name))>=0) { + emit(op_mcallg, index, node->get_location()); return; } die("undefined symbol \"" + name + "\"", node->get_location()); @@ -450,20 +472,26 @@ void codegen::mcall_vec(call_vector* node) { return; } calc_gen(call->get_begin()); - gen(op_mcallv, 0, node->get_location()); + emit(op_mcallv, 0, node->get_location()); } void codegen::mcall_hash(call_hash* node) { regist_str(node->get_field()); - gen(op_mcallh, const_string_map.at(node->get_field()), node->get_location()); + emit(op_mcallh, const_string_map.at(node->get_field()), node->get_location()); } void codegen::single_def(definition_expr* node) { const auto& str = node->get_variable_name()->get_name(); calc_gen(node->get_value()); - local.empty()? - gen(op_loadg, global_find(str), node->get_location()): - gen(op_loadl, local_find(str), node->get_location()); + // 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 { + emit(op_loadl, local_symbol_find(str), node->get_location()); + } } void codegen::multi_def(definition_expr* node) { @@ -474,30 +502,32 @@ void codegen::multi_def(definition_expr* node) { auto& vals = node->get_tuple()->get_elements(); if (identifiers.size()get_tuple()->get_location()); + node->get_tuple()->get_location() + ); } else if (identifiers.size()>vals.size()) { die("too many values in multi-definition", - node->get_tuple()->get_location()); + node->get_tuple()->get_location() + ); } for(usize i = 0; iget_name(); local.empty()? - gen(op_loadg, global_find(name), identifiers[i]->get_location()): - gen(op_loadl, local_find(name), identifiers[i]->get_location()); + emit(op_loadg, global_symbol_find(name), identifiers[i]->get_location()): + emit(op_loadl, local_symbol_find(name), identifiers[i]->get_location()); } return; } // (var a,b,c) = [0,1,2]; calc_gen(node->get_value()); for(usize i = 0; iget_value()->get_location()); + emit(op_callvi, i, node->get_value()->get_location()); const auto& name = identifiers[i]->get_name(); local.empty()? - gen(op_loadg, global_find(name), identifiers[i]->get_location()): - gen(op_loadl, local_find(name), identifiers[i]->get_location()); + emit(op_loadg, global_symbol_find(name), identifiers[i]->get_location()): + emit(op_loadl, local_symbol_find(name), identifiers[i]->get_location()); } - gen(op_pop, 0, node->get_location()); + emit(op_pop, 0, node->get_location()); } void codegen::def_gen(definition_expr* node) { @@ -512,7 +542,7 @@ void codegen::assignment_expression(assignment_expr* node) { case assignment_expr::assign_type::equal: calc_gen(node->get_right()); mcall(node->get_left()); - gen(op_meq, 0, node->get_location()); + emit(op_meq, 0, node->get_location()); break; case assignment_expr::assign_type::add_equal: if (node->get_right()->get_type()!=expr_type::ast_num) { @@ -520,11 +550,11 @@ void codegen::assignment_expression(assignment_expr* node) { } mcall(node->get_left()); if (node->get_right()->get_type()!=expr_type::ast_num) { - gen(op_addeq, 0, node->get_location()); + emit(op_addeq, 0, node->get_location()); } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_addeqc, const_number_map[num], node->get_location()); + emit(op_addeqc, const_number_map[num], node->get_location()); } break; case assignment_expr::assign_type::sub_equal: @@ -533,11 +563,11 @@ void codegen::assignment_expression(assignment_expr* node) { } mcall(node->get_left()); if (node->get_right()->get_type()!=expr_type::ast_num) { - gen(op_subeq, 0, node->get_location()); + emit(op_subeq, 0, node->get_location()); } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_subeqc, const_number_map[num], node->get_location()); + emit(op_subeqc, const_number_map[num], node->get_location()); } break; case assignment_expr::assign_type::mult_equal: @@ -546,11 +576,11 @@ void codegen::assignment_expression(assignment_expr* node) { } mcall(node->get_left()); if (node->get_right()->get_type()!=expr_type::ast_num) { - gen(op_muleq, 0, node->get_location()); + emit(op_muleq, 0, node->get_location()); } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_muleqc, const_number_map[num], node->get_location()); + emit(op_muleqc, const_number_map[num], node->get_location()); } break; case assignment_expr::assign_type::div_equal: @@ -559,11 +589,11 @@ void codegen::assignment_expression(assignment_expr* node) { } mcall(node->get_left()); if (node->get_right()->get_type()!=expr_type::ast_num) { - gen(op_diveq, 0, node->get_location()); + emit(op_diveq, 0, node->get_location()); } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_diveqc, const_number_map[num], node->get_location()); + emit(op_diveqc, const_number_map[num], node->get_location()); } break; case assignment_expr::assign_type::concat_equal: @@ -572,53 +602,77 @@ void codegen::assignment_expression(assignment_expr* node) { } mcall(node->get_left()); if (node->get_right()->get_type()!=expr_type::ast_str) { - gen(op_lnkeq, 0, node->get_location()); + emit(op_lnkeq, 0, node->get_location()); } else { const auto& str = ((string_literal*)node->get_right())->get_content(); regist_str(str); - gen(op_lnkeqc, const_string_map[str], node->get_location()); + emit(op_lnkeqc, const_string_map[str], node->get_location()); } break; case assignment_expr::assign_type::bitwise_and_equal: calc_gen(node->get_right()); mcall(node->get_left()); - gen(op_btandeq, 0, node->get_location()); + emit(op_btandeq, 0, node->get_location()); break; case assignment_expr::assign_type::bitwise_or_equal: calc_gen(node->get_right()); mcall(node->get_left()); - gen(op_btoreq, 0, node->get_location()); + emit(op_btoreq, 0, node->get_location()); break; case assignment_expr::assign_type::bitwise_xor_equal: calc_gen(node->get_right()); mcall(node->get_left()); - gen(op_btxoreq, 0, node->get_location()); + emit(op_btxoreq, 0, node->get_location()); break; } } +void codegen::gen_assignment_equal_statement(assignment_expr* node) { + // if is not symbol load type assignment, use calc_gen directly + // what is symbol load assignment? example: + // a = 1; # this is symbol load + // a.foo = "bar"; # this is not symbol load + if (node->get_left()->get_type()!=expr_type::ast_id) { + calc_gen(node); + if (code.back().op==op_meq) { + code.back().num = 1; // 1 means need pop after op_meq + } else { + emit(op_pop, 0, node->get_location()); + } + return; + } + + // generate symbol load + calc_gen(node->get_right()); + // get memory space of left identifier + mcall_id((identifier*)node->get_left()); + // check memory get operand type and replace it with load operand + switch(code.back().op) { + case op_mcallg: code.back().op = op_loadg; break; + case op_mcalll: code.back().op = op_loadl; break; + case op_mupval: code.back().op = op_loadu; break; + default: die("unexpected operand to replace", node->get_location()); + } +} + +void codegen::replace_left_assignment_with_load(const span& location) { + // replace mcall with load, + // because mcall needs meq(1) (meq-pop) after it to load, + // but load to mcall-meq-pop in one operand. + // if is not mcall operand, emit meq(1) (meq-pop). + switch(code.back().op) { + case op_mcallg: code.back().op = op_loadg; break; + case op_mcalll: code.back().op = op_loadl; break; + case op_mupval: code.back().op = op_loadu; break; + default: emit(op_meq, 1, location); break; + } + return; +} + void codegen::assignment_statement(assignment_expr* node) { switch(node->get_assignment_type()) { case assignment_expr::assign_type::equal: - if (node->get_left()->get_type()==expr_type::ast_id) { - calc_gen(node->get_right()); - mcall_id((identifier*)node->get_left()); - // only the first mcall_id can use load - if (code.back().op==op_mcalll) { - code.back().op=op_loadl; - } else if (code.back().op==op_mupval) { - code.back().op=op_loadu; - } else { - code.back().op=op_loadg; - } - } else { - calc_gen(node); - if (code.back().op==op_meq) { - code.back().num=1; - } else { - gen(op_pop, 0, node->get_location()); - } - } + gen_assignment_equal_statement(node); break; case assignment_expr::assign_type::add_equal: case assignment_expr::assign_type::sub_equal: @@ -630,11 +684,11 @@ void codegen::assignment_statement(assignment_expr* node) { case assignment_expr::assign_type::bitwise_xor_equal: calc_gen(node); if (op_addeq<=code.back().op && code.back().op<=op_btxoreq) { - code.back().num=1; + code.back().num = 1; } else if (op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) { - code.back().op=code.back().op-op_addeqc+op_addecp; + code.back().op = code.back().op-op_addeqc+op_addecp; } else { - gen(op_pop, 0, node->get_location()); + emit(op_pop, 0, node->get_location()); } break; } @@ -648,7 +702,9 @@ void codegen::multi_assign_gen(multi_assign* node) { node->get_tuple()->get_elements().size()>((tuple_expr*)node->get_value())->get_elements().size()) { die("too many values in multi-assignment", node->get_value()->get_location()); } + i32 size = node->get_tuple()->get_elements().size(); + // generate multiple assignment: (a, b, c) = (1, 2, 3); if (node->get_value()->get_type()==expr_type::ast_tuple) { for(i32 i = size-1; i>=0; --i) { calc_gen(((tuple_expr*)node->get_value())->get_elements()[i]); @@ -656,63 +712,50 @@ void codegen::multi_assign_gen(multi_assign* node) { auto& tuple = node->get_tuple()->get_elements(); for(i32 i = 0; iget_location()); - } + replace_left_assignment_with_load(tuple[i]->get_location()); } return; } + + // generate multiple assignment: (a, b, c) = [1, 2, 3]; calc_gen(node->get_value()); auto& tuple = node->get_tuple()->get_elements(); for(i32 i = 0; iget_value()->get_location()); - // multi assign user loadl and loadg to avoid meq's stack-- - // and this operation changes local and global value directly + emit(op_callvi, i, node->get_value()->get_location()); mcall(tuple[i]); - if (code.back().op==op_mcalll) { - code.back().op=op_loadl; - } else if (code.back().op==op_mupval) { - code.back().op=op_loadu; - } else if (code.back().op==op_mcallg) { - code.back().op=op_loadg; - } else { - gen(op_meq, 1, tuple[i]->get_location()); - } + // use load operands to avoid meq's pop operand + // and this operation changes local and global value directly + replace_left_assignment_with_load(tuple[i]->get_location()); } - gen(op_pop, 0, node->get_location()); + // pop source vector + emit(op_pop, 0, node->get_location()); } void codegen::cond_gen(condition_expr* node) { std::vector jmp_label; calc_gen(node->get_if_statement()->get_condition()); auto ptr = code.size(); - gen(op_jf, 0, node->get_if_statement()->get_location()); + emit(op_jf, 0, node->get_if_statement()->get_location()); block_gen(node->get_if_statement()->get_code_block()); if (node->get_elsif_stataments().size() || node->get_else_statement()) { jmp_label.push_back(code.size()); - gen(op_jmp, 0, node->get_if_statement()->get_location()); + emit(op_jmp, 0, node->get_if_statement()->get_location()); } code[ptr].num = code.size(); for(auto tmp : node->get_elsif_stataments()) { calc_gen(tmp->get_condition()); ptr = code.size(); - gen(op_jf, 0, tmp->get_location()); + emit(op_jf, 0, tmp->get_location()); block_gen(tmp->get_code_block()); // the last condition doesn't need to jmp if (tmp!=node->get_elsif_stataments().back() || node->get_else_statement()) { jmp_label.push_back(code.size()); - gen(op_jmp, 0, tmp->get_location()); + emit(op_jmp, 0, tmp->get_location()); } code[ptr].num=code.size(); } @@ -729,12 +772,9 @@ void codegen::loop_gen(expr* node) { continue_ptr.push_front({}); break_ptr.push_front({}); switch(node->get_type()) { - case expr_type::ast_while: - while_gen((while_expr*)node); break; - case expr_type::ast_for: - for_gen((for_expr*)node); break; - case expr_type::ast_forei: - forei_gen((forei_expr*)node); break; + case expr_type::ast_while: while_gen((while_expr*)node); break; + case expr_type::ast_for: for_gen((for_expr*)node); break; + case expr_type::ast_forei: forei_gen((forei_expr*)node); break; default: break; } } @@ -754,10 +794,10 @@ void codegen::while_gen(while_expr* node) { usize loop_ptr = code.size(); calc_gen(node->get_condition()); usize condition_ptr = code.size(); - gen(op_jf, 0, node->get_condition()->get_location()); + emit(op_jf, 0, node->get_condition()->get_location()); block_gen(node->get_code_block()); - gen(op_jmp, loop_ptr, node->get_code_block()->get_location()); + emit(op_jmp, loop_ptr, node->get_code_block()->get_location()); code[condition_ptr].num = code.size(); load_continue_break(code.size()-1, code.size()); } @@ -767,17 +807,17 @@ void codegen::for_gen(for_expr* node) { usize jmp_place = code.size(); if (node->get_condition()->get_type()==expr_type::ast_null) { regist_num(1); - gen(op_pnum, const_number_map.at(1), node->get_condition()->get_location()); + emit(op_pnum, const_number_map.at(1), node->get_condition()->get_location()); } else { calc_gen(node->get_condition()); } usize label_exit = code.size(); - gen(op_jf, 0, node->get_condition()->get_location()); + emit(op_jf, 0, node->get_condition()->get_location()); block_gen(node->get_code_block()); usize continue_place = code.size(); statement_generation(node->get_step()); - gen(op_jmp, jmp_place, node->get_step()->get_location()); + emit(op_jmp, jmp_place, node->get_step()->get_location()); code[label_exit].num = code.size(); load_continue_break(continue_place, code.size()); @@ -785,39 +825,40 @@ void codegen::for_gen(for_expr* node) { void codegen::forei_gen(forei_expr* node) { calc_gen(node->get_value()); - gen(op_cnt, 0, node->get_value()->get_location()); - usize ptr = code.size(); + emit(op_cnt, 0, node->get_value()->get_location()); + usize loop_begin = code.size(); if (node->get_loop_type()==forei_expr::forei_loop_type::forindex) { - gen(op_findex, 0, node->get_location()); + emit(op_findex, 0, node->get_location()); } else { - gen(op_feach, 0, node->get_location()); + emit(op_feach, 0, node->get_location()); } - if (node->get_iterator()->get_name()) { // define a new iterator + if (node->get_iterator()->get_name()) { + // define a new iterator auto name_node = node->get_iterator()->get_name(); const auto& str = name_node->get_name(); local.empty()? - gen(op_loadg, global_find(str), name_node->get_location()): - gen(op_loadl, local_find(str), name_node->get_location()); - } else { // use exist variable as the iterator + emit(op_loadg, global_symbol_find(str), name_node->get_location()): + emit(op_loadl, local_symbol_find(str), name_node->get_location()); + } else { + // use exist variable as the iterator mcall(node->get_iterator()->get_call()); - if (code.back().op==op_mcallg) { - code.back().op=op_loadg; - } else if (code.back().op==op_mcalll) { - code.back().op=op_loadl; - } else if (code.back().op==op_mupval) { - code.back().op=op_loadu; - } else { - gen(op_meq, 1, node->get_iterator()->get_location()); - } + replace_left_assignment_with_load(node->get_iterator()->get_location()); } + + // generate code block ++in_loop_level.back(); block_gen(node->get_code_block()); --in_loop_level.back(); - gen(op_jmp, ptr, node->get_location()); - code[ptr].num=code.size(); + + // jump to loop begin + emit(op_jmp, loop_begin, node->get_location()); + code[loop_begin].num=code.size(); load_continue_break(code.size()-1, code.size()); - gen(op_pop, 0, node->get_value()->get_location());// pop vector - gen(op_pop, 0, node->get_location());// pop iterator + + // pop source vector + emit(op_pop, 0, node->get_value()->get_location()); + // pop loop iterator + emit(op_pop, 0, node->get_location()); } void codegen::statement_generation(expr* node) { @@ -841,7 +882,11 @@ void codegen::statement_generation(expr* node) { case expr_type::ast_binary: case expr_type::ast_ternary: calc_gen(node); - gen(op_pop, 0, node->get_location()); + // 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; } @@ -850,33 +895,33 @@ void codegen::statement_generation(expr* node) { void codegen::or_gen(binary_operator* node) { calc_gen(node->get_left()); usize label_jump_true_1 = code.size(); - gen(op_jt, 0, node->get_left()->get_location()); + emit(op_jt, 0, node->get_left()->get_location()); - gen(op_pop, 0, node->get_left()->get_location()); + emit(op_pop, 0, node->get_left()->get_location()); calc_gen(node->get_right()); usize label_jump_true_2 = code.size(); - gen(op_jt, 0, node->get_right()->get_location()); + emit(op_jt, 0, node->get_right()->get_location()); - gen(op_pop, 0, node->get_right()->get_location()); - gen(op_pnil, 0, node->get_right()->get_location()); + emit(op_pop, 0, node->get_right()->get_location()); + emit(op_pnil, 0, node->get_right()->get_location()); code[label_jump_true_1].num = code[label_jump_true_2].num = code.size(); } void codegen::and_gen(binary_operator* node) { calc_gen(node->get_left()); - gen(op_jt, code.size()+2, node->get_left()->get_location()); + emit(op_jt, code.size()+2, node->get_left()->get_location()); usize lable_jump_false = code.size(); - gen(op_jmp, 0, node->get_left()->get_location()); - gen(op_pop, 0, node->get_right()->get_location()); // jt jumps here + emit(op_jmp, 0, node->get_left()->get_location()); + emit(op_pop, 0, node->get_right()->get_location()); // jt jumps here calc_gen(node->get_right()); - gen(op_jt, code.size()+3, node->get_right()->get_location()); + emit(op_jt, code.size()+3, node->get_right()->get_location()); code[lable_jump_false].num = code.size(); - gen(op_pop, 0, node->get_right()->get_location()); - gen(op_pnil, 0, node->get_right()->get_location()); + emit(op_pop, 0, node->get_right()->get_location()); + emit(op_pnil, 0, node->get_right()->get_location()); // jt jumps here, avoid pop and pnil } @@ -890,11 +935,11 @@ void codegen::unary_gen(unary_operator* node) { calc_gen(node->get_value()); switch(node->get_operator_type()) { case unary_operator::unary_type::negative: - gen(op_usub, 0, node->get_location()); break; + emit(op_usub, 0, node->get_location()); break; case unary_operator::unary_type::logical_not: - gen(op_lnot, 0, node->get_location()); break; + emit(op_lnot, 0, node->get_location()); break; case unary_operator::unary_type::bitwise_not: - gen(op_bnot, 0, node->get_location()); break; + emit(op_bnot, 0, node->get_location()); break; } } @@ -918,27 +963,27 @@ void codegen::binary_gen(binary_operator* node) { case binary_operator::binary_type::cmpeq: calc_gen(node->get_left()); calc_gen(node->get_right()); - gen(op_eq, 0, node->get_location()); + emit(op_eq, 0, node->get_location()); return; case binary_operator::binary_type::cmpneq: calc_gen(node->get_left()); calc_gen(node->get_right()); - gen(op_neq, 0, node->get_location()); + emit(op_neq, 0, node->get_location()); return; case binary_operator::binary_type::bitwise_or: calc_gen(node->get_left()); calc_gen(node->get_right()); - gen(op_btor, 0, node->get_location()); + emit(op_btor, 0, node->get_location()); return; case binary_operator::binary_type::bitwise_xor: calc_gen(node->get_left()); calc_gen(node->get_right()); - gen(op_btxor, 0, node->get_location()); + emit(op_btxor, 0, node->get_location()); return; case binary_operator::binary_type::bitwise_and: calc_gen(node->get_left()); calc_gen(node->get_right()); - gen(op_btand, 0, node->get_location()); + emit(op_btand, 0, node->get_location()); return; default: break; } @@ -947,99 +992,99 @@ void codegen::binary_gen(binary_operator* node) { calc_gen(node->get_left()); if (node->get_right()->get_type()!=expr_type::ast_num) { calc_gen(node->get_right()); - gen(op_add, 0, node->get_location()); + emit(op_add, 0, node->get_location()); } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_addc, const_number_map.at(num), node->get_location()); + emit(op_addc, const_number_map.at(num), node->get_location()); } return; case binary_operator::binary_type::sub: calc_gen(node->get_left()); if (node->get_right()->get_type()!=expr_type::ast_num) { calc_gen(node->get_right()); - gen(op_sub, 0, node->get_location()); + emit(op_sub, 0, node->get_location()); } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_subc, const_number_map.at(num), node->get_location()); + emit(op_subc, const_number_map.at(num), node->get_location()); } return; case binary_operator::binary_type::mult: calc_gen(node->get_left()); if (node->get_right()->get_type()!=expr_type::ast_num) { calc_gen(node->get_right()); - gen(op_mul, 0, node->get_location()); + emit(op_mul, 0, node->get_location()); } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_mulc, const_number_map.at(num), node->get_location()); + emit(op_mulc, const_number_map.at(num), node->get_location()); } return; case binary_operator::binary_type::div: calc_gen(node->get_left()); if (node->get_right()->get_type()!=expr_type::ast_num) { calc_gen(node->get_right()); - gen(op_div, 0, node->get_location()); + emit(op_div, 0, node->get_location()); } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_divc, const_number_map.at(num), node->get_location()); + emit(op_divc, const_number_map.at(num), node->get_location()); } return; case binary_operator::binary_type::concat: calc_gen(node->get_left()); if (node->get_right()->get_type()!=expr_type::ast_str) { calc_gen(node->get_right()); - gen(op_lnk, 0, node->get_location()); + emit(op_lnk, 0, node->get_location()); } else { const auto& str = ((string_literal*)node->get_right())->get_content(); regist_str(str); - gen(op_lnkc, const_string_map.at(str), node->get_location()); + emit(op_lnkc, const_string_map.at(str), node->get_location()); } break; case binary_operator::binary_type::less: calc_gen(node->get_left()); if (node->get_right()->get_type()!=expr_type::ast_num) { calc_gen(node->get_right()); - gen(op_less, 0, node->get_location()); + emit(op_less, 0, node->get_location()); } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_lessc, const_number_map.at(num), node->get_location()); + emit(op_lessc, const_number_map.at(num), node->get_location()); } return; case binary_operator::binary_type::leq: calc_gen(node->get_left()); if (node->get_right()->get_type()!=expr_type::ast_num) { calc_gen(node->get_right()); - gen(op_leq, 0, node->get_location()); + emit(op_leq, 0, node->get_location()); } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_leqc, const_number_map.at(num), node->get_location()); + emit(op_leqc, const_number_map.at(num), node->get_location()); } return; case binary_operator::binary_type::grt: calc_gen(node->get_left()); if (node->get_right()->get_type()!=expr_type::ast_num) { calc_gen(node->get_right()); - gen(op_grt, 0, node->get_location()); + emit(op_grt, 0, node->get_location()); } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_grtc, const_number_map.at(num), node->get_location()); + emit(op_grtc, const_number_map.at(num), node->get_location()); } return; case binary_operator::binary_type::geq: calc_gen(node->get_left()); if (node->get_right()->get_type()!=expr_type::ast_num) { calc_gen(node->get_right()); - gen(op_geq, 0, node->get_location()); + emit(op_geq, 0, node->get_location()); } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_geqc, const_number_map.at(num), node->get_location()); + emit(op_geqc, const_number_map.at(num), node->get_location()); } return; default: break; @@ -1049,10 +1094,10 @@ void codegen::binary_gen(binary_operator* node) { void codegen::trino_gen(ternary_operator* node) { calc_gen(node->get_condition()); usize label_jump_false = code.size(); - gen(op_jf, 0, node->get_condition()->get_location()); + emit(op_jf, 0, node->get_condition()->get_location()); calc_gen(node->get_left()); usize label_jump_to_exit = code.size(); - gen(op_jmp, 0, node->get_left()->get_location()); + emit(op_jmp, 0, node->get_left()->get_location()); code[label_jump_false].num = code.size(); calc_gen(node->get_right()); code[label_jump_to_exit].num = code.size(); @@ -1061,7 +1106,7 @@ void codegen::trino_gen(ternary_operator* node) { void codegen::calc_gen(expr* node) { switch(node->get_type()) { case expr_type::ast_nil: - gen(op_pnil, 0, node->get_location()); break; + emit(op_pnil, 0, node->get_location()); break; case expr_type::ast_num: num_gen((number_literal*)node); break; case expr_type::ast_str: @@ -1095,25 +1140,49 @@ 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: continue_ptr.front().push_back(code.size()); - gen(op_jmp, 0, tmp->get_location()); + emit(op_jmp, 0, tmp->get_location()); break; case expr_type::ast_break: break_ptr.front().push_back(code.size()); - gen(op_jmp, 0, tmp->get_location()); + emit(op_jmp, 0, tmp->get_location()); break; case expr_type::ast_while: case expr_type::ast_for: @@ -1139,16 +1208,17 @@ void codegen::block_gen(code_block* node) { void codegen::ret_gen(return_expr* node) { for(u32 i = 0; iget_location()); - gen(op_pop, 0, node->get_location()); + emit(op_pop, 0, node->get_location()); + emit(op_pop, 0, node->get_location()); } calc_gen(node->get_value()); - gen(op_ret, 0, node->get_location()); + 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); @@ -1159,35 +1229,40 @@ const error& codegen::compile(parse& parse, linker& import) { // search global symbols first find_symbol(parse.tree()); - gen(op_intg, global.size(), parse.tree()->get_location()); // generate main block block_gen(parse.tree()); // generate exit operand, vm stops here - gen(op_exit, 0, parse.tree()->get_location()); + emit(op_exit, 0, parse.tree()->get_location()); // size out of bound check if (const_number_table.size()>0xffffff) { err.err("code", "too many constant numbers: " + - std::to_string(const_number_table.size())); + std::to_string(const_number_table.size()) + ); } if (const_string_table.size()>0xffffff) { err.err("code", "too many constant strings: " + - std::to_string(const_string_table.size())); + std::to_string(const_string_table.size()) + ); } // check global variables size if (global.size()>=STACK_DEPTH/2) { err.err("code", - "too many global variables: " + std::to_string(global.size())); + "too many global variables: " + + std::to_string(global.size()) + ); } // check generated code size if (code.size()>0xffffff) { err.err("code", - "bytecode size overflow: " + std::to_string(code.size())); + "bytecode size overflow: " + + std::to_string(code.size()) + ); } return err; } @@ -1216,7 +1291,8 @@ void codegen::print(std::ostream& out) { codestream::set( const_number_table.data(), const_string_table.data(), - native_function.data()); + native_function.data() + ); for(u32 i = 0; i index std::unordered_map file_map; void init_file_map(const std::vector&); @@ -79,11 +82,11 @@ private: void regist_str(const std::string&); void find_symbol(code_block*); void add_symbol(const std::string&); - i32 local_find(const std::string&); - i32 global_find(const std::string&); - i32 upvalue_find(const std::string&); + i32 local_symbol_find(const std::string&); + i32 global_symbol_find(const std::string&); + i32 upvalue_symbol_find(const std::string&); - void gen(u8, u32, const span&); + void emit(u8, u32, const span&); void num_gen(number_literal*); void str_gen(string_literal*); @@ -104,6 +107,8 @@ private: void single_def(definition_expr*); void def_gen(definition_expr*); void assignment_expression(assignment_expr*); + void gen_assignment_equal_statement(assignment_expr*); + void replace_left_assignment_with_load(const span&); void assignment_statement(assignment_expr*); void multi_assign_gen(multi_assign*); void cond_gen(condition_expr*); @@ -119,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*); @@ -134,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_gc.cpp b/src/nasal_gc.cpp index b1bec6a..b85986d 100644 --- a/src/nasal_gc.cpp +++ b/src/nasal_gc.cpp @@ -536,7 +536,9 @@ void gc::extend(u8 type) { } void gc::init( - const std::vector& s, const std::vector& argv) { + const std::vector& constant_strings, + const std::vector& argv +) { // initialize counters worktime = 0; for(u8 i = 0; iunmut = 1; - strs[i].str() = s[i]; + strs[i].str() = constant_strings[i]; } // record arguments env_argv.resize(argv.size()); for(usize i = 0; iunmut = 1; env_argv[i].str() = argv[i]; diff --git a/src/nasal_gc.h b/src/nasal_gc.h index 4b5c85c..590d1ed 100644 --- a/src/nasal_gc.h +++ b/src/nasal_gc.h @@ -66,7 +66,7 @@ struct nas_val; // nas_val includes gc-managed types struct var { public: - u8 type; + u8 type = vm_none; union { u32 ret; i64 cnt; diff --git a/src/nasal_misc.cpp b/src/nasal_misc.cpp index c35670d..f529db8 100644 --- a/src/nasal_misc.cpp +++ b/src/nasal_misc.cpp @@ -183,7 +183,7 @@ f64 str2num(const char* str) { i32 utf8_hdchk(const char head) { // RFC-2279 but now we use RFC-3629 so nbytes is less than 4 - const u8 c = (u8)head; + const auto c = static_cast(head); if ((c>>5)==0x06) { // 110x xxxx (10xx xxxx)^1 return 1; } 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 812e0e5..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, // 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_parse.h b/src/nasal_parse.h index 2d9f6dd..1bcf508 100644 --- a/src/nasal_parse.h +++ b/src/nasal_parse.h @@ -150,11 +150,7 @@ public: public: parse(): ptr(0), in_func(0), in_loop(0), toks(nullptr), root(nullptr) {} - ~parse() { - if (root) { - delete root; - } - } + ~parse() {delete root;} const error& compile(const lexer&); static void easter_egg(); }; diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index 49999a4..143e773 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -55,7 +55,7 @@ void vm::context_and_global_init() { ctx.canary = ctx.stack+STACK_DEPTH-1; /* nothing is on stack */ - ctx.top = ctx.stack; + ctx.top = ctx.stack - 1; /* clear main stack and global */ for(u32 i = 0; i(ctx.top[-1].tonum())| - static_cast(ctx.top[0].tonum())); + static_cast(ctx.top[-1].tonum())| + static_cast(ctx.top[0].tonum()) + ); --ctx.top; } inline void vm::o_btxor() { ctx.top[-1] = var::num( - static_cast(ctx.top[-1].tonum())^ - static_cast(ctx.top[0].tonum())); + static_cast(ctx.top[-1].tonum())^ + static_cast(ctx.top[0].tonum()) + ); --ctx.top; } inline void vm::o_btand() { ctx.top[-1] = var::num( - static_cast(ctx.top[-1].tonum())& - static_cast(ctx.top[0].tonum())); + static_cast(ctx.top[-1].tonum())& + static_cast(ctx.top[0].tonum()) + ); --ctx.top; } @@ -388,25 +392,36 @@ inline void vm::o_subeq() {op_calc_eq(-);} inline void vm::o_muleq() {op_calc_eq(*);} inline void vm::o_diveq() {op_calc_eq(/);} inline void vm::o_lnkeq() { - ctx.top[-1] = ctx.memr[0] = ngc.newstr(ctx.memr[0].tostr()+ctx.top[-1].tostr()); + ctx.top[-1] = ctx.memr[0] = ngc.newstr( + ctx.memr[0].tostr()+ctx.top[-1].tostr() + ); ctx.memr = nullptr; ctx.top -= imm[ctx.pc]+1; } inline void vm::o_bandeq() { - ctx.top[-1] = ctx.memr[0] = var::num(i32(ctx.memr[0].tonum())&i32(ctx.top[-1].tonum())); + ctx.top[-1] = ctx.memr[0] = var::num( + static_cast(ctx.memr[0].tonum())& + static_cast(ctx.top[-1].tonum()) + ); ctx.memr = nullptr; ctx.top -= imm[ctx.pc]+1; } inline void vm::o_boreq() { - ctx.top[-1] = ctx.memr[0] = var::num(i32(ctx.memr[0].tonum())|i32(ctx.top[-1].tonum())); + ctx.top[-1] = ctx.memr[0] = var::num( + static_cast(ctx.memr[0].tonum())| + static_cast(ctx.top[-1].tonum()) + ); ctx.memr = nullptr; ctx.top -= imm[ctx.pc]+1; } inline void vm::o_bxoreq() { - ctx.top[-1] = ctx.memr[0] = var::num(i32(ctx.memr[0].tonum())^i32(ctx.top[-1].tonum())); + ctx.top[-1] = ctx.memr[0] = var::num( + static_cast(ctx.memr[0].tonum())^ + static_cast(ctx.top[-1].tonum()) + ); ctx.memr = nullptr; ctx.top -= imm[ctx.pc]+1; } @@ -439,7 +454,9 @@ inline void vm::o_subecp() {op_calc_eq_const_and_pop(-);} inline void vm::o_mulecp() {op_calc_eq_const_and_pop(*);} inline void vm::o_divecp() {op_calc_eq_const_and_pop(/);} inline void vm::o_lnkecp() { - ctx.top[0] = ctx.memr[0] = ngc.newstr(ctx.memr[0].tostr()+cstr[imm[ctx.pc]]); + ctx.top[0] = ctx.memr[0] = ngc.newstr( + ctx.memr[0].tostr()+cstr[imm[ctx.pc]] + ); ctx.memr = nullptr; --ctx.top; } @@ -461,12 +478,12 @@ inline void vm::o_eq() { if (val1.type==vm_nil && val2.type==vm_nil) { ctx.top[0] = one; } else if (val1.type==vm_str && val2.type==vm_str) { - ctx.top[0] = (val1.str()==val2.str())?one:zero; + ctx.top[0] = (val1.str()==val2.str())? one:zero; } else if ((val1.type==vm_num || val2.type==vm_num) && val1.type!=vm_nil && val2.type!=vm_nil) { - ctx.top[0] = (val1.tonum()==val2.tonum())?one:zero; + ctx.top[0] = (val1.tonum()==val2.tonum())? one:zero; } else { - ctx.top[0] = (val1==val2)?one:zero; + ctx.top[0] = (val1==val2)? one:zero; } } @@ -476,12 +493,12 @@ inline void vm::o_neq() { if (val1.type==vm_nil && val2.type==vm_nil) { ctx.top[0] = zero; } else if (val1.type==vm_str && val2.type==vm_str) { - ctx.top[0] = (val1.str()!=val2.str())?one:zero; + ctx.top[0] = (val1.str()!=val2.str())? one:zero; } else if ((val1.type==vm_num || val2.type==vm_num) && val1.type!=vm_nil && val2.type!=vm_nil) { - ctx.top[0] = (val1.tonum()!=val2.tonum())?one:zero; + ctx.top[0] = (val1.tonum()!=val2.tonum())? one:zero; } else { - ctx.top[0] = (val1!=val2)?one:zero; + ctx.top[0] = (val1!=val2)? one:zero; } } @@ -597,7 +614,9 @@ inline void vm::o_callv() { die("out of range:"+std::to_string(val.tonum())); return; } - ctx.top[0] = var::num(f64((u8)str[num>=0? num:num+len])); + ctx.top[0] = var::num( + static_cast(static_cast(str[num>=0? num:num+len])) + ); } else if (vec.type==vm_map) { if (val.type!=vm_str) { die("must use string as the key"); diff --git a/src/optimizer.cpp b/src/optimizer.cpp index 3b785f4..25bd769 100644 --- a/src/optimizer.cpp +++ b/src/optimizer.cpp @@ -32,11 +32,11 @@ void optimizer::const_number( case binary_operator::binary_type::grt: res = left>right; break; case binary_operator::binary_type::geq: res = left>=right; break; case binary_operator::binary_type::bitwise_or: - res = i32(left)|i32(right); break; + res = static_cast(left)|static_cast(right); break; case binary_operator::binary_type::bitwise_xor: - res = i32(left)^i32(right); break; + res = static_cast(left)^static_cast(right); break; case binary_operator::binary_type::bitwise_and: - res = i32(left)&i32(right); break; + res = static_cast(left)&static_cast(right); break; default: return; } if (std::isinf(res) || std::isnan(res)) { @@ -51,9 +51,12 @@ void optimizer::const_number( number_literal* value_node) { auto res = value_node->get_number(); switch(node->get_operator_type()) { - case unary_operator::unary_type::negative: res = -res; break; - case unary_operator::unary_type::bitwise_not: res = ~i32(res); break; - case unary_operator::unary_type::logical_not: res = !res; break; + case unary_operator::unary_type::negative: + res = -res; break; + case unary_operator::unary_type::bitwise_not: + res = ~static_cast(res); break; + case unary_operator::unary_type::logical_not: + res = !res; break; } if (std::isinf(res) || std::isnan(res)) { return; diff --git a/src/repl.cpp b/src/repl.cpp index a348a2a..d749c07 100644 --- a/src/repl.cpp +++ b/src/repl.cpp @@ -9,6 +9,16 @@ namespace nasal { namespace repl { +void repl::add_command_history(const std::string& history) { + if (command_history.size() && command_history.back()==history) { + return; + } + command_history.push_back(history); + if (command_history.size()>1000) { + command_history.pop_front(); + } +} + std::string repl::readline(std::string prompt = ">>> ") { auto line = std::string(""); std::cout << prompt; @@ -51,6 +61,7 @@ bool repl::check_need_more_input() { } auto line = readline("... "); + add_command_history(line); source.back() += "\n" + line; } return true; @@ -66,16 +77,12 @@ void repl::help() { } bool repl::run() { - using clk = std::chrono::high_resolution_clock; - const auto den = clk::duration::period::den; - auto nasal_lexer = std::unique_ptr(new lexer); auto nasal_parser = std::unique_ptr(new parse); auto nasal_linker = std::unique_ptr(new linker); auto nasal_opt = std::unique_ptr(new optimizer); auto nasal_codegen = std::unique_ptr(new codegen); - auto start = clk::now(); update_temp_file(); if (nasal_lexer->scan("").geterr()) { return false; @@ -89,25 +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; } - auto end = clk::now(); - std::clog << "[compile time: " << (end-start).count()*1000.0/den << " ms]\n"; - - // 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(); @@ -117,6 +124,7 @@ void repl::execute() { if (!line.length()) { continue; } + add_command_history(line); if (line == ".e" || line == ".exit") { break; diff --git a/src/repl.h b/src/repl.h index ea677c5..a7afdd3 100644 --- a/src/repl.h +++ b/src/repl.h @@ -8,6 +8,7 @@ #include #include #include +#include namespace nasal { namespace repl { @@ -27,9 +28,11 @@ struct info { class repl { private: std::vector source; + std::deque command_history; vm runtime; private: + void add_command_history(const std::string&); std::string readline(std::string); bool check_need_more_input(); void update_temp_file(); @@ -42,6 +45,8 @@ public: runtime.set_repl_mode_flag(true); // no detail report info runtime.set_detail_report_info(false); + // set empty history + command_history = {""}; } void execute(); }; 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