diff --git a/src/ast_visitor.cpp b/src/ast_visitor.cpp index 07ca0b7..8757e63 100644 --- a/src/ast_visitor.cpp +++ b/src/ast_visitor.cpp @@ -5,6 +5,11 @@ bool ast_visitor::visit_expr(expr* node) { return true; } +bool ast_visitor::visit_call(call* node) { + node->accept(this); + return true; +} + bool ast_visitor::visit_file_info(file_info* node) { return true; } diff --git a/src/ast_visitor.h b/src/ast_visitor.h index 4c2a1ed..932c912 100644 --- a/src/ast_visitor.h +++ b/src/ast_visitor.h @@ -5,6 +5,7 @@ class ast_visitor { public: virtual bool visit_expr(expr*); + virtual bool visit_call(call*); virtual bool visit_file_info(file_info*); virtual bool visit_null_expr(null_expr*); virtual bool visit_nil_expr(nil_expr*); diff --git a/src/main.cpp b/src/main.cpp index c5bc8c0..3fddb4e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -131,7 +131,7 @@ void execute( // code generator gets parser's ast and import file list to generate code gen.compile(parse, ld).chkerr(); if (cmd&VM_CODE) { - gen.print(); + gen.print(std::cout); } // run diff --git a/src/nasal_ast.cpp b/src/nasal_ast.cpp index 52254da..03c8f14 100644 --- a/src/nasal_ast.cpp +++ b/src/nasal_ast.cpp @@ -5,6 +5,10 @@ void expr::accept(ast_visitor* visitor) { visitor->visit_expr(this); } +void call::accept(ast_visitor* visitor) { + visitor->visit_call(this); +} + void file_info::accept(ast_visitor* visitor) { visitor->visit_file_info(this); } diff --git a/src/nasal_ast.h b/src/nasal_ast.h index 0b81a8d..35d03da 100644 --- a/src/nasal_ast.h +++ b/src/nasal_ast.h @@ -76,6 +76,14 @@ public: virtual void accept(ast_visitor*); }; +class call:public expr { +public: + call(const span& location, expr_type node_type): + expr(location, node_type) {} + ~call() = default; + virtual void accept(ast_visitor*); +}; + class file_info:public expr { private: uint16_t index; @@ -353,7 +361,7 @@ public: class call_expr:public expr { private: expr* first; - std::vector calls; + std::vector calls; public: call_expr(const span& location): @@ -361,45 +369,45 @@ public: first(nullptr) {} ~call_expr(); void set_first(expr* node) {first = node;} - void add_call(expr* node) {calls.push_back(node);} + void add_call(call* node) {calls.push_back(node);} expr* get_first() {return first;} - std::vector& get_calls() {return calls;} + std::vector& get_calls() {return calls;} void accept(ast_visitor*) override; }; -class call_hash:public expr { +class call_hash:public call { private: std::string field; public: call_hash(const span& location, const std::string& name): - expr(location, expr_type::ast_callh), + call(location, expr_type::ast_callh), field(name) {} ~call_hash() = default; const std::string& get_field() const {return field;} void accept(ast_visitor*) override; }; -class call_vector:public expr { +class call_vector:public call { private: std::vector calls; public: call_vector(const span& location): - expr(location, expr_type::ast_callv) {} + call(location, expr_type::ast_callv) {} ~call_vector(); void add_slice(slice_vector* node) {calls.push_back(node);} std::vector& get_slices() {return calls;} void accept(ast_visitor*) override; }; -class call_function:public expr { +class call_function:public call { private: std::vector args; public: call_function(const span& location): - expr(location, expr_type::ast_callf) {} + call(location, expr_type::ast_callf) {} ~call_function(); void add_argument(expr* node) {args.push_back(node);} std::vector& get_argument() {return args;} diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index f4914fb..0312fec 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -27,31 +27,31 @@ void codegen::check_id_exist(identifier* node) { } void codegen::regist_num(const f64 num) { - if (num_table.count(num)) { + if (const_number_map.count(num)) { return; } - u32 size = num_table.size(); - num_table[num] = size; - num_res.push_back(num); + u32 size = const_number_map.size(); + const_number_map[num] = size; + const_number_table.push_back(num); } void codegen::regist_str(const std::string& str) { - if (str_table.count(str)) { + if (const_string_map.count(str)) { return; } - u32 size = str_table.size(); - str_table[str] = size; - str_res.push_back(str); + u32 size = const_string_map.size(); + const_string_map[str] = size; + const_string_table.push_back(str); } void codegen::find_symbol(code_block* node) { auto finder = std::unique_ptr(new symbol_finder); for(const auto& i : finder->do_find(node)) { - add_sym(i); + add_symbol(i); } } -void codegen::add_sym(const std::string& name) { +void codegen::add_symbol(const std::string& name) { if (local.empty()) { if (global.count(name)) { return; @@ -101,19 +101,19 @@ void codegen::gen(u8 operation_code, u32 num, u32 line) { void codegen::num_gen(number_literal* node) { f64 num = node->get_number(); regist_num(num); - gen(op_pnum,num_table.at(num), node->get_line()); + gen(op_pnum,const_number_map.at(num), node->get_line()); } void codegen::str_gen(string_literal* node) { const auto& str = node->get_content(); regist_str(str); - gen(op_pstr, str_table.at(str), node->get_line()); + gen(op_pstr, const_string_map.at(str), node->get_line()); } void codegen::bool_gen(bool_literal* node) { f64 num = node->get_flag()? 1:0; regist_num(num); - gen(op_pnum, num_table.at(num), node->get_line()); + gen(op_pnum, const_number_map.at(num), node->get_line()); } void codegen::vec_gen(vector_expr* node) { @@ -129,7 +129,7 @@ void codegen::hash_gen(hash_expr* node) { calc_gen(child->get_value()); const auto& field_name = child->get_name(); regist_str(field_name); - gen(op_happ, str_table.at(field_name), child->get_line()); + gen(op_happ, const_string_map.at(field_name), child->get_line()); } } @@ -190,17 +190,17 @@ void codegen::func_gen(function* node) { regist_str(name); switch(tmp->get_parameter_type()) { case parameter::param_type::normal_parameter: - gen(op_para, str_table.at(name), tmp->get_line()); + gen(op_para, const_string_map.at(name), tmp->get_line()); break; case parameter::param_type::default_parameter: calc_gen(tmp->get_default_value()); - gen(op_deft, str_table.at(name), tmp->get_line()); + gen(op_deft, const_string_map.at(name), tmp->get_line()); break; case parameter::param_type::dynamic_parameter: - gen(op_dyn, str_table.at(name), tmp->get_line()); + gen(op_dyn, const_string_map.at(name), tmp->get_line()); break; } - add_sym(name); + add_symbol(name); } code[newf].num = code.size()+1; // entry @@ -274,7 +274,7 @@ void codegen::call_id(identifier* node) { void codegen::call_hash_gen(call_hash* node) { regist_str(node->get_field()); - gen(op_callh, str_table.at(node->get_field()), node->get_line()); + gen(op_callh, const_string_map.at(node->get_field()), node->get_line()); } void codegen::call_vector_gen(call_vector* node) { @@ -307,7 +307,7 @@ void codegen::call_func_gen(call_function* node) { calc_gen(((hash_pair*)child)->get_value()); const auto& field_name = ((hash_pair*)child)->get_name(); regist_str(field_name); - gen(op_happ, str_table.at(field_name), child->get_line()); + gen(op_happ, const_string_map.at(field_name), child->get_line()); } gen(op_callfh, 0, node->get_line()); } else { @@ -399,7 +399,7 @@ void codegen::mcall_vec(call_vector* node) { void codegen::mcall_hash(call_hash* node) { regist_str(node->get_field()); - gen(op_mcallh, str_table.at(node->get_field()), node->get_line()); + gen(op_mcallh, const_string_map.at(node->get_field()), node->get_line()); } void codegen::single_def(definition_expr* node) { @@ -417,9 +417,11 @@ void codegen::multi_def(definition_expr* node) { if (node->get_tuple()) { auto& vals = node->get_tuple()->get_elements(); if (identifiers.size()get_tuple()->get_location()); + die("lack values in multi-definition", + node->get_tuple()->get_location()); } else if (identifiers.size()>vals.size()) { - die("too many values in multi-definition", node->get_tuple()->get_location()); + die("too many values in multi-definition", + node->get_tuple()->get_location()); } for(usize i = 0; iget_right())->get_number(); regist_num(num); - gen(op_addeqc, num_table[num], node->get_line()); + gen(op_addeqc, const_number_map[num], node->get_line()); } break; case assignment_expr::assign_type::sub_equal: @@ -479,7 +481,7 @@ void codegen::assignment_expression(assignment_expr* node) { } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_subeqc, num_table[num], node->get_line()); + gen(op_subeqc, const_number_map[num], node->get_line()); } break; case assignment_expr::assign_type::mult_equal: @@ -492,7 +494,7 @@ void codegen::assignment_expression(assignment_expr* node) { } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_muleqc, num_table[num], node->get_line()); + gen(op_muleqc, const_number_map[num], node->get_line()); } break; case assignment_expr::assign_type::div_equal: @@ -505,7 +507,7 @@ void codegen::assignment_expression(assignment_expr* node) { } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_diveqc, num_table[num], node->get_line()); + gen(op_diveqc, const_number_map[num], node->get_line()); } break; case assignment_expr::assign_type::concat_equal: @@ -518,7 +520,7 @@ void codegen::assignment_expression(assignment_expr* node) { } else { const auto& str = ((string_literal*)node->get_right())->get_content(); regist_str(str); - gen(op_lnkeqc, str_table[str], node->get_line()); + gen(op_lnkeqc, const_string_map[str], node->get_line()); } break; case assignment_expr::assign_type::bitwise_and_equal: @@ -610,26 +612,26 @@ void codegen::multi_assign_gen(multi_assign* node) { gen(op_meq, 1, tuple[i]->get_line()); } } - } else { - calc_gen(node->get_value()); - auto& tuple = node->get_tuple()->get_elements(); - for(i32 i = 0; iget_value()->get_line()); - // multi assign user loadl and loadg to avoid meq's stack-- - // and this operation changes local and global value directly - 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_line()); - } - } - gen(op_pop, 0, node->get_line()); + return; } + calc_gen(node->get_value()); + auto& tuple = node->get_tuple()->get_elements(); + for(i32 i = 0; iget_value()->get_line()); + // multi assign user loadl and loadg to avoid meq's stack-- + // and this operation changes local and global value directly + 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_line()); + } + } + gen(op_pop, 0, node->get_line()); } void codegen::cond_gen(condition_expr* node) { @@ -709,7 +711,7 @@ 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, num_table.at(1), node->get_condition()->get_line()); + gen(op_pnum, const_number_map.at(1), node->get_condition()->get_line()); } else { calc_gen(node->get_condition()); } @@ -735,10 +737,11 @@ void codegen::forei_gen(forei_expr* node) { gen(op_feach, 0, node->get_line()); } if (node->get_iterator()->get_name()) { // define a new iterator - const auto& str = node->get_iterator()->get_name()->get_name(); + auto name_node = node->get_iterator()->get_name(); + const auto& str = name_node->get_name(); local.empty()? - gen(op_loadg, global_find(str), node->get_iterator()->get_name()->get_line()): - gen(op_loadl, local_find(str), node->get_iterator()->get_name()->get_line()); + gen(op_loadg, global_find(str), name_node->get_line()): + gen(op_loadl, local_find(str), name_node->get_line()); } else { // use exist variable as the iterator mcall(node->get_iterator()->get_call()); if (code.back().op==op_mcallg) { @@ -763,15 +766,17 @@ void codegen::forei_gen(forei_expr* node) { void codegen::statement_generation(expr* node) { switch(node->get_type()) { - case expr_type::ast_null:break; + case expr_type::ast_null: break; case expr_type::ast_def: def_gen((definition_expr*)node); break; case expr_type::ast_multi_assign: multi_assign_gen((multi_assign*)node); break; case expr_type::ast_assign: assignment_statement((assignment_expr*)node); 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_nil: + case expr_type::ast_num: + case expr_type::ast_str: + case expr_type::ast_bool: break; case expr_type::ast_vec: case expr_type::ast_hash: case expr_type::ast_func: @@ -788,35 +793,35 @@ void codegen::statement_generation(expr* node) { void codegen::or_gen(binary_operator* node) { calc_gen(node->get_left()); - usize l1 = code.size(); + usize label_jump_true_1 = code.size(); gen(op_jt, 0, node->get_left()->get_line()); gen(op_pop, 0, node->get_left()->get_line()); calc_gen(node->get_right()); - usize l2=code.size(); + usize label_jump_true_2 = code.size(); gen(op_jt, 0, node->get_right()->get_line()); gen(op_pop, 0, node->get_right()->get_line()); gen(op_pnil, 0, node->get_right()->get_line()); - code[l1].num = code[l2].num = code.size(); + 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_line()); - usize lfalse = code.size(); + usize lable_jump_false = code.size(); gen(op_jmp, 0, node->get_left()->get_line()); - gen(op_pop, 0, node->get_right()->get_line());// jt jumps here + gen(op_pop, 0, node->get_right()->get_line()); // jt jumps here calc_gen(node->get_right()); gen(op_jt, code.size()+3, node->get_right()->get_line()); - code[lfalse].num = code.size(); + code[lable_jump_false].num = code.size(); gen(op_pop, 0, node->get_right()->get_line()); gen(op_pnil, 0, node->get_right()->get_line()); - // jt jumps here + // jt jumps here, avoid pop and pnil } void codegen::unary_gen(unary_operator* node) { @@ -884,7 +889,7 @@ void codegen::binary_gen(binary_operator* node) { } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_addc, num_table.at(num), node->get_line()); + gen(op_addc, const_number_map.at(num), node->get_line()); } return; case binary_operator::binary_type::sub: @@ -895,7 +900,7 @@ void codegen::binary_gen(binary_operator* node) { } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_subc, num_table.at(num), node->get_line()); + gen(op_subc, const_number_map.at(num), node->get_line()); } return; case binary_operator::binary_type::mult: @@ -906,7 +911,7 @@ void codegen::binary_gen(binary_operator* node) { } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_mulc, num_table.at(num), node->get_line()); + gen(op_mulc, const_number_map.at(num), node->get_line()); } return; case binary_operator::binary_type::div: @@ -917,7 +922,7 @@ void codegen::binary_gen(binary_operator* node) { } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_divc, num_table.at(num), node->get_line()); + gen(op_divc, const_number_map.at(num), node->get_line()); } return; case binary_operator::binary_type::concat: @@ -928,7 +933,7 @@ void codegen::binary_gen(binary_operator* node) { } else { const auto& str = ((string_literal*)node->get_right())->get_content(); regist_str(str); - gen(op_lnkc, str_table.at(str), node->get_line()); + gen(op_lnkc, const_string_map.at(str), node->get_line()); } break; case binary_operator::binary_type::less: @@ -939,7 +944,7 @@ void codegen::binary_gen(binary_operator* node) { } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_lessc, num_table.at(num), node->get_line()); + gen(op_lessc, const_number_map.at(num), node->get_line()); } return; case binary_operator::binary_type::leq: @@ -950,7 +955,7 @@ void codegen::binary_gen(binary_operator* node) { } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_leqc, num_table.at(num), node->get_line()); + gen(op_leqc, const_number_map.at(num), node->get_line()); } return; case binary_operator::binary_type::grt: @@ -961,7 +966,7 @@ void codegen::binary_gen(binary_operator* node) { } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_grtc, num_table.at(num), node->get_line()); + gen(op_grtc, const_number_map.at(num), node->get_line()); } return; case binary_operator::binary_type::geq: @@ -972,7 +977,7 @@ void codegen::binary_gen(binary_operator* node) { } else { auto num = ((number_literal*)node->get_right())->get_number(); regist_num(num); - gen(op_geqc, num_table.at(num), node->get_line()); + gen(op_geqc, const_number_map.at(num), node->get_line()); } return; default: break; @@ -981,14 +986,14 @@ void codegen::binary_gen(binary_operator* node) { void codegen::trino_gen(ternary_operator* node) { calc_gen(node->get_condition()); - usize lfalse = code.size(); + usize label_jump_false = code.size(); gen(op_jf, 0, node->get_condition()->get_line()); calc_gen(node->get_left()); - usize lexit = code.size(); + usize label_jump_to_exit = code.size(); gen(op_jmp, 0, node->get_left()->get_line()); - code[lfalse].num = code.size(); + code[label_jump_false].num = code.size(); calc_gen(node->get_right()); - code[lexit].num = code.size(); + code[label_jump_to_exit].num = code.size(); } void codegen::calc_gen(expr* node) { @@ -1031,11 +1036,13 @@ void codegen::calc_gen(expr* node) { 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_null: break; case expr_type::ast_id: 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_nil: + case expr_type::ast_num: + case expr_type::ast_str: + case expr_type::ast_bool: break; case expr_type::ast_file_info: // special node type in main block fileindex = ((file_info*)tmp)->get_index(); break; @@ -1090,73 +1097,76 @@ const error& codegen::compile(parse& parse, linker& import) { gen(op_exit, 0, 0); // size out of bound check - if (num_res.size()>0xffffff) { - err.load(file[0]); // load main execute file + err.load(file[0]); // load main execute file + if (const_number_table.size()>0xffffff) { err.err("code", - "too many constant numbers: " + std::to_string(num_res.size())); + "too many constant numbers: " + + std::to_string(const_number_table.size())); } - if (str_res.size()>0xffffff) { - err.load(file[0]); // load main execute file + if (const_string_table.size()>0xffffff) { err.err("code", - "too many constant strings: " + std::to_string(str_res.size())); + "too many constant strings: " + + std::to_string(const_string_table.size())); } if (global.size()>=STACK_DEPTH) { - err.load(file[0]); // load main execute file err.err("code", - "too many global variants: " + std::to_string(global.size())); + "too many global variables: " + std::to_string(global.size())); } if (code.size()>0xffffff) { - err.load(file[0]); // load main execute file err.err("code", "bytecode size overflow: " + std::to_string(code.size())); } return err; } -void codegen::print() { +void codegen::print(std::ostream& out) { // func end stack, reserved for code print - std::stack fbstk; - std::stack festk; + std::stack func_begin_stack; + std::stack func_end_stack; // print const numbers - for(auto num : num_res) { - std::cout << " .number " << num << "\n"; + for(auto num : const_number_table) { + out << " .number " << num << "\n"; } // print const strings - for(const auto& str : str_res) { - std::cout << " .symbol \"" << rawstr(str) << "\"\n"; + for(const auto& str : const_string_table) { + out << " .symbol \"" << rawstr(str) << "\"\n"; + } + + // print blank line + if (const_number_table.size() || const_string_table.size()) { + out << "\n"; } // print code - std::cout<<"\n"; - codestream::set(num_res.data(), str_res.data()); + codestream::set(const_number_table.data(), const_string_table.data()); for(u32 i = 0; i;\n"; + if (!func_end_stack.empty() && i==func_end_stack.top()) { + out << std::hex << "<0x" << func_begin_stack.top() << std::dec << ">;\n"; // avoid two empty lines if (c.op!=op_newf) { - std::cout<<"\n"; + out<<"\n"; } - fbstk.pop(); - festk.pop(); + func_begin_stack.pop(); + func_end_stack.pop(); } // get function begin index and end index if (c.op==op_newf) { - std::cout << std::hex << "\nfunc <0x" << i << std::dec << ">:\n"; + out << std::hex << "\nfunc <0x" << i << std::dec << ">:\n"; for(u32 j = i; j in_iterloop; - std::unordered_map num_table; - std::unordered_map str_table; - std::vector num_res; - std::vector str_res; + std::unordered_map const_number_map; + std::unordered_map const_string_map; + std::vector const_number_table; + std::vector const_string_table; std::vector code; std::list> continue_ptr; std::list> break_ptr; @@ -49,7 +49,7 @@ private: void regist_num(const f64); void regist_str(const std::string&); void find_symbol(code_block*); - void add_sym(const std::string&); + void add_symbol(const std::string&); i32 local_find(const std::string&); i32 global_find(const std::string&); i32 upvalue_find(const std::string&); @@ -93,11 +93,13 @@ private: void block_gen(code_block*); void ret_gen(return_expr*); +public: + const std::vector& strs() const {return const_string_table;} + const std::vector& nums() const {return const_number_table;} + const std::vector& codes() const {return code;} + public: codegen(error& e): fileindex(0), err(e), file(nullptr) {} const error& compile(parse&, linker&); - void print(); - const std::vector& strs() const {return str_res;} - const std::vector& nums() const {return num_res;} - const std::vector& codes() const {return code;} + void print(std::ostream&); }; diff --git a/src/nasal_opcode.cpp b/src/nasal_opcode.cpp index 3b027c1..f02dee8 100644 --- a/src/nasal_opcode.cpp +++ b/src/nasal_opcode.cpp @@ -1,35 +1,34 @@ #include "nasal_opcode.h" -const char* opname[]={ - "exit ","intg ","intl ","loadg ", - "loadl ","loadu ","pnum ","pnil ", - "pstr ","newv ","newh ","newf ", - "happ ","para ","def ","dyn ", - "lnot ","usub ","bnot ","btor ", - "btxor ","btand ","add ","sub ", - "mult ","div ","lnk ","addc ", - "subc ","multc ","divc ","lnkc ", - "addeq ","subeq ","muleq ","diveq ", - "lnkeq ","bandeq","boreq ","bxoreq", - "addeqc","subeqc","muleqc","diveqc", - "lnkeqc","addecp","subecp","mulecp", - "divecp","lnkecp","meq ","eq ", - "neq ","less ","leq ","grt ", - "geq ","lessc ","leqc ","grtc ", - "geqc ","pop ","jmp ","jt ", - "jf ","cnt ","findx ","feach ", - "callg ","calll ","upval ","callv ", - "callvi","callh ","callfv","callfh", - "callb ","slcbeg","slcend","slc ", - "slc2 ","mcallg","mcalll","mupval", - "mcallv","mcallh","ret " +const char* opname[] = { + "exit ", "intg ", "intl ", "loadg ", + "loadl ", "loadu ", "pnum ", "pnil ", + "pstr ", "newv ", "newh ", "newf ", + "happ ", "para ", "def ", "dyn ", + "lnot ", "usub ", "bitnot", "bitor ", + "bitxor", "bitand", "add ", "sub ", + "mult ", "div ", "lnk ", "addc ", + "subc ", "multc ", "divc ", "lnkc ", + "addeq ", "subeq ", "muleq ", "diveq ", + "lnkeq ", "bandeq", "boreq ", "bxoreq", + "addeqc", "subeqc", "muleqc", "diveqc", + "lnkeqc", "addecp", "subecp", "mulecp", + "divecp", "lnkecp", "meq ", "eq ", + "neq ", "less ", "leq ", "grt ", + "geq ", "lessc ", "leqc ", "grtc ", + "geqc ", "pop ", "jmp ", "jt ", + "jf ", "cnt ", "findx ", "feach ", + "callg ", "calll ", "upval ", "callv ", + "callvi", "callh ", "callfv", "callfh", + "callb ", "slcbeg", "slcend", "slice ", + "slice2", "mcallg", "mcalll", "mupval", + "mcallv", "mcallh", "ret " }; void codestream::set( const f64* numbuff, const std::string* strbuff, - const std::string* filelist -) { + const std::string* filelist) { nums = numbuff; strs = strbuff; files = filelist; @@ -40,14 +39,14 @@ void codestream::dump(std::ostream& out) const { using std::setfill; using std::hex; using std::dec; - auto op=code.op; - auto num=code.num; - out<>16)&0xff)<<" " - <>8)&0xff)<<" " - <>16)&0xff) << " " + << setw(2) << setfill('0') << ((num>>8)&0xff) << " " + << setw(2) << setfill('0') << (num&0xff) << " " <";break; + out << hex << "0x" << num << " <" << builtin[num].name + << "@0x" << (u64)builtin[num].func << dec << ">"; break; case op_upval: case op_mupval: case op_loadu: - out<>16)&0xffff) - <<"[0x"<<(num&0xffff)<<"]"<>16)&0xffff) + << "[0x" << (num&0xffff) << "]" << dec; break; case op_happ: case op_pstr: case op_lnkc: case op_callh: case op_mcallh: case op_para: case op_deft: case op_dyn: - out< ") { +var readline = func(prompt = "> ") { print(prompt); return input("\n"); } @@ -38,224 +38,224 @@ var readline=func(prompt="> ") { # split a string by separator for example: # split("ll","hello world") -> ["he","o world"] # this function will return a vector. -var split=func(separator,str){ - return __split(separator,str); +var split = func(separator, str) { + return __split(separator, str); } # rand has the same function as the rand in C # if seed is nil, it will return the random number. # if seed is not nil, it will be initialized by this seed. -var rand=func(seed=nil){ +var rand = func(seed = nil) { return __rand(seed); } # id will return the pointer of an gc-object. # if this object is not managed by gc, it will return 0. -var id=func(object){ +var id = func(object) { return __id(object); } # int will get the integer of input number/string. # but carefully use it, because int has range between -2147483648~2147483647 -var int=func(val){ +var int = func(val) { return __int(val); } # floor will get the integral number of input argument # which is less than or equal to this argument -var floor=func(val){ +var floor = func(val) { return __floor(val); } # exit using std::exit -var exit=func(val=-1){ +var exit = func(val = -1) { return __exit(val); } # abort using std::abort -var abort=func(){ +var abort = func() { __abort(); } # abs gets absolute number. -var abs=func(n){ - return n>0?n:-n; +var abs = func(n) { + return n>0? n:-n; } # num will change all the other types into number. # mostly used to change a numerable string. -var num=func(val){ +var num = func(val) { return __num(val); } # pop used to pop the last element in a vector. # this function will return the value that poped if vector has element(s). # if the vector is empty, it will return nil. -var pop=func(vec){ +var pop = func(vec) { return __pop(vec); } # str is used to change number into string. -var str=func(num){ +var str = func(num) { return __str(num); } # size can get the size of a string/vector/hashmap. # in fact it can also get the size of number, and the result is the number itself. # so don't do useless things, though it really works. -var size=func(object){ +var size = func(object) { return __size(object); } # contains is used to check if a key exists in a hashmap/dict. -var contains=func(hash,key){ - return __contains(hash,key); +var contains = func(hash, key) { + return __contains(hash, key); } # delete is used to delete a pair in a hashmap/dict by key. -var delete=func(hash,key){ - return __delete(hash,key); +var delete = func(hash, key) { + return __delete(hash, key); } # keys is used to get all keys in a hashmap/dict. # this function will return a vector. -var keys=func(hash){ +var keys = func(hash) { return __keys(hash); } # time has the same function in C. -var time=func(begin){ +var time = func(begin) { return __time(begin); } -var systime=func(){ +var systime = func() { return time(0); } # die is a special native function. # use it at where you want the program to crash immediately. -var die=func(str){ +var die = func(str = "error occurred.") { return __die(str); } # find will give the first position of the needle in haystack -var find=func(needle,haystack){ - return __find(needle,haystack); +var find = func(needle, haystack) { + return __find(needle, haystack); } # typeof is used to get the type of an object. # this function returns a string. -var typeof=func(object){ +var typeof = func(object) { return __type(object); } # subvec is used to get part of a vector -var subvec=func(vec,begin,length=nil){ - return vec[begin:(length==nil?nil:begin+length-1)]; +var subvec = func(vec, begin, length = nil) { + return vec[begin:(length==nil? nil:begin+length-1)]; } # substr will get the sub-string. # it gets the string, the begin index and sub-string's length as arguments. -var substr=func(str,begin,len){ - return __substr(str,begin,len); +var substr = func(str, begin, len) { + return __substr(str, begin, len); } # streq is used to compare if two strings are the same. -var streq=func(a,b){ - return __streq(a,b); +var streq = func(a, b) { + return __streq(a, b); } # left is used to get the sub-string like substr. # but the begin index is 0. -var left=func(str,len){ - return __left(str,len); +var left = func(str, len) { + return __left(str, len); } # right i used to get the sub-string like substr. # but the begin index is strlen-len. -var right=func(str,len){ - return __right(str,len); +var right = func(str, len) { + return __right(str, len); } # cmp is used to compare two strings. # normal string will not be correctly compared by operators < > <= >= # because these operators will turn strings into numbers then compare. -var cmp=func(a,b){ +var cmp = func(a, b) { return __cmp(a,b); } # chr is used to get the character by ascii-number. # for example chr(65) -> 'A' -var chr=func(code){ +var chr = func(code) { return __chr(code); } # char will give you the real character of ascii-number # instead of extend-ascii when number between 128~256 -var char=func(code){ +var char = func(code) { return __char(code); } # mut is used to change unmutable strings to mutable. -var mut=func(str){ +var mut = func(str) { return str~""; } # srand wraps up rand, using time(0) as the seed. -var srand=func(){ +var srand = func() { rand(time(0)); return 0; } # values() gets all values in a hash. -var values=func(hash){ +var values = func(hash) { return __values(hash); } # println has the same function as print. # but it will output a '\n' after using print. -var println=func(elems...){ +var println = func(elems...) { return __println(elems); } -var isfunc=func(f){ +var isfunc = func(f) { return typeof(f)=="func"; } -var isghost=func(g){ +var isghost = func(g) { return typeof(g)=="obj"; } -var ishash=func(h){ +var ishash = func(h) { return typeof(h)=="hash"; } -var isint=func(x){ +var isint = func(x) { return x==floor(x); } -var isnum=func(x){ +var isnum = func(x) { return typeof(x)=="num" or !math.isnan(num(x)); } -var isscalar=func(s){ +var isscalar = func(s) { var t=typeof(s); - return (t=="num" or t=="str")?1:0; + return (t=="num" or t=="str")? 1:0; } -var isstr=func(s){ +var isstr = func(s) { return typeof(s)=="str"; } -var isvec=func(v){ +var isvec = func(v) { return typeof(v)=="vec"; } -var ghosttype=func(ghost_object) { +var ghosttype = func(ghost_object) { return __ghosttype(ghost_object); } # get the index of val in the vec -var vecindex=func(vec,val){ +var vecindex = func(vec,val) { forindex(var i;vec) if(val==vec[i]) return i; @@ -263,8 +263,8 @@ var vecindex=func(vec,val){ } # check if the object is an instance of the class -var isa=func(object,class){ - if(!contains(object,"parents") or typeof(object.parents)!="vec") +var isa = func(object, class) { + if(!contains(object, "parents") or typeof(object.parents)!="vec") return 0; foreach(var elem;object.parents) if(elem==class) @@ -273,202 +273,202 @@ var isa=func(object,class){ } # assert aborts when condition is not true -var assert=func(condition,message="assertion failed!"){ +var assert = func(condition, message = "assertion failed!") { if(condition) return 1; die(message); } # get time stamp, this will return a timestamp object -var maketimestamp=func(){ - var t=0; +var maketimestamp = func() { + var t = 0; return { - stamp:func(){t=__millisec();}, - elapsedMSec:func(){return __millisec()-t;}, - elapsedUSec:func(){return (__millisec()-t)*1000;} + stamp: func() {t = __millisec();}, + elapsedMSec: func() {return __millisec()-t;}, + elapsedUSec: func() {return (__millisec()-t)*1000;} }; } # md5 -var md5=func(str){ +var md5 = func(str) { return __md5(str); } -var io={ - SEEK_SET:0, - SEEK_CUR:1, - SEEK_END:2, +var io = { + SEEK_SET: 0, + SEEK_CUR: 1, + SEEK_END: 2, # get content of a file by filename. returns a string. - readfile: func(filename){return __readfile(filename);}, + readfile: func(filename) {return __readfile(filename);}, # input a string as the content of a file. - fout: func(filename,str){return __fout(filename,str);}, + fout: func(filename, str) {return __fout(filename, str);}, # use C access - exists:func(filename){return __exists(filename);}, + exists:func(filename) {return __exists(filename);}, # same as C fopen. open file and get the FILE*. - open: func(filename,mode="r"){return __open(filename,mode);}, + open: func(filename, mode = "r") {return __open(filename, mode);}, # same as C fclose. close file by FILE*. - close: func(filehandle){return __close(filehandle);}, + close: func(filehandle) {return __close(filehandle);}, # same as C fread. read file by FILE*. # caution: buf must be a mutable string.use mut("") to get an empty mutable string. - read: func(filehandle,buf,len){return __read(filehandle,buf,len);}, + read: func(filehandle, buf, len) {return __read(filehandle, buf, len);}, # same as C fwrite. write file by FILE*. - write: func(filehandle,str){return __write(filehandle,str);}, + write: func(filehandle, str) {return __write(filehandle, str);}, # same as C fseek. seek place by FILE*. - seek: func(filehandle,pos,whence){return __seek(filehandle,pos,whence);}, + seek: func(filehandle, pos, whence) {return __seek(filehandle, pos, whence);}, # same as C ftell. - tell: func(filehandle){return __tell(filehandle);}, + tell: func(filehandle) {return __tell(filehandle);}, # read file by lines. use FILE*. # get nil if EOF - readln:func(filehandle){return __readln(filehandle);}, + readln: func(filehandle) {return __readln(filehandle);}, # same as C stat. - stat: func(filename){return __stat(filename);}, + stat: func(filename) {return __stat(filename);}, # same as C feof. check if FILE* gets the end of file(EOF). - eof: func(filehandle){return __eof(filehandle);} + eof: func(filehandle) {return __eof(filehandle);} }; # get file status. using data from io.stat -var fstat=func(filename){ - var s=io.stat(filename); +var fstat = func(filename) { + var s = io.stat(filename); return { - st_dev: s[0], - st_ino: s[1], + st_dev: s[0], + st_ino: s[1], st_mode: s[2], - st_nlink:s[3], - st_uid: s[4], - st_gid: s[5], + st_nlink: s[3], + st_uid: s[4], + st_gid: s[5], st_rdev: s[6], st_size: s[7], - st_atime:s[8], - st_mtime:s[9], - st_ctime:s[10] + st_atime: s[8], + st_mtime: s[9], + st_ctime: s[10] }; } # functions that do bitwise calculation. # carefully use it, all the calculations are based on integer. -var bits={ +var bits = { # u32 xor - u32_xor: func(a,b){return __u32xor(a,b); }, + u32_xor: func(a, b) {return __u32xor(a, b);}, # u32 and - u32_and: func(a,b){return __u32and(a,b); }, + u32_and: func(a, b) {return __u32and(a, b);}, # u32 or - u32_or: func(a,b){return __u32or(a,b); }, + u32_or: func(a, b) {return __u32or(a, b);}, # u32 nand - u32_nand:func(a,b){return __u32nand(a,b);}, + u32_nand: func(a, b) {return __u32nand(a, b);}, # u32 not - u32_not: func(a) {return __u32not(a); }, + u32_not: func(a) {return __u32not(a);}, # get bit data from a special string. for example: # bits.fld(s,0,3); # if s stores 10100010(162) # will get 101(5). - fld: func(str,startbit,len){return __fld;}, + fld: func(str, startbit, len) {return __fld;}, # get sign-extended data from a special string. for example: # bits.sfld(s,0,3); # if s stores 10100010(162) # will get 101(5) then this will be signed extended to # 11111101(-3). - sfld: func(str,startbit,len){return __sfld;}, + sfld: func(str, startbit, len) {return __sfld;}, # set value into a special string to store it. little-endian, for example: # bits.setfld(s,0,8,69); # set 01000101(69) to string will get this: # 10100010(162) # so s[0]=162. - setfld: func(str,startbit,len,val){return __setfld;}, + setfld: func(str, startbit, len, val) {return __setfld;}, # get a special string filled by '\0' to use in setfld. - buf: func(len){return __buf;} + buf: func(len) {return __buf;} }; # mostly used math functions and special constants, you know. -var math={ - e: 2.7182818284590452354, - pi: 3.14159265358979323846264338327950288, - D2R: 2.7182818284590452354/180, - R2D: 180/2.7182818284590452354, - inf: 1/0, - nan: 0/0, - abs: func(x) {return x>0?x:-x; }, - floor: func(x) {return __floor(x); }, - pow: func(x,y){return __pow(x,y); }, - sin: func(x) {return __sin(x); }, - cos: func(x) {return __cos(x); }, - tan: func(x) {return __tan(x); }, - exp: func(x) {return __exp(x); }, - lg: func(x) {return __lg(x); }, - ln: func(x) {return __ln(x); }, - sqrt: func(x) {return __sqrt(x); }, - atan2: func(x,y){return __atan2(x,y);}, - isnan: func(x) {return __isnan(x); }, - max: func(x,y){return x>y?x:y; }, - min: func(x,y){return x0? x:-x;}, + floor: func(x) {return __floor(x);}, + pow: func(x, y) {return __pow(x, y);}, + sin: func(x) {return __sin(x);}, + cos: func(x) {return __cos(x);}, + tan: func(x) {return __tan(x);}, + exp: func(x) {return __exp(x);}, + lg: func(x) {return __lg(x);}, + ln: func(x) {return __ln(x);}, + sqrt: func(x) {return __sqrt(x);}, + atan2: func(x, y) {return __atan2(x, y);}, + isnan: func(x) {return __isnan(x);}, + max: func(x, y) {return x>y? x:y;}, + min: func(x, y) {return x"){ +var compile = func(code, filename = "") { die("this runtime uses static code generator"); } -var coroutine={ - create: func(function) {return __cocreate;}, - resume: func(co,args...) {return __coresume;}, - yield: func(args...) {return __coyield; }, - status: func(co) {return __costatus;}, - running:func() {return __corun; } +var coroutine = { + create: func(function) {return __cocreate;}, + resume: func(co, args...) {return __coresume;}, + yield: func(args...) {return __coyield; }, + status: func(co) {return __costatus;}, + running:func() {return __corun; } }; diff --git a/test/gc_test.nas b/test/gc_test.nas new file mode 100644 index 0000000..147cc7c --- /dev/null +++ b/test/gc_test.nas @@ -0,0 +1,12 @@ +var res = []; +for(var i=0;i<1e6;i+=1) { + append(res, []); +} +res = []; +for(var i=0;i<1e6;i+=1) { + append(res, {}); +} +res = []; +for(var i=0;i<1e6;i+=1) { + append(res, func {}); +} \ No newline at end of file diff --git a/test/push.nas b/tools/push.nas similarity index 100% rename from test/push.nas rename to tools/push.nas