forked from xxq250/Nasal-Interpreter
Merge pull request #21 from ValKmjolnir/develop
👾 Update docs & optimize codes
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# __Nasal Script__
|
||||
# __Nasal - Modern Interpreter__
|
||||
|
||||
<img src="./doc/pic/header.png" style="width:800px"></img>
|
||||
|
||||
@@ -36,7 +36,7 @@ This interpreter is totally rewritten by [ValKmjolnir](https://github.com/ValKmj
|
||||
without reusing the code in [Andy Ross's nasal interpreter](https://github.com/andyross/nasal).
|
||||
But we really appreciate that Andy created this amazing programming language.
|
||||
|
||||
This project uses __MIT license__ (2019/7~2021/5/4~2023/5), __GPL v2 license__ (since 2023/6).
|
||||
This project uses __MIT license__ (2019/7 ~ 2021/5/4 ~ 2023/5), __GPL v2 license__ (since 2023/6).
|
||||
|
||||
### __Why writing this nasal interpreter?__
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# __Nasal Script__
|
||||
# __Nasal - Modern Interpreter__
|
||||
|
||||
<img src="../doc/pic/header.png" style="width:800px"></img>
|
||||
|
||||
@@ -32,9 +32,9 @@ __如果有好的意见或建议,欢迎联系我们!__
|
||||
是一款语法与ECMAscript相似的编程语言,并作为运行脚本被著名开源飞行模拟器 [FlightGear](https://www.flightgear.org/) 所使用。
|
||||
该语言的设计者为 [Andy Ross](https://github.com/andyross)。
|
||||
|
||||
该解释器项目由 [ValKmjolnir](https://github.com/ValKmjolnir) 完全使用 `C++`(`-std=c++14`)重新实现,没有复用 [Andy Ross的nasal解释器](https://github.com/andyross/nasal) 中的任何一行代码。尽管没有参考任何代码,我们依然非常感谢Andy为我们带来了这样一个神奇且简洁的编程语言。
|
||||
该解释器项目由 [ValKmjolnir](https://github.com/ValKmjolnir) 完全使用 `C++`(`-std=c++17`)重新实现,没有复用 [Andy Ross的nasal解释器](https://github.com/andyross/nasal) 中的任何一行代码。尽管没有参考任何代码,我们依然非常感谢Andy为我们带来了这样一个神奇且简洁的编程语言。
|
||||
|
||||
该项目使用 __MIT__ 协议开源 (2019/7~2021/5/4~2023/5),从 2023/6 开始使用 __GPL v2__ 协议。
|
||||
该项目使用 __MIT__ 协议开源 (2019/7 ~ 2021/5/4 ~ 2023/5),从 2023/6 开始使用 __GPL v2__ 协议。
|
||||
|
||||
### __我们为什么想要重新写一个nasal解释器?__
|
||||
|
||||
|
||||
@@ -289,14 +289,29 @@ bool ast_dumper::visit_definition_expr(definition_expr* node) {
|
||||
node->get_variables()->accept(this);
|
||||
}
|
||||
set_last();
|
||||
node->get_value()->accept(this);
|
||||
if (node->get_tuple()) {
|
||||
node->get_tuple()->accept(this);
|
||||
} else {
|
||||
node->get_value()->accept(this);
|
||||
}
|
||||
pop_indent();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ast_dumper::visit_assignment_expr(assignment_expr* node) {
|
||||
dump_indent();
|
||||
std::cout << "assignment";
|
||||
std::cout << "assignment ";
|
||||
switch(node->get_assignment_type()) {
|
||||
case assignment_expr::assign_type::add_equal: std::cout << "+="; break;
|
||||
case assignment_expr::assign_type::sub_equal: std::cout << "-="; break;
|
||||
case assignment_expr::assign_type::mult_equal: std::cout << "*="; break;
|
||||
case assignment_expr::assign_type::div_equal: std::cout << "/="; break;
|
||||
case assignment_expr::assign_type::concat_equal: std::cout << "~="; break;
|
||||
case assignment_expr::assign_type::equal: std::cout << "="; break;
|
||||
case assignment_expr::assign_type::bitwise_and_equal: std::cout << "&="; break;
|
||||
case assignment_expr::assign_type::bitwise_or_equal: std::cout << "|="; break;
|
||||
case assignment_expr::assign_type::bitwise_xor_equal: std::cout << "^="; break;
|
||||
}
|
||||
std::cout << format_location(node->get_location());
|
||||
push_indent();
|
||||
node->get_left()->accept(this);
|
||||
@@ -308,7 +323,7 @@ bool ast_dumper::visit_assignment_expr(assignment_expr* node) {
|
||||
|
||||
bool ast_dumper::visit_multi_identifier(multi_identifier* node) {
|
||||
dump_indent();
|
||||
std::cout << "multiple_definition";
|
||||
std::cout << "multiple_identifier";
|
||||
std::cout << format_location(node->get_location());
|
||||
push_indent();
|
||||
for(auto i : node->get_variables()) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -134,7 +139,11 @@ bool ast_visitor::visit_definition_expr(definition_expr* node) {
|
||||
} else {
|
||||
node->get_variables()->accept(this);
|
||||
}
|
||||
node->get_value()->accept(this);
|
||||
if (node->get_tuple()) {
|
||||
node->get_tuple()->accept(this);
|
||||
} else {
|
||||
node->get_value()->accept(this);
|
||||
}
|
||||
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*);
|
||||
|
||||
10
src/main.cpp
10
src/main.cpp
@@ -78,7 +78,7 @@ std::ostream& version(std::ostream& out) {
|
||||
if (num<0.01) {
|
||||
parse::easter_egg();
|
||||
}
|
||||
out << "version " << __nasver;
|
||||
out << "nasal interpreter version " << __nasver;
|
||||
out << " (" << __DATE__ << " " << __TIME__ << ")\n";
|
||||
return out;
|
||||
}
|
||||
@@ -112,9 +112,8 @@ void execute(
|
||||
// parser gets lexer's token list to compile
|
||||
parse.compile(lex).chkerr();
|
||||
if (cmd&VM_RAW_AST) {
|
||||
auto dumper = new ast_dumper;
|
||||
auto dumper = std::unique_ptr<ast_dumper>(new ast_dumper);
|
||||
dumper->dump(parse.tree());
|
||||
delete dumper;
|
||||
}
|
||||
|
||||
// linker gets parser's ast and load import files to this ast
|
||||
@@ -125,15 +124,14 @@ void execute(
|
||||
opt->do_optimization(parse.tree());
|
||||
delete opt;
|
||||
if (cmd&VM_AST) {
|
||||
auto dumper = new ast_dumper;
|
||||
auto dumper = std::unique_ptr<ast_dumper>(new ast_dumper);
|
||||
dumper->dump(parse.tree());
|
||||
delete dumper;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
@@ -201,6 +205,9 @@ definition_expr::~definition_expr() {
|
||||
if (variables) {
|
||||
delete variables;
|
||||
}
|
||||
if (tuple) {
|
||||
delete tuple;
|
||||
}
|
||||
if (value) {
|
||||
delete value;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ class slice_vector;
|
||||
class multi_identifier;
|
||||
class code_block;
|
||||
class if_expr;
|
||||
class tuple_expr;
|
||||
|
||||
class expr {
|
||||
protected:
|
||||
@@ -75,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;
|
||||
@@ -352,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):
|
||||
@@ -360,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;}
|
||||
@@ -426,18 +435,22 @@ class definition_expr:public expr {
|
||||
private:
|
||||
identifier* variable_name;
|
||||
multi_identifier* variables;
|
||||
tuple_expr* tuple;
|
||||
expr* value;
|
||||
|
||||
public:
|
||||
definition_expr(const span& location):
|
||||
expr(location, expr_type::ast_def),
|
||||
variable_name(nullptr), variables(nullptr), value(nullptr) {}
|
||||
variable_name(nullptr), variables(nullptr),
|
||||
tuple(nullptr), value(nullptr) {}
|
||||
~definition_expr();
|
||||
void set_identifier(identifier* node) {variable_name = node;}
|
||||
void set_multi_define(multi_identifier* node) {variables = node;}
|
||||
void set_tuple(tuple_expr* node) {tuple = node;}
|
||||
void set_value(expr* node) {value = node;}
|
||||
identifier* get_variable_name() {return variable_name;}
|
||||
multi_identifier* get_variables() {return variables;}
|
||||
tuple_expr* get_tuple() {return tuple;}
|
||||
expr* get_value() {return value;}
|
||||
void accept(ast_visitor*) override;
|
||||
};
|
||||
@@ -562,7 +575,7 @@ public:
|
||||
class iter_expr:public expr {
|
||||
private:
|
||||
identifier* name;
|
||||
expr* call;
|
||||
call_expr* call;
|
||||
|
||||
public:
|
||||
iter_expr(const span& location):
|
||||
@@ -570,9 +583,9 @@ public:
|
||||
name(nullptr), call(nullptr) {}
|
||||
~iter_expr();
|
||||
void set_name(identifier* node) {name = node;}
|
||||
void set_call(expr* node) {call = node;}
|
||||
void set_call(call_expr* node) {call = node;}
|
||||
identifier* get_name() {return name;}
|
||||
expr* get_call() {return call;}
|
||||
call_expr* get_call() {return call;}
|
||||
void accept(ast_visitor*) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -27,30 +27,31 @@ void codegen::check_id_exist(identifier* node) {
|
||||
}
|
||||
|
||||
void codegen::regist_num(const f64 num) {
|
||||
if (!num_table.count(num)) {
|
||||
u32 size = num_table.size();
|
||||
num_table[num] = size;
|
||||
num_res.push_back(num);
|
||||
if (const_number_map.count(num)) {
|
||||
return;
|
||||
}
|
||||
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)) {
|
||||
u32 size = str_table.size();
|
||||
str_table[str] = size;
|
||||
str_res.push_back(str);
|
||||
if (const_string_map.count(str)) {
|
||||
return;
|
||||
}
|
||||
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 = new symbol_finder;
|
||||
auto finder = std::unique_ptr<symbol_finder>(new symbol_finder);
|
||||
for(const auto& i : finder->do_find(node)) {
|
||||
add_sym(i);
|
||||
add_symbol(i);
|
||||
}
|
||||
delete finder;
|
||||
}
|
||||
|
||||
void codegen::add_sym(const std::string& name) {
|
||||
void codegen::add_symbol(const std::string& name) {
|
||||
if (local.empty()) {
|
||||
if (global.count(name)) {
|
||||
return;
|
||||
@@ -100,18 +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) {
|
||||
regist_str(node->get_content());
|
||||
gen(op_pstr, str_table.at(node->get_content()), node->get_line());
|
||||
const auto& str = node->get_content();
|
||||
regist_str(str);
|
||||
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) {
|
||||
@@ -127,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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,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
|
||||
@@ -235,8 +237,8 @@ void codegen::call_gen(call_expr* node) {
|
||||
for(auto i : node->get_calls()) {
|
||||
switch(i->get_type()) {
|
||||
case expr_type::ast_callh: call_hash_gen((call_hash*)i); break;
|
||||
case expr_type::ast_callv: call_vec((call_vector*)i); break;
|
||||
case expr_type::ast_callf: call_func((call_function*)i); break;
|
||||
case expr_type::ast_callv: call_vector_gen((call_vector*)i); break;
|
||||
case expr_type::ast_callf: call_func_gen((call_function*)i); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@@ -272,10 +274,10 @@ 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_vec(call_vector* node) {
|
||||
void codegen::call_vector_gen(call_vector* node) {
|
||||
// maybe this place can use callv-const if ast's first child is ast_num
|
||||
if (node->get_slices().size()==1 &&
|
||||
!node->get_slices()[0]->get_end()) {
|
||||
@@ -297,7 +299,7 @@ void codegen::call_vec(call_vector* node) {
|
||||
gen(op_slcend, 0, node->get_line());
|
||||
}
|
||||
|
||||
void codegen::call_func(call_function* node) {
|
||||
void codegen::call_func_gen(call_function* node) {
|
||||
if (node->get_argument().size() &&
|
||||
node->get_argument()[0]->get_type()==expr_type::ast_pair) {
|
||||
gen(op_newh, 0, node->get_line());
|
||||
@@ -305,7 +307,7 @@ void codegen::call_func(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 {
|
||||
@@ -340,8 +342,8 @@ void codegen::mcall(expr* node) {
|
||||
auto tmp = call_node->get_calls()[i];
|
||||
switch(tmp->get_type()) {
|
||||
case expr_type::ast_callh: call_hash_gen((call_hash*)tmp); break;
|
||||
case expr_type::ast_callv: call_vec((call_vector*)tmp); break;
|
||||
case expr_type::ast_callf: call_func((call_function*)tmp); break;
|
||||
case expr_type::ast_callv: call_vector_gen((call_vector*)tmp); break;
|
||||
case expr_type::ast_callf: call_func_gen((call_function*)tmp); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@@ -397,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) {
|
||||
@@ -411,12 +413,15 @@ void codegen::single_def(definition_expr* node) {
|
||||
void codegen::multi_def(definition_expr* node) {
|
||||
auto& identifiers = node->get_variables()->get_variables();
|
||||
usize size = identifiers.size();
|
||||
if (node->get_value()->get_type()==expr_type::ast_tuple) { // (var a,b,c)=(c,b,a);
|
||||
auto& vals = ((tuple_expr*)node->get_value())->get_elements();
|
||||
// (var a,b,c) = (c,b,a);
|
||||
if (node->get_tuple()) {
|
||||
auto& vals = node->get_tuple()->get_elements();
|
||||
if (identifiers.size()<vals.size()) {
|
||||
die("lack values in multi-definition", node->get_value()->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_value()->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]);
|
||||
@@ -425,22 +430,22 @@ void codegen::multi_def(definition_expr* node) {
|
||||
gen(op_loadg, global_find(name), identifiers[i]->get_line()):
|
||||
gen(op_loadl, local_find(name), identifiers[i]->get_line());
|
||||
}
|
||||
} else { // (var a,b,c)=[0,1,2];
|
||||
calc_gen(node->get_value());
|
||||
for(usize i = 0; i<size; ++i) {
|
||||
gen(op_callvi, i, node->get_value()->get_line());
|
||||
const auto& name = identifiers[i]->get_name();
|
||||
local.empty()?
|
||||
gen(op_loadg, global_find(name), identifiers[i]->get_line()):
|
||||
gen(op_loadl, local_find(name), identifiers[i]->get_line());
|
||||
}
|
||||
gen(op_pop, 0, node->get_line());
|
||||
return;
|
||||
}
|
||||
// (var a,b,c) = [0,1,2];
|
||||
calc_gen(node->get_value());
|
||||
for(usize i = 0; i<size; ++i) {
|
||||
gen(op_callvi, i, node->get_value()->get_line());
|
||||
const auto& name = identifiers[i]->get_name();
|
||||
local.empty()?
|
||||
gen(op_loadg, global_find(name), identifiers[i]->get_line()):
|
||||
gen(op_loadl, local_find(name), identifiers[i]->get_line());
|
||||
}
|
||||
gen(op_pop, 0, node->get_line());
|
||||
}
|
||||
|
||||
void codegen::def_gen(definition_expr* node) {
|
||||
if (node->get_variable_name() &&
|
||||
node->get_value()->get_type()==expr_type::ast_tuple) {
|
||||
if (node->get_variable_name() && node->get_tuple()) {
|
||||
die("cannot accept too many values", node->get_value()->get_location());
|
||||
}
|
||||
node->get_variable_name()? single_def(node):multi_def(node);
|
||||
@@ -463,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:
|
||||
@@ -476,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:
|
||||
@@ -489,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:
|
||||
@@ -502,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:
|
||||
@@ -515,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:
|
||||
@@ -607,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) {
|
||||
@@ -706,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());
|
||||
}
|
||||
@@ -732,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) {
|
||||
@@ -760,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:
|
||||
@@ -785,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) {
|
||||
@@ -881,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:
|
||||
@@ -892,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:
|
||||
@@ -903,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:
|
||||
@@ -914,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:
|
||||
@@ -925,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:
|
||||
@@ -936,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:
|
||||
@@ -947,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:
|
||||
@@ -958,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:
|
||||
@@ -969,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;
|
||||
@@ -978,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) {
|
||||
@@ -1028,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;
|
||||
@@ -1087,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&);
|
||||
@@ -65,8 +65,8 @@ private:
|
||||
void call_gen(call_expr*);
|
||||
void call_id(identifier*);
|
||||
void call_hash_gen(call_hash*);
|
||||
void call_vec(call_vector*);
|
||||
void call_func(call_function*);
|
||||
void call_vector_gen(call_vector*);
|
||||
void call_func_gen(call_function*);
|
||||
void mcall(expr*);
|
||||
void mcall_id(identifier*);
|
||||
void mcall_vec(call_vector*);
|
||||
@@ -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&);
|
||||
};
|
||||
|
||||
224
src/nasal_gc.cpp
224
src/nasal_gc.cpp
@@ -26,33 +26,33 @@ void dylib_destructor(void* ptr) {
|
||||
void func_addr_destructor(void* ptr) {}
|
||||
|
||||
var nas_vec::get_val(const i32 n) {
|
||||
i32 size=elems.size();
|
||||
i32 size = elems.size();
|
||||
if (n<-size || n>=size) {
|
||||
return var::none();
|
||||
}
|
||||
return elems[n>=0?n:n+size];
|
||||
return elems[n>=0? n:n+size];
|
||||
}
|
||||
|
||||
var* nas_vec::get_mem(const i32 n) {
|
||||
i32 size=elems.size();
|
||||
i32 size = elems.size();
|
||||
if (n<-size || n>=size) {
|
||||
return nullptr;
|
||||
}
|
||||
return &elems[n>=0?n:n+size];
|
||||
return &elems[n>=0? n:n+size];
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, nas_vec& vec) {
|
||||
if (!vec.elems.size() || vec.printed) {
|
||||
out<<(vec.elems.size()?"[..]":"[]");
|
||||
out << (vec.elems.size()? "[..]":"[]");
|
||||
return out;
|
||||
}
|
||||
vec.printed=true;
|
||||
usize iter=0,size=vec.elems.size();
|
||||
out<<'[';
|
||||
vec.printed = true;
|
||||
usize iter = 0, size = vec.elems.size();
|
||||
out << "[";
|
||||
for(auto& i:vec.elems) {
|
||||
out<<i<<",]"[(++iter)==size];
|
||||
out << i << ",]"[(++iter)==size];
|
||||
}
|
||||
vec.printed=false;
|
||||
vec.printed = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -62,14 +62,14 @@ var nas_hash::get_val(const std::string& key) {
|
||||
} else if (!elems.count("parents")) {
|
||||
return var::none();
|
||||
}
|
||||
var ret=var::none();
|
||||
var val=elems.at("parents");
|
||||
var ret = var::none();
|
||||
var val = elems.at("parents");
|
||||
if (val.type!=vm_vec) {
|
||||
return ret;
|
||||
}
|
||||
for(auto& i:val.vec().elems) {
|
||||
for(auto& i : val.vec().elems) {
|
||||
if (i.type==vm_hash) {
|
||||
ret=i.hash().get_val(key);
|
||||
ret = i.hash().get_val(key);
|
||||
}
|
||||
if (ret.type!=vm_none) {
|
||||
return ret;
|
||||
@@ -84,14 +84,14 @@ var* nas_hash::get_mem(const std::string& key) {
|
||||
} else if (!elems.count("parents")) {
|
||||
return nullptr;
|
||||
}
|
||||
var* addr=nullptr;
|
||||
var val=elems.at("parents");
|
||||
var* addr = nullptr;
|
||||
var val = elems.at("parents");
|
||||
if (val.type!=vm_vec) {
|
||||
return addr;
|
||||
}
|
||||
for(auto& i:val.vec().elems) {
|
||||
for(auto& i : val.vec().elems) {
|
||||
if (i.type==vm_hash) {
|
||||
addr=i.hash().get_mem(key);
|
||||
addr = i.hash().get_mem(key);
|
||||
}
|
||||
if (addr) {
|
||||
return addr;
|
||||
@@ -102,30 +102,31 @@ var* nas_hash::get_mem(const std::string& key) {
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, nas_hash& hash) {
|
||||
if (!hash.elems.size() || hash.printed) {
|
||||
out<<(hash.elems.size()?"{..}":"{}");
|
||||
out << (hash.elems.size()? "{..}":"{}");
|
||||
return out;
|
||||
}
|
||||
hash.printed=true;
|
||||
usize iter=0,size=hash.elems.size();
|
||||
out<<'{';
|
||||
for(auto& i:hash.elems) {
|
||||
out<<i.first<<':'<<i.second<<",}"[(++iter)==size];
|
||||
hash.printed = true;
|
||||
usize iter = 0, size = hash.elems.size();
|
||||
out << "{";
|
||||
for(auto& i : hash.elems) {
|
||||
out << i.first << ":" << i.second << ",}"[(++iter)==size];
|
||||
}
|
||||
hash.printed=false;
|
||||
hash.printed = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
void nas_func::clear() {
|
||||
dpara=-1;
|
||||
dpara = -1;
|
||||
local.clear();
|
||||
upval.clear();
|
||||
keys.clear();
|
||||
}
|
||||
|
||||
void nas_ghost::set(usize t, void* p, ghost_register_table* table) {
|
||||
type=t;
|
||||
ptr=p;
|
||||
ghost_type_table=table;
|
||||
void nas_ghost::set(
|
||||
usize ghost_type, void* ghost_pointer, ghost_register_table* table) {
|
||||
type = ghost_type;
|
||||
ptr = ghost_pointer;
|
||||
ghost_type_table = table;
|
||||
}
|
||||
|
||||
void nas_ghost::clear() {
|
||||
@@ -133,37 +134,37 @@ void nas_ghost::clear() {
|
||||
return;
|
||||
}
|
||||
ghost_type_table->destructor(type)(ptr);
|
||||
ptr=nullptr;
|
||||
ptr = nullptr;
|
||||
}
|
||||
|
||||
void nas_co::clear() {
|
||||
for(u32 i=0;i<STACK_DEPTH;++i) {
|
||||
stack[i]=var::nil();
|
||||
for(u32 i = 0; i<STACK_DEPTH; ++i) {
|
||||
stack[i] = var::nil();
|
||||
}
|
||||
ctx.pc=0;
|
||||
ctx.localr=nullptr;
|
||||
ctx.memr=nullptr;
|
||||
ctx.canary=stack+STACK_DEPTH-1;
|
||||
ctx.top=stack;
|
||||
ctx.funcr=var::nil();
|
||||
ctx.upvalr=var::nil();
|
||||
ctx.stack=stack;
|
||||
ctx.pc = 0;
|
||||
ctx.localr = nullptr;
|
||||
ctx.memr = nullptr;
|
||||
ctx.canary = stack+STACK_DEPTH-1;
|
||||
ctx.top = stack;
|
||||
ctx.funcr = var::nil();
|
||||
ctx.upvalr = var::nil();
|
||||
ctx.stack = stack;
|
||||
|
||||
status=coroutine_status::suspended;
|
||||
status = coroutine_status::suspended;
|
||||
}
|
||||
|
||||
nas_val::nas_val(u8 val_type) {
|
||||
mark=gc_status::collected;
|
||||
type=val_type;
|
||||
unmut=0;
|
||||
mark = gc_status::collected;
|
||||
type = val_type;
|
||||
unmut = 0;
|
||||
switch(val_type) {
|
||||
case vm_str: ptr.str=new std::string; break;
|
||||
case vm_vec: ptr.vec=new nas_vec; break;
|
||||
case vm_hash: ptr.hash=new nas_hash; break;
|
||||
case vm_func: ptr.func=new nas_func; break;
|
||||
case vm_upval: ptr.upval=new nas_upval; break;
|
||||
case vm_obj: ptr.obj=new nas_ghost; break;
|
||||
case vm_co: ptr.co=new nas_co; break;
|
||||
case vm_str: ptr.str = new std::string; break;
|
||||
case vm_vec: ptr.vec = new nas_vec; break;
|
||||
case vm_hash: ptr.hash = new nas_hash; break;
|
||||
case vm_func: ptr.func = new nas_func; break;
|
||||
case vm_upval: ptr.upval = new nas_upval; break;
|
||||
case vm_obj: ptr.obj = new nas_ghost; break;
|
||||
case vm_co: ptr.co = new nas_co; break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,15 +211,15 @@ std::string var::tostr() {
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, var& ref) {
|
||||
switch(ref.type) {
|
||||
case vm_none: out<<"undefined"; break;
|
||||
case vm_nil: out<<"nil"; break;
|
||||
case vm_num: out<<ref.val.num; break;
|
||||
case vm_str: out<<ref.str(); break;
|
||||
case vm_vec: out<<ref.vec(); break;
|
||||
case vm_hash: out<<ref.hash(); break;
|
||||
case vm_func: out<<"func(..) {..}";break;
|
||||
case vm_obj: out<<ref.obj(); break;
|
||||
case vm_co: out<<"<coroutine>"; break;
|
||||
case vm_none: out << "undefined"; break;
|
||||
case vm_nil: out << "nil"; break;
|
||||
case vm_num: out << ref.val.num; break;
|
||||
case vm_str: out << ref.str(); break;
|
||||
case vm_vec: out << ref.vec(); break;
|
||||
case vm_hash: out << ref.hash(); break;
|
||||
case vm_func: out << "func(..) {..}"; break;
|
||||
case vm_obj: out << ref.obj(); break;
|
||||
case vm_co: out << "<coroutine>"; break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -304,7 +305,7 @@ void gc::mark() {
|
||||
mark_context(bfs);
|
||||
|
||||
while(!bfs.empty()) {
|
||||
var value=bfs.back();
|
||||
var value = bfs.back();
|
||||
bfs.pop_back();
|
||||
if (value.type<=vm_num ||
|
||||
value.val.gcobj->mark!=gc_status::uncollected) {
|
||||
@@ -317,7 +318,7 @@ void gc::mark() {
|
||||
void gc::mark_context(std::vector<var>& bfs_queue) {
|
||||
|
||||
// scan now running context, this context maybe related to coroutine or main
|
||||
for(var* i=rctx->stack;i<=rctx->top;++i) {
|
||||
for(var* i = rctx->stack; i<=rctx->top; ++i) {
|
||||
bfs_queue.push_back(*i);
|
||||
}
|
||||
bfs_queue.push_back(rctx->funcr);
|
||||
@@ -329,7 +330,7 @@ void gc::mark_context(std::vector<var>& bfs_queue) {
|
||||
}
|
||||
|
||||
// coroutine is running, so scan main process stack from mctx
|
||||
for(var* i=mctx.stack;i<=mctx.top;++i) {
|
||||
for(var* i = mctx.stack; i<=mctx.top; ++i) {
|
||||
bfs_queue.push_back(*i);
|
||||
}
|
||||
bfs_queue.push_back(mctx.funcr);
|
||||
@@ -337,7 +338,7 @@ void gc::mark_context(std::vector<var>& bfs_queue) {
|
||||
}
|
||||
|
||||
void gc::mark_var(std::vector<var>& bfs_queue, var& value) {
|
||||
value.val.gcobj->mark=gc_status::found;
|
||||
value.val.gcobj->mark = gc_status::found;
|
||||
switch(value.type) {
|
||||
case vm_vec: mark_vec(bfs_queue, value.vec()); break;
|
||||
case vm_hash: mark_hash(bfs_queue, value.hash()); break;
|
||||
@@ -349,28 +350,28 @@ void gc::mark_var(std::vector<var>& bfs_queue, var& value) {
|
||||
}
|
||||
|
||||
void gc::mark_vec(std::vector<var>& bfs_queue, nas_vec& vec) {
|
||||
for(auto& i:vec.elems) {
|
||||
for(auto& i : vec.elems) {
|
||||
bfs_queue.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
void gc::mark_hash(std::vector<var>& bfs_queue, nas_hash& hash) {
|
||||
for(auto& i:hash.elems) {
|
||||
for(auto& i : hash.elems) {
|
||||
bfs_queue.push_back(i.second);
|
||||
}
|
||||
}
|
||||
|
||||
void gc::mark_func(std::vector<var>& bfs_queue, nas_func& function) {
|
||||
for(auto& i:function.local) {
|
||||
for(auto& i : function.local) {
|
||||
bfs_queue.push_back(i);
|
||||
}
|
||||
for(auto& i:function.upval) {
|
||||
for(auto& i : function.upval) {
|
||||
bfs_queue.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
void gc::mark_upval(std::vector<var>& bfs_queue, nas_upval& upval) {
|
||||
for(auto& i:upval.elems) {
|
||||
for(auto& i : upval.elems) {
|
||||
bfs_queue.push_back(i);
|
||||
}
|
||||
}
|
||||
@@ -378,84 +379,79 @@ void gc::mark_upval(std::vector<var>& bfs_queue, nas_upval& upval) {
|
||||
void gc::mark_co(std::vector<var>& bfs_queue, nas_co& co) {
|
||||
bfs_queue.push_back(co.ctx.funcr);
|
||||
bfs_queue.push_back(co.ctx.upvalr);
|
||||
for(var* i=co.stack;i<=co.ctx.top;++i) {
|
||||
for(var* i = co.stack; i<=co.ctx.top; ++i) {
|
||||
bfs_queue.push_back(*i);
|
||||
}
|
||||
}
|
||||
|
||||
void gc::sweep() {
|
||||
for(auto i:memory) {
|
||||
for(auto i : memory) {
|
||||
if (i->mark==gc_status::uncollected) {
|
||||
i->clear();
|
||||
unused[i->type-vm_str].push_back(i);
|
||||
i->mark=gc_status::collected;
|
||||
i->mark = gc_status::collected;
|
||||
} else if (i->mark==gc_status::found) {
|
||||
i->mark=gc_status::uncollected;
|
||||
i->mark = gc_status::uncollected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gc::extend(u8 type) {
|
||||
const u8 index=type-vm_str;
|
||||
size[index]+=incr[index];
|
||||
const u8 index = type-vm_str;
|
||||
size[index] += incr[index];
|
||||
|
||||
for(u32 i=0;i<incr[index];++i) {
|
||||
nas_val* tmp=new(std::nothrow) nas_val(type);
|
||||
|
||||
if (!tmp) {
|
||||
std::cerr<<"nasal_gc.h: gc::extend: ";
|
||||
std::cerr<<"failed to allocate memory\n";
|
||||
std::exit(1);
|
||||
}
|
||||
for(u32 i = 0; i<incr[index]; ++i) {
|
||||
// no need to check, will be killed if memory is not enough
|
||||
nas_val* tmp = new nas_val(type);
|
||||
|
||||
// add to heap
|
||||
memory.push_back(tmp);
|
||||
unused[index].push_back(tmp);
|
||||
}
|
||||
|
||||
incr[index]=incr[index]+incr[index]/2;
|
||||
incr[index] = incr[index]+incr[index]/2;
|
||||
}
|
||||
|
||||
void gc::init(
|
||||
const std::vector<std::string>& s, const std::vector<std::string>& argv) {
|
||||
// initialize function register
|
||||
rctx->funcr=nil;
|
||||
worktime=0;
|
||||
rctx->funcr = nil;
|
||||
worktime = 0;
|
||||
|
||||
// initialize counters
|
||||
for(u8 i=0;i<gc_type_size;++i) {
|
||||
size[i]=gcnt[i]=acnt[i]=0;
|
||||
for(u8 i = 0; i<gc_type_size; ++i) {
|
||||
size[i] = gcnt[i] = acnt[i] = 0;
|
||||
}
|
||||
|
||||
// coroutine pointer set to nullptr
|
||||
cort=nullptr;
|
||||
cort = nullptr;
|
||||
|
||||
// init constant strings
|
||||
strs.resize(s.size());
|
||||
for(u32 i=0;i<strs.size();++i) {
|
||||
for(u32 i = 0; i<strs.size(); ++i) {
|
||||
strs[i]=var::gcobj(new nas_val(vm_str));
|
||||
strs[i].val.gcobj->unmut=1;
|
||||
strs[i].str()=s[i];
|
||||
strs[i].val.gcobj->unmut = 1;
|
||||
strs[i].str() = s[i];
|
||||
}
|
||||
|
||||
// record arguments
|
||||
env_argv.resize(argv.size());
|
||||
for(usize i=0;i<argv.size();++i) {
|
||||
env_argv[i]=var::gcobj(new nas_val(vm_str));
|
||||
env_argv[i].val.gcobj->unmut=1;
|
||||
env_argv[i].str()=argv[i];
|
||||
for(usize i = 0; i<argv.size(); ++i) {
|
||||
env_argv[i] = var::gcobj(new nas_val(vm_str));
|
||||
env_argv[i].val.gcobj->unmut = 1;
|
||||
env_argv[i].str() = argv[i];
|
||||
}
|
||||
}
|
||||
|
||||
void gc::clear() {
|
||||
for(auto i:memory) {
|
||||
for(auto i : memory) {
|
||||
delete i;
|
||||
}
|
||||
memory.clear();
|
||||
for(u8 i=0;i<gc_type_size;++i) {
|
||||
for(u8 i = 0; i<gc_type_size; ++i) {
|
||||
unused[i].clear();
|
||||
}
|
||||
for(auto& i:strs) {
|
||||
for(auto& i : strs) {
|
||||
delete i.val.gcobj;
|
||||
}
|
||||
strs.clear();
|
||||
@@ -476,8 +472,8 @@ void gc::info() {
|
||||
"coroutine"
|
||||
};
|
||||
|
||||
usize indent=0;
|
||||
for(u8 i=0;i<gc_type_size;++i) {
|
||||
usize indent = 0;
|
||||
for(u8 i = 0; i<gc_type_size; ++i) {
|
||||
usize len = 0;
|
||||
len = std::to_string(gcnt[i]).length();
|
||||
indent = indent<len? len:indent;
|
||||
@@ -487,7 +483,7 @@ void gc::info() {
|
||||
indent = indent<len? len:indent;
|
||||
}
|
||||
|
||||
double total=0;
|
||||
double total = 0;
|
||||
std::clog << "\ngc info (gc count|alloc count|memory size)\n";
|
||||
for(u8 i = 0; i<gc_type_size; ++i) {
|
||||
if (!gcnt[i] && !acnt[i] && !size[i]) {
|
||||
@@ -535,43 +531,43 @@ var gc::alloc(u8 type) {
|
||||
if (unused[index].empty()) {
|
||||
extend(type);
|
||||
}
|
||||
var ret=var::gcobj(unused[index].back());
|
||||
ret.val.gcobj->mark=gc_status::uncollected;
|
||||
var ret = var::gcobj(unused[index].back());
|
||||
ret.val.gcobj->mark = gc_status::uncollected;
|
||||
unused[index].pop_back();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gc::ctxchg(nas_co& co) {
|
||||
// store running state to main context
|
||||
mctx=*rctx;
|
||||
mctx = *rctx;
|
||||
|
||||
// restore coroutine context state
|
||||
*rctx=co.ctx;
|
||||
*rctx = co.ctx;
|
||||
|
||||
// set coroutine pointer
|
||||
cort=&co;
|
||||
cort = &co;
|
||||
|
||||
// set coroutine state to running
|
||||
cort->status=coroutine_status::running;
|
||||
cort->status = coroutine_status::running;
|
||||
}
|
||||
|
||||
void gc::ctxreserve() {
|
||||
// pc=0 means this coroutine is finished
|
||||
cort->status=rctx->pc?
|
||||
cort->status = rctx->pc?
|
||||
coroutine_status::suspended:
|
||||
coroutine_status::dead;
|
||||
|
||||
// store running state to coroutine
|
||||
cort->ctx=*rctx;
|
||||
cort->ctx = *rctx;
|
||||
|
||||
// restore main context state
|
||||
*rctx=mctx;
|
||||
*rctx = mctx;
|
||||
|
||||
// set coroutine pointer to nullptr
|
||||
cort=nullptr;
|
||||
cort = nullptr;
|
||||
}
|
||||
|
||||
var nas_err(const std::string& error_function_name, const std::string& info) {
|
||||
std::cerr<<"[vm] "<<error_function_name<<": "<<info<<"\n";
|
||||
std::cerr << "[vm] " << error_function_name << ": " << info << "\n";
|
||||
return var::none();
|
||||
}
|
||||
@@ -50,7 +50,7 @@ enum vm_type:u8 {
|
||||
vm_co
|
||||
};
|
||||
|
||||
const u32 gc_type_size=vm_co-vm_str+1;
|
||||
const u32 gc_type_size = vm_co-vm_str+1;
|
||||
|
||||
enum class coroutine_status:u32 {
|
||||
suspended,
|
||||
@@ -84,11 +84,11 @@ public:
|
||||
} val;
|
||||
|
||||
private:
|
||||
var(u8 t, u32 pc) {type=t;val.ret=pc;}
|
||||
var(u8 t, i64 ct) {type=t;val.cnt=ct;}
|
||||
var(u8 t, f64 n) {type=t;val.num=n;}
|
||||
var(u8 t, var* p) {type=t;val.addr=p;}
|
||||
var(u8 t, nas_val* p) {type=t;val.gcobj=p;}
|
||||
var(u8 t, u32 pc) {type = t; val.ret = pc;}
|
||||
var(u8 t, i64 ct) {type = t; val.cnt = ct;}
|
||||
var(u8 t, f64 n) {type = t; val.num = n;}
|
||||
var(u8 t, var* p) {type = t; val.addr = p;}
|
||||
var(u8 t, nas_val* p) {type = t; val.gcobj = p;}
|
||||
|
||||
public:
|
||||
var() = default;
|
||||
@@ -147,7 +147,7 @@ struct nas_hash {
|
||||
// mark if this is printed, avoid stackoverflow
|
||||
bool printed;
|
||||
|
||||
nas_hash():printed(false) {}
|
||||
nas_hash(): printed(false) {}
|
||||
usize size() const {return elems.size();}
|
||||
var get_val(const std::string&);
|
||||
var* get_mem(const std::string&);
|
||||
@@ -184,9 +184,9 @@ public:
|
||||
}
|
||||
|
||||
void clear() {
|
||||
onstk=true;
|
||||
onstk = true;
|
||||
elems.clear();
|
||||
size=0;
|
||||
size = 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -233,12 +233,12 @@ public:
|
||||
|
||||
usize register_ghost_type(const std::string& name, dtor ptr) {
|
||||
if (mapper.count(name)) {
|
||||
std::cerr<<"nasal_gc.h: ghost_register_table::register_ghost_type: ";
|
||||
std::cerr<<"ghost type \""<<name<<"\" already exists.\n";
|
||||
std::cerr << "nasal_gc.h: ghost_register_table::register_ghost_type: ";
|
||||
std::cerr << "ghost type \"" << name << "\" already exists.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
auto res=destructors.size();
|
||||
mapper[name]=res;
|
||||
auto res = destructors.size();
|
||||
mapper[name] = res;
|
||||
ghost_name.push_back(name);
|
||||
destructors.push_back(ptr);
|
||||
return res;
|
||||
@@ -265,8 +265,8 @@ public:
|
||||
|
||||
public:
|
||||
friend std::ostream& operator<<(std::ostream& out, nas_ghost& ghost) {
|
||||
out<<"<object "<<ghost.ghost_type_table->get_ghost_name(ghost.type);
|
||||
out<<" at 0x"<<std::hex<<(u64)ghost.ptr<<std::dec<<">";
|
||||
out << "<object " << ghost.ghost_type_table->get_ghost_name(ghost.type);
|
||||
out << " at 0x" << std::hex << (u64)ghost.ptr << std::dec << ">";
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ struct gc {
|
||||
nas_co* cort = nullptr; // running coroutine
|
||||
|
||||
/* temporary space used in builtin/module functions */
|
||||
var temp=nil;
|
||||
var temp = nil;
|
||||
|
||||
/* constants and memory pool */
|
||||
std::vector<var> strs; // reserved address for const vm_str
|
||||
@@ -385,20 +385,20 @@ public:
|
||||
|
||||
public:
|
||||
var newstr(char c) {
|
||||
var s=alloc(vm_str);
|
||||
s.str()=c;
|
||||
var s = alloc(vm_str);
|
||||
s.str() = c;
|
||||
return s;
|
||||
}
|
||||
|
||||
var newstr(const char* buff) {
|
||||
var s=alloc(vm_str);
|
||||
s.str()=buff;
|
||||
s.str() = buff;
|
||||
return s;
|
||||
}
|
||||
|
||||
var newstr(const std::string& buff) {
|
||||
var s=alloc(vm_str);
|
||||
s.str()=buff;
|
||||
s.str() = buff;
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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 << ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -314,7 +314,7 @@ void parse::params(function* func_node) {
|
||||
expr* parse::lcurve_expr() {
|
||||
if (toks[ptr+1].type==tok::var)
|
||||
return definition();
|
||||
return check_tuple()?multi_assignment():calc();
|
||||
return check_tuple()? multi_assignment():calc();
|
||||
}
|
||||
|
||||
expr* parse::expression() {
|
||||
@@ -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() {
|
||||
@@ -741,7 +741,9 @@ expr* parse::definition() {
|
||||
}
|
||||
match(tok::eq);
|
||||
if (lookahead(tok::lcurve)) {
|
||||
node->set_value(check_tuple()?multi_scalar():calc());
|
||||
check_tuple()?
|
||||
node->set_tuple(multi_scalar()):
|
||||
node->set_value(calc());
|
||||
} else {
|
||||
node->set_value(calc());
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -8,7 +8,11 @@ bool symbol_finder::visit_definition_expr(definition_expr* node) {
|
||||
symbols.push_back(i->get_name());
|
||||
}
|
||||
}
|
||||
node->get_value()->accept(this);
|
||||
if (node->get_tuple()) {
|
||||
node->get_tuple()->accept(this);
|
||||
} else {
|
||||
node->get_value()->accept(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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; }
|
||||
};
|
||||
|
||||
12
test/gc_test.nas
Normal file
12
test/gc_test.nas
Normal file
@@ -0,0 +1,12 @@
|
||||
var res = [];
|
||||
for(var i=0;i<1e6;i+=1) {
|
||||
append(res, []);
|
||||
}
|
||||
res = [];
|
||||
for(var i=0;i<1e6;i+=1) {
|
||||
append(res, {});
|
||||
}
|
||||
res = [];
|
||||
for(var i=0;i<1e6;i+=1) {
|
||||
append(res, func {});
|
||||
}
|
||||
Reference in New Issue
Block a user