✨ update
This commit is contained in:
parent
27bc544bbe
commit
5c714d26aa
|
@ -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()) {
|
||||
|
|
|
@ -134,7 +134,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,9 +124,8 @@ 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
|
||||
|
|
|
@ -201,6 +201,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:
|
||||
|
@ -426,18 +427,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 +567,7 @@ public:
|
|||
class iter_expr:public expr {
|
||||
private:
|
||||
identifier* name;
|
||||
expr* call;
|
||||
call_expr* call;
|
||||
|
||||
public:
|
||||
iter_expr(const span& location):
|
||||
|
@ -570,9 +575,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,27 +27,28 @@ 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 (num_table.count(num)) {
|
||||
return;
|
||||
}
|
||||
u32 size = num_table.size();
|
||||
num_table[num] = size;
|
||||
num_res.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 (str_table.count(str)) {
|
||||
return;
|
||||
}
|
||||
u32 size = str_table.size();
|
||||
str_table[str] = size;
|
||||
str_res.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);
|
||||
}
|
||||
delete finder;
|
||||
}
|
||||
|
||||
void codegen::add_sym(const std::string& name) {
|
||||
|
@ -104,8 +105,9 @@ void codegen::num_gen(number_literal* node) {
|
|||
}
|
||||
|
||||
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, str_table.at(str), node->get_line());
|
||||
}
|
||||
|
||||
void codegen::bool_gen(bool_literal* node) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -275,7 +277,7 @@ void codegen::call_hash_gen(call_hash* node) {
|
|||
gen(op_callh, str_table.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());
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -411,12 +413,13 @@ 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 +428,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);
|
||||
|
|
|
@ -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*);
|
||||
|
|
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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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() {
|
||||
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue