diff --git a/README.md b/README.md index e12c4b9..9dd3309 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ![GitHub code size](https://img.shields.io/github/languages/code-size/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github) ![GitHub release(latest by date)](https://img.shields.io/github/v/release/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github) -![in dev](https://img.shields.io/badge/dev-v11.0-blue?style=flat-square&logo=github) +![in dev](https://img.shields.io/badge/dev-v11.1-blue?style=flat-square&logo=github) [![license](https://img.shields.io/badge/license-GPLv2-green?style=flat-square&logo=github)](./LICENSE) > This document is also available in: [__中文__](./doc/README_zh.md) | [__English__](./README.md) diff --git a/doc/README_zh.md b/doc/README_zh.md index 8e5bf11..c1fb67f 100644 --- a/doc/README_zh.md +++ b/doc/README_zh.md @@ -4,7 +4,7 @@ ![GitHub code size](https://img.shields.io/github/languages/code-size/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github) ![GitHub release(latest by date)](https://img.shields.io/github/v/release/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github) -![in dev](https://img.shields.io/badge/dev-v11.0-blue?style=flat-square&logo=github) +![in dev](https://img.shields.io/badge/dev-v11.1-blue?style=flat-square&logo=github) [![license](https://img.shields.io/badge/license-GPLv2-green?style=flat-square&logo=github)](../LICENSE) > 这篇文档包含多语言版本: [__中文__](../doc/README_zh.md) | [__English__](../README.md) diff --git a/src/coroutine.cpp b/src/coroutine.cpp index 332cf18..5df1397 100644 --- a/src/coroutine.cpp +++ b/src/coroutine.cpp @@ -28,7 +28,7 @@ var builtin_cocreate(var* local, gc& ngc) { cort.ctx.top[0] = nil; cort.ctx.localr = cort.ctx.top+1; - cort.ctx.top = cort.ctx.localr+func.func().lsize; + cort.ctx.top = cort.ctx.localr+func.func().local_size; cort.ctx.localr[0] = func.func().local[0]; cort.ctx.top[0] = nil; // old upvalr cort.ctx.top++; diff --git a/src/nasal.h b/src/nasal.h index 6d4e15e..7b43271 100644 --- a/src/nasal.h +++ b/src/nasal.h @@ -1,7 +1,7 @@ #pragma once #ifndef __nasver -#define __nasver "11.0" +#define __nasver "11.1" #endif #include diff --git a/src/nasal_gc.cpp b/src/nasal_gc.cpp index b85986d..193127a 100644 --- a/src/nasal_gc.cpp +++ b/src/nasal_gc.cpp @@ -93,7 +93,7 @@ std::ostream& operator<<(std::ostream& out, nas_hash& hash) { } void nas_func::clear() { - dpara = -1; + dynamic_parameter_index = -1; local.clear(); upval.clear(); keys.clear(); diff --git a/src/nasal_gc.h b/src/nasal_gc.h index 590d1ed..af6ec61 100644 --- a/src/nasal_gc.h +++ b/src/nasal_gc.h @@ -146,22 +146,26 @@ struct nas_hash { }; struct nas_func { - i32 dpara; // dynamic parameter name index in hash. + i32 dynamic_parameter_index; // dynamic parameter name index in hash. u32 entry; // pc will set to entry-1 to call this function - u32 psize; // used to load default parameters to a new function - u32 lsize; // used to expand memory space for local values on stack + u32 parameter_size; // used to load default parameters to a new function + u32 local_size; // used to expand memory space for local values on stack std::vector local; // local scope with default value(var) std::vector upval; // closure - std::unordered_map keys; // parameter table, u32 begins from 1 - nas_func(): dpara(-1), entry(0), psize(0), lsize(0) {} + // parameter table, u32 begins from 1 + std::unordered_map keys; + + nas_func(): + dynamic_parameter_index(-1), entry(0), + parameter_size(0), local_size(0) {} void clear(); }; struct nas_upval { public: /* on stack, use these variables */ - bool onstk; + bool on_stack; u32 size; var* stk; @@ -169,14 +173,14 @@ public: std::vector elems; public: - nas_upval(): onstk(true), size(0), stk(nullptr) {} + nas_upval(): on_stack(true), size(0), stk(nullptr) {} var& operator[](usize n) { - return onstk? stk[n]:elems[n]; + return on_stack? stk[n]:elems[n]; } void clear() { - onstk = true; + on_stack = true; elems.clear(); size = 0; } @@ -184,7 +188,7 @@ public: struct nas_ghost { private: - using destructor=void (*)(void*); + using destructor = void (*)(void*); public: std::string type_name; diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index 143e773..c42d6a8 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -188,10 +188,10 @@ void vm::gstate() { } void vm::lstate() { - if (!ctx.localr || !ctx.funcr.func().lsize) { + if (!ctx.localr || !ctx.funcr.func().local_size) { return; } - const u32 lsize = ctx.funcr.func().lsize; + const u32 lsize = ctx.funcr.func().local_size; std::clog << "local (0x" << std::hex << reinterpret_cast(ctx.localr) << " <+" << static_cast(ctx.localr-ctx.stack) << ">)\n" << std::dec; @@ -228,6 +228,22 @@ void vm::detail() { ustate(); } +std::string vm::report_lack_arguments(u32 argc, const nas_func& func) const { + auto result = std::string("lack argument(s): "); + std::vector argument_list = {}; + argument_list.resize(func.keys.size()); + for(const auto& i : func.keys) { + argument_list[i.second-1] = i.first; + } + for(u32 i = argc; i>16)&0xffff] - .upval()[imm[ctx.pc]&0xffff] = (ctx.top--)[0]; + .upval()[imm[ctx.pc]&0xffff] = (ctx.top--)[0]; } inline void vm::o_pnum() { @@ -252,7 +253,7 @@ inline void vm::o_newf() { (++ctx.top)[0] = ngc.alloc(vm_func); auto& func = ctx.top[0].func(); func.entry = imm[ctx.pc]; - func.psize = 1; + func.parameter_size = 1; /* this means you create a new function in local scope */ if (ctx.localr) { @@ -260,7 +261,7 @@ inline void vm::o_newf() { // function created in the same local scope shares one closure // so this size & stk setting has no problem var upval = (ctx.upvalr.type==vm_nil)? ngc.alloc(vm_upval):ctx.upvalr; - upval.upval().size = ctx.funcr.func().lsize; + upval.upval().size = ctx.funcr.func().local_size; upval.upval().stk = ctx.localr; func.upval.push_back(upval); ctx.upvalr = upval; @@ -275,20 +276,20 @@ inline void vm::o_happ() { inline void vm::o_para() { auto& func = ctx.top[0].func(); // func->size has 1 place reserved for "me" - func.keys[imm[ctx.pc]] = func.psize; - func.local[func.psize++] = var::none(); + func.keys[cstr[imm[ctx.pc]]] = func.parameter_size; + func.local[func.parameter_size++] = var::none(); } inline void vm::o_deft() { var val = ctx.top[0]; auto& func = (--ctx.top)[0].func(); // func->size has 1 place reserved for "me" - func.keys[imm[ctx.pc]] = func.psize; - func.local[func.psize++] = val; + func.keys[cstr[imm[ctx.pc]]] = func.parameter_size; + func.local[func.parameter_size++] = val; } inline void vm::o_dyn() { - ctx.top[0].func().dpara = imm[ctx.pc]; + ctx.top[0].func().dynamic_parameter_index = imm[ctx.pc]; } inline void vm::o_lnot() { @@ -349,6 +350,7 @@ inline void vm::o_sub() {op_calc(-);} inline void vm::o_mul() {op_calc(*);} inline void vm::o_div() {op_calc(/);} inline void vm::o_lnk() { + // concat two vectors into one if (ctx.top[-1].type==vm_vec && ctx.top[0].type==vm_vec) { ngc.temp = ngc.alloc(vm_vec); for(auto i : ctx.top[-1].vec().elems) { @@ -362,6 +364,7 @@ inline void vm::o_lnk() { --ctx.top; return; } + // concat strings ctx.top[-1] = ngc.newstr(ctx.top[-1].tostr()+ctx.top[0].tostr()); --ctx.top; } @@ -607,7 +610,7 @@ inline void vm::o_callv() { ctx.top[0].func().local[0] = val; // 'me' } } else if (vec.type==vm_str) { - auto& str = vec.str(); + const auto& str = vec.str(); i32 num = val.tonum(); i32 len = str.length(); if (num<-len || num>=len) { @@ -670,13 +673,13 @@ inline void vm::o_callh() { } inline void vm::o_callfv() { - u32 argc = imm[ctx.pc]; // arguments counter + const u32 argc = imm[ctx.pc]; // arguments counter var* local = ctx.top-argc+1; // arguments begin address if (local[-1].type!=vm_func) { die("must call a function"); return; } - auto& func = local[-1].func(); + const auto& func = local[-1].func(); // swap funcr with local[-1] var tmp = local[-1]; @@ -684,27 +687,29 @@ inline void vm::o_callfv() { ctx.funcr = tmp; // top-argc+lsize(local) +1(old pc) +1(old localr) +1(old upvalr) - if (ctx.top-argc+func.lsize+3>=ctx.canary) { + if (ctx.top-argc+func.local_size+3>=ctx.canary) { die("stack overflow"); return; } // parameter size is func->psize-1, 1 is reserved for "me" - u32 psize = func.psize-1; - if (argc=0) { // load dynamic arguments + if (func.dynamic_parameter_index>=0) { + // load dynamic argument dynamic = ngc.alloc(vm_vec); - for(u32 i = psize; i=1; --i) { // load arguments local[i] = local[i-1]; } local[0] = func.local[0];// load "me" // load local scope & default arguments - for(u32 i = min_size+1; i=0? psize+1:func.lsize-1] = dynamic; + // load dynamic argument + local[func.dynamic_parameter_index>=0? + parameter_size+1:func.local_size-1] = dynamic; ctx.top[0] = ctx.upvalr; (++ctx.top)[0] = var::addr(ctx.localr); @@ -736,41 +743,56 @@ inline void vm::o_callfv() { } inline void vm::o_callfh() { - auto& hash = ctx.top[0].hash().elems; + const auto& hash = ctx.top[0].hash().elems; if (ctx.top[-1].type!=vm_func) { die("must call a function"); return; } - auto& func = ctx.top[-1].func(); + const auto& func = ctx.top[-1].func(); var tmp = ctx.top[-1]; ctx.top[-1] = ctx.funcr; ctx.funcr = tmp; // top -1(hash) +lsize(local) +1(old pc) +1(old localr) +1(old upvalr) - if (ctx.top+func.lsize+2>= ctx.canary) { + if (ctx.top+func.local_size+2>= ctx.canary) { die("stack overflow"); return; } - if (func.dpara>=0) { - die("special call cannot use dynamic argument"); + // dynamic parameter is not allowed in this kind of function call + if (func.dynamic_parameter_index>=0) { + die("special call cannot use dynamic argument \"" + + cstr[func.dynamic_parameter_index] + "\"" + ); return; } var* local = ctx.top; - ctx.top += func.lsize; - for(u32 i = 0; i>16)&0xffff] - .upval()[imm[ctx.pc]&0xffff]); + .upval[(imm[ctx.pc]>>16)&0xffff] + .upval()[imm[ctx.pc]&0xffff] + ); (++ctx.top)[0] = ctx.memr[0]; // push value in this memory space on stack // to avoid being garbage collected @@ -897,7 +920,7 @@ inline void vm::o_mcallv() { return; } auto& ref = vec.hash(); - auto& str = val.str(); + const auto& str = val.str(); ctx.memr = ref.get_mem(str); if (!ctx.memr) { ref.elems[str] = nil; @@ -909,7 +932,7 @@ inline void vm::o_mcallv() { return; } auto& ref = vec.map(); - auto& str = val.str(); + const auto& str = val.str(); ctx.memr = ref.get_mem(str); if (!ctx.memr) { die("cannot find symbol \"" + str + "\""); @@ -926,7 +949,7 @@ inline void vm::o_mcallh() { die("must call a hash"); return; } - auto& str = cstr[imm[ctx.pc]]; + const auto& str = cstr[imm[ctx.pc]]; if (hash.type==vm_map) { ctx.memr = hash.map().get_mem(str); if (!ctx.memr) { @@ -936,7 +959,8 @@ inline void vm::o_mcallh() { } auto& ref = hash.hash(); ctx.memr = ref.get_mem(str); - if (!ctx.memr) { // create a new key + // create a new key + if (!ctx.memr) { ref.elems[str] = nil; ctx.memr = ref.get_mem(str); } @@ -970,10 +994,11 @@ inline void vm::o_ret() { ctx.funcr = ctx.top[0]; ctx.top[0] = ret; // rewrite func with returned value - if (up.type==vm_upval) { // synchronize upvalue + // synchronize upvalue + if (up.type==vm_upval) { auto& upval = up.upval(); - auto size = func.func().lsize; - upval.onstk = false; + auto size = func.func().local_size; + upval.on_stack = false; upval.elems.resize(size); for(u32 i = 0; i