optimize codegen

This commit is contained in:
ValKmjolnir 2023-07-05 00:24:34 +08:00
parent 5c714d26aa
commit eca6141408
13 changed files with 403 additions and 356 deletions

View File

@ -5,6 +5,11 @@ bool ast_visitor::visit_expr(expr* node) {
return true; return true;
} }
bool ast_visitor::visit_call(call* node) {
node->accept(this);
return true;
}
bool ast_visitor::visit_file_info(file_info* node) { bool ast_visitor::visit_file_info(file_info* node) {
return true; return true;
} }

View File

@ -5,6 +5,7 @@
class ast_visitor { class ast_visitor {
public: public:
virtual bool visit_expr(expr*); virtual bool visit_expr(expr*);
virtual bool visit_call(call*);
virtual bool visit_file_info(file_info*); virtual bool visit_file_info(file_info*);
virtual bool visit_null_expr(null_expr*); virtual bool visit_null_expr(null_expr*);
virtual bool visit_nil_expr(nil_expr*); virtual bool visit_nil_expr(nil_expr*);

View File

@ -131,7 +131,7 @@ void execute(
// code generator gets parser's ast and import file list to generate code // code generator gets parser's ast and import file list to generate code
gen.compile(parse, ld).chkerr(); gen.compile(parse, ld).chkerr();
if (cmd&VM_CODE) { if (cmd&VM_CODE) {
gen.print(); gen.print(std::cout);
} }
// run // run

View File

@ -5,6 +5,10 @@ void expr::accept(ast_visitor* visitor) {
visitor->visit_expr(this); visitor->visit_expr(this);
} }
void call::accept(ast_visitor* visitor) {
visitor->visit_call(this);
}
void file_info::accept(ast_visitor* visitor) { void file_info::accept(ast_visitor* visitor) {
visitor->visit_file_info(this); visitor->visit_file_info(this);
} }

View File

@ -76,6 +76,14 @@ public:
virtual void accept(ast_visitor*); 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 { class file_info:public expr {
private: private:
uint16_t index; uint16_t index;
@ -353,7 +361,7 @@ public:
class call_expr:public expr { class call_expr:public expr {
private: private:
expr* first; expr* first;
std::vector<expr*> calls; std::vector<call*> calls;
public: public:
call_expr(const span& location): call_expr(const span& location):
@ -361,45 +369,45 @@ public:
first(nullptr) {} first(nullptr) {}
~call_expr(); ~call_expr();
void set_first(expr* node) {first = node;} 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;} expr* get_first() {return first;}
std::vector<expr*>& get_calls() {return calls;} std::vector<call*>& get_calls() {return calls;}
void accept(ast_visitor*) override; void accept(ast_visitor*) override;
}; };
class call_hash:public expr { class call_hash:public call {
private: private:
std::string field; std::string field;
public: public:
call_hash(const span& location, const std::string& name): call_hash(const span& location, const std::string& name):
expr(location, expr_type::ast_callh), call(location, expr_type::ast_callh),
field(name) {} field(name) {}
~call_hash() = default; ~call_hash() = default;
const std::string& get_field() const {return field;} const std::string& get_field() const {return field;}
void accept(ast_visitor*) override; void accept(ast_visitor*) override;
}; };
class call_vector:public expr { class call_vector:public call {
private: private:
std::vector<slice_vector*> calls; std::vector<slice_vector*> calls;
public: public:
call_vector(const span& location): call_vector(const span& location):
expr(location, expr_type::ast_callv) {} call(location, expr_type::ast_callv) {}
~call_vector(); ~call_vector();
void add_slice(slice_vector* node) {calls.push_back(node);} void add_slice(slice_vector* node) {calls.push_back(node);}
std::vector<slice_vector*>& get_slices() {return calls;} std::vector<slice_vector*>& get_slices() {return calls;}
void accept(ast_visitor*) override; void accept(ast_visitor*) override;
}; };
class call_function:public expr { class call_function:public call {
private: private:
std::vector<expr*> args; std::vector<expr*> args;
public: public:
call_function(const span& location): call_function(const span& location):
expr(location, expr_type::ast_callf) {} call(location, expr_type::ast_callf) {}
~call_function(); ~call_function();
void add_argument(expr* node) {args.push_back(node);} void add_argument(expr* node) {args.push_back(node);}
std::vector<expr*>& get_argument() {return args;} std::vector<expr*>& get_argument() {return args;}

View File

@ -27,31 +27,31 @@ void codegen::check_id_exist(identifier* node) {
} }
void codegen::regist_num(const f64 num) { void codegen::regist_num(const f64 num) {
if (num_table.count(num)) { if (const_number_map.count(num)) {
return; return;
} }
u32 size = num_table.size(); u32 size = const_number_map.size();
num_table[num] = size; const_number_map[num] = size;
num_res.push_back(num); const_number_table.push_back(num);
} }
void codegen::regist_str(const std::string& str) { void codegen::regist_str(const std::string& str) {
if (str_table.count(str)) { if (const_string_map.count(str)) {
return; return;
} }
u32 size = str_table.size(); u32 size = const_string_map.size();
str_table[str] = size; const_string_map[str] = size;
str_res.push_back(str); const_string_table.push_back(str);
} }
void codegen::find_symbol(code_block* node) { void codegen::find_symbol(code_block* node) {
auto finder = std::unique_ptr<symbol_finder>(new symbol_finder); auto finder = std::unique_ptr<symbol_finder>(new symbol_finder);
for(const auto& i : finder->do_find(node)) { 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 (local.empty()) {
if (global.count(name)) { if (global.count(name)) {
return; return;
@ -101,19 +101,19 @@ void codegen::gen(u8 operation_code, u32 num, u32 line) {
void codegen::num_gen(number_literal* node) { void codegen::num_gen(number_literal* node) {
f64 num = node->get_number(); f64 num = node->get_number();
regist_num(num); 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) { void codegen::str_gen(string_literal* node) {
const auto& str = node->get_content(); const auto& str = node->get_content();
regist_str(str); 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) { void codegen::bool_gen(bool_literal* node) {
f64 num = node->get_flag()? 1:0; f64 num = node->get_flag()? 1:0;
regist_num(num); 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) { void codegen::vec_gen(vector_expr* node) {
@ -129,7 +129,7 @@ void codegen::hash_gen(hash_expr* node) {
calc_gen(child->get_value()); calc_gen(child->get_value());
const auto& field_name = child->get_name(); const auto& field_name = child->get_name();
regist_str(field_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); regist_str(name);
switch(tmp->get_parameter_type()) { switch(tmp->get_parameter_type()) {
case parameter::param_type::normal_parameter: 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; break;
case parameter::param_type::default_parameter: case parameter::param_type::default_parameter:
calc_gen(tmp->get_default_value()); 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; break;
case parameter::param_type::dynamic_parameter: 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; break;
} }
add_sym(name); add_symbol(name);
} }
code[newf].num = code.size()+1; // entry 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) { void codegen::call_hash_gen(call_hash* node) {
regist_str(node->get_field()); 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) { 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()); calc_gen(((hash_pair*)child)->get_value());
const auto& field_name = ((hash_pair*)child)->get_name(); const auto& field_name = ((hash_pair*)child)->get_name();
regist_str(field_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()); gen(op_callfh, 0, node->get_line());
} else { } else {
@ -399,7 +399,7 @@ void codegen::mcall_vec(call_vector* node) {
void codegen::mcall_hash(call_hash* node) { void codegen::mcall_hash(call_hash* node) {
regist_str(node->get_field()); 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) { void codegen::single_def(definition_expr* node) {
@ -417,9 +417,11 @@ void codegen::multi_def(definition_expr* node) {
if (node->get_tuple()) { if (node->get_tuple()) {
auto& vals = node->get_tuple()->get_elements(); auto& vals = node->get_tuple()->get_elements();
if (identifiers.size()<vals.size()) { if (identifiers.size()<vals.size()) {
die("lack values in multi-definition", node->get_tuple()->get_location()); die("lack values in multi-definition",
node->get_tuple()->get_location());
} else if (identifiers.size()>vals.size()) { } 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; i<size; ++i) { for(usize i = 0; i<size; ++i) {
calc_gen(vals[i]); calc_gen(vals[i]);
@ -466,7 +468,7 @@ void codegen::assignment_expression(assignment_expr* node) {
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_addeqc, num_table[num], node->get_line()); gen(op_addeqc, const_number_map[num], node->get_line());
} }
break; break;
case assignment_expr::assign_type::sub_equal: case assignment_expr::assign_type::sub_equal:
@ -479,7 +481,7 @@ void codegen::assignment_expression(assignment_expr* node) {
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_subeqc, num_table[num], node->get_line()); gen(op_subeqc, const_number_map[num], node->get_line());
} }
break; break;
case assignment_expr::assign_type::mult_equal: case assignment_expr::assign_type::mult_equal:
@ -492,7 +494,7 @@ void codegen::assignment_expression(assignment_expr* node) {
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_muleqc, num_table[num], node->get_line()); gen(op_muleqc, const_number_map[num], node->get_line());
} }
break; break;
case assignment_expr::assign_type::div_equal: case assignment_expr::assign_type::div_equal:
@ -505,7 +507,7 @@ void codegen::assignment_expression(assignment_expr* node) {
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); regist_num(num);
gen(op_diveqc, num_table[num], node->get_line()); gen(op_diveqc, const_number_map[num], node->get_line());
} }
break; break;
case assignment_expr::assign_type::concat_equal: case assignment_expr::assign_type::concat_equal:
@ -518,7 +520,7 @@ void codegen::assignment_expression(assignment_expr* node) {
} else { } else {
const auto& str = ((string_literal*)node->get_right())->get_content(); const auto& str = ((string_literal*)node->get_right())->get_content();
regist_str(str); regist_str(str);
gen(op_lnkeqc, str_table[str], node->get_line()); gen(op_lnkeqc, const_string_map[str], node->get_line());
} }
break; break;
case assignment_expr::assign_type::bitwise_and_equal: 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()); gen(op_meq, 1, tuple[i]->get_line());
} }
} }
} else { return;
calc_gen(node->get_value());
auto& tuple = node->get_tuple()->get_elements();
for(i32 i = 0; i<size; ++i) {
gen(op_callvi, i, node->get_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());
} }
calc_gen(node->get_value());
auto& tuple = node->get_tuple()->get_elements();
for(i32 i = 0; i<size; ++i) {
gen(op_callvi, i, node->get_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) { void codegen::cond_gen(condition_expr* node) {
@ -709,7 +711,7 @@ void codegen::for_gen(for_expr* node) {
usize jmp_place = code.size(); usize jmp_place = code.size();
if (node->get_condition()->get_type()==expr_type::ast_null) { if (node->get_condition()->get_type()==expr_type::ast_null) {
regist_num(1); 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 { } else {
calc_gen(node->get_condition()); calc_gen(node->get_condition());
} }
@ -735,10 +737,11 @@ void codegen::forei_gen(forei_expr* node) {
gen(op_feach, 0, node->get_line()); gen(op_feach, 0, node->get_line());
} }
if (node->get_iterator()->get_name()) { // define a new iterator 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()? local.empty()?
gen(op_loadg, global_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), node->get_iterator()->get_name()->get_line()); gen(op_loadl, local_find(str), name_node->get_line());
} else { // use exist variable as the iterator } else { // use exist variable as the iterator
mcall(node->get_iterator()->get_call()); mcall(node->get_iterator()->get_call());
if (code.back().op==op_mcallg) { if (code.back().op==op_mcallg) {
@ -763,15 +766,17 @@ void codegen::forei_gen(forei_expr* node) {
void codegen::statement_generation(expr* node) { void codegen::statement_generation(expr* node) {
switch(node->get_type()) { switch(node->get_type()) {
case expr_type::ast_null:break; case expr_type::ast_null: break;
case expr_type::ast_def: case expr_type::ast_def:
def_gen((definition_expr*)node); break; def_gen((definition_expr*)node); break;
case expr_type::ast_multi_assign: case expr_type::ast_multi_assign:
multi_assign_gen((multi_assign*)node); break; multi_assign_gen((multi_assign*)node); break;
case expr_type::ast_assign: case expr_type::ast_assign:
assignment_statement((assignment_expr*)node); break; assignment_statement((assignment_expr*)node); break;
case expr_type::ast_nil:case expr_type::ast_num: case expr_type::ast_nil:
case expr_type::ast_str:case expr_type::ast_bool: break; 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_vec:
case expr_type::ast_hash: case expr_type::ast_hash:
case expr_type::ast_func: case expr_type::ast_func:
@ -788,35 +793,35 @@ void codegen::statement_generation(expr* node) {
void codegen::or_gen(binary_operator* node) { void codegen::or_gen(binary_operator* node) {
calc_gen(node->get_left()); 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_jt, 0, node->get_left()->get_line());
gen(op_pop, 0, node->get_left()->get_line()); gen(op_pop, 0, node->get_left()->get_line());
calc_gen(node->get_right()); 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_jt, 0, node->get_right()->get_line());
gen(op_pop, 0, node->get_right()->get_line()); gen(op_pop, 0, node->get_right()->get_line());
gen(op_pnil, 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) { void codegen::and_gen(binary_operator* node) {
calc_gen(node->get_left()); calc_gen(node->get_left());
gen(op_jt, code.size()+2, node->get_left()->get_line()); 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_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()); calc_gen(node->get_right());
gen(op_jt, code.size()+3, node->get_right()->get_line()); 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_pop, 0, node->get_right()->get_line());
gen(op_pnil, 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) { void codegen::unary_gen(unary_operator* node) {
@ -884,7 +889,7 @@ void codegen::binary_gen(binary_operator* node) {
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); 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; return;
case binary_operator::binary_type::sub: case binary_operator::binary_type::sub:
@ -895,7 +900,7 @@ void codegen::binary_gen(binary_operator* node) {
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); 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; return;
case binary_operator::binary_type::mult: case binary_operator::binary_type::mult:
@ -906,7 +911,7 @@ void codegen::binary_gen(binary_operator* node) {
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); 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; return;
case binary_operator::binary_type::div: case binary_operator::binary_type::div:
@ -917,7 +922,7 @@ void codegen::binary_gen(binary_operator* node) {
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); 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; return;
case binary_operator::binary_type::concat: case binary_operator::binary_type::concat:
@ -928,7 +933,7 @@ void codegen::binary_gen(binary_operator* node) {
} else { } else {
const auto& str = ((string_literal*)node->get_right())->get_content(); const auto& str = ((string_literal*)node->get_right())->get_content();
regist_str(str); 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; break;
case binary_operator::binary_type::less: case binary_operator::binary_type::less:
@ -939,7 +944,7 @@ void codegen::binary_gen(binary_operator* node) {
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); 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; return;
case binary_operator::binary_type::leq: case binary_operator::binary_type::leq:
@ -950,7 +955,7 @@ void codegen::binary_gen(binary_operator* node) {
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); 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; return;
case binary_operator::binary_type::grt: case binary_operator::binary_type::grt:
@ -961,7 +966,7 @@ void codegen::binary_gen(binary_operator* node) {
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); 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; return;
case binary_operator::binary_type::geq: case binary_operator::binary_type::geq:
@ -972,7 +977,7 @@ void codegen::binary_gen(binary_operator* node) {
} else { } else {
auto num = ((number_literal*)node->get_right())->get_number(); auto num = ((number_literal*)node->get_right())->get_number();
regist_num(num); 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; return;
default: break; default: break;
@ -981,14 +986,14 @@ void codegen::binary_gen(binary_operator* node) {
void codegen::trino_gen(ternary_operator* node) { void codegen::trino_gen(ternary_operator* node) {
calc_gen(node->get_condition()); calc_gen(node->get_condition());
usize lfalse = code.size(); usize label_jump_false = code.size();
gen(op_jf, 0, node->get_condition()->get_line()); gen(op_jf, 0, node->get_condition()->get_line());
calc_gen(node->get_left()); 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()); 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()); calc_gen(node->get_right());
code[lexit].num = code.size(); code[label_jump_to_exit].num = code.size();
} }
void codegen::calc_gen(expr* node) { void codegen::calc_gen(expr* node) {
@ -1031,11 +1036,13 @@ void codegen::calc_gen(expr* node) {
void codegen::block_gen(code_block* node) { void codegen::block_gen(code_block* node) {
for(auto tmp : node->get_expressions()) { for(auto tmp : node->get_expressions()) {
switch(tmp->get_type()) { switch(tmp->get_type()) {
case expr_type::ast_null:break; case expr_type::ast_null: break;
case expr_type::ast_id: case expr_type::ast_id:
check_id_exist((identifier*)tmp); break; check_id_exist((identifier*)tmp); break;
case expr_type::ast_nil:case expr_type::ast_num: case expr_type::ast_nil:
case expr_type::ast_str:case expr_type::ast_bool:break; case expr_type::ast_num:
case expr_type::ast_str:
case expr_type::ast_bool: break;
case expr_type::ast_file_info: case expr_type::ast_file_info:
// special node type in main block // special node type in main block
fileindex = ((file_info*)tmp)->get_index(); break; fileindex = ((file_info*)tmp)->get_index(); break;
@ -1090,73 +1097,76 @@ const error& codegen::compile(parse& parse, linker& import) {
gen(op_exit, 0, 0); gen(op_exit, 0, 0);
// size out of bound check // 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", 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) { if (const_string_table.size()>0xffffff) {
err.load(file[0]); // load main execute file
err.err("code", 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) { if (global.size()>=STACK_DEPTH) {
err.load(file[0]); // load main execute file
err.err("code", 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) { if (code.size()>0xffffff) {
err.load(file[0]); // load main execute file
err.err("code", err.err("code",
"bytecode size overflow: " + std::to_string(code.size())); "bytecode size overflow: " + std::to_string(code.size()));
} }
return err; return err;
} }
void codegen::print() { void codegen::print(std::ostream& out) {
// func end stack, reserved for code print // func end stack, reserved for code print
std::stack<u32> fbstk; std::stack<u32> func_begin_stack;
std::stack<u32> festk; std::stack<u32> func_end_stack;
// print const numbers // print const numbers
for(auto num : num_res) { for(auto num : const_number_table) {
std::cout << " .number " << num << "\n"; out << " .number " << num << "\n";
} }
// print const strings // print const strings
for(const auto& str : str_res) { for(const auto& str : const_string_table) {
std::cout << " .symbol \"" << rawstr(str) << "\"\n"; out << " .symbol \"" << rawstr(str) << "\"\n";
}
// print blank line
if (const_number_table.size() || const_string_table.size()) {
out << "\n";
} }
// print code // print code
std::cout<<"\n"; codestream::set(const_number_table.data(), const_string_table.data());
codestream::set(num_res.data(), str_res.data());
for(u32 i = 0; i<code.size(); ++i) { for(u32 i = 0; i<code.size(); ++i) {
// print opcode index, opcode name, opcode immediate number // print opcode index, opcode name, opcode immediate number
const auto& c = code[i]; const auto& c = code[i];
if (!festk.empty() && i==festk.top()) { if (!func_end_stack.empty() && i==func_end_stack.top()) {
std::cout << std::hex << "<0x" << fbstk.top() << std::dec << ">;\n"; out << std::hex << "<0x" << func_begin_stack.top() << std::dec << ">;\n";
// avoid two empty lines // avoid two empty lines
if (c.op!=op_newf) { if (c.op!=op_newf) {
std::cout<<"\n"; out<<"\n";
} }
fbstk.pop(); func_begin_stack.pop();
festk.pop(); func_end_stack.pop();
} }
// get function begin index and end index // get function begin index and end index
if (c.op==op_newf) { 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<code.size(); ++j) { for(u32 j = i; j<code.size(); ++j) {
if (code[j].op==op_jmp) { if (code[j].op==op_jmp) {
fbstk.push(i); func_begin_stack.push(i);
festk.push(code[j].num); func_end_stack.push(code[j].num);
break; break;
} }
} }
} }
// output bytecode // output bytecode
std::cout << " " << codestream(c,i) << "\n"; out << " " << codestream(c,i) << "\n";
} }
} }

View File

@ -25,10 +25,10 @@ private:
error& err; error& err;
const std::string* file; const std::string* file;
std::stack<u32> in_iterloop; std::stack<u32> in_iterloop;
std::unordered_map<f64,u32> num_table; std::unordered_map<f64,u32> const_number_map;
std::unordered_map<std::string,u32> str_table; std::unordered_map<std::string,u32> const_string_map;
std::vector<f64> num_res; std::vector<f64> const_number_table;
std::vector<std::string> str_res; std::vector<std::string> const_string_table;
std::vector<opcode> code; std::vector<opcode> code;
std::list<std::vector<i32>> continue_ptr; std::list<std::vector<i32>> continue_ptr;
std::list<std::vector<i32>> break_ptr; std::list<std::vector<i32>> break_ptr;
@ -49,7 +49,7 @@ private:
void regist_num(const f64); void regist_num(const f64);
void regist_str(const std::string&); void regist_str(const std::string&);
void find_symbol(code_block*); void find_symbol(code_block*);
void add_sym(const std::string&); void add_symbol(const std::string&);
i32 local_find(const std::string&); i32 local_find(const std::string&);
i32 global_find(const std::string&); i32 global_find(const std::string&);
i32 upvalue_find(const std::string&); i32 upvalue_find(const std::string&);
@ -93,11 +93,13 @@ private:
void block_gen(code_block*); void block_gen(code_block*);
void ret_gen(return_expr*); void ret_gen(return_expr*);
public:
const std::vector<std::string>& strs() const {return const_string_table;}
const std::vector<f64>& nums() const {return const_number_table;}
const std::vector<opcode>& codes() const {return code;}
public: public:
codegen(error& e): fileindex(0), err(e), file(nullptr) {} codegen(error& e): fileindex(0), err(e), file(nullptr) {}
const error& compile(parse&, linker&); const error& compile(parse&, linker&);
void print(); void print(std::ostream&);
const std::vector<std::string>& strs() const {return str_res;}
const std::vector<f64>& nums() const {return num_res;}
const std::vector<opcode>& codes() const {return code;}
}; };

View File

@ -1,35 +1,34 @@
#include "nasal_opcode.h" #include "nasal_opcode.h"
const char* opname[]={ const char* opname[] = {
"exit ","intg ","intl ","loadg ", "exit ", "intg ", "intl ", "loadg ",
"loadl ","loadu ","pnum ","pnil ", "loadl ", "loadu ", "pnum ", "pnil ",
"pstr ","newv ","newh ","newf ", "pstr ", "newv ", "newh ", "newf ",
"happ ","para ","def ","dyn ", "happ ", "para ", "def ", "dyn ",
"lnot ","usub ","bnot ","btor ", "lnot ", "usub ", "bitnot", "bitor ",
"btxor ","btand ","add ","sub ", "bitxor", "bitand", "add ", "sub ",
"mult ","div ","lnk ","addc ", "mult ", "div ", "lnk ", "addc ",
"subc ","multc ","divc ","lnkc ", "subc ", "multc ", "divc ", "lnkc ",
"addeq ","subeq ","muleq ","diveq ", "addeq ", "subeq ", "muleq ", "diveq ",
"lnkeq ","bandeq","boreq ","bxoreq", "lnkeq ", "bandeq", "boreq ", "bxoreq",
"addeqc","subeqc","muleqc","diveqc", "addeqc", "subeqc", "muleqc", "diveqc",
"lnkeqc","addecp","subecp","mulecp", "lnkeqc", "addecp", "subecp", "mulecp",
"divecp","lnkecp","meq ","eq ", "divecp", "lnkecp", "meq ", "eq ",
"neq ","less ","leq ","grt ", "neq ", "less ", "leq ", "grt ",
"geq ","lessc ","leqc ","grtc ", "geq ", "lessc ", "leqc ", "grtc ",
"geqc ","pop ","jmp ","jt ", "geqc ", "pop ", "jmp ", "jt ",
"jf ","cnt ","findx ","feach ", "jf ", "cnt ", "findx ", "feach ",
"callg ","calll ","upval ","callv ", "callg ", "calll ", "upval ", "callv ",
"callvi","callh ","callfv","callfh", "callvi", "callh ", "callfv", "callfh",
"callb ","slcbeg","slcend","slc ", "callb ", "slcbeg", "slcend", "slice ",
"slc2 ","mcallg","mcalll","mupval", "slice2", "mcallg", "mcalll", "mupval",
"mcallv","mcallh","ret " "mcallv", "mcallh", "ret "
}; };
void codestream::set( void codestream::set(
const f64* numbuff, const f64* numbuff,
const std::string* strbuff, const std::string* strbuff,
const std::string* filelist const std::string* filelist) {
) {
nums = numbuff; nums = numbuff;
strs = strbuff; strs = strbuff;
files = filelist; files = filelist;
@ -40,14 +39,14 @@ void codestream::dump(std::ostream& out) const {
using std::setfill; using std::setfill;
using std::hex; using std::hex;
using std::dec; using std::dec;
auto op=code.op; auto op = code.op;
auto num=code.num; auto num = code.num;
out<<hex<<"0x" out << hex << "0x"
<<setw(6)<<setfill('0')<<index<<" " << setw(6) << setfill('0') << index << " "
<<setw(2)<<setfill('0')<<(u32)op<<" " << setw(2) << setfill('0') << (u32)op << " "
<<setw(2)<<setfill('0')<<((num>>16)&0xff)<<" " << setw(2) << setfill('0') << ((num>>16)&0xff) << " "
<<setw(2)<<setfill('0')<<((num>>8)&0xff)<<" " << setw(2) << setfill('0') << ((num>>8)&0xff) << " "
<<setw(2)<<setfill('0')<<(num&0xff)<<" " << setw(2) << setfill('0') << (num&0xff) << " "
<<opname[op]<<" "<<dec; <<opname[op]<<" "<<dec;
switch(op) { switch(op) {
case op_addeq: case op_subeq: case op_addeq: case op_subeq:
@ -55,23 +54,28 @@ void codestream::dump(std::ostream& out) const {
case op_lnkeq: case op_meq: case op_lnkeq: case op_meq:
case op_btandeq: case op_btoreq: case op_btandeq: case op_btoreq:
case op_btxoreq: case op_btxoreq:
out<<hex<<"0x"<<num<<dec<<" sp-"<<num;break; out << hex << "0x" << num << dec << " sp-" << num; break;
case op_addeqc: case op_subeqc: case op_addeqc: case op_subeqc:
case op_muleqc:case op_diveqc: case op_muleqc:case op_diveqc:
out<<hex<<"0x"<<num<<dec<<" ("<<nums[num]<<")";break; out << hex << "0x" << num << dec
<< " (" << nums[num] << ")"; break;
case op_lnkeqc: case op_lnkeqc:
out<<hex<<"0x"<<num<<dec<<" ("<<rawstr(strs[num], 16)<<")";break; out << hex << "0x" << num << dec
<< " (" << rawstr(strs[num], 16) << ")"; break;
case op_addecp: case op_subecp: case op_addecp: case op_subecp:
case op_mulecp: case op_divecp: case op_mulecp: case op_divecp:
out<<hex<<"0x"<<num<<dec<<" ("<<nums[num]<<") sp-1";break; out << hex << "0x" << num << dec
<< " (" << nums[num] << ") sp-1"; break;
case op_lnkecp: case op_lnkecp:
out<<hex<<"0x"<<num<<dec<<" ("<<rawstr(strs[num], 16)<<") sp-1";break; out << hex << "0x" << num << dec
<< " (" << rawstr(strs[num], 16) << ") sp-1"; break;
case op_addc: case op_subc: case op_addc: case op_subc:
case op_mulc: case op_divc: case op_mulc: case op_divc:
case op_lessc: case op_leqc: case op_lessc: case op_leqc:
case op_grtc: case op_geqc: case op_grtc: case op_geqc:
case op_pnum: case op_pnum:
out<<hex<<"0x"<<num<<dec<<" ("<<nums[num]<<")";break; out << hex << "0x" << num << dec
<< " (" << nums[num] << ")"; break;
case op_callvi: case op_newv: case op_callvi: case op_newv:
case op_callfv: case op_intg: case op_callfv: case op_intg:
case op_intl: case op_findex: case op_intl: case op_findex:
@ -81,27 +85,28 @@ void codestream::dump(std::ostream& out) const {
case op_mcallg: case op_loadg: case op_mcallg: case op_loadg:
case op_calll: case op_mcalll: case op_calll: case op_mcalll:
case op_loadl: case op_loadl:
out<<hex<<"0x"<<num<<dec;break; out << hex << "0x" << num << dec; break;
case op_callb: case op_callb:
out<<hex<<"0x"<<num<<" <"<<builtin[num].name out << hex << "0x" << num << " <" << builtin[num].name
<<"@0x"<<(u64)builtin[num].func<<dec<<">";break; << "@0x" << (u64)builtin[num].func << dec << ">"; break;
case op_upval: case op_mupval: case op_upval: case op_mupval:
case op_loadu: case op_loadu:
out<<hex<<"0x"<<((num>>16)&0xffff) out << hex << "0x" << ((num>>16)&0xffff)
<<"[0x"<<(num&0xffff)<<"]"<<dec;break; << "[0x" << (num&0xffff) << "]" << dec; break;
case op_happ: case op_pstr: case op_happ: case op_pstr:
case op_lnkc: case op_callh: case op_lnkc: case op_callh:
case op_mcallh: case op_para: case op_mcallh: case op_para:
case op_deft: case op_dyn: case op_deft: case op_dyn:
out<<hex<<"0x"<<num<<dec<<" ("<<rawstr(strs[num], 16)<<")";break; out << hex << "0x" << num << dec
<< " (" << rawstr(strs[num], 16) << ")"; break;
default: default:
if (files) { if (files) {
out<<hex<<"0x"<<num<<dec; out << hex << "0x" << num << dec;
} }
break; break;
} }
if (files) { if (files) {
out<<"("<<files[code.fidx]<<":"<<code.line<<")"; out << "(" << files[code.fidx] << ":" << code.line << ")";
} }
} }

View File

@ -639,7 +639,7 @@ expr* parse::scalar() {
return node; return node;
} }
expr* parse::call_scalar() { call* parse::call_scalar() {
switch(toks[ptr].type) { switch(toks[ptr].type) {
case tok::lcurve: return callf(); break; case tok::lcurve: return callf(); break;
case tok::lbracket: return callv(); break; case tok::lbracket: return callv(); break;
@ -647,7 +647,7 @@ expr* parse::call_scalar() {
default: break; default: break;
} }
// unreachable // unreachable
return null(); return new call(toks[ptr].loc, expr_type::ast_null);
} }
call_hash* parse::callh() { call_hash* parse::callh() {

View File

@ -114,7 +114,7 @@ private:
expr* multive_expr(); expr* multive_expr();
unary_operator* unary(); unary_operator* unary();
expr* scalar(); expr* scalar();
expr* call_scalar(); call* call_scalar();
call_hash* callh(); call_hash* callh();
call_vector* callv(); call_vector* callv();
call_function* callf(); call_function* callf();

View File

@ -3,34 +3,34 @@
# print is used to print all things in nasal, try and see how it works. # print is used to print all things in nasal, try and see how it works.
# this function uses std::cout to output logs. # this function uses std::cout to output logs.
var print=func(elems...){ var print = func(elems...) {
return __print(elems); return __print(elems);
} }
# append is used to add values into a vector. # append is used to add values into a vector.
var append=func(vec,elems...){ var append = func(vec, elems...) {
return __append(vec,elems); return __append(vec, elems);
} }
# setsize is used to change the size of vector. # setsize is used to change the size of vector.
# if the size is larger than before, # if the size is larger than before,
# this function will fill vm_nil into uninitialized space. # this function will fill vm_nil into uninitialized space.
var setsize=func(vec,size){ var setsize = func(vec, size) {
return __setsize(vec,size); return __setsize(vec, size);
} }
# system has the same use in C. # system has the same use in C.
var system=func(str){ var system = func(str) {
return __system(str); return __system(str);
} }
# input uses std::cin and returns what we input. # input uses std::cin and returns what we input.
var input=func(end=nil){ var input = func(end = nil) {
return __input(end); return __input(end);
} }
# readline # readline
var readline=func(prompt="> ") { var readline = func(prompt = "> ") {
print(prompt); print(prompt);
return input("\n"); return input("\n");
} }
@ -38,224 +38,224 @@ var readline=func(prompt="> ") {
# split a string by separator for example: # split a string by separator for example:
# split("ll","hello world") -> ["he","o world"] # split("ll","hello world") -> ["he","o world"]
# this function will return a vector. # this function will return a vector.
var split=func(separator,str){ var split = func(separator, str) {
return __split(separator,str); return __split(separator, str);
} }
# rand has the same function as the rand in C # rand has the same function as the rand in C
# if seed is nil, it will return the random number. # if seed is nil, it will return the random number.
# if seed is not nil, it will be initialized by this seed. # 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); return __rand(seed);
} }
# id will return the pointer of an gc-object. # id will return the pointer of an gc-object.
# if this object is not managed by gc, it will return 0. # if this object is not managed by gc, it will return 0.
var id=func(object){ var id = func(object) {
return __id(object); return __id(object);
} }
# int will get the integer of input number/string. # int will get the integer of input number/string.
# but carefully use it, because int has range between -2147483648~2147483647 # but carefully use it, because int has range between -2147483648~2147483647
var int=func(val){ var int = func(val) {
return __int(val); return __int(val);
} }
# floor will get the integral number of input argument # floor will get the integral number of input argument
# which is less than or equal to this argument # which is less than or equal to this argument
var floor=func(val){ var floor = func(val) {
return __floor(val); return __floor(val);
} }
# exit using std::exit # exit using std::exit
var exit=func(val=-1){ var exit = func(val = -1) {
return __exit(val); return __exit(val);
} }
# abort using std::abort # abort using std::abort
var abort=func(){ var abort = func() {
__abort(); __abort();
} }
# abs gets absolute number. # abs gets absolute number.
var abs=func(n){ var abs = func(n) {
return n>0?n:-n; return n>0? n:-n;
} }
# num will change all the other types into number. # num will change all the other types into number.
# mostly used to change a numerable string. # mostly used to change a numerable string.
var num=func(val){ var num = func(val) {
return __num(val); return __num(val);
} }
# pop used to pop the last element in a vector. # pop used to pop the last element in a vector.
# this function will return the value that poped if vector has element(s). # this function will return the value that poped if vector has element(s).
# if the vector is empty, it will return nil. # if the vector is empty, it will return nil.
var pop=func(vec){ var pop = func(vec) {
return __pop(vec); return __pop(vec);
} }
# str is used to change number into string. # str is used to change number into string.
var str=func(num){ var str = func(num) {
return __str(num); return __str(num);
} }
# size can get the size of a string/vector/hashmap. # 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. # 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. # so don't do useless things, though it really works.
var size=func(object){ var size = func(object) {
return __size(object); return __size(object);
} }
# contains is used to check if a key exists in a hashmap/dict. # contains is used to check if a key exists in a hashmap/dict.
var contains=func(hash,key){ var contains = func(hash, key) {
return __contains(hash,key); return __contains(hash, key);
} }
# delete is used to delete a pair in a hashmap/dict by key. # delete is used to delete a pair in a hashmap/dict by key.
var delete=func(hash,key){ var delete = func(hash, key) {
return __delete(hash,key); return __delete(hash, key);
} }
# keys is used to get all keys in a hashmap/dict. # keys is used to get all keys in a hashmap/dict.
# this function will return a vector. # this function will return a vector.
var keys=func(hash){ var keys = func(hash) {
return __keys(hash); return __keys(hash);
} }
# time has the same function in C. # time has the same function in C.
var time=func(begin){ var time = func(begin) {
return __time(begin); return __time(begin);
} }
var systime=func(){ var systime = func() {
return time(0); return time(0);
} }
# die is a special native function. # die is a special native function.
# use it at where you want the program to crash immediately. # use it at where you want the program to crash immediately.
var die=func(str){ var die = func(str = "error occurred.") {
return __die(str); return __die(str);
} }
# find will give the first position of the needle in haystack # find will give the first position of the needle in haystack
var find=func(needle,haystack){ var find = func(needle, haystack) {
return __find(needle,haystack); return __find(needle, haystack);
} }
# typeof is used to get the type of an object. # typeof is used to get the type of an object.
# this function returns a string. # this function returns a string.
var typeof=func(object){ var typeof = func(object) {
return __type(object); return __type(object);
} }
# subvec is used to get part of a vector # subvec is used to get part of a vector
var subvec=func(vec,begin,length=nil){ var subvec = func(vec, begin, length = nil) {
return vec[begin:(length==nil?nil:begin+length-1)]; return vec[begin:(length==nil? nil:begin+length-1)];
} }
# substr will get the sub-string. # substr will get the sub-string.
# it gets the string, the begin index and sub-string's length as arguments. # it gets the string, the begin index and sub-string's length as arguments.
var substr=func(str,begin,len){ var substr = func(str, begin, len) {
return __substr(str,begin,len); return __substr(str, begin, len);
} }
# streq is used to compare if two strings are the same. # streq is used to compare if two strings are the same.
var streq=func(a,b){ var streq = func(a, b) {
return __streq(a,b); return __streq(a, b);
} }
# left is used to get the sub-string like substr. # left is used to get the sub-string like substr.
# but the begin index is 0. # but the begin index is 0.
var left=func(str,len){ var left = func(str, len) {
return __left(str,len); return __left(str, len);
} }
# right i used to get the sub-string like substr. # right i used to get the sub-string like substr.
# but the begin index is strlen-len. # but the begin index is strlen-len.
var right=func(str,len){ var right = func(str, len) {
return __right(str,len); return __right(str, len);
} }
# cmp is used to compare two strings. # cmp is used to compare two strings.
# normal string will not be correctly compared by operators < > <= >= # normal string will not be correctly compared by operators < > <= >=
# because these operators will turn strings into numbers then compare. # because these operators will turn strings into numbers then compare.
var cmp=func(a,b){ var cmp = func(a, b) {
return __cmp(a,b); return __cmp(a,b);
} }
# chr is used to get the character by ascii-number. # chr is used to get the character by ascii-number.
# for example chr(65) -> 'A' # for example chr(65) -> 'A'
var chr=func(code){ var chr = func(code) {
return __chr(code); return __chr(code);
} }
# char will give you the real character of ascii-number # char will give you the real character of ascii-number
# instead of extend-ascii when number between 128~256 # instead of extend-ascii when number between 128~256
var char=func(code){ var char = func(code) {
return __char(code); return __char(code);
} }
# mut is used to change unmutable strings to mutable. # mut is used to change unmutable strings to mutable.
var mut=func(str){ var mut = func(str) {
return str~""; return str~"";
} }
# srand wraps up rand, using time(0) as the seed. # srand wraps up rand, using time(0) as the seed.
var srand=func(){ var srand = func() {
rand(time(0)); rand(time(0));
return 0; return 0;
} }
# values() gets all values in a hash. # values() gets all values in a hash.
var values=func(hash){ var values = func(hash) {
return __values(hash); return __values(hash);
} }
# println has the same function as print. # println has the same function as print.
# but it will output a '\n' after using print. # but it will output a '\n' after using print.
var println=func(elems...){ var println = func(elems...) {
return __println(elems); return __println(elems);
} }
var isfunc=func(f){ var isfunc = func(f) {
return typeof(f)=="func"; return typeof(f)=="func";
} }
var isghost=func(g){ var isghost = func(g) {
return typeof(g)=="obj"; return typeof(g)=="obj";
} }
var ishash=func(h){ var ishash = func(h) {
return typeof(h)=="hash"; return typeof(h)=="hash";
} }
var isint=func(x){ var isint = func(x) {
return x==floor(x); return x==floor(x);
} }
var isnum=func(x){ var isnum = func(x) {
return typeof(x)=="num" or !math.isnan(num(x)); return typeof(x)=="num" or !math.isnan(num(x));
} }
var isscalar=func(s){ var isscalar = func(s) {
var t=typeof(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"; return typeof(s)=="str";
} }
var isvec=func(v){ var isvec = func(v) {
return typeof(v)=="vec"; return typeof(v)=="vec";
} }
var ghosttype=func(ghost_object) { var ghosttype = func(ghost_object) {
return __ghosttype(ghost_object); return __ghosttype(ghost_object);
} }
# get the index of val in the vec # get the index of val in the vec
var vecindex=func(vec,val){ var vecindex = func(vec,val) {
forindex(var i;vec) forindex(var i;vec)
if(val==vec[i]) if(val==vec[i])
return i; return i;
@ -263,8 +263,8 @@ var vecindex=func(vec,val){
} }
# check if the object is an instance of the class # check if the object is an instance of the class
var isa=func(object,class){ var isa = func(object, class) {
if(!contains(object,"parents") or typeof(object.parents)!="vec") if(!contains(object, "parents") or typeof(object.parents)!="vec")
return 0; return 0;
foreach(var elem;object.parents) foreach(var elem;object.parents)
if(elem==class) if(elem==class)
@ -273,202 +273,202 @@ var isa=func(object,class){
} }
# assert aborts when condition is not true # assert aborts when condition is not true
var assert=func(condition,message="assertion failed!"){ var assert = func(condition, message = "assertion failed!") {
if(condition) if(condition)
return 1; return 1;
die(message); die(message);
} }
# get time stamp, this will return a timestamp object # get time stamp, this will return a timestamp object
var maketimestamp=func(){ var maketimestamp = func() {
var t=0; var t = 0;
return { return {
stamp:func(){t=__millisec();}, stamp: func() {t = __millisec();},
elapsedMSec:func(){return __millisec()-t;}, elapsedMSec: func() {return __millisec()-t;},
elapsedUSec:func(){return (__millisec()-t)*1000;} elapsedUSec: func() {return (__millisec()-t)*1000;}
}; };
} }
# md5 # md5
var md5=func(str){ var md5 = func(str) {
return __md5(str); return __md5(str);
} }
var io={ var io = {
SEEK_SET:0, SEEK_SET: 0,
SEEK_CUR:1, SEEK_CUR: 1,
SEEK_END:2, SEEK_END: 2,
# get content of a file by filename. returns a string. # 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. # 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 # 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*. # 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*. # 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*. # same as C fread. read file by FILE*.
# caution: buf must be a mutable string.use mut("") to get an empty mutable string. # 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*. # 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*. # 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. # same as C ftell.
tell: func(filehandle){return __tell(filehandle);}, tell: func(filehandle) {return __tell(filehandle);},
# read file by lines. use FILE*. # read file by lines. use FILE*.
# get nil if EOF # get nil if EOF
readln:func(filehandle){return __readln(filehandle);}, readln: func(filehandle) {return __readln(filehandle);},
# same as C stat. # 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). # 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 # get file status. using data from io.stat
var fstat=func(filename){ var fstat = func(filename) {
var s=io.stat(filename); var s = io.stat(filename);
return { return {
st_dev: s[0], st_dev: s[0],
st_ino: s[1], st_ino: s[1],
st_mode: s[2], st_mode: s[2],
st_nlink:s[3], st_nlink: s[3],
st_uid: s[4], st_uid: s[4],
st_gid: s[5], st_gid: s[5],
st_rdev: s[6], st_rdev: s[6],
st_size: s[7], st_size: s[7],
st_atime:s[8], st_atime: s[8],
st_mtime:s[9], st_mtime: s[9],
st_ctime:s[10] st_ctime: s[10]
}; };
} }
# functions that do bitwise calculation. # functions that do bitwise calculation.
# carefully use it, all the calculations are based on integer. # carefully use it, all the calculations are based on integer.
var bits={ var bits = {
# u32 xor # u32 xor
u32_xor: func(a,b){return __u32xor(a,b); }, u32_xor: func(a, b) {return __u32xor(a, b);},
# u32 and # u32 and
u32_and: func(a,b){return __u32and(a,b); }, u32_and: func(a, b) {return __u32and(a, b);},
# u32 or # u32 or
u32_or: func(a,b){return __u32or(a,b); }, u32_or: func(a, b) {return __u32or(a, b);},
# u32 nand # u32 nand
u32_nand:func(a,b){return __u32nand(a,b);}, u32_nand: func(a, b) {return __u32nand(a, b);},
# u32 not # 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: # get bit data from a special string. for example:
# bits.fld(s,0,3); # bits.fld(s,0,3);
# if s stores 10100010(162) # if s stores 10100010(162)
# will get 101(5). # 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: # get sign-extended data from a special string. for example:
# bits.sfld(s,0,3); # bits.sfld(s,0,3);
# if s stores 10100010(162) # if s stores 10100010(162)
# will get 101(5) then this will be signed extended to # will get 101(5) then this will be signed extended to
# 11111101(-3). # 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: # set value into a special string to store it. little-endian, for example:
# bits.setfld(s,0,8,69); # bits.setfld(s,0,8,69);
# set 01000101(69) to string will get this: # set 01000101(69) to string will get this:
# 10100010(162) # 10100010(162)
# so s[0]=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. # 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. # mostly used math functions and special constants, you know.
var math={ var math = {
e: 2.7182818284590452354, e: 2.7182818284590452354,
pi: 3.14159265358979323846264338327950288, pi: 3.14159265358979323846264338327950288,
D2R: 2.7182818284590452354/180, D2R: 2.7182818284590452354/180,
R2D: 180/2.7182818284590452354, R2D: 180/2.7182818284590452354,
inf: 1/0, inf: 1/0,
nan: 0/0, nan: 0/0,
abs: func(x) {return x>0?x:-x; }, abs: func(x) {return x>0? x:-x;},
floor: func(x) {return __floor(x); }, floor: func(x) {return __floor(x);},
pow: func(x,y){return __pow(x,y); }, pow: func(x, y) {return __pow(x, y);},
sin: func(x) {return __sin(x); }, sin: func(x) {return __sin(x);},
cos: func(x) {return __cos(x); }, cos: func(x) {return __cos(x);},
tan: func(x) {return __tan(x); }, tan: func(x) {return __tan(x);},
exp: func(x) {return __exp(x); }, exp: func(x) {return __exp(x);},
lg: func(x) {return __lg(x); }, lg: func(x) {return __lg(x);},
ln: func(x) {return __ln(x); }, ln: func(x) {return __ln(x);},
sqrt: func(x) {return __sqrt(x); }, sqrt: func(x) {return __sqrt(x);},
atan2: func(x,y){return __atan2(x,y);}, atan2: func(x, y) {return __atan2(x, y);},
isnan: func(x) {return __isnan(x); }, isnan: func(x) {return __isnan(x);},
max: func(x,y){return x>y?x:y; }, max: func(x, y) {return x>y? x:y;},
min: func(x,y){return x<y?x:y; } min: func(x, y) {return x<y? x:y;}
}; };
var unix={ var unix = {
pipe: func(){return __pipe;}, pipe: func() {return __pipe;},
fork: func(){return __fork;}, fork: func() {return __fork;},
dup2: func(fd0,fd1){die("not supported yet");}, dup2: func(fd0, fd1) {die("not supported yet");},
exec: func(filename,argv,envp){die("not supported yet");}, exec: func(filename, argv, envp) {die("not supported yet");},
waitpid: func(pid,nohang=0){return __waitpid;}, waitpid: func(pid, nohang = 0) {return __waitpid;},
isdir: func(path){return !!bits.u32_and(io.stat(path)[2],0x4000);}, # S_IFDIR 0x4000 isdir: func(path) {return !!bits.u32_and(io.stat(path)[2],0x4000);}, # S_IFDIR 0x4000
isfile: func(path){return !!bits.u32_and(io.stat(path)[2],0x8000);}, # S_IFREG 0x8000 isfile: func(path) {return !!bits.u32_and(io.stat(path)[2],0x8000);}, # S_IFREG 0x8000
opendir: func(path){return __opendir;}, opendir: func(path) {return __opendir;},
readdir: func(handle){return __readdir;}, readdir: func(handle) {return __readdir;},
closedir: func(handle){return __closedir;}, closedir: func(handle) {return __closedir;},
time: func(){return time(0);}, time: func() {return time(0);},
sleep: func(secs){return __sleep(secs);}, sleep: func(secs) {return __sleep(secs);},
chdir: func(path){return __chdir(path);}, chdir: func(path) {return __chdir(path);},
environ: func(){return __environ();}, environ: func() {return __environ();},
getcwd: func(){return __getcwd();}, getcwd: func() {return __getcwd();},
getenv: func(envvar){return __getenv(envvar);}, getenv: func(envvar) {return __getenv(envvar);},
getpath: func(){return split(os.platform()=="windows"?";":":",unix.getenv("PATH"));} getpath: func() {return split(os.platform()=="windows"? ";":":", unix.getenv("PATH"));}
}; };
# dylib is the core hashmap for developers to load their own library. # dylib is the core hashmap for developers to load their own library.
# for safe using dynamic library, you could use 'module' in stl/module.nas # for safe using dynamic library, you could use 'module' in stl/module.nas
var dylib={ var dylib = {
# open dynamic lib. return a hash including dl pointer and function pointers # open dynamic lib. return a hash including dl pointer and function pointers
dlopen: func(libname){ dlopen: func(libname) {
# find dynamic lib from local dir first # find dynamic lib from local dir first
libname=(os.platform()=="windows"?".\\":"./")~libname; libname = (os.platform()=="windows"? ".\\":"./")~libname;
if(io.exists(libname)) if(io.exists(libname))
return __dlopen(libname); return __dlopen(libname);
# find dynamic lib through PATH # find dynamic lib through PATH
var envpath=split(os.platform()=="windows"?";":":",unix.getenv("PATH")); var envpath = split(os.platform()=="windows"? ";":":",unix.getenv("PATH"));
# first find ./module # first find ./module
append(envpath,"."); append(envpath, ".");
var path=os.platform()=="windows"?"\\module\\":"/module/"; var path = os.platform()=="windows"? "\\module\\":"/module/";
foreach(var p;envpath){ foreach(var p;envpath) {
p~=path~libname; p ~= path~libname;
if(io.exists(p)){ if(io.exists(p)) {
libname=p; libname = p;
break; break;
} }
} }
return __dlopen(libname); return __dlopen(libname);
}, },
# close dynamic lib, this operation will make all the symbols loaded from it invalid. # close dynamic lib, this operation will make all the symbols loaded from it invalid.
dlclose: func(lib){return __dlclose; }, dlclose: func(lib) {return __dlclose;},
# call the loaded symbol, with infinite parameters: # call the loaded symbol, with infinite parameters:
# Caution: this may cause garbage collection process, be aware of the performance. # Caution: this may cause garbage collection process, be aware of the performance.
dlcall: func(ptr,args...){return __dlcallv}, dlcall: func(ptr, args...) {return __dlcallv},
# get dlcall function with limited parameter list # get dlcall function with limited parameter list
limitcall: func(arg_size=0){ limitcall: func(arg_size = 0) {
if(arg_size==0){return func(ptr){return __dlcall};} if(arg_size==0) {return func(ptr) {return __dlcall};}
elsif(arg_size==1){return func(ptr,_0){return __dlcall};} elsif(arg_size==1) {return func(ptr, _0) {return __dlcall};}
elsif(arg_size==2){return func(ptr,_0,_1){return __dlcall};} elsif(arg_size==2) {return func(ptr, _0, _1) {return __dlcall};}
elsif(arg_size==3){return func(ptr,_0,_1,_2){return __dlcall};} elsif(arg_size==3) {return func(ptr, _0, _1, _2) {return __dlcall};}
elsif(arg_size==4){return func(ptr,_0,_1,_2,_3){return __dlcall};} elsif(arg_size==4) {return func(ptr, _0, _1, _2, _3) {return __dlcall};}
elsif(arg_size==5){return func(ptr,_0,_1,_2,_3,_4){return __dlcall};} elsif(arg_size==5) {return func(ptr, _0, _1, _2, _3, _4) {return __dlcall};}
elsif(arg_size==6){return func(ptr,_0,_1,_2,_3,_4,_5){return __dlcall};} elsif(arg_size==6) {return func(ptr, _0, _1, _2, _3, _4, _5) {return __dlcall};}
elsif(arg_size==7){return func(ptr,_0,_1,_2,_3,_4,_5,_6){return __dlcall};} elsif(arg_size==7) {return func(ptr, _0, _1, _2, _3, _4, _5, _6) {return __dlcall};}
elsif(arg_size==8){return func(ptr,_0,_1,_2,_3,_4,_5,_6,_7){return __dlcall};} elsif(arg_size==8) {return func(ptr, _0, _1, _2, _3, _4, _5, _6, _7) {return __dlcall};}
else{return func(ptr,args...){return __dlcallv};} else {return func(ptr, args...) {return __dlcallv};}
} }
}; };
# os is used to use or get some os-related info/functions. # os is used to use or get some os-related info/functions.
# windows/macOS/linux are supported. # windows/macOS/linux are supported.
var os={ var os = {
# get a string that tell which os it runs on. # get a string that tell which os it runs on.
platform: func() {return __platform;}, platform: func() {return __platform;},
time: func() {return __logtime;}, time: func() {return __logtime;},
@ -476,39 +476,39 @@ var os={
}; };
# runtime gives us some functions that we could manage it manually. # runtime gives us some functions that we could manage it manually.
var runtime={ var runtime = {
# command line arguments # command line arguments
argv: func(){return __sysargv;}, argv: func() {return __sysargv;},
gc: { gc: {
extend: func(type){return __gcextd;} extend: func(type) {return __gcextd;}
} }
}; };
# functions that not supported in this runtime: # functions that not supported in this runtime:
var bind=func(function,locals,outer_scope=nil){ var bind = func(function, locals, outer_scope = nil) {
die("this runtime does not support bind"); die("this runtime does not support bind");
} }
var call=func(function,args=nil,_me=nil,locals=nil,error=nil){ var call = func(function ,args = nil, _me = nil, locals = nil, error = nil) {
die("this runtime does not support call"); die("this runtime does not support call");
} }
var caller=func(level=1){ var caller = func(level = 1) {
die("this runtime does not support caller"); die("this runtime does not support caller");
} }
var closure=func(function,level=1){ var closure = func(function, level = 1) {
die("this runtime uses \"vm_upval\" instead of \"vm_hash\" as the closure"); die("this runtime uses \"vm_upval\" instead of \"vm_hash\" as the closure");
} }
var compile=func(code,filename="<compile>"){ var compile = func(code, filename = "<compile>") {
die("this runtime uses static code generator"); die("this runtime uses static code generator");
} }
var coroutine={ var coroutine = {
create: func(function) {return __cocreate;}, create: func(function) {return __cocreate;},
resume: func(co,args...) {return __coresume;}, resume: func(co, args...) {return __coresume;},
yield: func(args...) {return __coyield; }, yield: func(args...) {return __coyield; },
status: func(co) {return __costatus;}, status: func(co) {return __costatus;},
running:func() {return __corun; } running:func() {return __corun; }
}; };

12
test/gc_test.nas Normal file
View File

@ -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 {});
}