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