diff --git a/README.md b/README.md index 153fc09..d8b7a06 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# __Nasal Script__ +# __Nasal - Modern Interpreter__ @@ -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?__ diff --git a/doc/README_zh.md b/doc/README_zh.md index aef8878..43bbaa3 100644 --- a/doc/README_zh.md +++ b/doc/README_zh.md @@ -1,4 +1,4 @@ -# __Nasal Script__ +# __Nasal - Modern Interpreter__ @@ -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解释器?__ diff --git a/src/ast_dumper.cpp b/src/ast_dumper.cpp index 2596527..a549ded 100644 --- a/src/ast_dumper.cpp +++ b/src/ast_dumper.cpp @@ -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()) { diff --git a/src/ast_visitor.cpp b/src/ast_visitor.cpp index 6d8c3e1..07ca0b7 100644 --- a/src/ast_visitor.cpp +++ b/src/ast_visitor.cpp @@ -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; } diff --git a/src/main.cpp b/src/main.cpp index 8202636..c5bc8c0 100644 --- a/src/main.cpp +++ b/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(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(new ast_dumper); dumper->dump(parse.tree()); - delete dumper; } // code generator gets parser's ast and import file list to generate code diff --git a/src/nasal_ast.cpp b/src/nasal_ast.cpp index 5eb9aee..52254da 100644 --- a/src/nasal_ast.cpp +++ b/src/nasal_ast.cpp @@ -201,6 +201,9 @@ definition_expr::~definition_expr() { if (variables) { delete variables; } + if (tuple) { + delete tuple; + } if (value) { delete value; } diff --git a/src/nasal_ast.h b/src/nasal_ast.h index 370891d..0b81a8d 100644 --- a/src/nasal_ast.h +++ b/src/nasal_ast.h @@ -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; }; diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index a6282f6..f4914fb 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -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(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()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; iget_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; iget_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; iget_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); diff --git a/src/nasal_codegen.h b/src/nasal_codegen.h index f1f8afa..53beb13 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -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*); diff --git a/src/nasal_gc.cpp b/src/nasal_gc.cpp index 1a66794..b1888f5 100644 --- a/src/nasal_gc.cpp +++ b/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<destructor(type)(ptr); - ptr=nullptr; + ptr = nullptr; } void nas_co::clear() { - for(u32 i=0;i"; 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 << ""; 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& 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& 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& bfs_queue) { } void gc::mark_var(std::vector& 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& bfs_queue, var& value) { } void gc::mark_vec(std::vector& 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& 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& 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& 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& bfs_queue, nas_upval& upval) { void gc::mark_co(std::vector& 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& s, const std::vector& argv) { // initialize function register - rctx->funcr=nil; - worktime=0; + rctx->funcr = nil; + worktime = 0; // initialize counters - for(u8 i=0;iunmut=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;iunmut=1; - env_argv[i].str()=argv[i]; + for(usize i = 0; iunmut = 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;imark=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] "<get_ghost_name(ghost.type); - out<<" at 0x"<"; + out << "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 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; } }; diff --git a/src/nasal_parse.cpp b/src/nasal_parse.cpp index dc195e1..33ef358 100644 --- a/src/nasal_parse.cpp +++ b/src/nasal_parse.cpp @@ -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()); } diff --git a/src/symbol_finder.cpp b/src/symbol_finder.cpp index 883c80a..275dcfc 100644 --- a/src/symbol_finder.cpp +++ b/src/symbol_finder.cpp @@ -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; }