✨ optimize codegen
This commit is contained in:
parent
5c714d26aa
commit
eca6141408
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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*);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;}
|
||||||
|
|
|
@ -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,7 +612,8 @@ 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());
|
calc_gen(node->get_value());
|
||||||
auto& tuple = node->get_tuple()->get_elements();
|
auto& tuple = node->get_tuple()->get_elements();
|
||||||
for(i32 i = 0; i<size; ++i) {
|
for(i32 i = 0; i<size; ++i) {
|
||||||
|
@ -630,7 +633,6 @@ void codegen::multi_assign_gen(multi_assign* node) {
|
||||||
}
|
}
|
||||||
gen(op_pop, 0, node->get_line());
|
gen(op_pop, 0, node->get_line());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void codegen::cond_gen(condition_expr* node) {
|
void codegen::cond_gen(condition_expr* node) {
|
||||||
std::vector<usize> jmp_label;
|
std::vector<usize> jmp_label;
|
||||||
|
@ -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) {
|
||||||
|
@ -770,8 +773,10 @@ void codegen::statement_generation(expr* node) {
|
||||||
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) {
|
||||||
|
@ -1034,8 +1039,10 @@ void codegen::block_gen(code_block* node) {
|
||||||
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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,8 +5,8 @@ const char* opname[]={
|
||||||
"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 ",
|
||||||
|
@ -20,16 +20,15 @@ const char* opname[]={
|
||||||
"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;
|
||||||
|
@ -58,20 +57,25 @@ void codestream::dump(std::ostream& out) const {
|
||||||
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:
|
||||||
|
@ -93,7 +97,8 @@ void codestream::dump(std::ostream& out) const {
|
||||||
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;
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -133,7 +133,7 @@ var systime=func(){
|
||||||
|
|
||||||
# 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {});
|
||||||
|
}
|
Loading…
Reference in New Issue