From 80f9fc5842e9a712d625f8370159d645dae1d930 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Wed, 11 Oct 2023 00:20:02 +0800 Subject: [PATCH 01/18] :zap: can convert minimum double from string --- src/nasal_misc.cpp | 9 ++++++--- test/scalar.nas | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/nasal_misc.cpp b/src/nasal_misc.cpp index 374e190..183ec9e 100644 --- a/src/nasal_misc.cpp +++ b/src/nasal_misc.cpp @@ -120,7 +120,8 @@ f64 oct2f(const char* str) { // but this also makes 0.1+0.2==0.3, // not another result that you may get in other languages. f64 dec2f(const char* str) { - f64 ret = 0, negative = 1, num_pow = 0; + f64 ret = 0, num_pow = 0; + bool negative = false; while('0'<=*str && *str<='9') { ret = ret*10+(*str++-'0'); } @@ -147,7 +148,7 @@ f64 dec2f(const char* str) { return nan(""); } if (*str=='-' || *str=='+') { - negative = (*str++=='-'? -1:1); + negative = (*str++=='-'); } if (!*str) { return nan(""); @@ -159,7 +160,9 @@ f64 dec2f(const char* str) { if (*str) { return nan(""); } - return ret*std::pow(10, negative*num_pow); + return negative? + ret*std::pow(10, 1-num_pow)*0.1: + ret*std::pow(10, num_pow-1)*10; } f64 str2num(const char* str) { diff --git a/test/scalar.nas b/test/scalar.nas index 4d853f7..afad81f 100644 --- a/test/scalar.nas +++ b/test/scalar.nas @@ -234,4 +234,6 @@ for(var a=0;a<16;a+=1) { } print([0, 1, 2]~[3, 4, 5], "\n"); + +print(num("1.79769313486231570814527423731704357e+308"), "\n"); print(num("4.94065645841246544176568792868e-324"), "\n"); \ No newline at end of file From ecfb67921874fe7f705702bf63bc6900c4e56f50 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sat, 14 Oct 2023 00:39:25 +0800 Subject: [PATCH 02/18] :sparkles: improve error info when lack arguments in function call --- README.md | 2 +- doc/README_zh.md | 2 +- src/coroutine.cpp | 2 +- src/nasal.h | 2 +- src/nasal_gc.cpp | 2 +- src/nasal_gc.h | 24 ++++++---- src/nasal_vm.cpp | 20 +++++++- src/nasal_vm.h | 117 ++++++++++++++++++++++++++++------------------ 8 files changed, 108 insertions(+), 63 deletions(-) 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 Date: Sat, 14 Oct 2023 21:30:33 +0800 Subject: [PATCH 03/18] :bug: fix mingw make error --- makefile | 6 ++++-- module/fib.cpp | 4 ++-- module/makefile | 5 ++++- src/coroutine.cpp | 32 +++++++++++++++++++++++--------- src/dylib_lib.cpp | 10 +++++----- src/io_lib.cpp | 16 ++++++++++------ src/nasal_builtin.cpp | 2 +- src/nasal_gc.cpp | 42 +++++++++++++++++++++--------------------- src/nasal_gc.h | 17 +++++++++-------- src/nasal_vm.cpp | 2 +- src/unix_lib.cpp | 4 ++-- 11 files changed, 82 insertions(+), 58 deletions(-) diff --git a/makefile b/makefile index 031925d..8e0c434 100644 --- a/makefile +++ b/makefile @@ -1,11 +1,13 @@ STD = c++17 -OS = $(shell uname) + +ifndef OS + OS = $(shell uname) +endif ifeq ($(OS), Darwin) CXXFLAGS = -std=$(STD) -c -O3 -fno-exceptions -fPIC -mmacosx-version-min=10.15 else CXXFLAGS = -std=$(STD) -c -O3 -fno-exceptions -fPIC endif -CPPFLAGS = -I . NASAL_HEADER=\ src/ast_dumper.h\ diff --git a/module/fib.cpp b/module/fib.cpp index 1e81a99..9d570ef 100644 --- a/module/fib.cpp +++ b/module/fib.cpp @@ -62,7 +62,7 @@ var set_new_ghost(var* args, usize size, gc* ngc) { return nil; } f64 num = args[1].num(); - *((u32*)res.obj().ptr) = static_cast(num); + *((u32*)res.obj().pointer) = static_cast(num); std::cout << "set_new_ghost: successfully set ghost = " << num << "\n"; return nil; } @@ -74,7 +74,7 @@ var print_new_ghost(var* args, usize size, gc* ngc) { return nil; } std::cout << "print_new_ghost: " << res.obj() << " result = " - << *((u32*)res.obj().ptr) << "\n"; + << *((u32*)res.obj().pointer) << "\n"; return nil; } diff --git a/module/makefile b/module/makefile index be81a35..5c9ab1c 100644 --- a/module/makefile +++ b/module/makefile @@ -7,7 +7,10 @@ used_header = ../src/nasal.h ../src/nasal_gc.h used_object = ../build/nasal_misc.o ../build/nasal_gc.o STD = c++17 -OS = $(shell uname) + +ifndef OS + OS = $(shell uname) +endif ifeq ($(OS), Darwin) CXXFLAGS = -std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15 else diff --git a/src/coroutine.cpp b/src/coroutine.cpp index 5df1397..319698e 100644 --- a/src/coroutine.cpp +++ b/src/coroutine.cpp @@ -17,10 +17,16 @@ var builtin_cocreate(var* local, gc& ngc) { // +-------------+ var func = local[1]; if (func.type!=vm_func) { - return nas_err("coroutine::create", "must use a function to create coroutine"); + return nas_err( + "coroutine::create", + "must use a function to create coroutine" + ); } if (ngc.cort) { - return nas_err("coroutine::create", "cannot create another coroutine in a coroutine"); + return nas_err( + "coroutine::create", + "cannot create another coroutine in a coroutine" + ); } var co = ngc.alloc(vm_co); nas_co& cort = co.co(); @@ -30,13 +36,18 @@ var builtin_cocreate(var* local, gc& ngc) { cort.ctx.localr = cort.ctx.top+1; 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 + // store old upvalr on stack + cort.ctx.top[0] = nil; cort.ctx.top++; - cort.ctx.top[0] = var::addr((var*)nullptr); // old localr + // store old localr on stack + cort.ctx.top[0] = var::addr((var*)nullptr); cort.ctx.top++; - cort.ctx.top[0] = var::ret(0); // old pc, set to zero to make op_ret recognizing this as coroutine function + // store old pc on stack + // set to zero to make op_ret recognizing this as coroutine function + cort.ctx.top[0] = var::ret(0); - cort.ctx.funcr = func; // make sure the coroutine function can use correct upvalues + // make sure the coroutine function can use correct upvalues + cort.ctx.funcr = func; cort.status = nas_co::status::suspended; return co; @@ -44,7 +55,10 @@ var builtin_cocreate(var* local, gc& ngc) { var builtin_coresume(var* local, gc& ngc) { if (ngc.cort) { - return nas_err("coroutine::resume", "cannot start another coroutine when one is running"); + return nas_err( + "coroutine::resume", + "cannot start another coroutine when one is running" + ); } var co = local[1]; // return nil if is not a coroutine object @@ -61,9 +75,9 @@ var builtin_coresume(var* local, gc& ngc) { // fetch coroutine's stack top and return // so the coroutine's stack top in fact is not changed - if (ngc.rctx->top[0].type==vm_ret) { + if (ngc.running_context->top[0].type==vm_ret) { // when first calling this coroutine, the stack top must be vm_ret - return ngc.rctx->top[0]; + return ngc.running_context->top[0]; } // after first calling the coroutine, each time coroutine.yield triggered diff --git a/src/dylib_lib.cpp b/src/dylib_lib.cpp index 75c8aee..daae5aa 100644 --- a/src/dylib_lib.cpp +++ b/src/dylib_lib.cpp @@ -42,11 +42,11 @@ var builtin_dlopen(var* local, gc& ngc) { #ifdef _WIN32 void* func = (void*)GetProcAddress( - static_cast(lib.obj().ptr), + static_cast(lib.obj().pointer), "get" ); #else - void* func = dlsym(lib.obj().ptr, "get"); + void* func = dlsym(lib.obj().pointer, "get"); #endif if (!func) { return nas_err("dlopen", "cannot find function"); @@ -83,7 +83,7 @@ var builtin_dlcallv(var* local, gc& ngc) { return nas_err("dlcall", "\"ptr\" is not a valid function pointer"); } auto& vec = args.vec().elems; - return reinterpret_cast(fp.obj().ptr)( + return reinterpret_cast(fp.obj().pointer)( vec.data(), vec.size(), &ngc @@ -97,9 +97,9 @@ var builtin_dlcall(var* local, gc& ngc) { } var* local_frame_start = local+2; - usize local_frame_size = ngc.rctx->top-local_frame_start; + usize local_frame_size = ngc.running_context->top-local_frame_start; // arguments' stored place begins at local +2 - return reinterpret_cast(fp.obj().ptr)( + return reinterpret_cast(fp.obj().pointer)( local_frame_start, local_frame_size, &ngc diff --git a/src/io_lib.cpp b/src/io_lib.cpp index d057e1e..406ab17 100644 --- a/src/io_lib.cpp +++ b/src/io_lib.cpp @@ -92,7 +92,7 @@ var builtin_read(var* local, gc& ngc) { if (!buff) { return nas_err("read", "malloc failed"); } - f64 res = fread(buff, 1, len.num(), static_cast(fd.obj().ptr)); + f64 res = fread(buff, 1, len.num(), static_cast(fd.obj().pointer)); buf.str() = buff; buf.val.gcobj->unmut = true; delete []buff; @@ -112,7 +112,7 @@ var builtin_write(var* local, gc& ngc) { str.str().c_str(), 1, str.str().length(), - static_cast(fd.obj().ptr) + static_cast(fd.obj().pointer) ))); } @@ -124,7 +124,7 @@ var builtin_seek(var* local, gc& ngc) { return nas_err("seek", "not a valid filehandle"); } return var::num(static_cast(fseek( - static_cast(fd.obj().ptr), + static_cast(fd.obj().pointer), pos.num(), whence.num() ))); @@ -135,7 +135,9 @@ var builtin_tell(var* local, gc& ngc) { if (!fd.objchk(file_type_name)) { return nas_err("tell", "not a valid filehandle"); } - return var::num(static_cast(ftell(static_cast(fd.obj().ptr)))); + return var::num(static_cast( + ftell(static_cast(fd.obj().pointer)) + )); } var builtin_readln(var* local, gc& ngc) { @@ -145,7 +147,7 @@ var builtin_readln(var* local, gc& ngc) { } var str = ngc.alloc(vm_str); char c; - while((c = fgetc(static_cast(fd.obj().ptr)))!=EOF) { + while((c = fgetc(static_cast(fd.obj().pointer)))!=EOF) { if (c=='\r') { continue; } @@ -191,7 +193,9 @@ var builtin_eof(var* local, gc& ngc) { if (!fd.objchk(file_type_name)) { return nas_err("readln", "not a valid filehandle"); } - return var::num(static_cast(feof(static_cast(fd.obj().ptr)))); + return var::num(static_cast( + feof(static_cast(fd.obj().pointer)) + )); } nasal_builtin_table io_lib_native[] = { diff --git a/src/nasal_builtin.cpp b/src/nasal_builtin.cpp index 11fc253..1aacb4c 100644 --- a/src/nasal_builtin.cpp +++ b/src/nasal_builtin.cpp @@ -616,7 +616,7 @@ var builtin_ghosttype(var* local, gc& ngc) { } const auto& name = arg.obj().get_ghost_name(); if (!name.length()) { - return var::num(reinterpret_cast(arg.obj().ptr)); + return var::num(reinterpret_cast(arg.obj().pointer)); } return ngc.newstr(name); } diff --git a/src/nasal_gc.cpp b/src/nasal_gc.cpp index 193127a..0dda3b8 100644 --- a/src/nasal_gc.cpp +++ b/src/nasal_gc.cpp @@ -104,34 +104,34 @@ void nas_ghost::set( destructor destructor_pointer, void* ghost_pointer) { type_name = ghost_type_name; - dtor_ptr = destructor_pointer; - ptr = ghost_pointer; + destructor_function = destructor_pointer; + pointer = ghost_pointer; } void nas_ghost::clear() { // do nothing if pointer is null - if (!ptr) { + if (!pointer) { return; } // do clear pointer if destructor function pointer is null - if (!dtor_ptr) { + if (!destructor_function) { type_name = ""; - ptr = nullptr; + pointer = nullptr; return; } // do destruction - dtor_ptr(ptr); + destructor_function(pointer); type_name = ""; - ptr = nullptr; - dtor_ptr = nullptr; + pointer = nullptr; + destructor_function = nullptr; } std::ostream& operator<<(std::ostream& out, const nas_ghost& ghost) { out << "(ghost.ptr) << std::dec << ">"; + out << reinterpret_cast(ghost.pointer) << std::dec << ">"; return out; } @@ -265,7 +265,7 @@ std::ostream& operator<<(std::ostream& out, var& ref) { } bool var::objchk(const std::string& name) { - return type==vm_obj && obj().type_name==name && obj().ptr; + return type==vm_obj && obj().type_name==name && obj().pointer; } var var::none() { @@ -418,13 +418,13 @@ void gc::mark_context_root(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 = running_context->stack; i<=running_context->top; ++i) { if (i->type>vm_num) { bfs_queue.push_back(*i); } } - bfs_queue.push_back(rctx->funcr); - bfs_queue.push_back(rctx->upvalr); + bfs_queue.push_back(running_context->funcr); + bfs_queue.push_back(running_context->upvalr); bfs_queue.push_back(temp); if (!cort) { @@ -432,13 +432,13 @@ void gc::mark_context_root(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 = main_context.stack; i<=main_context.top; ++i) { if (i->type>vm_num) { bfs_queue.push_back(*i); } } - bfs_queue.push_back(mctx.funcr); - bfs_queue.push_back(mctx.upvalr); + bfs_queue.push_back(main_context.funcr); + bfs_queue.push_back(main_context.upvalr); } void gc::mark_var(std::vector& bfs_queue, var& value) { @@ -696,10 +696,10 @@ var gc::alloc(u8 type) { void gc::ctxchg(nas_co& co) { // store running state to main context - mctx = *rctx; + main_context = *running_context; // restore coroutine context state - *rctx = co.ctx; + *running_context = co.ctx; // set coroutine pointer cort = &co; @@ -710,15 +710,15 @@ void gc::ctxchg(nas_co& co) { void gc::ctxreserve() { // pc=0 means this coroutine is finished - cort->status = rctx->pc? + cort->status = running_context->pc? nas_co::status::suspended: nas_co::status::dead; // store running state to coroutine - cort->ctx = *rctx; + cort->ctx = *running_context; // restore main context state - *rctx = mctx; + *running_context = main_context; // set coroutine pointer to nullptr cort = nullptr; diff --git a/src/nasal_gc.h b/src/nasal_gc.h index af6ec61..906700f 100644 --- a/src/nasal_gc.h +++ b/src/nasal_gc.h @@ -192,11 +192,12 @@ private: public: std::string type_name; - destructor dtor_ptr; - void* ptr; + destructor destructor_function; + void* pointer; public: - nas_ghost(): type_name(""), dtor_ptr(nullptr), ptr(nullptr) {} + nas_ghost(): + type_name(""), destructor_function(nullptr), pointer(nullptr) {} ~nas_ghost() {clear();} void set(const std::string&, destructor, void*); void clear(); @@ -290,14 +291,14 @@ const var nil = var::nil(); struct gc { /* main context temporary storage */ - context mctx; + context main_context; /* global storage */ var* main_context_global = nullptr; usize main_context_global_size = 0; /* runtime context */ - context* rctx = nullptr; + context* running_context = nullptr; nas_co* cort = nullptr; // running coroutine /* temporary space used in native/module functions */ @@ -331,7 +332,7 @@ struct gc { i64 max_sweep_time = 0; void set(context* _ctx, var* _global, usize _size) { - rctx = _ctx; + running_context = _ctx; main_context_global = _global; main_context_global_size = _size; } @@ -368,13 +369,13 @@ public: } var newstr(const char* buff) { - var s=alloc(vm_str); + var s = alloc(vm_str); s.str() = buff; return s; } var newstr(const std::string& buff) { - var s=alloc(vm_str); + var s = alloc(vm_str); s.str() = buff; return s; } diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index c42d6a8..ed16232 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -93,7 +93,7 @@ void vm::valinfo(var& val) { << " val}"; break; case vm_obj: std::clog << "| obj | <0x" << std::hex << p << "> obj:0x" - << reinterpret_cast(val.obj().ptr) + << reinterpret_cast(val.obj().pointer) << std::dec; break; case vm_co: std::clog << "| co | <0x" << std::hex << p << std::dec << "> coroutine"; break; diff --git a/src/unix_lib.cpp b/src/unix_lib.cpp index e3ecad2..865384f 100644 --- a/src/unix_lib.cpp +++ b/src/unix_lib.cpp @@ -84,12 +84,12 @@ var builtin_readdir(var* local, gc& ngc) { } #ifdef _MSC_VER WIN32_FIND_DATAA data; - if (!FindNextFileA(handle.obj().ptr,&data)) { + if (!FindNextFileA(handle.obj().pointer, &data)) { return nil; } return ngc.newstr(data.cFileName); #else - dirent* p = readdir(static_cast(handle.obj().ptr)); + dirent* p = readdir(static_cast(handle.obj().pointer)); return p? ngc.newstr(p->d_name):nil; #endif } From aab7decd706600dd2a1bd7e137facc73f5116b20 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 15 Oct 2023 21:46:53 +0800 Subject: [PATCH 04/18] :zap: split type definition from gc.h --- CMakeLists.txt | 1 + makefile | 8 +- module/fib.cpp | 2 + module/keyboard.cpp | 2 + module/makefile | 4 +- module/matrix.cpp | 2 + module/nasocket.cpp | 2 + src/bits_lib.cpp | 6 +- src/io_lib.cpp | 6 +- src/io_lib.h | 6 + src/main.cpp | 2 + src/math_lib.cpp | 2 +- src/nasal.h | 7 +- src/nasal_builtin.h | 5 + src/nasal_gc.cpp | 351 +------------------------------------------ src/nasal_gc.h | 277 +--------------------------------- src/nasal_type.cpp | 352 ++++++++++++++++++++++++++++++++++++++++++++ src/nasal_type.h | 272 ++++++++++++++++++++++++++++++++++ src/nasal_vm.h | 6 +- tools/file2ppm.nas | 28 ++++ 20 files changed, 699 insertions(+), 642 deletions(-) create mode 100644 src/nasal_type.cpp create mode 100644 src/nasal_type.h create mode 100644 tools/file2ppm.nas diff --git a/CMakeLists.txt b/CMakeLists.txt index ef2d704..151e760 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ set(NASAL_OBJECT_SOURCE_FILE ${CMAKE_SOURCE_DIR}/src/nasal_misc.cpp ${CMAKE_SOURCE_DIR}/src/nasal_opcode.cpp ${CMAKE_SOURCE_DIR}/src/nasal_parse.cpp + ${CMAKE_SOURCE_DIR}/src/nasal_type.cpp ${CMAKE_SOURCE_DIR}/src/nasal_vm.cpp ${CMAKE_SOURCE_DIR}/src/optimizer.cpp ${CMAKE_SOURCE_DIR}/src/symbol_finder.cpp diff --git a/makefile b/makefile index 8e0c434..7317864 100644 --- a/makefile +++ b/makefile @@ -23,6 +23,7 @@ NASAL_HEADER=\ src/nasal_opcode.h\ src/nasal_parse.h\ src/nasal_vm.h\ + src/nasal_type.h\ src/nasal.h\ src/optimizer.h\ src/symbol_finder.h\ @@ -57,6 +58,7 @@ NASAL_OBJECT=\ build/unix_lib.o\ build/dylib_lib.o\ build/coroutine.o\ + build/nasal_type.o\ build/nasal_vm.o\ build/nasal_dbg.o\ build/repl.o\ @@ -89,7 +91,10 @@ build/repl.o: $(NASAL_HEADER) src/repl.h src/repl.cpp | build build/nasal_err.o: src/nasal.h src/repl.h src/nasal_err.h src/nasal_err.cpp | build $(CXX) $(CXXFLAGS) src/nasal_err.cpp -o build/nasal_err.o -build/nasal_gc.o: src/nasal.h src/nasal_gc.h src/nasal_gc.cpp | build +build/nasal_type.o: src/nasal.h src/nasal_type.h src/nasal_type.cpp | build + $(CXX) $(CXXFLAGS) src/nasal_type.cpp -o build/nasal_type.o + +build/nasal_gc.o: src/nasal.h src/nasal_type.h src/nasal_gc.h src/nasal_gc.cpp | build $(CXX) $(CXXFLAGS) src/nasal_gc.cpp -o build/nasal_gc.o build/nasal_import.o: \ @@ -115,6 +120,7 @@ build/nasal_ast.o: \ build/nasal_builtin.o: \ src/nasal.h\ + src/nasal_type.h\ src/nasal_gc.h\ src/nasal_builtin.h src/nasal_builtin.cpp | build $(CXX) $(CXXFLAGS) src/nasal_builtin.cpp -o build/nasal_builtin.o diff --git a/module/fib.cpp b/module/fib.cpp index 9d570ef..aec5dcb 100644 --- a/module/fib.cpp +++ b/module/fib.cpp @@ -2,6 +2,8 @@ #include #include "../src/nasal.h" +#include "../src/nasal_type.h" +#include "../src/nasal_gc.h" namespace nasal { namespace fib_module { diff --git a/module/keyboard.cpp b/module/keyboard.cpp index 0cdeb72..8586c58 100644 --- a/module/keyboard.cpp +++ b/module/keyboard.cpp @@ -1,4 +1,6 @@ #include "../src/nasal.h" +#include "../src/nasal_type.h" +#include "../src/nasal_gc.h" #include #ifndef _MSC_VER diff --git a/module/makefile b/module/makefile index 5c9ab1c..d80702e 100644 --- a/module/makefile +++ b/module/makefile @@ -3,8 +3,8 @@ dynamic_libs_so = libfib.so libkey.so libnasock.so libmat.so dynamic_libs_dll = libfib.dll libkey.dll libnasock.dll libmat.dll -used_header = ../src/nasal.h ../src/nasal_gc.h -used_object = ../build/nasal_misc.o ../build/nasal_gc.o +used_header = ../src/nasal.h ../src/nasal_type.h ../src/nasal_gc.h +used_object = ../build/nasal_misc.o ../build/nasal_type.o ../build/nasal_gc.o STD = c++17 diff --git a/module/matrix.cpp b/module/matrix.cpp index 8f67f13..5481af4 100644 --- a/module/matrix.cpp +++ b/module/matrix.cpp @@ -1,4 +1,6 @@ #include "../src/nasal.h" +#include "../src/nasal_type.h" +#include "../src/nasal_gc.h" #include namespace nasal { diff --git a/module/nasocket.cpp b/module/nasocket.cpp index 6208321..2ac1069 100644 --- a/module/nasocket.cpp +++ b/module/nasocket.cpp @@ -1,4 +1,6 @@ #include "../src/nasal.h" +#include "../src/nasal_type.h" +#include "../src/nasal_gc.h" #ifndef _MSC_VER #include diff --git a/src/bits_lib.cpp b/src/bits_lib.cpp index a4000d8..f33c79b 100644 --- a/src/bits_lib.cpp +++ b/src/bits_lib.cpp @@ -41,7 +41,7 @@ var builtin_fld(var* local, gc& ngc) { var str = local[1]; var startbit = local[2]; var length = local[3]; - if (str.type!=vm_str || str.val.gcobj->unmut) { + if (str.type!=vm_str || str.val.gcobj->unmutable) { return nas_err("fld", "\"str\" must be mutable string"); } if (startbit.type!=vm_num || length.type!=vm_num) { @@ -70,7 +70,7 @@ var builtin_sfld(var* local, gc& ngc) { var str = local[1]; var startbit = local[2]; var length = local[3]; - if (str.type!=vm_str || str.val.gcobj->unmut) { + if (str.type!=vm_str || str.val.gcobj->unmutable) { return nas_err("sfld", "\"str\" must be mutable string"); } if (startbit.type!=vm_num || length.type!=vm_num) { @@ -103,7 +103,7 @@ var builtin_setfld(var* local, gc& ngc) { var startbit = local[2]; var length = local[3]; var value = local[4]; - if (str.type!=vm_str || str.val.gcobj->unmut) { + if (str.type!=vm_str || str.val.gcobj->unmutable) { return nas_err("setfld", "\"str\" must be mutable string"); } if (startbit.type!=vm_num || length.type!=vm_num || value.type!=vm_num) { diff --git a/src/io_lib.cpp b/src/io_lib.cpp index 406ab17..63c5dee 100644 --- a/src/io_lib.cpp +++ b/src/io_lib.cpp @@ -42,7 +42,7 @@ var builtin_exists(var* local, gc& ngc) { if (local[1].type!=vm_str) { return zero; } - return access(local[1].str().c_str(), F_OK)!=-1?one:zero; + return access(local[1].str().c_str(), F_OK)!=-1? one:zero; } var builtin_open(var* local, gc& ngc) { @@ -79,7 +79,7 @@ var builtin_read(var* local, gc& ngc) { if (!fd.objchk(file_type_name)) { return nas_err("read", "not a valid filehandle"); } - if (buf.type!=vm_str || buf.val.gcobj->unmut) { + if (buf.type!=vm_str || buf.val.gcobj->unmutable) { return nas_err("read", "\"buf\" must be mutable string"); } if (len.type!=vm_num) { @@ -94,7 +94,7 @@ var builtin_read(var* local, gc& ngc) { } f64 res = fread(buff, 1, len.num(), static_cast(fd.obj().pointer)); buf.str() = buff; - buf.val.gcobj->unmut = true; + buf.val.gcobj->unmutable = true; delete []buff; return var::num(res); } diff --git a/src/io_lib.h b/src/io_lib.h index 6740984..3ea800d 100644 --- a/src/io_lib.h +++ b/src/io_lib.h @@ -6,6 +6,12 @@ #include +#ifndef _MSC_VER +#include +#else +#include +#endif + #ifdef _MSC_VER #define F_OK 0 // fuck msc #endif diff --git a/src/main.cpp b/src/main.cpp index e8ec9b1..1867f67 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,6 @@ #include "nasal.h" +#include "nasal_type.h" +#include "nasal_gc.h" #include "nasal_err.h" #include "nasal_lexer.h" #include "nasal_ast.h" diff --git a/src/math_lib.cpp b/src/math_lib.cpp index 2804e1d..e751636 100644 --- a/src/math_lib.cpp +++ b/src/math_lib.cpp @@ -57,7 +57,7 @@ var builtin_atan2(var* local, gc& ngc) { var builtin_isnan(var* local, gc& ngc) { var x = local[1]; - return (x.type==vm_num && std::isnan(x.num()))?one:zero; + return (x.type==vm_num && std::isnan(x.num()))? one:zero; } nasal_builtin_table math_lib_native[] = { diff --git a/src/nasal.h b/src/nasal.h index 7b43271..6ad8084 100644 --- a/src/nasal.h +++ b/src/nasal.h @@ -9,7 +9,6 @@ #include #include #include -#include // abbreviation of some useful basic type using i32 = std::int32_t; @@ -54,8 +53,6 @@ f64 dec2f(const char*); f64 str2num(const char*); i32 utf8_hdchk(const char); std::string chrhex(const char); -std::string rawstr(const std::string&, const usize maxlen=0); +std::string rawstr(const std::string&, const usize maxlen = 0); -} - -#include "nasal_gc.h" +} \ No newline at end of file diff --git a/src/nasal_builtin.h b/src/nasal_builtin.h index c436a52..cf7d6ea 100644 --- a/src/nasal_builtin.h +++ b/src/nasal_builtin.h @@ -1,8 +1,13 @@ #pragma once #include "nasal.h" +#include "nasal_type.h" #include "nasal_gc.h" +#ifdef _WIN32 +#include +#endif + #ifdef _MSC_VER #pragma warning (disable:4566) // i know i'm using utf-8, fuck you #pragma warning (disable:4244) diff --git a/src/nasal_gc.cpp b/src/nasal_gc.cpp index 0dda3b8..688feb4 100644 --- a/src/nasal_gc.cpp +++ b/src/nasal_gc.cpp @@ -2,348 +2,6 @@ namespace nasal { -var nas_vec::get_val(const i32 n) { - i32 size = elems.size(); - if (n<-size || n>=size) { - return var::none(); - } - return elems[n>=0? n:n+size]; -} - -var* nas_vec::get_mem(const i32 n) { - i32 size = elems.size(); - if (n<-size || n>=size) { - return nullptr; - } - 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()? "[..]":"[]"); - return out; - } - vec.printed = true; - usize iter = 0, size = vec.elems.size(); - out << "["; - for(auto& i:vec.elems) { - out << i << ",]"[(++iter)==size]; - } - vec.printed = false; - return out; -} - -var nas_hash::get_val(const std::string& key) { - if (elems.count(key)) { - return elems.at(key); - } else if (!elems.count("parents")) { - return var::none(); - } - var ret = var::none(); - var val = elems.at("parents"); - if (val.type!=vm_vec) { - return ret; - } - for(auto& i : val.vec().elems) { - if (i.type==vm_hash) { - ret = i.hash().get_val(key); - } - if (ret.type!=vm_none) { - return ret; - } - } - return ret; -} - -var* nas_hash::get_mem(const std::string& key) { - if (elems.count(key)) { - return &elems.at(key); - } else if (!elems.count("parents")) { - return nullptr; - } - var* addr = nullptr; - var val = elems.at("parents"); - if (val.type!=vm_vec) { - return addr; - } - for(auto& i : val.vec().elems) { - if (i.type==vm_hash) { - addr = i.hash().get_mem(key); - } - if (addr) { - return addr; - } - } - return addr; -} - -std::ostream& operator<<(std::ostream& out, nas_hash& hash) { - if (!hash.elems.size() || hash.printed) { - 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 = false; - return out; -} - -void nas_func::clear() { - dynamic_parameter_index = -1; - local.clear(); - upval.clear(); - keys.clear(); -} - -void nas_ghost::set( - const std::string& ghost_type_name, - destructor destructor_pointer, - void* ghost_pointer) { - type_name = ghost_type_name; - destructor_function = destructor_pointer; - pointer = ghost_pointer; -} - -void nas_ghost::clear() { - // do nothing if pointer is null - if (!pointer) { - return; - } - - // do clear pointer if destructor function pointer is null - if (!destructor_function) { - type_name = ""; - pointer = nullptr; - return; - } - - // do destruction - destructor_function(pointer); - type_name = ""; - pointer = nullptr; - destructor_function = nullptr; -} - -std::ostream& operator<<(std::ostream& out, const nas_ghost& ghost) { - out << "(ghost.pointer) << std::dec << ">"; - return out; -} - -void nas_co::clear() { - if (!ctx.stack) { - return; - } - for(u32 i = 0; i(&co) << std::dec << ">"; - return out; -} - -var nas_map::get_val(const std::string& key) { - if (mapper.count(key)) { - return *mapper.at(key); - } - return var::none(); -} - -var* nas_map::get_mem(const std::string& key) { - if (mapper.count(key)) { - return mapper.at(key); - } - return nullptr; -} - -std::ostream& operator<<(std::ostream& out, nas_map& mp) { - if (!mp.mapper.size() || mp.printed) { - out << (mp.mapper.size()? "{..}":"{}"); - return out; - } - mp.printed = true; - usize iter = 0, size = mp.mapper.size(); - out << "{"; - for(auto& i : mp.mapper) { - out << i.first << ":" << *i.second << ",}"[(++iter)==size]; - } - mp.printed = false; - return out; -} - -nas_val::nas_val(u8 val_type) { - 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_map: ptr.map = new nas_map; break; - } -} - -nas_val::~nas_val() { - switch(type) { - case vm_str: delete ptr.str; break; - case vm_vec: delete ptr.vec; break; - case vm_hash: delete ptr.hash; break; - case vm_func: delete ptr.func; break; - case vm_upval:delete ptr.upval;break; - case vm_obj: delete ptr.obj; break; - case vm_co: delete ptr.co; break; - case vm_map: delete ptr.map; break; - } - type=vm_nil; -} - -void nas_val::clear() { - switch(type) { - case vm_str: ptr.str->clear(); break; - case vm_vec: ptr.vec->elems.clear(); break; - case vm_hash: ptr.hash->elems.clear();break; - case vm_func: ptr.func->clear(); break; - case vm_upval:ptr.upval->clear(); break; - case vm_obj: ptr.obj->clear(); break; - case vm_co: ptr.co->clear(); break; - case vm_map: ptr.map->clear(); break; - } -} - -f64 var::tonum() { - return type!=vm_str? val.num:str2num(str().c_str()); -} - -std::string var::tostr() { - if (type==vm_str) { - return str(); - } else if (type==vm_num) { - std::string tmp=std::to_string(num()); - tmp.erase(tmp.find_last_not_of('0')+1, std::string::npos); - tmp.erase(tmp.find_last_not_of('.')+1, std::string::npos); - return tmp; - } - return ""; -} - -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 << ref.co(); break; - case vm_map: out << ref.map(); break; - } - return out; -} - -bool var::objchk(const std::string& name) { - return type==vm_obj && obj().type_name==name && obj().pointer; -} - -var var::none() { - return {vm_none, static_cast(0)}; -} - -var var::nil() { - return {vm_nil, static_cast(0)}; -} - -var var::ret(u32 pc) { - return {vm_ret, pc}; -} - -var var::cnt(i64 n) { - return {vm_cnt, n}; -} - -var var::num(f64 n) { - return {vm_num, n}; -} - -var var::gcobj(nas_val* p) { - return {p->type, p}; -} - -var var::addr(var* p) { - return {vm_addr, p}; -} - -var* var::addr() { - return val.addr; -} - -u32 var::ret() { - return val.ret; -} - -i64& var::cnt() { - return val.cnt; -} - -f64 var::num() { - return val.num; -} - -std::string& var::str() { - return *val.gcobj->ptr.str; -} - -nas_vec& var::vec() { - return *val.gcobj->ptr.vec; -} - -nas_hash& var::hash() { - return *val.gcobj->ptr.hash; -} - -nas_func& var::func() { - return *val.gcobj->ptr.func; -} - -nas_upval& var::upval() { - return *val.gcobj->ptr.upval; -} - -nas_ghost& var::obj() { - return *val.gcobj->ptr.obj; -} - -nas_co& var::co() { - return *val.gcobj->ptr.co; -} - -nas_map& var::map() { - return *val.gcobj->ptr.map; -} - void gc::do_mark_sweep() { using clk = std::chrono::high_resolution_clock; auto begin = clk::now(); @@ -556,7 +214,7 @@ void gc::init( continue; } strs[i] = var::gcobj(new nas_val(vm_str)); - strs[i].val.gcobj->unmut = 1; + strs[i].val.gcobj->unmutable = 1; strs[i].str() = constant_strings[i]; } @@ -568,7 +226,7 @@ void gc::init( continue; } env_argv[i] = var::gcobj(new nas_val(vm_str)); - env_argv[i].val.gcobj->unmut = 1; + env_argv[i].val.gcobj->unmutable = 1; env_argv[i].str() = argv[i]; } } @@ -724,9 +382,4 @@ void gc::ctxreserve() { cort = nullptr; } -var nas_err(const std::string& error_function_name, const std::string& info) { - std::cerr << "[vm] " << error_function_name << ": " << info << "\n"; - return var::none(); -} - } diff --git a/src/nasal_gc.h b/src/nasal_gc.h index 906700f..f5b4497 100644 --- a/src/nasal_gc.h +++ b/src/nasal_gc.h @@ -7,288 +7,18 @@ #pragma warning (disable:4102) #endif -#ifndef _MSC_VER -#include -#include -#else -#include -#include -#endif - -#ifdef _WIN32 -#include -#else -#include -#endif - #include #include -#include #include -#include #include #include #include #include "nasal.h" +#include "nasal_type.h" namespace nasal { -enum vm_type:u8 { - /* none-gc object */ - vm_none = 0, - vm_cnt, - vm_addr, - vm_ret, - vm_nil, - vm_num, - /* gc object */ - vm_str, - vm_vec, - vm_hash, - vm_func, - vm_upval, - vm_obj, - vm_co, - vm_map // for globals and namespaces -}; - -const u32 gc_type_size = vm_map-vm_str+1; - -struct nas_vec; // vector -struct nas_hash; // hashmap(dict) -struct nas_func; // function(lambda) -struct nas_upval; // upvalue -struct nas_ghost; // objects -struct nas_co; // coroutine -struct nas_map; // mapper -struct nas_val; // nas_val includes gc-managed types - -struct var { -public: - u8 type = vm_none; - union { - u32 ret; - i64 cnt; - f64 num; - var* addr; - nas_val* gcobj; - } 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;} - -public: - var() = default; - var(const var&) = default; - bool operator==(const var& nr) const { - return type==nr.type && val.gcobj==nr.val.gcobj; - } - bool operator!=(const var& nr) const { - return type!=nr.type || val.gcobj!=nr.val.gcobj; - } - - // number and string can be translated to each other - f64 tonum(); - std::string tostr(); - bool objchk(const std::string&); - - // create new var object - static var none(); - static var nil(); - static var ret(u32); - static var cnt(i64); - static var num(f64); - static var gcobj(nas_val*); - static var addr(var*); - - // get content - var* addr(); - u32 ret(); - i64& cnt(); - f64 num(); - std::string& str(); - nas_vec& vec(); - nas_hash& hash(); - nas_func& func(); - nas_upval& upval(); - nas_ghost& obj(); - nas_co& co(); - nas_map& map(); -}; - -struct nas_vec { - std::vector elems; - - // mark if this is printed, avoid stackoverflow - bool printed; - - nas_vec():printed(false) {} - usize size() const {return elems.size();} - var get_val(const i32); - var* get_mem(const i32); -}; - -struct nas_hash { - std::unordered_map elems; - - // mark if this is printed, avoid stackoverflow - bool printed; - - nas_hash(): printed(false) {} - usize size() const {return elems.size();} - var get_val(const std::string&); - var* get_mem(const std::string&); -}; - -struct nas_func { - i32 dynamic_parameter_index; // dynamic parameter name index in hash. - u32 entry; // pc will set to entry-1 to call this function - 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 - - // 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 on_stack; - u32 size; - var* stk; - - /* not on stack, use this */ - std::vector elems; - -public: - nas_upval(): on_stack(true), size(0), stk(nullptr) {} - - var& operator[](usize n) { - return on_stack? stk[n]:elems[n]; - } - - void clear() { - on_stack = true; - elems.clear(); - size = 0; - } -}; - -struct nas_ghost { -private: - using destructor = void (*)(void*); - -public: - std::string type_name; - destructor destructor_function; - void* pointer; - -public: - nas_ghost(): - type_name(""), destructor_function(nullptr), pointer(nullptr) {} - ~nas_ghost() {clear();} - void set(const std::string&, destructor, void*); - void clear(); - -public: - const std::string& get_ghost_name() const { - return type_name; - } -}; - -struct context { - u32 pc = 0; - var* localr = nullptr; - var* memr = nullptr; - var funcr = var::nil(); - var upvalr = var::nil(); - var* canary = nullptr; - var* stack = nullptr; - var* top = nullptr; -}; - -struct nas_co { - enum class status:u32 { - suspended, - running, - dead - }; - - context ctx; - status status; - - nas_co() { - ctx.stack = new var[STACK_DEPTH]; - clear(); - } - ~nas_co() { - delete[] ctx.stack; - } - void clear(); -}; - -struct nas_map { - bool printed = false; - std::unordered_map mapper; - - nas_map() {} - void clear() { - mapper.clear(); - } - - var get_val(const std::string&); - var* get_mem(const std::string&); -}; - -struct nas_val { - enum class gc_status:u8 { - uncollected = 0, - collected, - found - }; - - gc_status mark; - u8 type; // value type - u8 unmut; // used to mark if a string is unmutable - union { - std::string* str; - nas_vec* vec; - nas_hash* hash; - nas_func* func; - nas_upval* upval; - nas_ghost* obj; - nas_co* co; - nas_map* map; - } ptr; - - nas_val(u8); - ~nas_val(); - void clear(); -}; - -std::ostream& operator<<(std::ostream&, nas_vec&); -std::ostream& operator<<(std::ostream&, nas_hash&); -std::ostream& operator<<(std::ostream&, nas_map&); -std::ostream& operator<<(std::ostream&, const nas_ghost&); -std::ostream& operator<<(std::ostream&, const nas_co&); -std::ostream& operator<<(std::ostream&, var&); - -const var zero = var::num(0); -const var one = var::num(1); -const var nil = var::nil(); - struct gc { /* main context temporary storage */ context main_context; @@ -370,7 +100,7 @@ public: var newstr(const char* buff) { var s = alloc(vm_str); - s.str() = buff; + s.str() = std::string(buff); return s; } @@ -381,9 +111,6 @@ public: } }; -// use to print error log and return error value -var nas_err(const std::string&, const std::string&); - // module function type typedef var (*module_func)(var*, usize, gc*); diff --git a/src/nasal_type.cpp b/src/nasal_type.cpp new file mode 100644 index 0000000..829020a --- /dev/null +++ b/src/nasal_type.cpp @@ -0,0 +1,352 @@ +#include "nasal_type.h" + +namespace nasal { + +var nas_vec::get_val(const i32 n) { + i32 size = elems.size(); + if (n<-size || n>=size) { + return var::none(); + } + return elems[n>=0? n:n+size]; +} + +var* nas_vec::get_mem(const i32 n) { + i32 size = elems.size(); + if (n<-size || n>=size) { + return nullptr; + } + 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()? "[..]":"[]"); + return out; + } + vec.printed = true; + usize iter = 0, size = vec.elems.size(); + out << "["; + for(auto& i:vec.elems) { + out << i << ",]"[(++iter)==size]; + } + vec.printed = false; + return out; +} + +var nas_hash::get_val(const std::string& key) { + if (elems.count(key)) { + return elems.at(key); + } else if (!elems.count("parents")) { + return var::none(); + } + var ret = var::none(); + var val = elems.at("parents"); + if (val.type!=vm_vec) { + return ret; + } + for(auto& i : val.vec().elems) { + if (i.type==vm_hash) { + ret = i.hash().get_val(key); + } + if (ret.type!=vm_none) { + return ret; + } + } + return ret; +} + +var* nas_hash::get_mem(const std::string& key) { + if (elems.count(key)) { + return &elems.at(key); + } else if (!elems.count("parents")) { + return nullptr; + } + var* addr = nullptr; + var val = elems.at("parents"); + if (val.type!=vm_vec) { + return addr; + } + for(auto& i : val.vec().elems) { + if (i.type==vm_hash) { + addr = i.hash().get_mem(key); + } + if (addr) { + return addr; + } + } + return addr; +} + +std::ostream& operator<<(std::ostream& out, nas_hash& hash) { + if (!hash.elems.size() || hash.printed) { + 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 = false; + return out; +} + +void nas_func::clear() { + dynamic_parameter_index = -1; + local.clear(); + upval.clear(); + keys.clear(); +} + +void nas_ghost::set( + const std::string& ghost_type_name, + destructor destructor_pointer, + void* ghost_pointer) { + type_name = ghost_type_name; + destructor_function = destructor_pointer; + pointer = ghost_pointer; +} + +void nas_ghost::clear() { + // do nothing if pointer is null + if (!pointer) { + return; + } + + // do clear pointer if destructor function pointer is null + if (!destructor_function) { + type_name = ""; + pointer = nullptr; + return; + } + + // do destruction + destructor_function(pointer); + type_name = ""; + pointer = nullptr; + destructor_function = nullptr; +} + +std::ostream& operator<<(std::ostream& out, const nas_ghost& ghost) { + out << "(ghost.pointer) << std::dec << ">"; + return out; +} + +void nas_co::clear() { + if (!ctx.stack) { + return; + } + for(u32 i = 0; i(&co) << std::dec << ">"; + return out; +} + +var nas_map::get_val(const std::string& key) { + if (mapper.count(key)) { + return *mapper.at(key); + } + return var::none(); +} + +var* nas_map::get_mem(const std::string& key) { + if (mapper.count(key)) { + return mapper.at(key); + } + return nullptr; +} + +std::ostream& operator<<(std::ostream& out, nas_map& mp) { + if (!mp.mapper.size() || mp.printed) { + out << (mp.mapper.size()? "{..}":"{}"); + return out; + } + mp.printed = true; + usize iter = 0, size = mp.mapper.size(); + out << "{"; + for(auto& i : mp.mapper) { + out << i.first << ":" << *i.second << ",}"[(++iter)==size]; + } + mp.printed = false; + return out; +} + +nas_val::nas_val(u8 val_type) { + mark = gc_status::collected; + type = val_type; + unmutable = 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_map: ptr.map = new nas_map; break; + } +} + +nas_val::~nas_val() { + switch(type) { + case vm_str: delete ptr.str; break; + case vm_vec: delete ptr.vec; break; + case vm_hash: delete ptr.hash; break; + case vm_func: delete ptr.func; break; + case vm_upval:delete ptr.upval;break; + case vm_obj: delete ptr.obj; break; + case vm_co: delete ptr.co; break; + case vm_map: delete ptr.map; break; + } + type=vm_nil; +} + +void nas_val::clear() { + switch(type) { + case vm_str: ptr.str->clear(); break; + case vm_vec: ptr.vec->elems.clear(); break; + case vm_hash: ptr.hash->elems.clear();break; + case vm_func: ptr.func->clear(); break; + case vm_upval:ptr.upval->clear(); break; + case vm_obj: ptr.obj->clear(); break; + case vm_co: ptr.co->clear(); break; + case vm_map: ptr.map->clear(); break; + } +} + +f64 var::tonum() { + return type!=vm_str? val.num:str2num(str().c_str()); +} + +std::string var::tostr() { + if (type==vm_str) { + return str(); + } else if (type==vm_num) { + std::string tmp=std::to_string(num()); + tmp.erase(tmp.find_last_not_of('0')+1, std::string::npos); + tmp.erase(tmp.find_last_not_of('.')+1, std::string::npos); + return tmp; + } + return ""; +} + +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 << ref.co(); break; + case vm_map: out << ref.map(); break; + } + return out; +} + +bool var::objchk(const std::string& name) { + return type==vm_obj && obj().type_name==name && obj().pointer; +} + +var var::none() { + return {vm_none, static_cast(0)}; +} + +var var::nil() { + return {vm_nil, static_cast(0)}; +} + +var var::ret(u32 pc) { + return {vm_ret, pc}; +} + +var var::cnt(i64 n) { + return {vm_cnt, n}; +} + +var var::num(f64 n) { + return {vm_num, n}; +} + +var var::gcobj(nas_val* p) { + return {p->type, p}; +} + +var var::addr(var* p) { + return {vm_addr, p}; +} + +var* var::addr() { + return val.addr; +} + +u32 var::ret() { + return val.ret; +} + +i64& var::cnt() { + return val.cnt; +} + +f64 var::num() { + return val.num; +} + +std::string& var::str() { + return *val.gcobj->ptr.str; +} + +nas_vec& var::vec() { + return *val.gcobj->ptr.vec; +} + +nas_hash& var::hash() { + return *val.gcobj->ptr.hash; +} + +nas_func& var::func() { + return *val.gcobj->ptr.func; +} + +nas_upval& var::upval() { + return *val.gcobj->ptr.upval; +} + +nas_ghost& var::obj() { + return *val.gcobj->ptr.obj; +} + +nas_co& var::co() { + return *val.gcobj->ptr.co; +} + +nas_map& var::map() { + return *val.gcobj->ptr.map; +} + +var nas_err(const std::string& error_function_name, const std::string& info) { + std::cerr << "[vm] " << error_function_name << ": " << info << "\n"; + return var::none(); +} + +} \ No newline at end of file diff --git a/src/nasal_type.h b/src/nasal_type.h new file mode 100644 index 0000000..b3f6151 --- /dev/null +++ b/src/nasal_type.h @@ -0,0 +1,272 @@ +#pragma once + +#include "nasal.h" + +#include +#include + +namespace nasal { + +enum vm_type:u8 { + /* none-gc object */ + vm_none = 0, // error type + vm_cnt, // counter for forindex/foreach loop + vm_addr, // var* address + vm_ret, // return addres(program counter) + vm_nil, // nil + vm_num, // number + /* gc object */ + vm_str, // string + vm_vec, // vector + vm_hash, // hashmap(dict) + vm_func, // function(lambda) + vm_upval, // upvalue + vm_obj, // ghost type + vm_co, // coroutine + vm_map // for globals and namespaces +}; + +// size of gc object type +const u32 gc_type_size = vm_map-vm_str+1; + +// basic types +struct nas_vec; // vector +struct nas_hash; // hashmap(dict) +struct nas_func; // function(lambda) +struct nas_upval; // upvalue +struct nas_ghost; // objects +struct nas_co; // coroutine +struct nas_map; // mapper + +// union type +struct nas_val; // nas_val includes gc-managed types + +struct var { +public: + u8 type = vm_none; + union { + u32 ret; + i64 cnt; + f64 num; + var* addr; + nas_val* gcobj; + } 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;} + +public: + var() = default; + var(const var&) = default; + bool operator==(const var& nr) const { + return type==nr.type && val.gcobj==nr.val.gcobj; + } + bool operator!=(const var& nr) const { + return type!=nr.type || val.gcobj!=nr.val.gcobj; + } + + // number and string can be translated to each other + f64 tonum(); + std::string tostr(); + bool objchk(const std::string&); + + // create new var object + static var none(); + static var nil(); + static var ret(u32); + static var cnt(i64); + static var num(f64); + static var gcobj(nas_val*); + static var addr(var*); + + // get value + var* addr(); + u32 ret(); + i64& cnt(); + f64 num(); + std::string& str(); + nas_vec& vec(); + nas_hash& hash(); + nas_func& func(); + nas_upval& upval(); + nas_ghost& obj(); + nas_co& co(); + nas_map& map(); +}; + +struct nas_vec { + std::vector elems; + + // mark if this is printed, avoid stackoverflow + bool printed; + + nas_vec():printed(false) {} + usize size() const {return elems.size();} + var get_val(const i32); + var* get_mem(const i32); +}; + +struct nas_hash { + std::unordered_map elems; + + // mark if this is printed, avoid stackoverflow + bool printed; + + nas_hash(): printed(false) {} + usize size() const {return elems.size();} + var get_val(const std::string&); + var* get_mem(const std::string&); +}; + +struct nas_func { + i32 dynamic_parameter_index; // dynamic parameter name index in hash. + u32 entry; // pc will set to entry-1 to call this function + 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 + + // 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 on_stack; + u32 size; + var* stack_frame_offset; + + /* not on stack, use this */ + std::vector elems; + +public: + nas_upval(): on_stack(true), size(0), stack_frame_offset(nullptr) {} + + var& operator[](usize n) { + return on_stack? stack_frame_offset[n]:elems[n]; + } + + void clear() { + on_stack = true; + elems.clear(); + size = 0; + } +}; + +struct nas_ghost { +private: + using destructor = void (*)(void*); + +public: + std::string type_name; + destructor destructor_function; + void* pointer; + +public: + nas_ghost(): + type_name(""), destructor_function(nullptr), pointer(nullptr) {} + ~nas_ghost() {clear();} + void set(const std::string&, destructor, void*); + void clear(); + +public: + const std::string& get_ghost_name() const { + return type_name; + } +}; + +struct context { + u32 pc = 0; + var* localr = nullptr; + var* memr = nullptr; + var funcr = var::nil(); + var upvalr = var::nil(); + var* canary = nullptr; + var* stack = nullptr; + var* top = nullptr; +}; + +struct nas_co { + enum class status:u32 { + suspended, + running, + dead + }; + + context ctx; + status status; + + nas_co() { + ctx.stack = new var[STACK_DEPTH]; + clear(); + } + ~nas_co() { + delete[] ctx.stack; + } + void clear(); +}; + +struct nas_map { + bool printed = false; + std::unordered_map mapper; + + nas_map() {} + void clear() { + mapper.clear(); + } + + var get_val(const std::string&); + var* get_mem(const std::string&); +}; + +struct nas_val { + enum class gc_status:u8 { + uncollected = 0, + collected, + found + }; + + gc_status mark; + u8 type; // value type + u8 unmutable; // used to mark if a string is unmutable + union { + std::string* str; + nas_vec* vec; + nas_hash* hash; + nas_func* func; + nas_upval* upval; + nas_ghost* obj; + nas_co* co; + nas_map* map; + } ptr; + + nas_val(u8); + ~nas_val(); + void clear(); +}; + +std::ostream& operator<<(std::ostream&, nas_vec&); +std::ostream& operator<<(std::ostream&, nas_hash&); +std::ostream& operator<<(std::ostream&, nas_map&); +std::ostream& operator<<(std::ostream&, const nas_ghost&); +std::ostream& operator<<(std::ostream&, const nas_co&); +std::ostream& operator<<(std::ostream&, var&); + +const var zero = var::num(0); +const var one = var::num(1); +const var nil = var::nil(); + +// use to print error log and return error value +var nas_err(const std::string&, const std::string&); + +} \ No newline at end of file diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 278cb3d..930b845 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -262,7 +262,7 @@ inline void vm::o_newf() { // 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().local_size; - upval.upval().stk = ctx.localr; + upval.upval().stack_frame_offset = ctx.localr; func.upval.push_back(upval); ctx.upvalr = upval; } @@ -507,7 +507,7 @@ inline void vm::o_neq() { #define op_cmp(type)\ --ctx.top;\ - ctx.top[0] = (ctx.top[0].tonum() type ctx.top[1].tonum())?one:zero; + ctx.top[0] = (ctx.top[0].tonum() type ctx.top[1].tonum())? one:zero; inline void vm::o_less() {op_cmp(<);} inline void vm::o_leq() {op_cmp(<=);} @@ -515,7 +515,7 @@ inline void vm::o_grt() {op_cmp(>);} inline void vm::o_geq() {op_cmp(>=);} #define op_cmp_const(type)\ - ctx.top[0] = (ctx.top[0].tonum() type cnum[imm[ctx.pc]])?one:zero; + ctx.top[0] = (ctx.top[0].tonum() type cnum[imm[ctx.pc]])? one:zero; inline void vm::o_lessc() {op_cmp_const(<);} inline void vm::o_leqc() {op_cmp_const(<=);} diff --git a/tools/file2ppm.nas b/tools/file2ppm.nas new file mode 100644 index 0000000..b2498dc --- /dev/null +++ b/tools/file2ppm.nas @@ -0,0 +1,28 @@ + +var ppm = func(filename, buffer) { + # P3 use ASCII number + # P6 use binary character + var width = 256; + var height = int(size(buffer)/3/width); # ppm use 3 chars for one pixel + println("width ", width, ", height ", height); + + var fd = io.open(filename, "wb"); + io.write(fd, "P6\n"~width~" "~height~"\n255\n"); + io.write(fd, buffer); + io.close(fd); +} + +if (size(arg)<1) { + println("need input file and output file"); + exit(-1); +} + +var content = io.readfile(arg[0], "r"); +var tail_len = 0; +while(math.mod(size(content), 256*3)!=0) { + content ~= "A"; + tail_len += 1; +} +println("filled ", tail_len); +println("size ", size(content)); +ppm(size(arg)==2? arg[1]:"out.ppm", content); \ No newline at end of file From 1580b311229907f6c03b6d899c35933a7029d450 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 15 Oct 2023 23:49:11 +0800 Subject: [PATCH 05/18] :sparkles: add function call trace info --- makefile | 7 ++ src/nasal_dbg.cpp | 18 ++--- src/nasal_vm.cpp | 171 ++++++++++++++++++++++++++++++++++++---------- src/nasal_vm.h | 73 ++++++++++---------- 4 files changed, 188 insertions(+), 81 deletions(-) diff --git a/makefile b/makefile index 7317864..404ac74 100644 --- a/makefile +++ b/makefile @@ -127,12 +127,14 @@ build/nasal_builtin.o: \ build/coroutine.o: \ src/nasal.h\ + src/nasal_type.h\ src/nasal_gc.h\ src/coroutine.h src/coroutine.cpp | build $(CXX) $(CXXFLAGS) src/coroutine.cpp -o build/coroutine.o build/bits_lib.o: \ src/nasal.h\ + src/nasal_type.h\ src/nasal_gc.h\ src/bits_lib.h src/bits_lib.cpp | build $(CXX) $(CXXFLAGS) src/bits_lib.cpp -o build/bits_lib.o @@ -140,30 +142,35 @@ build/bits_lib.o: \ build/math_lib.o: \ src/nasal.h\ + src/nasal_type.h\ src/nasal_gc.h\ src/math_lib.h src/math_lib.cpp | build $(CXX) $(CXXFLAGS) src/math_lib.cpp -o build/math_lib.o build/io_lib.o: \ src/nasal.h\ + src/nasal_type.h\ src/nasal_gc.h\ src/io_lib.h src/io_lib.cpp | build $(CXX) $(CXXFLAGS) src/io_lib.cpp -o build/io_lib.o build/dylib_lib.o: \ src/nasal.h\ + src/nasal_type.h\ src/nasal_gc.h\ src/dylib_lib.h src/dylib_lib.cpp | build $(CXX) $(CXXFLAGS) src/dylib_lib.cpp -o build/dylib_lib.o build/unix_lib.o: \ src/nasal.h\ + src/nasal_type.h\ src/nasal_gc.h\ src/unix_lib.h src/unix_lib.cpp | build $(CXX) $(CXXFLAGS) src/unix_lib.cpp -o build/unix_lib.o build/fg_props.o: \ src/nasal.h\ + src/nasal_type.h\ src/nasal_gc.h\ src/fg_props.h src/fg_props.cpp | build $(CXX) $(CXXFLAGS) src/fg_props.cpp -o build/fg_props.o diff --git a/src/nasal_dbg.cpp b/src/nasal_dbg.cpp index e73fc46..491a2e1 100644 --- a/src/nasal_dbg.cpp +++ b/src/nasal_dbg.cpp @@ -159,7 +159,7 @@ void dbg::step_info() { begin = (ctx.pc>>3)==0? 0:((ctx.pc>>3)<<3); end = (1+(ctx.pc>>3))<<3; - codestream::set(cnum, cstr, native.data(), files); + codestream::set(const_number, const_string, native_function.data(), files); std::clog << "next bytecode:\n"; for(u32 i = begin; i> "; std::getline(std::cin, cmd); - auto res=parse(cmd); + auto res = parse(cmd); if (res.size()==0) { step_info(); } else if (res.size()==1) { switch(get_cmd_type(res[0])) { case dbg_cmd::cmd_help: help(); break; - case dbg_cmd::cmd_backtrace: traceback(); break; + case dbg_cmd::cmd_backtrace: trace_back(); break; case dbg_cmd::cmd_continue: return; case dbg_cmd::cmd_list_file: list_file(); break; - case dbg_cmd::cmd_global: gstate(); break; - case dbg_cmd::cmd_local: lstate(); break; - case dbg_cmd::cmd_upval: ustate(); break; - case dbg_cmd::cmd_register: reginfo(); break; - case dbg_cmd::cmd_show_all: detail(); break; + case dbg_cmd::cmd_global: global_state(); break; + case dbg_cmd::cmd_local: local_state(); break; + case dbg_cmd::cmd_upval: upvalue_state(); break; + case dbg_cmd::cmd_register: register_info(); break; + case dbg_cmd::cmd_show_all: all_state_detail(); break; case dbg_cmd::cmd_next: next = true; return; case dbg_cmd::cmd_exit: std::exit(0); default: err(); break; diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index ed16232..97ec928 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -11,14 +11,14 @@ void vm::init( const std::vector& filenames, const std::vector& argv ) { - cnum = nums.data(); - cstr = strs.data(); + const_number = nums.data(); + const_string = strs.data(); bytecode = code.data(); files = filenames.data(); global_size = global_symbol.size(); /* set native functions */ - native = natives; + native_function = natives; /* set context and global */ if (!is_repl_mode || first_exec_flag) { @@ -64,7 +64,7 @@ void vm::context_and_global_init() { } } -void vm::valinfo(var& val) { +void vm::value_info(var& val) { const auto p = reinterpret_cast(val.val.gcobj); switch(val.type) { case vm_none: std::clog << "| null |"; break; @@ -106,10 +106,74 @@ void vm::valinfo(var& val) { std::clog << "\n"; } -void vm::traceback() { +void vm::function_detail_info(const nas_func& func) { + std::clog << "func@0x"; + std::clog << std::hex << reinterpret_cast(&func) << std::dec; + + std::vector argument_list = {}; + argument_list.resize(func.keys.size()); + for(const auto& key : func.keys) { + argument_list[key.second-1] = key.first; + } + + std::clog << "("; + for(const auto& key : argument_list) { + std::clog << key; + if (key != argument_list.back()) { + std::clog << ", "; + } + } + if (func.dynamic_parameter_index>=0) { + std::clog << (argument_list.size()? ", ":""); + std::clog << const_string[func.dynamic_parameter_index] << "..."; + } + std::clog << ") "; + std::clog << "{entry: 0x" << std::hex << func.entry << std::dec << "}"; +} + +void vm::function_call_trace() { var* bottom = ctx.stack; var* top = ctx.top; + // generate trace back + std::stack functions; + for(var* i = bottom; i<=top; ++i) { + if (i->type==vm_func && i-1>=bottom && (i-1)->type==vm_ret) { + functions.push(&i->func()); + } + } + if (functions.empty()) { + return; + } + + std::clog << "\ncall trace " << (ngc.cort? "(coroutine)":"(main)") << "\n"; + const nas_func* last = nullptr; + u32 same = 0; + for(auto func = last; !functions.empty(); functions.pop()) { + func = functions.top(); + if (last==func) { + ++same; + continue; + } else if (same) { + std::clog << " --> " << same << " same call(s)\n"; + same = 0; + } + + last = func; + std::clog << " call "; + function_detail_info(*func); + std::clog << "\n"; + } + if (same) { + std::clog << " --> " << same << " same call(s)\n"; + } +} + +void vm::trace_back() { + var* bottom = ctx.stack; + var* top = ctx.top; + + // generate trace back std::stack ret; for(var* i = bottom; i<=top; ++i) { if (i->type==vm_ret && i->ret()!=0) { @@ -118,10 +182,8 @@ void vm::traceback() { } ret.push(ctx.pc); // store the position program crashed - std::clog << "trace back (" - << (ngc.cort? "coroutine":"main") - << ")\n"; - codestream::set(cnum, cstr, native.data(), files); + std::clog << "\ntrace back " << (ngc.cort? "(coroutine)":"(main)") << "\n"; + codestream::set(const_number, const_string, native_function.data(), files); for(u32 p = 0, same = 0, prev = 0xffffffff; !ret.empty(); prev = p, ret.pop()) { if ((p = ret.top())==prev) { ++same; @@ -132,17 +194,17 @@ void vm::traceback() { << std::setw(6) << std::setfill('0') << prev << std::dec << " " << same << " same call(s)\n"; + same = 0; } - same = 0; std::clog << " " << codestream(bytecode[p], p) << "\n"; } // the first called place has no same calls } -void vm::stackinfo(const u32 limit = 10) { +void vm::stack_info(const u32 limit = 10) { var* top = ctx.top; var* bottom = ctx.stack; - std::clog << "stack (0x" << std::hex << reinterpret_cast(bottom); + std::clog << "\nstack (0x" << std::hex << reinterpret_cast(bottom); std::clog << std::dec << ", limit " << limit << ", total "; std::clog << (top(top-bottom+1)) << ")\n"; for(u32 i = 0; i=bottom; ++i, --top) { @@ -150,12 +212,12 @@ void vm::stackinfo(const u32 limit = 10) { << std::setw(6) << std::setfill('0') << static_cast(top-bottom) << std::dec << " "; - valinfo(top[0]); + value_info(top[0]); } } -void vm::reginfo() { - std::clog << "registers (" << (ngc.cort? "coroutine":"main") +void vm::register_info() { + std::clog << "\nregisters (" << (ngc.cort? "coroutine":"main") << ")\n" << std::hex << " [pc ] | pc | 0x" << ctx.pc << "\n" << " [global] | addr | 0x" @@ -169,45 +231,45 @@ void vm::reginfo() { << " [top ] | addr | 0x" << reinterpret_cast(ctx.top) << "\n" << std::dec; - std::clog << " [funcr ] "; valinfo(ctx.funcr); - std::clog << " [upval ] "; valinfo(ctx.upvalr); + std::clog << " [funcr ] "; value_info(ctx.funcr); + std::clog << " [upval ] "; value_info(ctx.upvalr); } -void vm::gstate() { +void vm::global_state() { if (!global_size || global[0].type==vm_none) { return; } - std::clog << "global (0x" << std::hex + std::clog << "\nglobal (0x" << std::hex << reinterpret_cast(global) << ")\n" << std::dec; for(usize i = 0; i(ctx.localr) + std::clog << "\nlocal (0x" << std::hex << reinterpret_cast(ctx.localr) << " <+" << static_cast(ctx.localr-ctx.stack) << ">)\n" << std::dec; for(u32 i = 0; i upval[" << i << "]:\n"; @@ -216,42 +278,77 @@ void vm::ustate() { std::clog << " 0x" << std::hex << std::setw(6) << std::setfill('0') << j << std::dec << " "; - valinfo(uv[j]); + value_info(uv[j]); } } } -void vm::detail() { - reginfo(); - gstate(); - lstate(); - ustate(); +void vm::all_state_detail() { + register_info(); + global_state(); + local_state(); + upvalue_state(); } std::string vm::report_lack_arguments(u32 argc, const nas_func& func) const { - auto result = std::string("lack argument(s): "); + auto result = std::string("lack argument(s) when calling function:\n func("); 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=0) { + result += argument_list.size()? ", ":""; + result += const_string[func.dynamic_parameter_index] + "[dynamic]"; + } + result += ") "; + std::stringstream out; + out << "{entry: 0x" << std::hex << func.entry << std::dec << "}"; + out << " @ 0x" << std::hex << reinterpret_cast(&func) << std::dec; + return result + out.str(); +} + +std::string vm::report_special_call_lack_arguments( + var* local, const nas_func& func) const { + auto result = std::string("lack argument(s) when calling function:\n func("); + std::vector argument_list = {}; + argument_list.resize(func.keys.size()); + for(const auto& i : func.keys) { + argument_list[i.second-1] = i.first; + } + for(const auto& key : argument_list) { + if (local[func.keys.at(key)].type==vm_none) { + result += key + ", "; + } else { + result += key + "[get], "; + } + } + result = result.substr(0, result.length()-2); + result += ") "; + std::stringstream out; + out << "{entry: 0x" << std::hex << func.entry << std::dec << "}"; + out << " @ 0x" << std::hex << reinterpret_cast(&func) << std::dec; + return result + out.str(); } void vm::die(const std::string& str) { std::cerr << "[vm] error: " << str << "\n"; - traceback(); - stackinfo(); + function_call_trace(); + trace_back(); + stack_info(); // show verbose crash info if (verbose) { - detail(); + all_state_detail(); } if (!ngc.cort) { diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 930b845..cbd4f68 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -2,6 +2,8 @@ #include #include +#include +#include #include "nasal_import.h" #include "nasal_gc.h" @@ -22,10 +24,10 @@ protected: context ctx; /* constants */ - const f64* cnum = nullptr; // constant numbers - const std::string* cstr = nullptr; // constant symbols and strings + const f64* const_number = nullptr; // constant numbers + const std::string* const_string = nullptr; // constant symbols and strings std::vector imm; // immediate number table - std::vector native; + std::vector native_function; /* garbage collector */ gc ngc; @@ -57,15 +59,18 @@ protected: /* debug functions */ bool verbose = false; - void valinfo(var&); - void traceback(); - void stackinfo(const u32); - void reginfo(); - void gstate(); - void lstate(); - void ustate(); - void detail(); + void value_info(var&); + void function_detail_info(const nas_func&); + void function_call_trace(); + void trace_back(); + void stack_info(const u32); + void register_info(); + void global_state(); + void local_state(); + void upvalue_state(); + void all_state_detail(); std::string report_lack_arguments(u32, const nas_func&) const; + std::string report_special_call_lack_arguments(var*, const nas_func&) const; void die(const std::string&); /* vm calculation functions*/ @@ -222,7 +227,7 @@ inline void vm::o_loadu() { } inline void vm::o_pnum() { - (++ctx.top)[0] = var::num(cnum[imm[ctx.pc]]); + (++ctx.top)[0] = var::num(const_number[imm[ctx.pc]]); } inline void vm::o_pnil() { @@ -269,14 +274,14 @@ inline void vm::o_newf() { } inline void vm::o_happ() { - ctx.top[-1].hash().elems[cstr[imm[ctx.pc]]] = ctx.top[0]; + ctx.top[-1].hash().elems[const_string[imm[ctx.pc]]] = ctx.top[0]; --ctx.top; } inline void vm::o_para() { auto& func = ctx.top[0].func(); // func->size has 1 place reserved for "me" - func.keys[cstr[imm[ctx.pc]]] = func.parameter_size; + func.keys[const_string[imm[ctx.pc]]] = func.parameter_size; func.local[func.parameter_size++] = var::none(); } @@ -284,7 +289,7 @@ 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[cstr[imm[ctx.pc]]] = func.parameter_size; + func.keys[const_string[imm[ctx.pc]]] = func.parameter_size; func.local[func.parameter_size++] = val; } @@ -370,14 +375,14 @@ inline void vm::o_lnk() { } #define op_calc_const(type)\ - ctx.top[0] = var::num(ctx.top[0].tonum() type cnum[imm[ctx.pc]]); + ctx.top[0] = var::num(ctx.top[0].tonum() type const_number[imm[ctx.pc]]); inline void vm::o_addc() {op_calc_const(+);} inline void vm::o_subc() {op_calc_const(-);} inline void vm::o_mulc() {op_calc_const(*);} inline void vm::o_divc() {op_calc_const(/);} inline void vm::o_lnkc() { - ctx.top[0] = ngc.newstr(ctx.top[0].tostr()+cstr[imm[ctx.pc]]); + ctx.top[0] = ngc.newstr(ctx.top[0].tostr()+const_string[imm[ctx.pc]]); } // top[0] stores the value of memr[0], to avoid being garbage-collected @@ -435,7 +440,9 @@ inline void vm::o_bxoreq() { // like this: func{a+=1;}(); the result of 'a+1' will no be used later, imm[pc]>>31=1 // but if b+=a+=1; the result of 'a+1' will be used later, imm[pc]>>31=0 #define op_calc_eq_const(type)\ - ctx.top[0] = ctx.memr[0] = var::num(ctx.memr[0].tonum() type cnum[imm[ctx.pc]]);\ + ctx.top[0] = ctx.memr[0] = var::num(\ + ctx.memr[0].tonum() type const_number[imm[ctx.pc]]\ + );\ ctx.memr = nullptr; inline void vm::o_addeqc() {op_calc_eq_const(+);} @@ -443,12 +450,16 @@ inline void vm::o_subeqc() {op_calc_eq_const(-);} inline void vm::o_muleqc() {op_calc_eq_const(*);} inline void vm::o_diveqc() {op_calc_eq_const(/);} inline void vm::o_lnkeqc() { - ctx.top[0] = ctx.memr[0] = ngc.newstr(ctx.memr[0].tostr()+cstr[imm[ctx.pc]]); + ctx.top[0] = ctx.memr[0] = ngc.newstr( + ctx.memr[0].tostr()+const_string[imm[ctx.pc]] + ); ctx.memr = nullptr; } #define op_calc_eq_const_and_pop(type)\ - ctx.top[0] = ctx.memr[0] = var::num(ctx.memr[0].tonum() type cnum[imm[ctx.pc]]);\ + ctx.top[0] = ctx.memr[0] = var::num(\ + ctx.memr[0].tonum() type const_number[imm[ctx.pc]]\ + );\ ctx.memr = nullptr;\ --ctx.top; @@ -458,7 +469,7 @@ inline void vm::o_mulecp() {op_calc_eq_const_and_pop(*);} inline void vm::o_divecp() {op_calc_eq_const_and_pop(/);} inline void vm::o_lnkecp() { ctx.top[0] = ctx.memr[0] = ngc.newstr( - ctx.memr[0].tostr()+cstr[imm[ctx.pc]] + ctx.memr[0].tostr()+const_string[imm[ctx.pc]] ); ctx.memr = nullptr; --ctx.top; @@ -515,7 +526,7 @@ inline void vm::o_grt() {op_cmp(>);} inline void vm::o_geq() {op_cmp(>=);} #define op_cmp_const(type)\ - ctx.top[0] = (ctx.top[0].tonum() type cnum[imm[ctx.pc]])? one:zero; + ctx.top[0] = (ctx.top[0].tonum() type const_number[imm[ctx.pc]])? one:zero; inline void vm::o_lessc() {op_cmp_const(<);} inline void vm::o_leqc() {op_cmp_const(<=);} @@ -656,7 +667,7 @@ inline void vm::o_callh() { die("must call a hash"); return; } - const auto& str = cstr[imm[ctx.pc]]; + const auto& str = const_string[imm[ctx.pc]]; if (val.type==vm_hash) { ctx.top[0] = val.hash().get_val(str); } else { @@ -761,7 +772,7 @@ inline void vm::o_callfh() { // 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] + "\"" + const_string[func.dynamic_parameter_index] + "\"" ); return; } @@ -782,15 +793,7 @@ inline void vm::o_callfh() { } } if (lack_arguments_flag) { - auto info = std::string("lack argument(s): "); - for(const auto& i : func.keys) { - const auto& key = i.first; - if (local[i.second].type==vm_none) { - info += key + ", "; - } - } - info = info.substr(0, info.length()-2); - die(info); + die(report_special_call_lack_arguments(local, func)); return; } @@ -809,7 +812,7 @@ inline void vm::o_callb() { // if running a native function about coroutine // (top) will be set to another context.top, instead of main_context.top - var tmp = (*native[imm[ctx.pc]].func)(ctx.localr, ngc); + var tmp = (*native_function[imm[ctx.pc]].func)(ctx.localr, ngc); // so we use tmp variable to store this return value // and set it to top[0] later @@ -949,7 +952,7 @@ inline void vm::o_mcallh() { die("must call a hash"); return; } - const auto& str = cstr[imm[ctx.pc]]; + const auto& str = const_string[imm[ctx.pc]]; if (hash.type==vm_map) { ctx.memr = hash.map().get_mem(str); if (!ctx.memr) { From a298aa3a63432308fe68b1ed19259264ee8716d9 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Tue, 17 Oct 2023 00:44:45 +0800 Subject: [PATCH 06/18] :sparkles: add detail error info in callh --- module/fib.cpp | 4 +- src/nasal_builtin.cpp | 10 ++-- src/nasal_type.cpp | 4 +- src/nasal_type.h | 4 +- src/nasal_vm.cpp | 33 +++++++++++++ src/nasal_vm.h | 106 ++++++++++++++++++++++-------------------- 6 files changed, 100 insertions(+), 61 deletions(-) diff --git a/module/fib.cpp b/module/fib.cpp index aec5dcb..9116540 100644 --- a/module/fib.cpp +++ b/module/fib.cpp @@ -20,14 +20,14 @@ var fib(var* args, usize size, gc* ngc) { return nas_err("fib", "lack arguments"); } var num = args[0]; - return var::num(fibonaci(num.tonum())); + return var::num(fibonaci(num.to_num())); } var quick_fib(var* args, usize size, gc* ngc) { if (!size) { return nas_err("quick_fib","lack arguments"); } - double num = args[0].tonum(); + double num = args[0].to_num(); if (num<2) { return var::num(num); } diff --git a/src/nasal_builtin.cpp b/src/nasal_builtin.cpp index 1aacb4c..8d21a02 100644 --- a/src/nasal_builtin.cpp +++ b/src/nasal_builtin.cpp @@ -145,7 +145,7 @@ var builtin_int(var* local, gc& ngc) { if (val.type!=vm_num && val.type!=vm_str) { return nil; } - return var::num(static_cast(static_cast(val.tonum()))); + return var::num(static_cast(static_cast(val.to_num()))); } var builtin_floor(var* local, gc& ngc) { @@ -161,7 +161,7 @@ var builtin_num(var* local, gc& ngc) { if (val.type!=vm_str) { return nil; } - f64 res = val.tonum(); + f64 res = val.to_num(); if (std::isnan(res)) { return nil; } @@ -183,7 +183,7 @@ var builtin_pop(var* local, gc& ngc) { } var builtin_str(var* local, gc& ngc) { - return ngc.newstr(local[1].tostr()); + return ngc.newstr(local[1].to_str()); } var builtin_size(var* local, gc& ngc) { @@ -254,13 +254,13 @@ var builtin_keys(var* local, gc& ngc) { } var builtin_die(var* local, gc& ngc) { - return nas_err("error", local[1].tostr()); + return nas_err("error", local[1].to_str()); } var builtin_find(var* local, gc& ngc) { var needle = local[1]; var haystack = local[2]; - usize pos = haystack.tostr().find(needle.tostr()); + usize pos = haystack.to_str().find(needle.to_str()); if (pos==std::string::npos) { return var::num(-1.0); } diff --git a/src/nasal_type.cpp b/src/nasal_type.cpp index 829020a..ab11624 100644 --- a/src/nasal_type.cpp +++ b/src/nasal_type.cpp @@ -232,11 +232,11 @@ void nas_val::clear() { } } -f64 var::tonum() { +f64 var::to_num() { return type!=vm_str? val.num:str2num(str().c_str()); } -std::string var::tostr() { +std::string var::to_str() { if (type==vm_str) { return str(); } else if (type==vm_num) { diff --git a/src/nasal_type.h b/src/nasal_type.h index b3f6151..1cee06f 100644 --- a/src/nasal_type.h +++ b/src/nasal_type.h @@ -70,8 +70,8 @@ public: } // number and string can be translated to each other - f64 tonum(); - std::string tostr(); + f64 to_num(); + std::string to_str(); bool objchk(const std::string&); // create new var object diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index 97ec928..b1c1d63 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -340,6 +340,39 @@ std::string vm::report_special_call_lack_arguments( return result + out.str(); } +std::string vm::report_key_not_found( + const std::string& not_found, const nas_hash& hash) const { + auto result = "member \"" + not_found + "\" doesn't exist in hash {"; + for(const auto& i : hash.elems) { + result += i.first + ", "; + } + if (hash.elems.size()) { + result = result.substr(0, result.length()-2); + } + result += "}"; + return result; +} + +std::string vm::type_name_string(const var& value) const { + switch(value.type) { + case vm_none: return "none"; + case vm_cnt: return "counter"; + case vm_addr: return "address"; + case vm_ret: return "program counter"; + case vm_nil: return "nil"; + case vm_num: return "number"; + case vm_str: return "string"; + case vm_vec: return "vector"; + case vm_hash: return "hash"; + case vm_func: return "function"; + case vm_upval: return "upvalue"; + case vm_obj: return "ghost type"; + case vm_co: return "coroutine"; + case vm_map: return "namespace"; + } + return "unknown"; +} + void vm::die(const std::string& str) { std::cerr << "[vm] error: " << str << "\n"; function_call_trace(); diff --git a/src/nasal_vm.h b/src/nasal_vm.h index cbd4f68..366bcf5 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -71,6 +71,8 @@ protected: void all_state_detail(); std::string report_lack_arguments(u32, const nas_func&) const; std::string report_special_call_lack_arguments(var*, const nas_func&) const; + std::string report_key_not_found(const std::string&, const nas_hash&) const; + std::string type_name_string(const var&) const; void die(const std::string&); /* vm calculation functions*/ @@ -315,7 +317,7 @@ inline void vm::o_lnot() { } inline void vm::o_usub() { - ctx.top[0] = var::num(-ctx.top[0].tonum()); + ctx.top[0] = var::num(-ctx.top[0].to_num()); } inline void vm::o_bnot() { @@ -324,30 +326,30 @@ inline void vm::o_bnot() { inline void vm::o_btor() { ctx.top[-1] = var::num( - static_cast(ctx.top[-1].tonum())| - static_cast(ctx.top[0].tonum()) + static_cast(ctx.top[-1].to_num())| + static_cast(ctx.top[0].to_num()) ); --ctx.top; } inline void vm::o_btxor() { ctx.top[-1] = var::num( - static_cast(ctx.top[-1].tonum())^ - static_cast(ctx.top[0].tonum()) + static_cast(ctx.top[-1].to_num())^ + static_cast(ctx.top[0].to_num()) ); --ctx.top; } inline void vm::o_btand() { ctx.top[-1] = var::num( - static_cast(ctx.top[-1].tonum())& - static_cast(ctx.top[0].tonum()) + static_cast(ctx.top[-1].to_num())& + static_cast(ctx.top[0].to_num()) ); --ctx.top; } #define op_calc(type)\ - ctx.top[-1] = var::num(ctx.top[-1].tonum() type ctx.top[0].tonum());\ + ctx.top[-1] = var::num(ctx.top[-1].to_num() type ctx.top[0].to_num());\ --ctx.top; inline void vm::o_add() {op_calc(+);} @@ -370,19 +372,19 @@ inline void vm::o_lnk() { return; } // concat strings - ctx.top[-1] = ngc.newstr(ctx.top[-1].tostr()+ctx.top[0].tostr()); + ctx.top[-1] = ngc.newstr(ctx.top[-1].to_str()+ctx.top[0].to_str()); --ctx.top; } #define op_calc_const(type)\ - ctx.top[0] = var::num(ctx.top[0].tonum() type const_number[imm[ctx.pc]]); + ctx.top[0] = var::num(ctx.top[0].to_num() type const_number[imm[ctx.pc]]); inline void vm::o_addc() {op_calc_const(+);} inline void vm::o_subc() {op_calc_const(-);} inline void vm::o_mulc() {op_calc_const(*);} inline void vm::o_divc() {op_calc_const(/);} inline void vm::o_lnkc() { - ctx.top[0] = ngc.newstr(ctx.top[0].tostr()+const_string[imm[ctx.pc]]); + ctx.top[0] = ngc.newstr(ctx.top[0].to_str()+const_string[imm[ctx.pc]]); } // top[0] stores the value of memr[0], to avoid being garbage-collected @@ -391,7 +393,9 @@ inline void vm::o_lnkc() { // like this: func{a+=c;}(); the result of 'a+c' will no be used later, imm[pc] = 1 // but if b+=a+=c; the result of 'a+c' will be used later, imm[pc] = 0 #define op_calc_eq(type)\ - ctx.top[-1] = ctx.memr[0] = var::num(ctx.memr[0].tonum() type ctx.top[-1].tonum());\ + ctx.top[-1] = ctx.memr[0] = var::num(\ + ctx.memr[0].to_num() type ctx.top[-1].to_num()\ + );\ ctx.memr = nullptr;\ ctx.top -= imm[ctx.pc]+1; @@ -401,7 +405,7 @@ inline void vm::o_muleq() {op_calc_eq(*);} inline void vm::o_diveq() {op_calc_eq(/);} inline void vm::o_lnkeq() { ctx.top[-1] = ctx.memr[0] = ngc.newstr( - ctx.memr[0].tostr()+ctx.top[-1].tostr() + ctx.memr[0].to_str()+ctx.top[-1].to_str() ); ctx.memr = nullptr; ctx.top -= imm[ctx.pc]+1; @@ -409,8 +413,8 @@ inline void vm::o_lnkeq() { inline void vm::o_bandeq() { ctx.top[-1] = ctx.memr[0] = var::num( - static_cast(ctx.memr[0].tonum())& - static_cast(ctx.top[-1].tonum()) + static_cast(ctx.memr[0].to_num())& + static_cast(ctx.top[-1].to_num()) ); ctx.memr = nullptr; ctx.top -= imm[ctx.pc]+1; @@ -418,8 +422,8 @@ inline void vm::o_bandeq() { inline void vm::o_boreq() { ctx.top[-1] = ctx.memr[0] = var::num( - static_cast(ctx.memr[0].tonum())| - static_cast(ctx.top[-1].tonum()) + static_cast(ctx.memr[0].to_num())| + static_cast(ctx.top[-1].to_num()) ); ctx.memr = nullptr; ctx.top -= imm[ctx.pc]+1; @@ -427,8 +431,8 @@ inline void vm::o_boreq() { inline void vm::o_bxoreq() { ctx.top[-1] = ctx.memr[0] = var::num( - static_cast(ctx.memr[0].tonum())^ - static_cast(ctx.top[-1].tonum()) + static_cast(ctx.memr[0].to_num())^ + static_cast(ctx.top[-1].to_num()) ); ctx.memr = nullptr; ctx.top -= imm[ctx.pc]+1; @@ -441,7 +445,7 @@ inline void vm::o_bxoreq() { // but if b+=a+=1; the result of 'a+1' will be used later, imm[pc]>>31=0 #define op_calc_eq_const(type)\ ctx.top[0] = ctx.memr[0] = var::num(\ - ctx.memr[0].tonum() type const_number[imm[ctx.pc]]\ + ctx.memr[0].to_num() type const_number[imm[ctx.pc]]\ );\ ctx.memr = nullptr; @@ -451,14 +455,14 @@ inline void vm::o_muleqc() {op_calc_eq_const(*);} inline void vm::o_diveqc() {op_calc_eq_const(/);} inline void vm::o_lnkeqc() { ctx.top[0] = ctx.memr[0] = ngc.newstr( - ctx.memr[0].tostr()+const_string[imm[ctx.pc]] + ctx.memr[0].to_str()+const_string[imm[ctx.pc]] ); ctx.memr = nullptr; } #define op_calc_eq_const_and_pop(type)\ ctx.top[0] = ctx.memr[0] = var::num(\ - ctx.memr[0].tonum() type const_number[imm[ctx.pc]]\ + ctx.memr[0].to_num() type const_number[imm[ctx.pc]]\ );\ ctx.memr = nullptr;\ --ctx.top; @@ -469,7 +473,7 @@ inline void vm::o_mulecp() {op_calc_eq_const_and_pop(*);} inline void vm::o_divecp() {op_calc_eq_const_and_pop(/);} inline void vm::o_lnkecp() { ctx.top[0] = ctx.memr[0] = ngc.newstr( - ctx.memr[0].tostr()+const_string[imm[ctx.pc]] + ctx.memr[0].to_str()+const_string[imm[ctx.pc]] ); ctx.memr = nullptr; --ctx.top; @@ -495,7 +499,7 @@ inline void vm::o_eq() { ctx.top[0] = (val1.str()==val2.str())? one:zero; } else if ((val1.type==vm_num || val2.type==vm_num) && val1.type!=vm_nil && val2.type!=vm_nil) { - ctx.top[0] = (val1.tonum()==val2.tonum())? one:zero; + ctx.top[0] = (val1.to_num()==val2.to_num())? one:zero; } else { ctx.top[0] = (val1==val2)? one:zero; } @@ -510,7 +514,7 @@ inline void vm::o_neq() { ctx.top[0] = (val1.str()!=val2.str())? one:zero; } else if ((val1.type==vm_num || val2.type==vm_num) && val1.type!=vm_nil && val2.type!=vm_nil) { - ctx.top[0] = (val1.tonum()!=val2.tonum())? one:zero; + ctx.top[0] = (val1.to_num()!=val2.to_num())? one:zero; } else { ctx.top[0] = (val1!=val2)? one:zero; } @@ -518,7 +522,7 @@ inline void vm::o_neq() { #define op_cmp(type)\ --ctx.top;\ - ctx.top[0] = (ctx.top[0].tonum() type ctx.top[1].tonum())? one:zero; + ctx.top[0] = (ctx.top[0].to_num() type ctx.top[1].to_num())? one:zero; inline void vm::o_less() {op_cmp(<);} inline void vm::o_leq() {op_cmp(<=);} @@ -526,7 +530,7 @@ inline void vm::o_grt() {op_cmp(>);} inline void vm::o_geq() {op_cmp(>=);} #define op_cmp_const(type)\ - ctx.top[0] = (ctx.top[0].tonum() type const_number[imm[ctx.pc]])? one:zero; + ctx.top[0] = (ctx.top[0].to_num() type const_number[imm[ctx.pc]])? one:zero; inline void vm::o_lessc() {op_cmp_const(<);} inline void vm::o_leqc() {op_cmp_const(<=);} @@ -559,7 +563,9 @@ inline void vm::o_jf() { inline void vm::o_cnt() { if (ctx.top[0].type!=vm_vec) { - die("must use vector in forindex/foreach"); + die("must use vector in forindex/foreach but get "+ + type_name_string(ctx.top[0]) + ); return; } (++ctx.top)[0] = var::cnt(-1); @@ -603,14 +609,14 @@ inline void vm::o_callv() { var val = ctx.top[0]; var vec = (--ctx.top)[0]; if (vec.type==vm_vec) { - ctx.top[0] = vec.vec().get_val(val.tonum()); + ctx.top[0] = vec.vec().get_val(val.to_num()); if (ctx.top[0].type==vm_none) { - die("out of range:"+std::to_string(val.tonum())); + die("out of range:"+std::to_string(val.to_num())); return; } } else if (vec.type==vm_hash) { if (val.type!=vm_str) { - die("must use string as the key"); + die("must use string as the key but get "+type_name_string(val)); return; } ctx.top[0] = vec.hash().get_val(val.str()); @@ -622,10 +628,10 @@ inline void vm::o_callv() { } } else if (vec.type==vm_str) { const auto& str = vec.str(); - i32 num = val.tonum(); + i32 num = val.to_num(); i32 len = str.length(); if (num<-len || num>=len) { - die("out of range:"+std::to_string(val.tonum())); + die("out of range:"+std::to_string(val.to_num())); return; } ctx.top[0] = var::num( @@ -633,7 +639,7 @@ inline void vm::o_callv() { ); } else if (vec.type==vm_map) { if (val.type!=vm_str) { - die("must use string as the key"); + die("must use string as the key but get "+type_name_string(val)); return; } ctx.top[0] = vec.map().get_val(val.str()); @@ -642,7 +648,7 @@ inline void vm::o_callv() { return; } } else { - die("must call a vector/hash/string"); + die("must call a vector/hash/string but get "+type_name_string(vec)); return; } } @@ -650,7 +656,7 @@ inline void vm::o_callv() { inline void vm::o_callvi() { var val = ctx.top[0]; if (val.type!=vm_vec) { - die("must use a vector"); + die("must use a vector but get "+type_name_string(val)); return; } // cannot use operator[],because this may cause overflow @@ -664,7 +670,7 @@ inline void vm::o_callvi() { inline void vm::o_callh() { var val = ctx.top[0]; if (val.type!=vm_hash && val.type!=vm_map) { - die("must call a hash"); + die("must call a hash but get "+type_name_string(val)); return; } const auto& str = const_string[imm[ctx.pc]]; @@ -675,7 +681,7 @@ inline void vm::o_callh() { } if (ctx.top[0].type==vm_none) { val.type==vm_hash? - die("member \"" + str + "\" does not exist"): + die(report_key_not_found(str, val.hash())): die("cannot find symbol \"" + str + "\""); return; } else if (ctx.top[0].type==vm_func) { @@ -687,7 +693,7 @@ inline void vm::o_callfv() { 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"); + die("must call a function but get "+type_name_string(local[-1])); return; } const auto& func = local[-1].func(); @@ -756,7 +762,7 @@ inline void vm::o_callfv() { inline void vm::o_callfh() { const auto& hash = ctx.top[0].hash().elems; if (ctx.top[-1].type!=vm_func) { - die("must call a function"); + die("must call a function but get "+type_name_string(ctx.top[-1])); return; } const auto& func = ctx.top[-1].func(); @@ -833,7 +839,7 @@ inline void vm::o_slcbeg() { // +--------------+ (++ctx.top)[0] = ngc.alloc(vm_vec); if (ctx.top[-1].type!=vm_vec) { - die("must slice a vector"); + die("must slice a vector but get "+type_name_string(ctx.top[-1])); return; } } @@ -845,9 +851,9 @@ inline void vm::o_slcend() { inline void vm::o_slc() { var val = (ctx.top--)[0]; - var res = ctx.top[-1].vec().get_val(val.tonum()); + var res = ctx.top[-1].vec().get_val(val.to_num()); if (res.type==vm_none) { - die("index " + std::to_string(val.tonum()) + " out of range"); + die("index " + std::to_string(val.to_num()) + " out of range"); return; } ctx.top[0].vec().elems.push_back(res); @@ -860,8 +866,8 @@ inline void vm::o_slc2() { auto& aim = ctx.top[0].vec().elems; u8 type1 = val1.type,type2=val2.type; - i32 num1 = val1.tonum(); - i32 num2 = val2.tonum(); + i32 num1 = val1.to_num(); + i32 num2 = val2.to_num(); i32 size = ref.size(); if (type1==vm_nil && type2==vm_nil) { num1 = 0; @@ -912,14 +918,14 @@ inline void vm::o_mcallv() { var val = ctx.top[0]; // index var vec = (--ctx.top)[0]; // mcall vector, reserved on stack to avoid gc if (vec.type==vm_vec) { - ctx.memr = vec.vec().get_mem(val.tonum()); + ctx.memr = vec.vec().get_mem(val.to_num()); if (!ctx.memr) { - die("index "+std::to_string(val.tonum())+" out of range"); + die("index "+std::to_string(val.to_num())+" out of range"); return; } } else if (vec.type==vm_hash) { // do mcallh but use the mcallv way if (val.type!=vm_str) { - die("key must be string"); + die("must use string as the key but get "+type_name_string(val)); return; } auto& ref = vec.hash(); @@ -931,7 +937,7 @@ inline void vm::o_mcallv() { } } else if (vec.type==vm_map) { if (val.type!=vm_str) { - die("key must be string"); + die("must use string as the key but get "+type_name_string(val)); return; } auto& ref = vec.map(); @@ -949,7 +955,7 @@ inline void vm::o_mcallv() { inline void vm::o_mcallh() { var hash = ctx.top[0]; // mcall hash, reserved on stack to avoid gc if (hash.type!=vm_hash && hash.type!=vm_map) { - die("must call a hash"); + die("must call a hash/namespace but get "+type_name_string(hash)); return; } const auto& str = const_string[imm[ctx.pc]]; From 54317a39a7c6797b009246a451d3f8b91b2c6f7c Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Wed, 18 Oct 2023 00:29:53 +0800 Subject: [PATCH 07/18] :sparkles: improve error info of out-of-range --- module/fib.cpp | 4 ++-- src/dylib_lib.cpp | 6 +++--- src/io_lib.cpp | 14 +++++++------- src/nasal_type.cpp | 2 +- src/nasal_type.h | 2 +- src/nasal_vm.cpp | 11 +++++++++++ src/nasal_vm.h | 21 +++++++++++++-------- src/unix_lib.cpp | 4 ++-- 8 files changed, 40 insertions(+), 24 deletions(-) diff --git a/module/fib.cpp b/module/fib.cpp index 9116540..1bb9046 100644 --- a/module/fib.cpp +++ b/module/fib.cpp @@ -59,7 +59,7 @@ var create_new_ghost(var* args, usize size, gc* ngc) { var set_new_ghost(var* args, usize size, gc* ngc) { var res = args[0]; - if (!res.objchk(ghost_for_test)) { + if (!res.object_check(ghost_for_test)) { std::cout << "set_new_ghost: not ghost for test type.\n"; return nil; } @@ -71,7 +71,7 @@ var set_new_ghost(var* args, usize size, gc* ngc) { var print_new_ghost(var* args, usize size, gc* ngc) { var res = args[0]; - if (!res.objchk(ghost_for_test)) { + if (!res.object_check(ghost_for_test)) { std::cout << "print_new_ghost: not ghost for test type.\n"; return nil; } diff --git a/src/dylib_lib.cpp b/src/dylib_lib.cpp index daae5aa..0c424df 100644 --- a/src/dylib_lib.cpp +++ b/src/dylib_lib.cpp @@ -69,7 +69,7 @@ var builtin_dlopen(var* local, gc& ngc) { var builtin_dlclose(var* local, gc& ngc) { var libptr = local[1]; - if (!libptr.objchk(dylib_type_name)) { + if (!libptr.object_check(dylib_type_name)) { return nas_err("dlclose", "\"lib\" is not a valid dynamic lib"); } libptr.obj().clear(); @@ -79,7 +79,7 @@ var builtin_dlclose(var* local, gc& ngc) { var builtin_dlcallv(var* local, gc& ngc) { var fp = local[1]; var args = local[2]; - if (!fp.objchk(func_addr_type_name)) { + if (!fp.object_check(func_addr_type_name)) { return nas_err("dlcall", "\"ptr\" is not a valid function pointer"); } auto& vec = args.vec().elems; @@ -92,7 +92,7 @@ var builtin_dlcallv(var* local, gc& ngc) { var builtin_dlcall(var* local, gc& ngc) { var fp = local[1]; - if (!fp.objchk(func_addr_type_name)) { + if (!fp.object_check(func_addr_type_name)) { return nas_err("dlcall", "\"ptr\" is not a valid function pointer"); } diff --git a/src/io_lib.cpp b/src/io_lib.cpp index 63c5dee..089647c 100644 --- a/src/io_lib.cpp +++ b/src/io_lib.cpp @@ -65,7 +65,7 @@ var builtin_open(var* local, gc& ngc) { var builtin_close(var* local, gc& ngc) { var fd = local[1]; - if (!fd.objchk(file_type_name)) { + if (!fd.object_check(file_type_name)) { return nas_err("close", "not a valid filehandle"); } fd.obj().clear(); @@ -76,7 +76,7 @@ var builtin_read(var* local, gc& ngc) { var fd = local[1]; var buf = local[2]; var len = local[3]; - if (!fd.objchk(file_type_name)) { + if (!fd.object_check(file_type_name)) { return nas_err("read", "not a valid filehandle"); } if (buf.type!=vm_str || buf.val.gcobj->unmutable) { @@ -102,7 +102,7 @@ var builtin_read(var* local, gc& ngc) { var builtin_write(var* local, gc& ngc) { var fd = local[1]; var str = local[2]; - if (!fd.objchk(file_type_name)) { + if (!fd.object_check(file_type_name)) { return nas_err("write", "not a valid filehandle"); } if (str.type!=vm_str) { @@ -120,7 +120,7 @@ var builtin_seek(var* local, gc& ngc) { var fd = local[1]; var pos = local[2]; var whence = local[3]; - if (!fd.objchk(file_type_name)) { + if (!fd.object_check(file_type_name)) { return nas_err("seek", "not a valid filehandle"); } return var::num(static_cast(fseek( @@ -132,7 +132,7 @@ var builtin_seek(var* local, gc& ngc) { var builtin_tell(var* local, gc& ngc) { var fd = local[1]; - if (!fd.objchk(file_type_name)) { + if (!fd.object_check(file_type_name)) { return nas_err("tell", "not a valid filehandle"); } return var::num(static_cast( @@ -142,7 +142,7 @@ var builtin_tell(var* local, gc& ngc) { var builtin_readln(var* local, gc& ngc) { var fd = local[1]; - if (!fd.objchk(file_type_name)) { + if (!fd.object_check(file_type_name)) { return nas_err("readln", "not a valid filehandle"); } var str = ngc.alloc(vm_str); @@ -190,7 +190,7 @@ var builtin_stat(var* local, gc& ngc) { var builtin_eof(var* local, gc& ngc) { var fd = local[1]; - if (!fd.objchk(file_type_name)) { + if (!fd.object_check(file_type_name)) { return nas_err("readln", "not a valid filehandle"); } return var::num(static_cast( diff --git a/src/nasal_type.cpp b/src/nasal_type.cpp index ab11624..f3fe65e 100644 --- a/src/nasal_type.cpp +++ b/src/nasal_type.cpp @@ -264,7 +264,7 @@ std::ostream& operator<<(std::ostream& out, var& ref) { return out; } -bool var::objchk(const std::string& name) { +bool var::object_check(const std::string& name) { return type==vm_obj && obj().type_name==name && obj().pointer; } diff --git a/src/nasal_type.h b/src/nasal_type.h index 1cee06f..b4cefdd 100644 --- a/src/nasal_type.h +++ b/src/nasal_type.h @@ -72,7 +72,7 @@ public: // number and string can be translated to each other f64 to_num(); std::string to_str(); - bool objchk(const std::string&); + bool object_check(const std::string&); // create new var object static var none(); diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index b1c1d63..bc943ca 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -353,6 +353,17 @@ std::string vm::report_key_not_found( return result; } +std::string vm::report_out_of_range(f64 index, usize real_size) const { + auto result = "index out of range: " + std::to_string(index); + result += " but max size is " + std::to_string(real_size); + if (!real_size) { + return result; + } + result += ", index range is -" + std::to_string(real_size); + result += "~" + std::to_string(real_size-1); + return result; +} + std::string vm::type_name_string(const var& value) const { switch(value.type) { case vm_none: return "none"; diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 366bcf5..8b20630 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -72,6 +72,7 @@ protected: std::string report_lack_arguments(u32, const nas_func&) const; std::string report_special_call_lack_arguments(var*, const nas_func&) const; std::string report_key_not_found(const std::string&, const nas_hash&) const; + std::string report_out_of_range(f64, usize) const; std::string type_name_string(const var&) const; void die(const std::string&); @@ -312,7 +313,9 @@ inline void vm::o_lnot() { ctx.top[0] = num? zero:one; } } break; - default: die("incorrect value type"); return; + default: + die("cannot do not-operation on "+type_name_string(val)); + return; } } @@ -611,7 +614,7 @@ inline void vm::o_callv() { if (vec.type==vm_vec) { ctx.top[0] = vec.vec().get_val(val.to_num()); if (ctx.top[0].type==vm_none) { - die("out of range:"+std::to_string(val.to_num())); + die(report_out_of_range(val.to_num(), vec.vec().size())); return; } } else if (vec.type==vm_hash) { @@ -621,7 +624,7 @@ inline void vm::o_callv() { } ctx.top[0] = vec.hash().get_val(val.str()); if (ctx.top[0].type==vm_none) { - die("cannot find member \""+val.str()+"\""); + die(report_key_not_found(val.str(), vec.hash())); return; } else if (ctx.top[0].type==vm_func) { ctx.top[0].func().local[0] = val; // 'me' @@ -631,7 +634,7 @@ inline void vm::o_callv() { i32 num = val.to_num(); i32 len = str.length(); if (num<-len || num>=len) { - die("out of range:"+std::to_string(val.to_num())); + die(report_out_of_range(num, str.size())); return; } ctx.top[0] = var::num( @@ -662,7 +665,7 @@ inline void vm::o_callvi() { // cannot use operator[],because this may cause overflow (++ctx.top)[0] = val.vec().get_val(imm[ctx.pc]); if (ctx.top[0].type==vm_none) { - die("out of range:"+std::to_string(imm[ctx.pc])); + die(report_out_of_range(imm[ctx.pc], val.vec().size())); return; } } @@ -853,7 +856,7 @@ inline void vm::o_slc() { var val = (ctx.top--)[0]; var res = ctx.top[-1].vec().get_val(val.to_num()); if (res.type==vm_none) { - die("index " + std::to_string(val.to_num()) + " out of range"); + die(report_out_of_range(val.to_num(), ctx.top[-1].vec().size())); return; } ctx.top[0].vec().elems.push_back(res); @@ -880,7 +883,9 @@ inline void vm::o_slc2() { if (num1<-size || num1>=size || num2<-size || num2>=size) { die("index " + std::to_string(num1) + ":" + - std::to_string(num2) + " out of range"); + std::to_string(num2) + " out of range, real size is " + + std::to_string(size) + ); return; } else if (num1<=num2) { for(i32 i = num1; i<=num2; ++i) { @@ -920,7 +925,7 @@ inline void vm::o_mcallv() { if (vec.type==vm_vec) { ctx.memr = vec.vec().get_mem(val.to_num()); if (!ctx.memr) { - die("index "+std::to_string(val.to_num())+" out of range"); + die(report_out_of_range(val.to_num(), vec.vec().size())); return; } } else if (vec.type==vm_hash) { // do mcallh but use the mcallv way diff --git a/src/unix_lib.cpp b/src/unix_lib.cpp index 865384f..dbd64d9 100644 --- a/src/unix_lib.cpp +++ b/src/unix_lib.cpp @@ -79,7 +79,7 @@ var builtin_opendir(var* local, gc& ngc) { var builtin_readdir(var* local, gc& ngc) { var handle = local[1]; - if (!handle.objchk(dir_type_name)) { + if (!handle.object_check(dir_type_name)) { return nas_err("readdir", "not a valid dir handle"); } #ifdef _MSC_VER @@ -96,7 +96,7 @@ var builtin_readdir(var* local, gc& ngc) { var builtin_closedir(var* local, gc& ngc) { var handle = local[1]; - if (!handle.objchk(dir_type_name)) { + if (!handle.object_check(dir_type_name)) { return nas_err("closedir", "not a valid dir handle"); } handle.obj().clear(); From 7f8a0b64457652b781c7b032102871e54f8f774c Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Fri, 20 Oct 2023 00:24:17 +0800 Subject: [PATCH 08/18] :sparkles: improve code & add new test file --- src/nasal.h | 3 +-- src/nasal_type.cpp | 16 ++++++++-------- src/nasal_type.h | 27 +++++++++++---------------- src/nasal_vm.h | 28 ++++++++++++++-------------- std/result.nas | 23 ++++++++++++----------- test/ascii-art.nas | 1 - test/flush_screen.nas | 28 ++++++++++++++++++++++++++++ 7 files changed, 74 insertions(+), 52 deletions(-) create mode 100644 test/flush_screen.nas diff --git a/src/nasal.h b/src/nasal.h index 6ad8084..5b6b104 100644 --- a/src/nasal.h +++ b/src/nasal.h @@ -35,8 +35,7 @@ bool is_powerpc(); bool is_superh(); -// virtual machine stack depth -// both global depth and value stack depth +// virtual machine stack depth, both global depth and value stack depth const u32 STACK_DEPTH = 4096; f64 hex2f(const char*); diff --git a/src/nasal_type.cpp b/src/nasal_type.cpp index f3fe65e..15a6993 100644 --- a/src/nasal_type.cpp +++ b/src/nasal_type.cpp @@ -2,7 +2,7 @@ namespace nasal { -var nas_vec::get_val(const i32 n) { +var nas_vec::get_value(const i32 n) { i32 size = elems.size(); if (n<-size || n>=size) { return var::none(); @@ -10,7 +10,7 @@ var nas_vec::get_val(const i32 n) { return elems[n>=0? n:n+size]; } -var* nas_vec::get_mem(const i32 n) { +var* nas_vec::get_memory(const i32 n) { i32 size = elems.size(); if (n<-size || n>=size) { return nullptr; @@ -33,7 +33,7 @@ std::ostream& operator<<(std::ostream& out, nas_vec& vec) { return out; } -var nas_hash::get_val(const std::string& key) { +var nas_hash::get_value(const std::string& key) { if (elems.count(key)) { return elems.at(key); } else if (!elems.count("parents")) { @@ -46,7 +46,7 @@ var nas_hash::get_val(const std::string& key) { } for(auto& i : val.vec().elems) { if (i.type==vm_hash) { - ret = i.hash().get_val(key); + ret = i.hash().get_value(key); } if (ret.type!=vm_none) { return ret; @@ -55,7 +55,7 @@ var nas_hash::get_val(const std::string& key) { return ret; } -var* nas_hash::get_mem(const std::string& key) { +var* nas_hash::get_memory(const std::string& key) { if (elems.count(key)) { return &elems.at(key); } else if (!elems.count("parents")) { @@ -68,7 +68,7 @@ var* nas_hash::get_mem(const std::string& key) { } for(auto& i : val.vec().elems) { if (i.type==vm_hash) { - addr = i.hash().get_mem(key); + addr = i.hash().get_memory(key); } if (addr) { return addr; @@ -160,14 +160,14 @@ std::ostream& operator<<(std::ostream& out, const nas_co& co) { return out; } -var nas_map::get_val(const std::string& key) { +var nas_map::get_value(const std::string& key) { if (mapper.count(key)) { return *mapper.at(key); } return var::none(); } -var* nas_map::get_mem(const std::string& key) { +var* nas_map::get_memory(const std::string& key) { if (mapper.count(key)) { return mapper.at(key); } diff --git a/src/nasal_type.h b/src/nasal_type.h index b4cefdd..37d7cf7 100644 --- a/src/nasal_type.h +++ b/src/nasal_type.h @@ -101,25 +101,23 @@ public: struct nas_vec { std::vector elems; - // mark if this is printed, avoid stackoverflow - bool printed; + // mark if this is printed, avoid stack overflow + bool printed = false; - nas_vec():printed(false) {} usize size() const {return elems.size();} - var get_val(const i32); - var* get_mem(const i32); + var get_value(const i32); + var* get_memory(const i32); }; struct nas_hash { std::unordered_map elems; - // mark if this is printed, avoid stackoverflow - bool printed; + // mark if this is printed, avoid stack overflow + bool printed = false; - nas_hash(): printed(false) {} usize size() const {return elems.size();} - var get_val(const std::string&); - var* get_mem(const std::string&); + var get_value(const std::string&); + var* get_memory(const std::string&); }; struct nas_func { @@ -180,9 +178,7 @@ public: void clear(); public: - const std::string& get_ghost_name() const { - return type_name; - } + const auto& get_ghost_name() const {return type_name;} }; struct context { @@ -220,13 +216,12 @@ struct nas_map { bool printed = false; std::unordered_map mapper; - nas_map() {} void clear() { mapper.clear(); } - var get_val(const std::string&); - var* get_mem(const std::string&); + var get_value(const std::string&); + var* get_memory(const std::string&); }; struct nas_val { diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 8b20630..cb8f985 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -612,7 +612,7 @@ inline void vm::o_callv() { var val = ctx.top[0]; var vec = (--ctx.top)[0]; if (vec.type==vm_vec) { - ctx.top[0] = vec.vec().get_val(val.to_num()); + ctx.top[0] = vec.vec().get_value(val.to_num()); if (ctx.top[0].type==vm_none) { die(report_out_of_range(val.to_num(), vec.vec().size())); return; @@ -622,7 +622,7 @@ inline void vm::o_callv() { die("must use string as the key but get "+type_name_string(val)); return; } - ctx.top[0] = vec.hash().get_val(val.str()); + ctx.top[0] = vec.hash().get_value(val.str()); if (ctx.top[0].type==vm_none) { die(report_key_not_found(val.str(), vec.hash())); return; @@ -645,7 +645,7 @@ inline void vm::o_callv() { die("must use string as the key but get "+type_name_string(val)); return; } - ctx.top[0] = vec.map().get_val(val.str()); + ctx.top[0] = vec.map().get_value(val.str()); if (ctx.top[0].type==vm_none) { die("cannot find symbol \""+val.str()+"\""); return; @@ -663,7 +663,7 @@ inline void vm::o_callvi() { return; } // cannot use operator[],because this may cause overflow - (++ctx.top)[0] = val.vec().get_val(imm[ctx.pc]); + (++ctx.top)[0] = val.vec().get_value(imm[ctx.pc]); if (ctx.top[0].type==vm_none) { die(report_out_of_range(imm[ctx.pc], val.vec().size())); return; @@ -678,9 +678,9 @@ inline void vm::o_callh() { } const auto& str = const_string[imm[ctx.pc]]; if (val.type==vm_hash) { - ctx.top[0] = val.hash().get_val(str); + ctx.top[0] = val.hash().get_value(str); } else { - ctx.top[0] = val.map().get_val(str); + ctx.top[0] = val.map().get_value(str); } if (ctx.top[0].type==vm_none) { val.type==vm_hash? @@ -854,7 +854,7 @@ inline void vm::o_slcend() { inline void vm::o_slc() { var val = (ctx.top--)[0]; - var res = ctx.top[-1].vec().get_val(val.to_num()); + var res = ctx.top[-1].vec().get_value(val.to_num()); if (res.type==vm_none) { die(report_out_of_range(val.to_num(), ctx.top[-1].vec().size())); return; @@ -923,7 +923,7 @@ inline void vm::o_mcallv() { var val = ctx.top[0]; // index var vec = (--ctx.top)[0]; // mcall vector, reserved on stack to avoid gc if (vec.type==vm_vec) { - ctx.memr = vec.vec().get_mem(val.to_num()); + ctx.memr = vec.vec().get_memory(val.to_num()); if (!ctx.memr) { die(report_out_of_range(val.to_num(), vec.vec().size())); return; @@ -935,10 +935,10 @@ inline void vm::o_mcallv() { } auto& ref = vec.hash(); const auto& str = val.str(); - ctx.memr = ref.get_mem(str); + ctx.memr = ref.get_memory(str); if (!ctx.memr) { ref.elems[str] = nil; - ctx.memr = ref.get_mem(str); + ctx.memr = ref.get_memory(str); } } else if (vec.type==vm_map) { if (val.type!=vm_str) { @@ -947,7 +947,7 @@ inline void vm::o_mcallv() { } auto& ref = vec.map(); const auto& str = val.str(); - ctx.memr = ref.get_mem(str); + ctx.memr = ref.get_memory(str); if (!ctx.memr) { die("cannot find symbol \"" + str + "\""); } @@ -965,18 +965,18 @@ inline void vm::o_mcallh() { } const auto& str = const_string[imm[ctx.pc]]; if (hash.type==vm_map) { - ctx.memr = hash.map().get_mem(str); + ctx.memr = hash.map().get_memory(str); if (!ctx.memr) { die("cannot find symbol \"" + str + "\""); } return; } auto& ref = hash.hash(); - ctx.memr = ref.get_mem(str); + ctx.memr = ref.get_memory(str); // create a new key if (!ctx.memr) { ref.elems[str] = nil; - ctx.memr = ref.get_mem(str); + ctx.memr = ref.get_memory(str); } } diff --git a/std/result.nas b/std/result.nas index 6631b88..e048e52 100644 --- a/std/result.nas +++ b/std/result.nas @@ -1,22 +1,23 @@ # result.nas # ValKmjolnir 2021 -var Result=func(){ - var (ok,err,flag)=(nil,"",1); - return{ - Ok:func(val){ - ok=val; - flag=0; +var new = func() { + var (ok, err, flag) = (nil, "", 1); + return { + Ok: func(val) { + ok = val; + flag = 0; return me; }, - Err:func(info){ - err=info; - flag=1; + Err: func(info) { + err = info; + flag = 1; return me; }, - unwrap:func(){ - if(flag) + unwrap: func() { + if (flag) { die(err); + } return ok; } }; diff --git a/test/ascii-art.nas b/test/ascii-art.nas index 893f944..9e8335f 100644 --- a/test/ascii-art.nas +++ b/test/ascii-art.nas @@ -191,7 +191,6 @@ var ansi_escape_sequence=func(){ } unix.sleep(0.01); } - } # enable unicode diff --git a/test/flush_screen.nas b/test/flush_screen.nas new file mode 100644 index 0000000..18e064d --- /dev/null +++ b/test/flush_screen.nas @@ -0,0 +1,28 @@ +import.module.libkey; + +srand(); + +var chars = "abcdefghijklmnopqrstuvwxyz" ~ + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ~ + "1234567890" ~ + "!@#$%^&*()_+-=~`[]{}\\|'\";:,.<>/?"; +chars = split("", chars); + +print("\ec"); +while(1) { + var key = libkey.nonblock(); + if (key!=nil and chr(key)=="q") { + break; + } + var res = "\e[1;1H"; + for(var i = 0; i<20; i+=1) { + for(var j = 0; j<40; j+=1) { + res ~= "\e[38;5;" ~ int(rand()*256) ~ ";1m"; + res ~= chars[int(rand()*size(chars))]; + res ~= "\e[0m "; + } + res ~= "\n"; + } + print(res); + unix.sleep(1/30); +} \ No newline at end of file From 820c05c9867e8fb305c2ce1e13f1f52012f14577 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sat, 21 Oct 2023 00:31:39 +0800 Subject: [PATCH 09/18] :sparkles: change way of calling native functions --- src/bits_lib.cpp | 53 +++++---- src/bits_lib.h | 18 +-- src/coroutine.cpp | 105 ++++++++-------- src/coroutine.h | 10 +- src/dylib_lib.cpp | 34 +++--- src/dylib_lib.h | 8 +- src/fg_props.cpp | 7 +- src/fg_props.h | 2 +- src/io_lib.cpp | 76 ++++++------ src/io_lib.h | 24 ++-- src/math_lib.cpp | 44 +++---- src/math_lib.h | 20 ++-- src/nasal_builtin.cpp | 270 ++++++++++++++++++++++-------------------- src/nasal_builtin.h | 84 ++++++------- src/nasal_vm.h | 5 +- src/unix_lib.cpp | 78 ++++++------ src/unix_lib.h | 20 ++-- 17 files changed, 448 insertions(+), 410 deletions(-) diff --git a/src/bits_lib.cpp b/src/bits_lib.cpp index f33c79b..95639b9 100644 --- a/src/bits_lib.cpp +++ b/src/bits_lib.cpp @@ -2,45 +2,52 @@ namespace nasal { -var builtin_u32xor(var* local, gc& ngc) { +var builtin_u32xor(context* ctx, gc* ngc) { + auto local = ctx->localr; return var::num(static_cast( static_cast(local[1].num()) ^ static_cast(local[2].num()) )); } -var builtin_u32and(var* local, gc& ngc) { +var builtin_u32and(context* ctx, gc* ngc) { + auto local = ctx->localr; return var::num(static_cast( static_cast(local[1].num()) & static_cast(local[2].num()) )); } -var builtin_u32or(var* local, gc& ngc) { +var builtin_u32or(context* ctx, gc* ngc) { + auto local = ctx->localr; return var::num(static_cast( static_cast(local[1].num()) | static_cast(local[2].num()) )); } -var builtin_u32nand(var* local, gc& ngc) { +var builtin_u32nand(context* ctx, gc* ngc) { + auto local = ctx->localr; return var::num(static_cast(~( static_cast(local[1].num()) & static_cast(local[2].num()) ))); } -var builtin_u32not(var* local, gc& ngc) { - return var::num(static_cast(~static_cast(local[1].num()))); +var builtin_u32not(context* ctx, gc* ngc) { + return var::num(static_cast( + ~static_cast(ctx->localr[1].num()) + )); } -var builtin_fld(var* local, gc& ngc) { +var builtin_fld(context* ctx, gc* ngc) { // bits.fld(s,0,3); // if s stores 10100010(162) // will get 101(5) - var str = local[1]; - var startbit = local[2]; - var length = local[3]; + auto local = ctx->localr; + auto str = local[1]; + auto startbit = local[2]; + auto length = local[3]; if (str.type!=vm_str || str.val.gcobj->unmutable) { return nas_err("fld", "\"str\" must be mutable string"); } @@ -62,14 +69,15 @@ var builtin_fld(var* local, gc& ngc) { return var::num(static_cast(res)); } -var builtin_sfld(var* local, gc& ngc) { +var builtin_sfld(context* ctx, gc* ngc) { // bits.sfld(s,0,3); // if s stores 10100010(162) // will get 101(5) then this will be signed extended to // 11111101(-3) - var str = local[1]; - var startbit = local[2]; - var length = local[3]; + auto local = ctx->localr; + auto str = local[1]; + auto startbit = local[2]; + auto length = local[3]; if (str.type!=vm_str || str.val.gcobj->unmutable) { return nas_err("sfld", "\"str\" must be mutable string"); } @@ -94,15 +102,16 @@ var builtin_sfld(var* local, gc& ngc) { return var::num(static_cast(static_cast(res))); } -var builtin_setfld(var* local, gc& ngc) { +var builtin_setfld(context* ctx, gc* ngc) { // bits.setfld(s,0,8,69); // set 01000101(69) to string will get this: // 10100010(162) // so s[0]=162 - var str = local[1]; - var startbit = local[2]; - var length = local[3]; - var value = local[4]; + auto local = ctx->localr; + auto str = local[1]; + auto startbit = local[2]; + auto length = local[3]; + auto value = local[4]; if (str.type!=vm_str || str.val.gcobj->unmutable) { return nas_err("setfld", "\"str\" must be mutable string"); } @@ -126,12 +135,12 @@ var builtin_setfld(var* local, gc& ngc) { return nil; } -var builtin_buf(var* local, gc& ngc) { - var length = local[1]; +var builtin_buf(context* ctx, gc* ngc) { + var length = ctx->localr[1]; if (length.type!=vm_num || length.num()<=0) { return nas_err("buf", "\"len\" must be number greater than 0"); } - var str = ngc.alloc(vm_str); + var str = ngc->alloc(vm_str); auto& s = str.str(); s.resize(length.num(), '\0'); return str; diff --git a/src/bits_lib.h b/src/bits_lib.h index f2a8a37..0864cec 100644 --- a/src/bits_lib.h +++ b/src/bits_lib.h @@ -6,15 +6,15 @@ namespace nasal { -var builtin_u32xor(var*, gc&); -var builtin_u32and(var*, gc&); -var builtin_u32or(var*, gc&); -var builtin_u32nand(var*, gc&); -var builtin_u32not(var*, gc&); -var builtin_fld(var*, gc&); -var builtin_sfld(var*, gc&); -var builtin_setfld(var*, gc&); -var builtin_buf(var*, gc&); +var builtin_u32xor(context*, gc*); +var builtin_u32and(context*, gc*); +var builtin_u32or(context*, gc*); +var builtin_u32nand(context*, gc*); +var builtin_u32not(context*, gc*); +var builtin_fld(context*, gc*); +var builtin_sfld(context*, gc*); +var builtin_setfld(context*, gc*); +var builtin_buf(context*, gc*); extern nasal_builtin_table bits_native[]; diff --git a/src/coroutine.cpp b/src/coroutine.cpp index 319698e..5603656 100644 --- a/src/coroutine.cpp +++ b/src/coroutine.cpp @@ -2,7 +2,8 @@ namespace nasal { -var builtin_cocreate(var* local, gc& ngc) { +var builtin_cocreate(context* ctx, gc* ngc) { + // ``` // +-------------+ // | old pc | <- top[0] // +-------------+ @@ -15,69 +16,73 @@ var builtin_cocreate(var* local, gc& ngc) { // +-------------+ <- local pointer stored in localr // | old funcr | <- old function stored in funcr // +-------------+ - var func = local[1]; - if (func.type!=vm_func) { + // ``` + auto coroutine_function = ctx->localr[1]; + if (coroutine_function.type!=vm_func) { return nas_err( "coroutine::create", "must use a function to create coroutine" ); } - if (ngc.cort) { + if (ngc->cort) { return nas_err( "coroutine::create", "cannot create another coroutine in a coroutine" ); } - var co = ngc.alloc(vm_co); - nas_co& cort = co.co(); - cort.ctx.pc = func.func().entry-1; + auto coroutine_object = ngc->alloc(vm_co); + auto& coroutine = coroutine_object.co(); + coroutine.ctx.pc = coroutine_function.func().entry-1; + + coroutine.ctx.top[0] = nil; + coroutine.ctx.localr = coroutine.ctx.top+1; + coroutine.ctx.top = coroutine.ctx.localr + + coroutine_function.func().local_size; + coroutine.ctx.localr[0] = coroutine_function.func().local[0]; - cort.ctx.top[0] = nil; - cort.ctx.localr = cort.ctx.top+1; - cort.ctx.top = cort.ctx.localr+func.func().local_size; - cort.ctx.localr[0] = func.func().local[0]; // store old upvalr on stack - cort.ctx.top[0] = nil; - cort.ctx.top++; + coroutine.ctx.top[0] = nil; + coroutine.ctx.top++; + // store old localr on stack - cort.ctx.top[0] = var::addr((var*)nullptr); - cort.ctx.top++; + coroutine.ctx.top[0] = var::addr((var*)nullptr); + coroutine.ctx.top++; + // store old pc on stack // set to zero to make op_ret recognizing this as coroutine function - cort.ctx.top[0] = var::ret(0); + coroutine.ctx.top[0] = var::ret(0); // make sure the coroutine function can use correct upvalues - cort.ctx.funcr = func; - cort.status = nas_co::status::suspended; - - return co; + coroutine.ctx.funcr = coroutine_function; + coroutine.status = nas_co::status::suspended; + + return coroutine_object; } -var builtin_coresume(var* local, gc& ngc) { - if (ngc.cort) { +var builtin_coresume(context* ctx, gc* ngc) { + if (ngc->cort) { return nas_err( "coroutine::resume", "cannot start another coroutine when one is running" ); } - var co = local[1]; - // return nil if is not a coroutine object - if (co.type!=vm_co) { - return nil; - } - // cannot resume a dead coroutine - if (co.co().status==nas_co::status::dead) { + auto main_local_frame = ctx->localr; + auto coroutine_object = main_local_frame[1]; + // return nil if is not a coroutine object or coroutine exited + if (coroutine_object.type!=vm_co || + coroutine_object.co().status==nas_co::status::dead) { return nil; } // change to coroutine context - ngc.ctxchg(co.co()); + ngc->ctxchg(coroutine_object.co()); // fetch coroutine's stack top and return + // then coroutine's stack top will catch this return value // so the coroutine's stack top in fact is not changed - if (ngc.running_context->top[0].type==vm_ret) { + if (ngc->running_context->top[0].type==vm_ret) { // when first calling this coroutine, the stack top must be vm_ret - return ngc.running_context->top[0]; + return ngc->running_context->top[0]; } // after first calling the coroutine, each time coroutine.yield triggered @@ -87,39 +92,41 @@ var builtin_coresume(var* local, gc& ngc) { // the coroutine seems like coroutine.yield returns the value // but in fact coroutine.yield stop the coroutine // until main context calls the coroutine.resume - return local[2]; + return main_local_frame[2]; } -var builtin_coyield(var* local, gc& ngc) { - if (!ngc.cort) { +var builtin_coyield(context* ctx, gc* ngc) { + if (!ngc->cort) { return nas_err("coroutine::yield", "no coroutine is running"); } + // get coroutine local frame + auto coroutine_local_frame = ctx->localr; + + // vm context will set to main context + ngc->ctxreserve(); - // this will set to main stack top - ngc.ctxreserve(); - // then this will return value to main's stack top[0] // the procedure seems like coroutine.resume returns the value // but in fact coroutine.resume stop the main context // until coroutine calls the coroutine.yield - return local[1]; + return coroutine_local_frame[1]; } -var builtin_costatus(var* local, gc& ngc) { - var co = local[1]; - if (co.type!=vm_co) { - return ngc.newstr("error"); +var builtin_costatus(context* ctx, gc* ngc) { + auto coroutine_object = ctx->localr[1]; + if (coroutine_object.type!=vm_co) { + return ngc->newstr("error"); } - switch(co.co().status) { - case nas_co::status::suspended: return ngc.newstr("suspended"); - case nas_co::status::running: return ngc.newstr("running"); - case nas_co::status::dead: return ngc.newstr("dead"); + switch(coroutine_object.co().status) { + case nas_co::status::suspended: return ngc->newstr("suspended"); + case nas_co::status::running: return ngc->newstr("running"); + case nas_co::status::dead: return ngc->newstr("dead"); } return nil; } -var builtin_corun(var* local, gc& ngc) { - return ngc.cort? one:zero; +var builtin_corun(context* ctx, gc* ngc) { + return ngc->cort? one:zero; } nasal_builtin_table coroutine_native[] = { diff --git a/src/coroutine.h b/src/coroutine.h index e0fe1d3..44c0275 100644 --- a/src/coroutine.h +++ b/src/coroutine.h @@ -6,11 +6,11 @@ namespace nasal { -var builtin_cocreate(var*, gc&); -var builtin_coresume(var*, gc&); -var builtin_coyield(var*, gc&); -var builtin_costatus(var*, gc&); -var builtin_corun(var*, gc&); +var builtin_cocreate(context*, gc*); +var builtin_coresume(context*, gc*); +var builtin_coyield(context*, gc*); +var builtin_costatus(context*, gc*); +var builtin_corun(context*, gc*); extern nasal_builtin_table coroutine_native[]; diff --git a/src/dylib_lib.cpp b/src/dylib_lib.cpp index 0c424df..6d26152 100644 --- a/src/dylib_lib.cpp +++ b/src/dylib_lib.cpp @@ -15,8 +15,8 @@ void dylib_destructor(void* ptr) { void func_addr_destructor(void* ptr) {} -var builtin_dlopen(var* local, gc& ngc) { - var dlname = local[1]; +var builtin_dlopen(context* ctx, gc* ngc) { + auto dlname = ctx->localr[1]; if (dlname.type!=vm_str) { return nas_err("dlopen", "\"libname\" must be string"); } @@ -35,8 +35,8 @@ var builtin_dlopen(var* local, gc& ngc) { if (!ptr) { return nas_err("dlopen", "cannot open dynamic lib <"+dlname.str()+">"); } - var ret = ngc.temp = ngc.alloc(vm_hash); - var lib = ngc.alloc(vm_obj); + auto ret = ngc->temp = ngc->alloc(vm_hash); + auto lib = ngc->alloc(vm_obj); lib.obj().set(dylib_type_name, dylib_destructor, ptr); ret.hash().elems["lib"] = lib; @@ -52,23 +52,23 @@ var builtin_dlopen(var* local, gc& ngc) { return nas_err("dlopen", "cannot find function"); } // get function pointer by name - module_func_info* tbl = reinterpret_cast(func)(); + auto tbl = reinterpret_cast(func)(); if (!tbl) { return nas_err("dlopen", "failed to get module functions"); } for(u32 i = 0; tbl[i].name; ++i) { void* p = (void*)tbl[i].fd; - var tmp = ngc.alloc(vm_obj); + var tmp = ngc->alloc(vm_obj); tmp.obj().set(func_addr_type_name, func_addr_destructor, p); ret.hash().elems[tbl[i].name] = tmp; } - ngc.temp = nil; + ngc->temp = nil; return ret; } -var builtin_dlclose(var* local, gc& ngc) { - var libptr = local[1]; +var builtin_dlclose(context* ctx, gc* ngc) { + auto libptr = ctx->localr[1]; if (!libptr.object_check(dylib_type_name)) { return nas_err("dlclose", "\"lib\" is not a valid dynamic lib"); } @@ -76,9 +76,10 @@ var builtin_dlclose(var* local, gc& ngc) { return nil; } -var builtin_dlcallv(var* local, gc& ngc) { - var fp = local[1]; - var args = local[2]; +var builtin_dlcallv(context* ctx, gc* ngc) { + auto local = ctx->localr; + auto fp = local[1]; + auto args = local[2]; if (!fp.object_check(func_addr_type_name)) { return nas_err("dlcall", "\"ptr\" is not a valid function pointer"); } @@ -86,23 +87,24 @@ var builtin_dlcallv(var* local, gc& ngc) { return reinterpret_cast(fp.obj().pointer)( vec.data(), vec.size(), - &ngc + ngc ); } -var builtin_dlcall(var* local, gc& ngc) { +var builtin_dlcall(context* ctx, gc* ngc) { + auto local = ctx->localr; var fp = local[1]; if (!fp.object_check(func_addr_type_name)) { return nas_err("dlcall", "\"ptr\" is not a valid function pointer"); } var* local_frame_start = local+2; - usize local_frame_size = ngc.running_context->top-local_frame_start; + usize local_frame_size = ngc->running_context->top-local_frame_start; // arguments' stored place begins at local +2 return reinterpret_cast(fp.obj().pointer)( local_frame_start, local_frame_size, - &ngc + ngc ); } diff --git a/src/dylib_lib.h b/src/dylib_lib.h index 039f2b4..7eed093 100644 --- a/src/dylib_lib.h +++ b/src/dylib_lib.h @@ -16,10 +16,10 @@ namespace nasal { void dylib_destructor(void*); void func_addr_destructor(void*); -var builtin_dlopen(var*, gc&); -var builtin_dlclose(var*, gc&); -var builtin_dlcallv(var*, gc&); -var builtin_dlcall(var*, gc&); +var builtin_dlopen(context*, gc*); +var builtin_dlclose(context*, gc*); +var builtin_dlcallv(context*, gc*); +var builtin_dlcall(context*, gc*); extern nasal_builtin_table dylib_lib_native[]; diff --git a/src/fg_props.cpp b/src/fg_props.cpp index fd958f7..25ddf7e 100644 --- a/src/fg_props.cpp +++ b/src/fg_props.cpp @@ -4,9 +4,10 @@ namespace nasal { -var builtin_logprint(var* local, gc& ngc) { - var level = local[1]; - var elems = local[2]; +var builtin_logprint(context* ctx, gc* ngc) { + auto local = ctx->localr; + auto level = local[1]; + auto elems = local[2]; if (elems.type!=vm_vec) { return nas_err("logprint", "received argument is not vector."); } diff --git a/src/fg_props.h b/src/fg_props.h index 82a3f89..a76dcce 100644 --- a/src/fg_props.h +++ b/src/fg_props.h @@ -15,7 +15,7 @@ namespace nasal { #define SG_DEV_ALERT 8 #define SG_MANDATORY_INFO 9 -var builtin_logprint(var*, gc&); +var builtin_logprint(context*, gc*); extern nasal_builtin_table flight_gear_native[]; diff --git a/src/io_lib.cpp b/src/io_lib.cpp index 089647c..9fdd19a 100644 --- a/src/io_lib.cpp +++ b/src/io_lib.cpp @@ -11,8 +11,8 @@ void filehandle_destructor(void* ptr) { fclose(static_cast(ptr)); } -var builtin_readfile(var* local, gc& ngc) { - var val = local[1]; +var builtin_readfile(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; if (val.type!=vm_str) { return nas_err("io::readfile", "\"filename\" must be string"); } @@ -21,12 +21,13 @@ var builtin_readfile(var* local, gc& ngc) { if (!in.fail()) { rd << in.rdbuf(); } - return ngc.newstr(rd.str()); + return ngc->newstr(rd.str()); } -var builtin_fout(var* local, gc& ngc) { - var val = local[1]; - var str = local[2]; +var builtin_fout(context* ctx, gc* ngc) { + auto local = ctx->localr; + auto val = local[1]; + auto str = local[2]; if (val.type!=vm_str) { return nas_err("io::fout", "\"filename\" must be string"); } @@ -38,16 +39,18 @@ var builtin_fout(var* local, gc& ngc) { return nil; } -var builtin_exists(var* local, gc& ngc) { +var builtin_exists(context* ctx, gc* ngc) { + auto local = ctx->localr; if (local[1].type!=vm_str) { return zero; } return access(local[1].str().c_str(), F_OK)!=-1? one:zero; } -var builtin_open(var* local, gc& ngc) { - var name = local[1]; - var mode = local[2]; +var builtin_open(context* ctx, gc* ngc) { + auto local = ctx->localr; + auto name = local[1]; + auto mode = local[2]; if (name.type!=vm_str) { return nas_err("open", "\"filename\" must be string"); } @@ -58,13 +61,13 @@ var builtin_open(var* local, gc& ngc) { if (!res) { return nas_err("open", "failed to open file <"+name.str()+">"); } - var ret = ngc.alloc(vm_obj); + var ret = ngc->alloc(vm_obj); ret.obj().set(file_type_name, filehandle_destructor, res); return ret; } -var builtin_close(var* local, gc& ngc) { - var fd = local[1]; +var builtin_close(context* ctx, gc* ngc) { + var fd = ctx->localr[1]; if (!fd.object_check(file_type_name)) { return nas_err("close", "not a valid filehandle"); } @@ -72,10 +75,11 @@ var builtin_close(var* local, gc& ngc) { return nil; } -var builtin_read(var* local, gc& ngc) { - var fd = local[1]; - var buf = local[2]; - var len = local[3]; +var builtin_read(context* ctx, gc* ngc) { + auto local = ctx->localr; + auto fd = local[1]; + auto buf = local[2]; + auto len = local[3]; if (!fd.object_check(file_type_name)) { return nas_err("read", "not a valid filehandle"); } @@ -99,9 +103,10 @@ var builtin_read(var* local, gc& ngc) { return var::num(res); } -var builtin_write(var* local, gc& ngc) { - var fd = local[1]; - var str = local[2]; +var builtin_write(context* ctx, gc* ngc) { + auto local = ctx->localr; + auto fd = local[1]; + auto str = local[2]; if (!fd.object_check(file_type_name)) { return nas_err("write", "not a valid filehandle"); } @@ -116,10 +121,11 @@ var builtin_write(var* local, gc& ngc) { ))); } -var builtin_seek(var* local, gc& ngc) { - var fd = local[1]; - var pos = local[2]; - var whence = local[3]; +var builtin_seek(context* ctx, gc* ngc) { + auto local = ctx->localr; + auto fd = local[1]; + auto pos = local[2]; + auto whence = local[3]; if (!fd.object_check(file_type_name)) { return nas_err("seek", "not a valid filehandle"); } @@ -130,8 +136,8 @@ var builtin_seek(var* local, gc& ngc) { ))); } -var builtin_tell(var* local, gc& ngc) { - var fd = local[1]; +var builtin_tell(context* ctx, gc* ngc) { + auto fd = ctx->localr[1]; if (!fd.object_check(file_type_name)) { return nas_err("tell", "not a valid filehandle"); } @@ -140,12 +146,12 @@ var builtin_tell(var* local, gc& ngc) { )); } -var builtin_readln(var* local, gc& ngc) { - var fd = local[1]; +var builtin_readln(context* ctx, gc* ngc) { + auto fd = ctx->localr[1]; if (!fd.object_check(file_type_name)) { return nas_err("readln", "not a valid filehandle"); } - var str = ngc.alloc(vm_str); + auto str = ngc->alloc(vm_str); char c; while((c = fgetc(static_cast(fd.obj().pointer)))!=EOF) { if (c=='\r') { @@ -162,16 +168,16 @@ var builtin_readln(var* local, gc& ngc) { return nil; } -var builtin_stat(var* local, gc& ngc) { - var name = local[1]; +var builtin_stat(context* ctx, gc* ngc) { + auto name = ctx->localr[1]; if (name.type!=vm_str) { return nas_err("stat", "\"filename\" must be string"); } struct stat buf; - if (stat(name.str().c_str(),&buf)<0) { + if (stat(name.str().c_str(), &buf)<0) { return nas_err("stat", "failed to open file <"+name.str()+">"); } - var ret = ngc.alloc(vm_vec); + auto ret = ngc->alloc(vm_vec); ret.vec().elems = { var::num(static_cast(buf.st_dev)), var::num(static_cast(buf.st_ino)), @@ -188,8 +194,8 @@ var builtin_stat(var* local, gc& ngc) { return ret; } -var builtin_eof(var* local, gc& ngc) { - var fd = local[1]; +var builtin_eof(context* ctx, gc* ngc) { + auto fd = ctx->localr[1]; if (!fd.object_check(file_type_name)) { return nas_err("readln", "not a valid filehandle"); } diff --git a/src/io_lib.h b/src/io_lib.h index 3ea800d..a4dc136 100644 --- a/src/io_lib.h +++ b/src/io_lib.h @@ -20,18 +20,18 @@ namespace nasal { void filehandle_destructor(void*); -var builtin_readfile(var*, gc&); -var builtin_fout(var*, gc&); -var builtin_exists(var*, gc&); -var builtin_open(var*, gc&); -var builtin_close(var*, gc&); -var builtin_read(var*, gc&); -var builtin_write(var*, gc&); -var builtin_seek(var*, gc&); -var builtin_tell(var*, gc&); -var builtin_readln(var*, gc&); -var builtin_stat(var*, gc&); -var builtin_eof(var*, gc&); +var builtin_readfile(context*, gc*); +var builtin_fout(context*, gc*); +var builtin_exists(context*, gc*); +var builtin_open(context*, gc*); +var builtin_close(context*, gc*); +var builtin_read(context*, gc*); +var builtin_write(context*, gc*); +var builtin_seek(context*, gc*); +var builtin_tell(context*, gc*); +var builtin_readln(context*, gc*); +var builtin_stat(context*, gc*); +var builtin_eof(context*, gc*); extern nasal_builtin_table io_lib_native[]; diff --git a/src/math_lib.cpp b/src/math_lib.cpp index e751636..750648a 100644 --- a/src/math_lib.cpp +++ b/src/math_lib.cpp @@ -2,61 +2,61 @@ namespace nasal { -var builtin_pow(var* local, gc& ngc) { - var x = local[1]; - var y = local[2]; +var builtin_pow(context* ctx, gc* ngc) { + auto x = ctx->localr[1]; + auto y = ctx->localr[2]; if (x.type!=vm_num || y.type!=vm_num) { return var::num(std::nan("")); } return var::num(std::pow(x.num(), y.num())); } -var builtin_sin(var* local, gc& ngc) { - var val = local[1]; +var builtin_sin(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; return var::num(val.type==vm_num? sin(val.num()):std::nan("")); } -var builtin_cos(var* local, gc& ngc) { - var val = local[1]; +var builtin_cos(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; return var::num(val.type==vm_num? cos(val.num()):std::nan("")); } -var builtin_tan(var* local, gc& ngc) { - var val = local[1]; +var builtin_tan(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; return var::num(val.type==vm_num? tan(val.num()):std::nan("")); } -var builtin_exp(var* local, gc& ngc) { - var val = local[1]; +var builtin_exp(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; return var::num(val.type==vm_num? exp(val.num()):std::nan("")); } -var builtin_lg(var* local, gc& ngc) { - var val = local[1]; +var builtin_lg(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; return var::num(val.type==vm_num? log(val.num())/log(10.0):std::nan("")); } -var builtin_ln(var* local, gc& ngc) { - var val = local[1]; +var builtin_ln(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; return var::num(val.type==vm_num? log(val.num()):std::nan("")); } -var builtin_sqrt(var* local, gc& ngc) { - var val = local[1]; +var builtin_sqrt(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; return var::num(val.type==vm_num? sqrt(val.num()):std::nan("")); } -var builtin_atan2(var* local, gc& ngc) { - var x = local[1]; - var y = local[2]; +var builtin_atan2(context* ctx, gc* ngc) { + auto x = ctx->localr[1]; + auto y = ctx->localr[2]; if (x.type!=vm_num || y.type!=vm_num) { return var::num(std::nan("")); } return var::num(atan2(y.num(), x.num())); } -var builtin_isnan(var* local, gc& ngc) { - var x = local[1]; +var builtin_isnan(context* ctx, gc* ngc) { + auto x = ctx->localr[1]; return (x.type==vm_num && std::isnan(x.num()))? one:zero; } diff --git a/src/math_lib.h b/src/math_lib.h index a0c3550..e8a72b7 100644 --- a/src/math_lib.h +++ b/src/math_lib.h @@ -6,16 +6,16 @@ namespace nasal { -var builtin_pow(var*, gc&); -var builtin_sin(var*, gc&); -var builtin_cos(var*, gc&); -var builtin_tan(var*, gc&); -var builtin_exp(var*, gc&); -var builtin_lg(var*, gc&); -var builtin_ln(var*, gc&); -var builtin_sqrt(var*, gc&); -var builtin_atan2(var*, gc&); -var builtin_isnan(var*, gc&); +var builtin_pow(context*, gc*); +var builtin_sin(context*, gc*); +var builtin_cos(context*, gc*); +var builtin_tan(context*, gc*); +var builtin_exp(context*, gc*); +var builtin_lg(context*, gc*); +var builtin_ln(context*, gc*); +var builtin_sqrt(context*, gc*); +var builtin_atan2(context*, gc*); +var builtin_isnan(context*, gc*); extern nasal_builtin_table math_lib_native[]; diff --git a/src/nasal_builtin.cpp b/src/nasal_builtin.cpp index 8d21a02..499e92c 100644 --- a/src/nasal_builtin.cpp +++ b/src/nasal_builtin.cpp @@ -3,33 +3,34 @@ namespace nasal { -var builtin_print(var* local, gc& ngc) { - for(auto& i : local[1].vec().elems) { +var builtin_print(context* ctx, gc* ngc) { + for(auto& i : ctx->localr[1].vec().elems) { std::cout << i; } std::cout << std::flush; return nil; } -var builtin_println(var* local, gc& ngc) { - for(auto& i : local[1].vec().elems) { +var builtin_println(context* ctx, gc* ngc) { + for(auto& i : ctx->localr[1].vec().elems) { std::cout << i; } std::cout << std::endl; return nil; } -var builtin_exit(var* local, gc& ngc) { - std::exit(local[1].num()); +var builtin_exit(context* ctx, gc* ngc) { + std::exit(ctx->localr[1].num()); return nil; } -var builtin_abort(var* local, gc& ngc) { +var builtin_abort(context* ctx, gc* ngc) { std::abort(); return nil; } -var builtin_append(var* local, gc& ngc) { +var builtin_append(context* ctx, gc* ngc) { + auto local = ctx->localr; var vec = local[1]; var elem = local[2]; if (vec.type!=vm_vec) { @@ -42,7 +43,8 @@ var builtin_append(var* local, gc& ngc) { return nil; } -var builtin_setsize(var* local, gc& ngc) { +var builtin_setsize(context* ctx, gc* ngc) { + auto local = ctx->localr; var vec = local[1]; var size = local[2]; if (vec.type!=vm_vec) { @@ -55,17 +57,18 @@ var builtin_setsize(var* local, gc& ngc) { return nil; } -var builtin_system(var* local, gc& ngc) { - var str = local[1]; +var builtin_system(context* ctx, gc* ngc) { + auto str = ctx->localr[1]; if (str.type!=vm_str) { return var::num(-1); } return var::num(static_cast(system(str.str().c_str()))); } -var builtin_input(var* local, gc& ngc) { +var builtin_input(context* ctx, gc* ngc) { + auto local = ctx->localr; var end = local[1]; - var ret = ngc.alloc(vm_str); + var ret = ngc->alloc(vm_str); if (end.type!=vm_str || end.str().length()>1 || !end.str().length()) { std::cin >> ret.str(); } else { @@ -74,7 +77,8 @@ var builtin_input(var* local, gc& ngc) { return ret; } -var builtin_split(var* local, gc& ngc) { +var builtin_split(context* ctx, gc* ngc) { + auto local = ctx->localr; var delimeter = local[1]; var str = local[2]; if (delimeter.type!=vm_str) { @@ -87,34 +91,34 @@ var builtin_split(var* local, gc& ngc) { const auto& s = str.str(); // avoid being sweeped - var res = ngc.temp = ngc.alloc(vm_vec); + auto res = ngc->temp = ngc->alloc(vm_vec); auto& vec = res.vec().elems; if (!deli.length()) { for(auto i : s) { - vec.push_back(ngc.newstr(i)); + vec.push_back(ngc->newstr(i)); } - ngc.temp = nil; + ngc->temp = nil; return res; } usize last = 0; usize pos = s.find(deli, 0); while(pos!=std::string::npos) { if (pos>last) { - vec.push_back(ngc.newstr(s.substr(last, pos-last))); + vec.push_back(ngc->newstr(s.substr(last, pos-last))); } last = pos+deli.length(); pos = s.find(deli, last); } if (last!=s.length()) { - vec.push_back(ngc.newstr(s.substr(last))); + vec.push_back(ngc->newstr(s.substr(last))); } - ngc.temp = nil; + ngc->temp = nil; return res; } -var builtin_rand(var* local, gc& ngc) { - var val = local[1]; +var builtin_rand(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; if (val.type!=vm_num && val.type!=vm_nil) { return nas_err("rand", "\"seed\" must be nil or number"); } @@ -129,65 +133,65 @@ var builtin_rand(var* local, gc& ngc) { return var::num(num); } -var builtin_id(var* local, gc& ngc) { - var val = local[1]; +var builtin_id(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; std::stringstream ss; ss << "0"; if (val.type>vm_num) { ss << "x" << std::hex; ss << reinterpret_cast(val.val.gcobj) << std::dec; } - return ngc.newstr(ss.str()); + return ngc->newstr(ss.str()); } -var builtin_int(var* local, gc& ngc) { - var val = local[1]; +var builtin_int(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; if (val.type!=vm_num && val.type!=vm_str) { return nil; } return var::num(static_cast(static_cast(val.to_num()))); } -var builtin_floor(var* local, gc& ngc) { - var val = local[1]; - return var::num(std::floor(val.num())); +var builtin_floor(context* ctx, gc* ngc) { + auto value = ctx->localr[1]; + return var::num(std::floor(value.num())); } -var builtin_num(var* local, gc& ngc) { - var val = local[1]; +var builtin_num(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; if (val.type==vm_num) { return val; } if (val.type!=vm_str) { return nil; } - f64 res = val.to_num(); + auto res = val.to_num(); if (std::isnan(res)) { return nil; } return var::num(res); } -var builtin_pop(var* local, gc& ngc) { - var val = local[1]; +var builtin_pop(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; if (val.type!=vm_vec) { return nas_err("pop", "\"vec\" must be vector"); } auto& vec = val.vec().elems; if (vec.size()) { - var tmp = vec.back(); + auto tmp = vec.back(); vec.pop_back(); return tmp; } return nil; } -var builtin_str(var* local, gc& ngc) { - return ngc.newstr(local[1].to_str()); +var builtin_str(context* ctx, gc* ngc) { + return ngc->newstr(ctx->localr[1].to_str()); } -var builtin_size(var* local, gc& ngc) { - var val = local[1]; +var builtin_size(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; f64 num = 0; switch(val.type) { case vm_num: num = val.num(); break; @@ -199,16 +203,17 @@ var builtin_size(var* local, gc& ngc) { return var::num(num); } -var builtin_time(var* local, gc& ngc) { - var val = local[1]; +var builtin_time(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; if (val.type!=vm_num) { return nas_err("time", "\"begin\" must be number"); } - time_t begin = (time_t)val.num(); + auto begin = static_cast(val.num()); return var::num(static_cast(time(&begin))); } -var builtin_contains(var* local, gc& ngc) { +var builtin_contains(context* ctx, gc* ngc) { + auto local = ctx->localr; var hash = local[1]; var key = local[2]; if (hash.type!=vm_hash || key.type!=vm_str) { @@ -217,7 +222,8 @@ var builtin_contains(var* local, gc& ngc) { return hash.hash().elems.count(key.str())? one:zero; } -var builtin_delete(var* local, gc& ngc) { +var builtin_delete(context* ctx, gc* ngc) { + auto local = ctx->localr; var hash = local[1]; var key = local[2]; if (hash.type!=vm_hash) { @@ -232,32 +238,33 @@ var builtin_delete(var* local, gc& ngc) { return nil; } -var builtin_keys(var* local, gc& ngc) { - var hash = local[1]; +var builtin_keys(context* ctx, gc* ngc) { + auto hash = ctx->localr[1]; if (hash.type!=vm_hash && hash.type!=vm_map) { return nas_err("keys", "\"hash\" must be hash"); } // avoid being sweeped - var res = ngc.temp = ngc.alloc(vm_vec); + auto res = ngc->temp = ngc->alloc(vm_vec); auto& vec = res.vec().elems; if (hash.type==vm_hash) { for(const auto& iter : hash.hash().elems) { - vec.push_back(ngc.newstr(iter.first)); + vec.push_back(ngc->newstr(iter.first)); } } else { for(const auto& iter : hash.map().mapper) { - vec.push_back(ngc.newstr(iter.first)); + vec.push_back(ngc->newstr(iter.first)); } } - ngc.temp=nil; + ngc->temp=nil; return res; } -var builtin_die(var* local, gc& ngc) { - return nas_err("error", local[1].to_str()); +var builtin_die(context* ctx, gc* ngc) { + return nas_err("error", ctx->localr[1].to_str()); } -var builtin_find(var* local, gc& ngc) { +var builtin_find(context* ctx, gc* ngc) { + auto local = ctx->localr; var needle = local[1]; var haystack = local[2]; usize pos = haystack.to_str().find(needle.to_str()); @@ -267,23 +274,24 @@ var builtin_find(var* local, gc& ngc) { return var::num(static_cast(pos)); } -var builtin_type(var* local, gc& ngc) { - switch(local[1].type) { - case vm_none: return ngc.newstr("undefined"); - case vm_nil: return ngc.newstr("nil"); - case vm_num: return ngc.newstr("num"); - case vm_str: return ngc.newstr("str"); - case vm_vec: return ngc.newstr("vec"); - case vm_hash: return ngc.newstr("hash"); - case vm_func: return ngc.newstr("func"); - case vm_obj: return ngc.newstr("obj"); - case vm_co: return ngc.newstr("coroutine"); - case vm_map: return ngc.newstr("namespace"); +var builtin_type(context* ctx, gc* ngc) { + switch(ctx->localr[1].type) { + case vm_none: return ngc->newstr("undefined"); + case vm_nil: return ngc->newstr("nil"); + case vm_num: return ngc->newstr("num"); + case vm_str: return ngc->newstr("str"); + case vm_vec: return ngc->newstr("vec"); + case vm_hash: return ngc->newstr("hash"); + case vm_func: return ngc->newstr("func"); + case vm_obj: return ngc->newstr("obj"); + case vm_co: return ngc->newstr("coroutine"); + case vm_map: return ngc->newstr("namespace"); } return nil; } -var builtin_substr(var* local, gc& ngc) { +var builtin_substr(context* ctx, gc* ngc) { + auto local = ctx->localr; var str = local[1]; var beg = local[2]; var len = local[3]; @@ -301,10 +309,11 @@ var builtin_substr(var* local, gc& ngc) { if (begin>=str.str().length()) { return nas_err("susbtr", "begin index out of range: "+std::to_string(begin)); } - return ngc.newstr(str.str().substr(begin,length)); + return ngc->newstr(str.str().substr(begin,length)); } -var builtin_streq(var* local, gc& ngc) { +var builtin_streq(context* ctx, gc* ngc) { + auto local = ctx->localr; var a = local[1]; var b = local[2]; return var::num(static_cast( @@ -312,7 +321,8 @@ var builtin_streq(var* local, gc& ngc) { )); } -var builtin_left(var* local, gc& ngc) { +var builtin_left(context* ctx, gc* ngc) { + auto local = ctx->localr; var str = local[1]; var len = local[2]; if (str.type!=vm_str) { @@ -322,12 +332,13 @@ var builtin_left(var* local, gc& ngc) { return nas_err("left", "\"length\" must be number"); } if (len.num()<0) { - return ngc.newstr(""); + return ngc->newstr(""); } - return ngc.newstr(str.str().substr(0, len.num())); + return ngc->newstr(str.str().substr(0, len.num())); } -var builtin_right(var* local, gc& ngc) { +var builtin_right(context* ctx, gc* ngc) { + auto local = ctx->localr; var str = local[1]; var len = local[2]; if (str.type!=vm_str) { @@ -344,10 +355,11 @@ var builtin_right(var* local, gc& ngc) { if (length<0) { length = 0; } - return ngc.newstr(str.str().substr(srclen-length, srclen)); + return ngc->newstr(str.str().substr(srclen-length, srclen)); } -var builtin_cmp(var* local, gc& ngc) { +var builtin_cmp(context* ctx, gc* ngc) { + auto local = ctx->localr; var a = local[1]; var b = local[2]; if (a.type!=vm_str || b.type!=vm_str) { @@ -359,7 +371,7 @@ var builtin_cmp(var* local, gc& ngc) { ))); } -var builtin_chr(var* local, gc& ngc) { +var builtin_chr(context* ctx, gc* ngc) { const char* extend[] = { "€"," ","‚","ƒ","„","…","†","‡", "ˆ","‰","Š","‹","Œ"," ","Ž"," ", @@ -378,25 +390,25 @@ var builtin_chr(var* local, gc& ngc) { "ð","ñ","ò","ó","ô","õ","ö","÷", "ø","ù","ú","û","ü","ý","þ","ÿ" }; - i32 num = local[1].num(); + auto num = static_cast(ctx->localr[1].num()); if (0<=num && num<128) { - return ngc.newstr((char)num); + return ngc->newstr((char)num); } else if (128<=num && num<256) { - return ngc.newstr(extend[num-128]); + return ngc->newstr(extend[num-128]); } - return ngc.newstr(" "); + return ngc->newstr(" "); } -var builtin_char(var* local, gc& ngc) { - return ngc.newstr((unsigned char)local[1].num()); +var builtin_char(context* ctx, gc* ngc) { + return ngc->newstr(static_cast(ctx->localr[1].num())); } -var builtin_values(var* local, gc& ngc) { - var hash = local[1]; +var builtin_values(context* ctx, gc* ngc) { + auto hash = ctx->localr[1]; if (hash.type!=vm_hash) { return nas_err("values", "\"hash\" must be hash"); } - var vec = ngc.alloc(vm_vec); + var vec = ngc->alloc(vm_vec); auto& v = vec.vec().elems; for(auto& i : hash.hash().elems) { v.push_back(i.second); @@ -404,8 +416,8 @@ var builtin_values(var* local, gc& ngc) { return vec; } -var builtin_sleep(var* local, gc& ngc) { - var val = local[1]; +var builtin_sleep(context* ctx, gc* ngc) { + auto val = ctx->localr[1]; if (val.type!=vm_num) { return nil; } @@ -421,36 +433,36 @@ var builtin_sleep(var* local, gc& ngc) { return nil; } -var builtin_platform(var* local, gc& ngc) { +var builtin_platform(context* ctx, gc* ngc) { if (is_windows()) { - return ngc.newstr("windows"); + return ngc->newstr("windows"); } else if (is_linux()) { - return ngc.newstr("linux"); + return ngc->newstr("linux"); } else if (is_macos()) { - return ngc.newstr("macOS"); + return ngc->newstr("macOS"); } - return ngc.newstr("unknown"); + return ngc->newstr("unknown"); } -var builtin_arch(var* local, gc& ngc) { +var builtin_arch(context* ctx, gc* ngc) { if (is_x86()) { - return ngc.newstr("x86"); + return ngc->newstr("x86"); } else if (is_x86_64()) { - return ngc.newstr("x86-64"); + return ngc->newstr("x86-64"); } else if (is_amd64()) { - return ngc.newstr("amd64"); + return ngc->newstr("amd64"); } else if (is_arm()) { - return ngc.newstr("arm"); + return ngc->newstr("arm"); } else if (is_aarch64()) { - return ngc.newstr("aarch64"); + return ngc->newstr("aarch64"); } else if (is_ia64()) { - return ngc.newstr("ia64"); + return ngc->newstr("ia64"); } else if (is_powerpc()) { - return ngc.newstr("powerpc"); + return ngc->newstr("powerpc"); } else if (is_superh()) { - return ngc.newstr("superh"); + return ngc->newstr("superh"); } - return ngc.newstr("unknown"); + return ngc->newstr("unknown"); } // md5 related functions @@ -536,64 +548,64 @@ std::string md5(const std::string& src) { return tohex(atmp)+tohex(btmp)+tohex(ctmp)+tohex(dtmp); } -var builtin_md5(var* local, gc& ngc) { - var str = local[1]; +var builtin_md5(context* ctx, gc* ngc) { + auto str = ctx->localr[1]; if (str.type!=vm_str) { return nas_err("md5", "\"str\" must be string"); } - return ngc.newstr(md5(str.str())); + return ngc->newstr(md5(str.str())); } -var builtin_millisec(var* local, gc& ngc) { +var builtin_millisec(context* ctx, gc* ngc) { f64 res = std::chrono::duration_cast (std::chrono::high_resolution_clock::now().time_since_epoch()) .count(); return var::num(res); } -var builtin_gcextend(var* local, gc& ngc) { - var type = local[1]; +var builtin_gcextend(context* ctx, gc* ngc) { + auto type = ctx->localr[1]; if (type.type!=vm_str) { return nil; } - auto& s = type.str(); + const auto& s = type.str(); if (s=="str") { - ngc.extend(vm_str); + ngc->extend(vm_str); } else if (s=="vec") { - ngc.extend(vm_vec); + ngc->extend(vm_vec); } else if (s=="hash") { - ngc.extend(vm_hash); + ngc->extend(vm_hash); } else if (s=="func") { - ngc.extend(vm_func); + ngc->extend(vm_func); } else if (s=="upval") { - ngc.extend(vm_upval); + ngc->extend(vm_upval); } else if (s=="obj") { - ngc.extend(vm_obj); + ngc->extend(vm_obj); } else if (s=="co") { - ngc.extend(vm_co); + ngc->extend(vm_co); } return nil; } -var builtin_gcinfo(var* local, gc& ngc) { +var builtin_gcinfo(context* ctx, gc* ngc) { auto den = std::chrono::high_resolution_clock::duration::period::den; - var res = ngc.alloc(vm_hash); + var res = ngc->alloc(vm_hash); double total = 0; for(u32 i = 0; igcnt[i]; } // using ms auto& map = res.hash().elems; - map["total"] = var::num(ngc.worktime*1.0/den*1000); - map["average"] = var::num(ngc.worktime*1.0/den*1000/total); - map["max_gc"] = var::num(ngc.max_time*1.0/den*1000); - map["max_mark"] = var::num(ngc.max_mark_time*1.0/den*1000); - map["max_sweep"] = var::num(ngc.max_sweep_time*1.0/den*1000); + map["total"] = var::num(ngc->worktime*1.0/den*1000); + map["average"] = var::num(ngc->worktime*1.0/den*1000/total); + map["max_gc"] = var::num(ngc->max_time*1.0/den*1000); + map["max_mark"] = var::num(ngc->max_mark_time*1.0/den*1000); + map["max_sweep"] = var::num(ngc->max_sweep_time*1.0/den*1000); return res; } -var builtin_logtime(var* local, gc& ngc) { +var builtin_logtime(context* ctx, gc* ngc) { time_t t = time(nullptr); tm* tm_t = localtime(&t); char s[64]; @@ -606,11 +618,11 @@ var builtin_logtime(var* local, gc& ngc) { tm_t->tm_min, tm_t->tm_sec ); - return ngc.newstr(s); + return ngc->newstr(s); } -var builtin_ghosttype(var* local, gc& ngc) { - var arg = local[1]; +var builtin_ghosttype(context* ctx, gc* ngc) { + auto arg = ctx->localr[1]; if (arg.type!=vm_obj) { return nas_err("ghosttype", "this is not a ghost object."); } @@ -618,7 +630,7 @@ var builtin_ghosttype(var* local, gc& ngc) { if (!name.length()) { return var::num(reinterpret_cast(arg.obj().pointer)); } - return ngc.newstr(name); + return ngc->newstr(name); } nasal_builtin_table builtin[] = { diff --git a/src/nasal_builtin.h b/src/nasal_builtin.h index cf7d6ea..00f0878 100644 --- a/src/nasal_builtin.h +++ b/src/nasal_builtin.h @@ -29,56 +29,56 @@ namespace nasal { -var builtin_print(var*, gc&); -var builtin_println(var*, gc&); -var builtin_exit(var*, gc&); -var builtin_abort(var*, gc&); -var builtin_append(var*, gc&); -var builtin_setsize(var*, gc&); -var builtin_system(var*, gc&); -var builtin_input(var*, gc&); -var builtin_split(var*, gc&); -var builtin_rand(var*, gc&); -var builtin_id(var*, gc&); -var builtin_int(var*, gc&); -var builtin_floor(var*, gc&); -var builtin_num(var*, gc&); -var builtin_pop(var*, gc&); -var builtin_str(var*, gc&); -var builtin_size(var*, gc&); -var builtin_time(var*, gc&); -var builtin_contains(var*, gc&); -var builtin_delete(var*, gc&); -var builtin_keys(var*, gc&); -var builtin_die(var*, gc&); -var builtin_find(var*, gc&); -var builtin_type(var*, gc&); -var builtin_substr(var*, gc&); -var builtin_streq(var*, gc&); -var builtin_left(var*, gc&); -var builtin_right(var*, gc&); -var builtin_cmp(var*, gc&); -var builtin_chr(var*, gc&); -var builtin_char(var*, gc&); -var builtin_values(var*, gc&); -var builtin_sleep(var*, gc&); -var builtin_platform(var*, gc&); -var builtin_arch(var*, gc&); +var builtin_print(context*, gc*); +var builtin_println(context*, gc*); +var builtin_exit(context*, gc*); +var builtin_abort(context*, gc*); +var builtin_append(context*, gc*); +var builtin_setsize(context*, gc*); +var builtin_system(context*, gc*); +var builtin_input(context*, gc*); +var builtin_split(context*, gc*); +var builtin_rand(context*, gc*); +var builtin_id(context*, gc*); +var builtin_int(context*, gc*); +var builtin_floor(context*, gc*); +var builtin_num(context*, gc*); +var builtin_pop(context*, gc*); +var builtin_str(context*, gc*); +var builtin_size(context*, gc*); +var builtin_time(context*, gc*); +var builtin_contains(context*, gc*); +var builtin_delete(context*, gc*); +var builtin_keys(context*, gc*); +var builtin_die(context*, gc*); +var builtin_find(context*, gc*); +var builtin_type(context*, gc*); +var builtin_substr(context*, gc*); +var builtin_streq(context*, gc*); +var builtin_left(context*, gc*); +var builtin_right(context*, gc*); +var builtin_cmp(context*, gc*); +var builtin_chr(context*, gc*); +var builtin_char(context*, gc*); +var builtin_values(context*, gc*); +var builtin_sleep(context*, gc*); +var builtin_platform(context*, gc*); +var builtin_arch(context*, gc*); // md5 related functions std::string tohex(u32); std::string md5(const std::string&); -var builtin_md5(var*, gc&); -var builtin_millisec(var*, gc&); -var builtin_gcextend(var*, gc&); -var builtin_gcinfo(var*, gc&); -var builtin_logtime(var*, gc&); -var builtin_ghosttype(var*, gc&); +var builtin_md5(context*, gc*); +var builtin_millisec(context*, gc*); +var builtin_gcextend(context*, gc*); +var builtin_gcinfo(context*, gc*); +var builtin_logtime(context*, gc*); +var builtin_ghosttype(context*, gc*); // register builtin function's name and it's address here in this table below // this table must end with {nullptr,nullptr} struct nasal_builtin_table { const char* name; - var (*func)(var*, gc&); + var (*func)(context*, gc*); }; extern nasal_builtin_table builtin[]; diff --git a/src/nasal_vm.h b/src/nasal_vm.h index cb8f985..481627c 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -821,11 +821,12 @@ inline void vm::o_callb() { // if running a native function about coroutine // (top) will be set to another context.top, instead of main_context.top - var tmp = (*native_function[imm[ctx.pc]].func)(ctx.localr, ngc); + auto function_pointer = native_function[imm[ctx.pc]].func; + var result = (*function_pointer)(&ctx, &ngc); // so we use tmp variable to store this return value // and set it to top[0] later - ctx.top[0] = tmp; + ctx.top[0] = result; // if get none, this means errors occurred when calling this native function if (ctx.top[0].type==vm_none) { diff --git a/src/unix_lib.cpp b/src/unix_lib.cpp index dbd64d9..32e5f5f 100644 --- a/src/unix_lib.cpp +++ b/src/unix_lib.cpp @@ -12,130 +12,130 @@ void dir_entry_destructor(void* ptr) { #endif } -var builtin_pipe(var* local, gc& ngc) { +var builtin_pipe(context* ctx, gc* ngc) { #ifndef _WIN32 i32 fd[2]; - var res = ngc.alloc(vm_vec); + var res = ngc->alloc(vm_vec); if (pipe(fd)==-1) { - return nas_err("pipe", "failed to create pipe"); + return nas_err("unix::pipe", "failed to create pipe"); } res.vec().elems.push_back(var::num(static_cast(fd[0]))); res.vec().elems.push_back(var::num(static_cast(fd[1]))); return res; #endif - return nas_err("pipe", "not supported on windows"); + return nas_err("unix::pipe", "not supported on windows"); } -var builtin_fork(var* local, gc& ngc) { +var builtin_fork(context* ctx, gc* ngc) { #ifndef _WIN32 f64 res=fork(); if (res<0) { - return nas_err("fork", "failed to fork a process"); + return nas_err("unix::fork", "failed to fork a process"); } return var::num(static_cast(res)); #endif - return nas_err("fork", "not supported on windows"); + return nas_err("unix::fork", "not supported on windows"); } -var builtin_waitpid(var* local, gc& ngc) { - var pid = local[1]; - var nohang = local[2]; +var builtin_waitpid(context* ctx, gc* ngc) { + auto pid = ctx->localr[1]; + auto nohang = ctx->localr[2]; if (pid.type!=vm_num || nohang.type!=vm_num) { - return nas_err("waitpid", "pid and nohang must be number"); + return nas_err("unix::waitpid", "pid and nohang must be number"); } #ifndef _WIN32 i32 ret_pid, status; ret_pid = waitpid(pid.num(), &status, nohang.num()==0? 0:WNOHANG); - var vec = ngc.alloc(vm_vec); + var vec = ngc->alloc(vm_vec); vec.vec().elems.push_back(var::num(static_cast(ret_pid))); vec.vec().elems.push_back(var::num(static_cast(status))); return vec; #endif - return nas_err("waitpid", "not supported on windows"); + return nas_err("unix::waitpid", "not supported on windows"); } -var builtin_opendir(var* local, gc& ngc) { - var path = local[1]; +var builtin_opendir(context* ctx, gc* ngc) { + auto path = ctx->localr[1]; if (path.type!=vm_str) { - return nas_err("opendir", "\"path\" must be string"); + return nas_err("unix::opendir", "\"path\" must be string"); } #ifdef _MSC_VER WIN32_FIND_DATAA data; HANDLE p; p = FindFirstFileA((path.str()+"\\*.*").c_str(), &data); if (p==INVALID_HANDLE_VALUE) { - return nas_err("opendir", "cannot open dir <"+path.str()+">"); + return nas_err("unix::opendir", "cannot open dir <"+path.str()+">"); } #else DIR* p = opendir(path.str().c_str()); if (!p) { - return nas_err("opendir", "cannot open dir <"+path.str()+">"); + return nas_err("unix::opendir", "cannot open dir <"+path.str()+">"); } #endif - var ret = ngc.alloc(vm_obj); + var ret = ngc->alloc(vm_obj); ret.obj().set(dir_type_name, dir_entry_destructor, p); return ret; } -var builtin_readdir(var* local, gc& ngc) { - var handle = local[1]; +var builtin_readdir(context* ctx, gc* ngc) { + auto handle = ctx->localr[1]; if (!handle.object_check(dir_type_name)) { - return nas_err("readdir", "not a valid dir handle"); + return nas_err("unix::readdir", "not a valid dir handle"); } #ifdef _MSC_VER WIN32_FIND_DATAA data; if (!FindNextFileA(handle.obj().pointer, &data)) { return nil; } - return ngc.newstr(data.cFileName); + return ngc->newstr(data.cFileName); #else dirent* p = readdir(static_cast(handle.obj().pointer)); - return p? ngc.newstr(p->d_name):nil; + return p? ngc->newstr(p->d_name):nil; #endif } -var builtin_closedir(var* local, gc& ngc) { - var handle = local[1]; +var builtin_closedir(context* ctx, gc* ngc) { + auto handle = ctx->localr[1]; if (!handle.object_check(dir_type_name)) { - return nas_err("closedir", "not a valid dir handle"); + return nas_err("unix::closedir", "not a valid dir handle"); } handle.obj().clear(); return nil; } -var builtin_chdir(var* local, gc& ngc) { - var path = local[1]; +var builtin_chdir(context* ctx, gc* ngc) { + auto path = ctx->localr[1]; if (path.type!=vm_str) { return var::num(-1.0); } return var::num(static_cast(chdir(path.str().c_str()))); } -var builtin_environ(var* local, gc& ngc) { - var res = ngc.temp = ngc.alloc(vm_vec); +var builtin_environ(context* ctx, gc* ngc) { + var res = ngc->temp = ngc->alloc(vm_vec); auto& vec = res.vec().elems; for(char** env = environ; *env; ++env) { - vec.push_back(ngc.newstr(*env)); + vec.push_back(ngc->newstr(*env)); } - ngc.temp = nil; + ngc->temp = nil; return res; } -var builtin_getcwd(var* local, gc& ngc) { +var builtin_getcwd(context* ctx, gc* ngc) { char buf[1024]; if (!getcwd(buf, sizeof(buf))) { return nil; } - return ngc.newstr(buf); + return ngc->newstr(buf); } -var builtin_getenv(var* local, gc& ngc) { - var envvar = local[1]; +var builtin_getenv(context* ctx, gc* ngc) { + auto envvar = ctx->localr[1]; if (envvar.type!=vm_str) { - return nas_err("getenv", "\"envvar\" must be string"); + return nas_err("unix::getenv", "\"envvar\" must be string"); } char* res = getenv(envvar.str().c_str()); - return res? ngc.newstr(res):nil; + return res? ngc->newstr(res):nil; } nasal_builtin_table unix_lib_native[] = { diff --git a/src/unix_lib.h b/src/unix_lib.h index 06205f6..bc9f5cc 100644 --- a/src/unix_lib.h +++ b/src/unix_lib.h @@ -24,16 +24,16 @@ namespace nasal { void dir_entry_destructor(void*); -var builtin_pipe(var*, gc&); -var builtin_fork(var*, gc&); -var builtin_waitpid(var*, gc&); -var builtin_opendir(var*, gc&); -var builtin_readdir(var*, gc&); -var builtin_closedir(var*, gc&); -var builtin_chdir(var*, gc&); -var builtin_environ(var*, gc&); -var builtin_getcwd(var*, gc&); -var builtin_getenv(var*, gc&); +var builtin_pipe(context*, gc*); +var builtin_fork(context*, gc*); +var builtin_waitpid(context*, gc*); +var builtin_opendir(context*, gc*); +var builtin_readdir(context*, gc*); +var builtin_closedir(context*, gc*); +var builtin_chdir(context*, gc*); +var builtin_environ(context*, gc*); +var builtin_getcwd(context*, gc*); +var builtin_getenv(context*, gc*); extern nasal_builtin_table unix_lib_native[]; From dfcccd4523716fbdfae3ab184a38fdeb8f36e939 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sat, 21 Oct 2023 18:00:11 +0800 Subject: [PATCH 10/18] :bug: fix invalid debug mode problem --- src/nasal_dbg.cpp | 9 +++++---- test/flush_screen.nas | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/nasal_dbg.cpp b/src/nasal_dbg.cpp index 491a2e1..fd0ac51 100644 --- a/src/nasal_dbg.cpp +++ b/src/nasal_dbg.cpp @@ -181,10 +181,10 @@ void dbg::interact() { if (do_profiling) { return; } - - if ((bytecode[ctx.pc].fidx!=bk_fidx || - bytecode[ctx.pc].line!=bk_line) && // break point - !next) {// next step + + // is not break point and is not next stop command + const auto& code = bytecode[ctx.pc]; + if ((code.fidx!=bk_fidx || code.line!=bk_line) && !next) { return; } @@ -240,6 +240,7 @@ void dbg::run( set_detail_report_info(true); do_profiling = profile || show_all_prof_result; + next = true; const auto& file_list = linker.get_file_list(); fsize = file_list.size(); diff --git a/test/flush_screen.nas b/test/flush_screen.nas index 18e064d..231bfda 100644 --- a/test/flush_screen.nas +++ b/test/flush_screen.nas @@ -24,5 +24,5 @@ while(1) { res ~= "\n"; } print(res); - unix.sleep(1/30); -} \ No newline at end of file + unix.sleep(1/20); +} From 1e1ab37e8375335d352b8f57a288b4c9f472afb6 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sat, 21 Oct 2023 18:13:52 +0800 Subject: [PATCH 11/18] :sparkles: values can get data from namespace type --- src/nasal_builtin.cpp | 16 +++++++++++----- src/nasal_dbg.cpp | 18 +++++++++++++----- src/nasal_dbg.h | 2 +- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/nasal_builtin.cpp b/src/nasal_builtin.cpp index 499e92c..3f8eab8 100644 --- a/src/nasal_builtin.cpp +++ b/src/nasal_builtin.cpp @@ -405,13 +405,19 @@ var builtin_char(context* ctx, gc* ngc) { var builtin_values(context* ctx, gc* ngc) { auto hash = ctx->localr[1]; - if (hash.type!=vm_hash) { - return nas_err("values", "\"hash\" must be hash"); + if (hash.type!=vm_hash && hash.type!=vm_map) { + return nas_err("values", "\"hash\" must be hash or namespace"); } - var vec = ngc->alloc(vm_vec); + auto vec = ngc->alloc(vm_vec); auto& v = vec.vec().elems; - for(auto& i : hash.hash().elems) { - v.push_back(i.second); + if (hash.type==vm_hash) { + for(auto& i : hash.hash().elems) { + v.push_back(i.second); + } + } else { + for(auto& i : hash.map().mapper) { + v.push_back(*i.second); + } } return vec; } diff --git a/src/nasal_dbg.cpp b/src/nasal_dbg.cpp index fd0ac51..a4715cc 100644 --- a/src/nasal_dbg.cpp +++ b/src/nasal_dbg.cpp @@ -200,7 +200,10 @@ void dbg::interact() { } else if (res.size()==1) { switch(get_cmd_type(res[0])) { case dbg_cmd::cmd_help: help(); break; - case dbg_cmd::cmd_backtrace: trace_back(); break; + case dbg_cmd::cmd_backtrace: + function_call_trace(); + trace_back(); + break; case dbg_cmd::cmd_continue: return; case dbg_cmd::cmd_list_file: list_file(); break; case dbg_cmd::cmd_global: global_state(); break; @@ -240,13 +243,18 @@ void dbg::run( set_detail_report_info(true); do_profiling = profile || show_all_prof_result; - next = true; const auto& file_list = linker.get_file_list(); fsize = file_list.size(); - init(gen.strs(), gen.nums(), gen.natives(), - gen.codes(), gen.globals(), - file_list, argv); + init( + gen.strs(), + gen.nums(), + gen.natives(), + gen.codes(), + gen.globals(), + file_list, + argv + ); data.init(file_list); std::vector code; diff --git a/src/nasal_dbg.h b/src/nasal_dbg.h index 397bb7f..d351c61 100644 --- a/src/nasal_dbg.h +++ b/src/nasal_dbg.h @@ -158,7 +158,7 @@ private: public: dbg(): - next(false), fsize(0), + next(true), fsize(0), bk_fidx(0), bk_line(0), do_profiling(false) {} void run( From 9629108a1ea0f8f33163e3eb1089a4989baada65 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 22 Oct 2023 23:45:10 +0800 Subject: [PATCH 12/18] :zap: improve readability of some codes --- module/fib.cpp | 8 +- src/bits_lib.cpp | 22 ++--- src/coroutine.cpp | 4 +- src/dylib_lib.cpp | 143 +++++++++++++++++-------------- src/dylib_lib.h | 3 +- src/fg_props.cpp | 11 ++- src/io_lib.cpp | 191 +++++++++++++++++++++--------------------- src/nasal_ast.h | 70 ++++++++-------- src/nasal_builtin.cpp | 4 +- src/nasal_dbg.cpp | 10 +-- src/nasal_dbg.h | 8 +- src/nasal_gc.cpp | 8 +- src/nasal_gc.h | 4 +- src/nasal_import.cpp | 93 +++++++++++++------- src/nasal_opcode.cpp | 24 +++--- src/nasal_opcode.h | 4 +- src/nasal_type.cpp | 70 ++++++++-------- src/nasal_type.h | 12 +-- src/nasal_vm.cpp | 10 +-- src/nasal_vm.h | 2 +- src/unix_lib.cpp | 8 +- test/flush_screen.nas | 2 +- 22 files changed, 386 insertions(+), 325 deletions(-) diff --git a/module/fib.cpp b/module/fib.cpp index 1bb9046..529d77b 100644 --- a/module/fib.cpp +++ b/module/fib.cpp @@ -53,7 +53,7 @@ void ghost_for_test_destructor(void* ptr) { var create_new_ghost(var* args, usize size, gc* ngc) { var res = ngc->alloc(vm_obj); - res.obj().set(ghost_for_test, ghost_for_test_destructor, new u32); + res.ghost().set(ghost_for_test, ghost_for_test_destructor, new u32); return res; } @@ -64,7 +64,7 @@ var set_new_ghost(var* args, usize size, gc* ngc) { return nil; } f64 num = args[1].num(); - *((u32*)res.obj().pointer) = static_cast(num); + *((u32*)res.ghost().pointer) = static_cast(num); std::cout << "set_new_ghost: successfully set ghost = " << num << "\n"; return nil; } @@ -75,8 +75,8 @@ var print_new_ghost(var* args, usize size, gc* ngc) { std::cout << "print_new_ghost: not ghost for test type.\n"; return nil; } - std::cout << "print_new_ghost: " << res.obj() << " result = " - << *((u32*)res.obj().pointer) << "\n"; + std::cout << "print_new_ghost: " << res.ghost() << " result = " + << *((u32*)res.ghost().pointer) << "\n"; return nil; } diff --git a/src/bits_lib.cpp b/src/bits_lib.cpp index 95639b9..4ca0455 100644 --- a/src/bits_lib.cpp +++ b/src/bits_lib.cpp @@ -49,15 +49,15 @@ var builtin_fld(context* ctx, gc* ngc) { auto startbit = local[2]; auto length = local[3]; if (str.type!=vm_str || str.val.gcobj->unmutable) { - return nas_err("fld", "\"str\" must be mutable string"); + return nas_err("bits::fld", "\"str\" must be mutable string"); } if (startbit.type!=vm_num || length.type!=vm_num) { - return nas_err("fld", "\"startbit\",\"len\" must be number"); + return nas_err("bits::fld", "\"startbit\",\"len\" must be number"); } u32 bit = static_cast(startbit.num()); u32 len = static_cast(length.num()); if (bit+len>8*str.str().length()) { - return nas_err("fld", "bitfield out of bounds"); + return nas_err("bits::fld", "bitfield out of bounds"); } u32 res = 0; auto& s = str.str(); @@ -79,15 +79,15 @@ var builtin_sfld(context* ctx, gc* ngc) { auto startbit = local[2]; auto length = local[3]; if (str.type!=vm_str || str.val.gcobj->unmutable) { - return nas_err("sfld", "\"str\" must be mutable string"); + return nas_err("bits::sfld", "\"str\" must be mutable string"); } if (startbit.type!=vm_num || length.type!=vm_num) { - return nas_err("sfld", "\"startbit\",\"len\" must be number"); + return nas_err("bits::sfld", "\"startbit\",\"len\" must be number"); } u32 bit = static_cast(startbit.num()); u32 len = static_cast(length.num()); if (bit+len>8*str.str().length()) { - return nas_err("sfld", "bitfield out of bounds"); + return nas_err("bits::sfld", "bitfield out of bounds"); } u32 res = 0; auto& s = str.str(); @@ -113,16 +113,18 @@ var builtin_setfld(context* ctx, gc* ngc) { auto length = local[3]; auto value = local[4]; if (str.type!=vm_str || str.val.gcobj->unmutable) { - return nas_err("setfld", "\"str\" must be mutable string"); + return nas_err("bits::setfld", "\"str\" must be mutable string"); } if (startbit.type!=vm_num || length.type!=vm_num || value.type!=vm_num) { - return nas_err("setfld", "\"startbit\",\"len\",\"val\" must be number"); + return nas_err("bits::setfld", + "\"startbit\", \"len\", \"val\" must be number" + ); } u32 bit = static_cast(startbit.num()); u32 len = static_cast(length.num()); u64 val = static_cast(value.num()); if (bit+len>8*str.str().length()) { - return nas_err("setfld", "bitfield out of bounds"); + return nas_err("bits::setfld", "bitfield out of bounds"); } auto& s = str.str(); for(u32 i = bit; ilocalr[1]; if (length.type!=vm_num || length.num()<=0) { - return nas_err("buf", "\"len\" must be number greater than 0"); + return nas_err("bits::buf", "\"len\" must be number greater than 0"); } var str = ngc->alloc(vm_str); auto& s = str.str(); diff --git a/src/coroutine.cpp b/src/coroutine.cpp index 5603656..c0f5003 100644 --- a/src/coroutine.cpp +++ b/src/coroutine.cpp @@ -75,7 +75,7 @@ var builtin_coresume(context* ctx, gc* ngc) { } // change to coroutine context - ngc->ctxchg(coroutine_object.co()); + ngc->context_change(&coroutine_object.co()); // fetch coroutine's stack top and return // then coroutine's stack top will catch this return value @@ -103,7 +103,7 @@ var builtin_coyield(context* ctx, gc* ngc) { auto coroutine_local_frame = ctx->localr; // vm context will set to main context - ngc->ctxreserve(); + ngc->context_reserve(); // then this will return value to main's stack top[0] // the procedure seems like coroutine.resume returns the value diff --git a/src/dylib_lib.cpp b/src/dylib_lib.cpp index 6d26152..494466d 100644 --- a/src/dylib_lib.cpp +++ b/src/dylib_lib.cpp @@ -2,89 +2,108 @@ namespace nasal { -const auto dylib_type_name = "dylib"; -const auto func_addr_type_name = "faddr"; +const auto dynamic_library_type_name = "dylib"; +const auto function_address_type_name = "faddr"; -void dylib_destructor(void* ptr) { +void dynamic_library_destructor(void* pointer) { #ifdef _WIN32 - FreeLibrary(static_cast(ptr)); + FreeLibrary(static_cast(pointer)); #else - dlclose(ptr); + dlclose(pointer); #endif } -void func_addr_destructor(void* ptr) {} - var builtin_dlopen(context* ctx, gc* ngc) { auto dlname = ctx->localr[1]; if (dlname.type!=vm_str) { - return nas_err("dlopen", "\"libname\" must be string"); + return nas_err("dylib::dlopen", "\"libname\" must be string"); } -#ifdef _WIN32 - wchar_t* str = new wchar_t[dlname.str().size()+1]; - if (!str) { - return nas_err("dlopen", "malloc failed"); - } - memset(str, 0, sizeof(wchar_t)*dlname.str().size()+1); - mbstowcs(str, dlname.str().c_str(),dlname.str().size()+1); - void* ptr = LoadLibraryA(dlname.str().c_str()); - delete []str; -#else - void* ptr = dlopen(dlname.str().c_str(), RTLD_LOCAL|RTLD_LAZY); -#endif - if (!ptr) { - return nas_err("dlopen", "cannot open dynamic lib <"+dlname.str()+">"); - } - auto ret = ngc->temp = ngc->alloc(vm_hash); - auto lib = ngc->alloc(vm_obj); - lib.obj().set(dylib_type_name, dylib_destructor, ptr); - ret.hash().elems["lib"] = lib; + // get library pointer #ifdef _WIN32 - void* func = (void*)GetProcAddress( - static_cast(lib.obj().pointer), - "get" + wchar_t* wide_string = new wchar_t[dlname.str().size()+1]; + if (!wide_string) { + return nas_err("dylib::dlopen", "malloc failed"); + } + memset(wide_string, 0, sizeof(wchar_t) * dlname.str().size() + 1); + mbstowcs(wide_string, dlname.str().c_str(), dlname.str().size() + 1); + // load library by using wide string name + void* dynamic_library_pointer = LoadLibraryA(dlname.str().c_str()); + delete []wide_string; +#else + void* dynamic_library_pointer = dlopen( + dlname.str().c_str(), RTLD_LOCAL|RTLD_LAZY + ); +#endif + + // check library pointer and insert into returned hashmap + if (!dynamic_library_pointer) { + return nas_err("dylib::dlopen", + "cannot open dynamic lib <" + dlname.str() + ">" + ); + } + auto return_hash = ngc->temp = ngc->alloc(vm_hash); + auto library_object = ngc->alloc(vm_obj); + library_object.ghost().set( + dynamic_library_type_name, + dynamic_library_destructor, + dynamic_library_pointer + ); + return_hash.hash().elems["lib"] = library_object; + + // get "get" function, to get the register table +#ifdef _WIN32 + void* register_table_get_function = (void*)GetProcAddress( + static_cast(library_object.ghost().pointer), "get" ); #else - void* func = dlsym(lib.obj().pointer, "get"); + void* register_table_get_function = dlsym( + library_object.ghost().pointer, "get" + ); #endif - if (!func) { - return nas_err("dlopen", "cannot find function"); + if (!register_table_get_function) { + return nas_err("dylib::dlopen", "cannot find function"); } + // get function pointer by name - auto tbl = reinterpret_cast(func)(); - if (!tbl) { - return nas_err("dlopen", "failed to get module functions"); + auto table = reinterpret_cast(register_table_get_function)(); + if (!table) { + return nas_err("dylib::dlopen", "failed to get module functions"); } - for(u32 i = 0; tbl[i].name; ++i) { - void* p = (void*)tbl[i].fd; - var tmp = ngc->alloc(vm_obj); - tmp.obj().set(func_addr_type_name, func_addr_destructor, p); - ret.hash().elems[tbl[i].name] = tmp; + for(u32 i = 0; table[i].name; ++i) { + auto function_pointer = reinterpret_cast(table[i].fd); + auto function_object = ngc->alloc(vm_obj); + function_object.ghost().set( + function_address_type_name, + nullptr, + function_pointer + ); + return_hash.hash().elems[table[i].name] = function_object; } ngc->temp = nil; - return ret; + return return_hash; } var builtin_dlclose(context* ctx, gc* ngc) { - auto libptr = ctx->localr[1]; - if (!libptr.object_check(dylib_type_name)) { - return nas_err("dlclose", "\"lib\" is not a valid dynamic lib"); + auto library_pointer = ctx->localr[1]; + if (!library_pointer.object_check(dynamic_library_type_name)) { + return nas_err("dylib::dlclose", "\"lib\" is not a valid dynamic lib"); } - libptr.obj().clear(); + library_pointer.ghost().clear(); return nil; } var builtin_dlcallv(context* ctx, gc* ngc) { - auto local = ctx->localr; - auto fp = local[1]; - auto args = local[2]; - if (!fp.object_check(func_addr_type_name)) { - return nas_err("dlcall", "\"ptr\" is not a valid function pointer"); + auto function_object = ctx->localr[1]; + auto arguments = ctx->localr[2]; + if (!function_object.object_check(function_address_type_name)) { + return nas_err("dylib::dlcall", + "\"ptr\" is not a valid function pointer" + ); } - auto& vec = args.vec().elems; - return reinterpret_cast(fp.obj().pointer)( + auto& vec = arguments.vec().elems; + return reinterpret_cast(function_object.ghost().pointer)( vec.data(), vec.size(), ngc @@ -92,16 +111,18 @@ var builtin_dlcallv(context* ctx, gc* ngc) { } var builtin_dlcall(context* ctx, gc* ngc) { - auto local = ctx->localr; - var fp = local[1]; - if (!fp.object_check(func_addr_type_name)) { - return nas_err("dlcall", "\"ptr\" is not a valid function pointer"); + auto function_object = ctx->localr[1]; + if (!function_object.object_check(function_address_type_name)) { + return nas_err("dylib::dlcall", + "\"ptr\" is not a valid function pointer" + ); } - var* local_frame_start = local+2; - usize local_frame_size = ngc->running_context->top-local_frame_start; - // arguments' stored place begins at local +2 - return reinterpret_cast(fp.obj().pointer)( + // function pointer is at ctx->localr[1] + // so arguments starts from ctx->localr[2] + var* local_frame_start = ctx->localr + 2; + usize local_frame_size = ngc->running_context->top - local_frame_start; + return reinterpret_cast(function_object.ghost().pointer)( local_frame_start, local_frame_size, ngc diff --git a/src/dylib_lib.h b/src/dylib_lib.h index 7eed093..b379f9f 100644 --- a/src/dylib_lib.h +++ b/src/dylib_lib.h @@ -13,8 +13,7 @@ namespace nasal { -void dylib_destructor(void*); -void func_addr_destructor(void*); +void dynamic_library_destructor(void*); var builtin_dlopen(context*, gc*); var builtin_dlclose(context*, gc*); diff --git a/src/fg_props.cpp b/src/fg_props.cpp index 25ddf7e..8c5f371 100644 --- a/src/fg_props.cpp +++ b/src/fg_props.cpp @@ -9,7 +9,7 @@ var builtin_logprint(context* ctx, gc* ngc) { auto level = local[1]; auto elems = local[2]; if (elems.type!=vm_vec) { - return nas_err("logprint", "received argument is not vector."); + return nas_err("fg_env::logprint", "received argument is not vector."); } std::ofstream out("fgfs.log", std::ios::app); switch (static_cast(level.num())) { @@ -22,13 +22,12 @@ var builtin_logprint(context* ctx, gc* ngc) { case SG_DEV_ALERT: out << "[DEV_ALERT]"; break; case SG_MANDATORY_INFO: out << "[MANDATORY_INFO]"; break; default: - return nas_err("logprint", - "incorrect log level " + - std::to_string(level.num()) + return nas_err("fg_env::logprint", + "incorrect log level " + std::to_string(level.num()) ); } - for(auto& i : elems.vec().elems) { - out << i << " "; + for(auto& value : elems.vec().elems) { + out << value << " "; } out << "\n"; return nil; diff --git a/src/io_lib.cpp b/src/io_lib.cpp index 9fdd19a..848ba13 100644 --- a/src/io_lib.cpp +++ b/src/io_lib.cpp @@ -12,11 +12,11 @@ void filehandle_destructor(void* ptr) { } var builtin_readfile(context* ctx, gc* ngc) { - auto val = ctx->localr[1]; - if (val.type!=vm_str) { + auto filename = ctx->localr[1]; + if (filename.type!=vm_str) { return nas_err("io::readfile", "\"filename\" must be string"); } - std::ifstream in(val.str(), std::ios::binary); + std::ifstream in(filename.str(), std::ios::binary); std::stringstream rd; if (!in.fail()) { rd << in.rdbuf(); @@ -26,25 +26,25 @@ var builtin_readfile(context* ctx, gc* ngc) { var builtin_fout(context* ctx, gc* ngc) { auto local = ctx->localr; - auto val = local[1]; - auto str = local[2]; - if (val.type!=vm_str) { + auto filename = local[1]; + auto source = local[2]; + if (filename.type!=vm_str) { return nas_err("io::fout", "\"filename\" must be string"); } - std::ofstream out(val.str()); + std::ofstream out(filename.str()); if (out.fail()) { - return nas_err("io::fout", "cannot open <"+val.str()+">"); + return nas_err("io::fout", "cannot open <" + filename.str() + ">"); } - out << str; + out << source; return nil; } var builtin_exists(context* ctx, gc* ngc) { - auto local = ctx->localr; - if (local[1].type!=vm_str) { + auto filename = ctx->localr[1]; + if (filename.type!=vm_str) { return zero; } - return access(local[1].str().c_str(), F_OK)!=-1? one:zero; + return access(filename.str().c_str(), F_OK)!=-1? one:zero; } var builtin_open(context* ctx, gc* ngc) { @@ -52,118 +52,121 @@ var builtin_open(context* ctx, gc* ngc) { auto name = local[1]; auto mode = local[2]; if (name.type!=vm_str) { - return nas_err("open", "\"filename\" must be string"); + return nas_err("io::open", "\"filename\" must be string"); } if (mode.type!=vm_str) { - return nas_err("open", "\"mode\" must be string"); + return nas_err("io::open", "\"mode\" must be string"); } - FILE* res = fopen(name.str().c_str(), mode.str().c_str()); - if (!res) { - return nas_err("open", "failed to open file <"+name.str()+">"); + auto file_descriptor = fopen(name.str().c_str(), mode.str().c_str()); + if (!file_descriptor) { + return nas_err("io::open", "failed to open file <" + name.str() + ">"); } - var ret = ngc->alloc(vm_obj); - ret.obj().set(file_type_name, filehandle_destructor, res); - return ret; + var return_object = ngc->alloc(vm_obj); + return_object.ghost().set( + file_type_name, filehandle_destructor, file_descriptor + ); + return return_object; } var builtin_close(context* ctx, gc* ngc) { - var fd = ctx->localr[1]; - if (!fd.object_check(file_type_name)) { - return nas_err("close", "not a valid filehandle"); + var file_descriptor = ctx->localr[1]; + if (!file_descriptor.object_check(file_type_name)) { + return nas_err("io::close", "not a valid filehandle"); } - fd.obj().clear(); + file_descriptor.ghost().clear(); return nil; } var builtin_read(context* ctx, gc* ngc) { auto local = ctx->localr; - auto fd = local[1]; - auto buf = local[2]; - auto len = local[3]; - if (!fd.object_check(file_type_name)) { - return nas_err("read", "not a valid filehandle"); + auto file_descriptor = local[1]; + auto buffer = local[2]; + auto length = local[3]; + if (!file_descriptor.object_check(file_type_name)) { + return nas_err("io::read", "not a valid filehandle"); } - if (buf.type!=vm_str || buf.val.gcobj->unmutable) { - return nas_err("read", "\"buf\" must be mutable string"); + if (buffer.type!=vm_str || buffer.val.gcobj->unmutable) { + return nas_err("io::read", "\"buf\" must be mutable string"); } - if (len.type!=vm_num) { - return nas_err("read", "\"len\" must be number"); + if (length.type!=vm_num) { + return nas_err("io::read", "\"len\" must be number"); } - if (len.num()<=0 || len.num()>=(1<<30)) { - return nas_err("read", "\"len\" less than 1 or too large"); + if (length.num()<=0 || length.num()>=(1<<30)) { + return nas_err("io::read", "\"len\" less than 1 or too large"); } - char* buff = new char[(usize)len.num()+1]; - if (!buff) { - return nas_err("read", "malloc failed"); + auto temp_buffer = new char[static_cast(length.num())+1]; + if (!temp_buffer) { + return nas_err("io::read", "malloc failed"); } - f64 res = fread(buff, 1, len.num(), static_cast(fd.obj().pointer)); - buf.str() = buff; - buf.val.gcobj->unmutable = true; - delete []buff; - return var::num(res); + auto read_size = fread( + temp_buffer, 1, length.num(), + static_cast(file_descriptor.ghost().pointer) + ); + buffer.str() = temp_buffer; + buffer.val.gcobj->unmutable = true; + delete []temp_buffer; + return var::num(read_size); } var builtin_write(context* ctx, gc* ngc) { auto local = ctx->localr; - auto fd = local[1]; - auto str = local[2]; - if (!fd.object_check(file_type_name)) { - return nas_err("write", "not a valid filehandle"); + auto file_descriptor = local[1]; + auto source = local[2]; + if (!file_descriptor.object_check(file_type_name)) { + return nas_err("io::write", "not a valid filehandle"); } - if (str.type!=vm_str) { - return nas_err("write", "\"str\" must be string"); + if (source.type!=vm_str) { + return nas_err("io::write", "\"str\" must be string"); } return var::num(static_cast(fwrite( - str.str().c_str(), - 1, - str.str().length(), - static_cast(fd.obj().pointer) + source.str().c_str(), 1, source.str().length(), + static_cast(file_descriptor.ghost().pointer) ))); } var builtin_seek(context* ctx, gc* ngc) { auto local = ctx->localr; - auto fd = local[1]; - auto pos = local[2]; + auto file_descriptor = local[1]; + auto position = local[2]; auto whence = local[3]; - if (!fd.object_check(file_type_name)) { - return nas_err("seek", "not a valid filehandle"); + if (!file_descriptor.object_check(file_type_name)) { + return nas_err("io::seek", "not a valid filehandle"); } return var::num(static_cast(fseek( - static_cast(fd.obj().pointer), - pos.num(), + static_cast(file_descriptor.ghost().pointer), + position.num(), whence.num() ))); } var builtin_tell(context* ctx, gc* ngc) { - auto fd = ctx->localr[1]; - if (!fd.object_check(file_type_name)) { - return nas_err("tell", "not a valid filehandle"); + auto file_descriptor = ctx->localr[1]; + if (!file_descriptor.object_check(file_type_name)) { + return nas_err("io::tell", "not a valid filehandle"); } return var::num(static_cast( - ftell(static_cast(fd.obj().pointer)) + ftell(static_cast(file_descriptor.ghost().pointer)) )); } var builtin_readln(context* ctx, gc* ngc) { - auto fd = ctx->localr[1]; - if (!fd.object_check(file_type_name)) { - return nas_err("readln", "not a valid filehandle"); + auto file_descriptor = ctx->localr[1]; + if (!file_descriptor.object_check(file_type_name)) { + return nas_err("io::readln", "not a valid filehandle"); } - auto str = ngc->alloc(vm_str); + auto result = ngc->alloc(vm_str); char c; - while((c = fgetc(static_cast(fd.obj().pointer)))!=EOF) { + while((c = fgetc(static_cast(file_descriptor.ghost().pointer)))!=EOF) { if (c=='\r') { continue; } if (c=='\n') { - return str; + return result; } - str.str() += c; + result.str().push_back(c); } - if (str.str().length()) { - return str; + if (result.str().length()) { + return result; } return nil; } @@ -171,36 +174,36 @@ var builtin_readln(context* ctx, gc* ngc) { var builtin_stat(context* ctx, gc* ngc) { auto name = ctx->localr[1]; if (name.type!=vm_str) { - return nas_err("stat", "\"filename\" must be string"); + return nas_err("io::stat", "\"filename\" must be string"); } - struct stat buf; - if (stat(name.str().c_str(), &buf)<0) { - return nas_err("stat", "failed to open file <"+name.str()+">"); + struct stat buffer; + if (stat(name.str().c_str(), &buffer)<0) { + return nas_err("io::stat", "failed to open file <" + name.str() + ">"); } - auto ret = ngc->alloc(vm_vec); - ret.vec().elems = { - var::num(static_cast(buf.st_dev)), - var::num(static_cast(buf.st_ino)), - var::num(static_cast(buf.st_mode)), - var::num(static_cast(buf.st_nlink)), - var::num(static_cast(buf.st_uid)), - var::num(static_cast(buf.st_gid)), - var::num(static_cast(buf.st_rdev)), - var::num(static_cast(buf.st_size)), - var::num(static_cast(buf.st_atime)), - var::num(static_cast(buf.st_mtime)), - var::num(static_cast(buf.st_ctime)) + auto result = ngc->alloc(vm_vec); + result.vec().elems = { + var::num(static_cast(buffer.st_dev)), + var::num(static_cast(buffer.st_ino)), + var::num(static_cast(buffer.st_mode)), + var::num(static_cast(buffer.st_nlink)), + var::num(static_cast(buffer.st_uid)), + var::num(static_cast(buffer.st_gid)), + var::num(static_cast(buffer.st_rdev)), + var::num(static_cast(buffer.st_size)), + var::num(static_cast(buffer.st_atime)), + var::num(static_cast(buffer.st_mtime)), + var::num(static_cast(buffer.st_ctime)) }; - return ret; + return result; } var builtin_eof(context* ctx, gc* ngc) { - auto fd = ctx->localr[1]; - if (!fd.object_check(file_type_name)) { - return nas_err("readln", "not a valid filehandle"); + auto file_descriptor = ctx->localr[1]; + if (!file_descriptor.object_check(file_type_name)) { + return nas_err("io::readln", "not a valid filehandle"); } return var::num(static_cast( - feof(static_cast(fd.obj().pointer)) + feof(static_cast(file_descriptor.ghost().pointer)) )); } diff --git a/src/nasal_ast.h b/src/nasal_ast.h index 73142c1..55e91e8 100644 --- a/src/nasal_ast.h +++ b/src/nasal_ast.h @@ -77,7 +77,7 @@ public: virtual void accept(ast_visitor*); }; -class call:public expr { +class call: public expr { public: call(const span& location, expr_type node_type): expr(location, node_type) {} @@ -85,7 +85,7 @@ public: virtual void accept(ast_visitor*); }; -class null_expr:public expr { +class null_expr: public expr { public: null_expr(const span& location): expr(location, expr_type::ast_null) {} @@ -93,7 +93,7 @@ public: void accept(ast_visitor*) override; }; -class nil_expr:public expr { +class nil_expr: public expr { public: nil_expr(const span& location): expr(location, expr_type::ast_nil) {} @@ -101,7 +101,7 @@ public: void accept(ast_visitor*) override; }; -class number_literal:public expr { +class number_literal: public expr { private: f64 number; @@ -113,7 +113,7 @@ public: void accept(ast_visitor*) override; }; -class string_literal:public expr { +class string_literal: public expr { private: std::string content; @@ -125,7 +125,7 @@ public: void accept(ast_visitor*) override; }; -class identifier:public expr { +class identifier: public expr { private: std::string name; @@ -137,7 +137,7 @@ public: void accept(ast_visitor*) override; }; -class bool_literal:public expr { +class bool_literal: public expr { private: bool flag; @@ -149,7 +149,7 @@ public: void accept(ast_visitor*) override; }; -class vector_expr:public expr { +class vector_expr: public expr { private: std::vector elements; @@ -162,7 +162,7 @@ public: void accept(ast_visitor*) override; }; -class hash_expr:public expr { +class hash_expr: public expr { private: std::vector members; @@ -175,7 +175,7 @@ public: void accept(ast_visitor*) override; }; -class hash_pair:public expr { +class hash_pair: public expr { private: std::string name; expr* value; @@ -192,7 +192,7 @@ public: void accept(ast_visitor*) override; }; -class function:public expr { +class function: public expr { private: std::vector parameter_list; code_block* block; @@ -209,7 +209,7 @@ public: void accept(ast_visitor*) override; }; -class code_block:public expr { +class code_block: public expr { private: std::vector expressions; @@ -222,7 +222,7 @@ public: void accept(ast_visitor*) override; }; -class parameter:public expr { +class parameter: public expr { public: enum class param_type { normal_parameter, @@ -249,7 +249,7 @@ public: void accept(ast_visitor*) override; }; -class ternary_operator:public expr { +class ternary_operator: public expr { private: expr* condition; expr* left; @@ -269,7 +269,7 @@ public: void accept(ast_visitor*) override; }; -class binary_operator:public expr { +class binary_operator: public expr { public: enum class binary_type { add, @@ -317,7 +317,7 @@ public: void accept(ast_visitor*) override; }; -class unary_operator:public expr { +class unary_operator: public expr { public: enum class unary_type { negative, @@ -344,7 +344,7 @@ public: void accept(ast_visitor*) override; }; -class call_expr:public expr { +class call_expr: public expr { private: expr* first; std::vector calls; @@ -361,7 +361,7 @@ public: void accept(ast_visitor*) override; }; -class call_hash:public call { +class call_hash: public call { private: std::string field; @@ -374,7 +374,7 @@ public: void accept(ast_visitor*) override; }; -class call_vector:public call { +class call_vector: public call { private: std::vector calls; @@ -387,7 +387,7 @@ public: void accept(ast_visitor*) override; }; -class call_function:public call { +class call_function: public call { private: std::vector args; @@ -400,7 +400,7 @@ public: void accept(ast_visitor*) override; }; -class slice_vector:public expr { +class slice_vector: public expr { private: expr* begin; expr* end; @@ -417,7 +417,7 @@ public: void accept(ast_visitor*) override; }; -class definition_expr:public expr { +class definition_expr: public expr { private: identifier* variable_name; multi_identifier* variables; @@ -441,7 +441,7 @@ public: void accept(ast_visitor*) override; }; -class assignment_expr:public expr { +class assignment_expr: public expr { public: enum class assign_type { equal, @@ -474,7 +474,7 @@ public: void accept(ast_visitor*) override; }; -class multi_identifier:public expr { +class multi_identifier: public expr { private: std::vector variables; @@ -487,7 +487,7 @@ public: void accept(ast_visitor*) override; }; -class tuple_expr:public expr { +class tuple_expr: public expr { private: std::vector elements; @@ -500,7 +500,7 @@ public: void accept(ast_visitor*) override; }; -class multi_assign:public expr { +class multi_assign: public expr { private: tuple_expr* tuple; expr* value; @@ -517,7 +517,7 @@ public: void accept(ast_visitor*) override; }; -class while_expr:public expr { +class while_expr: public expr { private: expr* condition; code_block* block; @@ -534,7 +534,7 @@ public: void accept(ast_visitor*) override; }; -class for_expr:public expr { +class for_expr: public expr { private: expr* initializing; expr* condition; @@ -558,7 +558,7 @@ public: void accept(ast_visitor*) override; }; -class iter_expr:public expr { +class iter_expr: public expr { private: identifier* name; call_expr* call; @@ -575,7 +575,7 @@ public: void accept(ast_visitor*) override; }; -class forei_expr:public expr { +class forei_expr: public expr { public: enum class forei_loop_type { foreach, @@ -605,7 +605,7 @@ public: void accept(ast_visitor*) override; }; -class condition_expr:public expr { +class condition_expr: public expr { private: if_expr* if_stmt; std::vector elsif_stmt; @@ -625,7 +625,7 @@ public: void accept(ast_visitor*) override; }; -class if_expr:public expr { +class if_expr: public expr { private: expr* condition; code_block* block; @@ -642,7 +642,7 @@ public: void accept(ast_visitor*) override; }; -class continue_expr:public expr { +class continue_expr: public expr { public: continue_expr(const span& location): expr(location, expr_type::ast_continue) {} @@ -650,7 +650,7 @@ public: void accept(ast_visitor*) override; }; -class break_expr:public expr { +class break_expr: public expr { public: break_expr(const span& location): expr(location, expr_type::ast_break) {} @@ -658,7 +658,7 @@ public: void accept(ast_visitor*) override; }; -class return_expr:public expr { +class return_expr: public expr { private: expr* value; diff --git a/src/nasal_builtin.cpp b/src/nasal_builtin.cpp index 3f8eab8..6bdaf9c 100644 --- a/src/nasal_builtin.cpp +++ b/src/nasal_builtin.cpp @@ -632,9 +632,9 @@ var builtin_ghosttype(context* ctx, gc* ngc) { if (arg.type!=vm_obj) { return nas_err("ghosttype", "this is not a ghost object."); } - const auto& name = arg.obj().get_ghost_name(); + const auto& name = arg.ghost().get_ghost_name(); if (!name.length()) { - return var::num(reinterpret_cast(arg.obj().pointer)); + return var::num(reinterpret_cast(arg.ghost().pointer)); } return ngc->newstr(name); } diff --git a/src/nasal_dbg.cpp b/src/nasal_dbg.cpp index a4715cc..d6e4b59 100644 --- a/src/nasal_dbg.cpp +++ b/src/nasal_dbg.cpp @@ -160,7 +160,7 @@ void dbg::step_info() { begin = (ctx.pc>>3)==0? 0:((ctx.pc>>3)<<3); end = (1+(ctx.pc>>3))<<3; codestream::set(const_number, const_string, native_function.data(), files); - std::clog << "next bytecode:\n"; + std::clog << "\nnext bytecode:\n"; for(u32 i = begin; ictx; // set coroutine pointer - cort = &co; + cort = co; // set coroutine state to running cort->status = nas_co::status::running; } -void gc::ctxreserve() { +void gc::context_reserve() { // pc=0 means this coroutine is finished cort->status = running_context->pc? nas_co::status::suspended: diff --git a/src/nasal_gc.h b/src/nasal_gc.h index f5b4497..4ce39e7 100644 --- a/src/nasal_gc.h +++ b/src/nasal_gc.h @@ -88,8 +88,8 @@ public: void clear(); void info() const; var alloc(const u8); - void ctxchg(nas_co&); - void ctxreserve(); + void context_change(nas_co*); + void context_reserve(); public: var newstr(char c) { diff --git a/src/nasal_import.cpp b/src/nasal_import.cpp index 54f6f5d..3a5c2cf 100644 --- a/src/nasal_import.cpp +++ b/src/nasal_import.cpp @@ -1,6 +1,8 @@ #include "nasal_import.h" #include "symbol_finder.h" +#include + namespace nasal { linker::linker(): @@ -234,10 +236,14 @@ code_block* linker::import_nasal_lib() { // start importing... if (lex.scan(filename).geterr()) { - err.err("link", "error occurred when analysing library <" + filename + ">"); + err.err("link", + "error occurred when analysing library <" + filename + ">" + ); } if (par.compile(lex).geterr()) { - err.err("link", "error occurred when analysing library <" + filename + ">"); + err.err("link", + "error occurred when analysing library <" + filename + ">" + ); } auto tmp = par.swap(nullptr); @@ -245,41 +251,71 @@ code_block* linker::import_nasal_lib() { return load(tmp, find(filename)); } -std::string linker::generate_module_name(const std::string& filename) { - auto error_name = "error_generated@[" + filename + "]"; - auto pos = filename.find_last_of(".nas"); - if (pos==std::string::npos) { +std::string linker::generate_module_name(const std::string& file_path) { + auto error_name = "module@[" + file_path + "]"; + if (!file_path.length()) { return error_name; } - pos -= 4; - auto split_pos = filename.find_last_of("/"); - if (split_pos==std::string::npos) { - split_pos = filename.find_last_of("\\"); + + // check file suffix and get file suffix position + auto suffix_position = file_path.find(".nas"); + if (suffix_position==std::string::npos) { + err.warn("link", + "get invalid module name from <" + file_path + ">, " + + "will not be easily accessed. " + + "\".nas\" suffix is required." + ); + return error_name; } - auto res = split_pos==std::string::npos? - filename.substr(0, pos + 1): - filename.substr(split_pos + 1, pos - split_pos); - if (!res.length()) { - err.warn("link", "get empty module name from <" + filename + ">, " + - "will not be easily accessed."); + if (suffix_position+4!=file_path.length()) { + err.warn("link", + "get invalid module name from <" + file_path + ">, " + + "will not be easily accessed. " + + "only one \".nas\" suffix is required in the path." + ); + return error_name; } - if (res.length() && '0' <= res[0] && res[0] <= '9') { - err.warn("link", "get module <" + res + "> from <" + filename + ">, " + - "will not be easily accessed."); + + // only get the file name as module name, directory path is not included + auto split_position = file_path.find_last_of("/"); + // find "\\" in windows platform + if (split_position==std::string::npos) { + split_position = file_path.find_last_of("\\"); } - if (res.length() && res.find(".")!=std::string::npos) { - err.warn("link", "get module <" + res + "> from <" + filename + ">, " + - "will not be easily accessed."); + + // split file path to get module name + auto module_name = split_position==std::string::npos? + file_path.substr(0, suffix_position): + file_path.substr(split_position+1, suffix_position-split_position-1); + + // check validation of module name + if (!module_name.length()) { + err.warn("link", + "get empty module name from <" + file_path + ">, " + + "will not be easily accessed." + ); } - return res; + if (module_name.length() && '0' <= module_name[0] && module_name[0] <= '9') { + err.warn("link", + "get module <" + module_name + "> from <" + file_path + ">, " + + "will not be easily accessed." + ); + } + if (module_name.length() && module_name.find(".")!=std::string::npos) { + err.warn("link", + "get module <" + module_name + "> from <" + file_path + ">, " + + "will not be easily accessed." + ); + } + return module_name; } return_expr* linker::generate_module_return(code_block* block) { - auto sf = new symbol_finder; - auto res = new return_expr(block->get_location()); + auto finder = std::unique_ptr(new symbol_finder); + auto result = new return_expr(block->get_location()); auto value = new hash_expr(block->get_location()); - res->set_value(value); - for(const auto& i : sf->do_find(block)) { + result->set_value(value); + for(const auto& i : finder->do_find(block)) { auto pair = new hash_pair(block->get_location()); // do not export symbol begins with '_' if (i.name.length() && i.name[0]=='_') { @@ -289,8 +325,7 @@ return_expr* linker::generate_module_return(code_block* block) { pair->set_value(new identifier(block->get_location(), i.name)); value->add_member(pair); } - delete sf; - return res; + return result; } definition_expr* linker::generate_module_definition(code_block* block) { diff --git a/src/nasal_opcode.cpp b/src/nasal_opcode.cpp index 6977235..8d2478f 100644 --- a/src/nasal_opcode.cpp +++ b/src/nasal_opcode.cpp @@ -28,13 +28,13 @@ const char* opname[] = { }; void codestream::set( - const f64* num_buff, - const std::string* str_buff, - const nasal_builtin_table* native_table_ptr, + const f64* number_list, + const std::string* string_list, + const nasal_builtin_table* native_table, const std::string* file_list) { - nums = num_buff; - strs = str_buff; - natives = native_table_ptr; + const_number = number_list; + const_string = string_list; + natives = native_table; files = file_list; } @@ -62,24 +62,24 @@ void codestream::dump(std::ostream& out) const { case op_addeqc: case op_subeqc: case op_muleqc:case op_diveqc: out << hex << "0x" << num << dec - << " (" << nums[num] << ")"; break; + << " (" << const_number[num] << ")"; break; case op_lnkeqc: out << hex << "0x" << num << dec - << " (" << rawstr(strs[num], 16) << ")"; break; + << " (" << rawstr(const_string[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; + << " (" << const_number[num] << ") sp-1"; break; case op_lnkecp: out << hex << "0x" << num << dec - << " (" << rawstr(strs[num], 16) << ") sp-1"; break; + << " (" << rawstr(const_string[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; + << " (" << const_number[num] << ")"; break; case op_callvi: case op_newv: case op_callfv: case op_repl: case op_intl: case op_findex: @@ -103,7 +103,7 @@ void codestream::dump(std::ostream& out) const { case op_mcallh: case op_para: case op_deft: case op_dyn: out << hex << "0x" << num << dec - << " (" << rawstr(strs[num], 16) << ")"; break; + << " (" << rawstr(const_string[num], 16) << ")"; break; default: if (files) { out << hex << "0x" << num << dec; diff --git a/src/nasal_opcode.h b/src/nasal_opcode.h index 98e2459..bc31742 100644 --- a/src/nasal_opcode.h +++ b/src/nasal_opcode.h @@ -111,8 +111,8 @@ class codestream { private: opcode code; const u32 index; - inline static const f64* nums = nullptr; - inline static const std::string* strs = nullptr; + inline static const f64* const_number = nullptr; + inline static const std::string* const_string = nullptr; inline static const nasal_builtin_table* natives = nullptr; inline static const std::string* files = nullptr; diff --git a/src/nasal_type.cpp b/src/nasal_type.cpp index 15a6993..de42e25 100644 --- a/src/nasal_type.cpp +++ b/src/nasal_type.cpp @@ -2,20 +2,20 @@ namespace nasal { -var nas_vec::get_value(const i32 n) { +var nas_vec::get_value(const i32 index) { i32 size = elems.size(); - if (n<-size || n>=size) { + if (index<-size || index>=size) { return var::none(); } - return elems[n>=0? n:n+size]; + return elems[index>=0? index:index+size]; } -var* nas_vec::get_memory(const i32 n) { +var* nas_vec::get_memory(const i32 index) { i32 size = elems.size(); - if (n<-size || n>=size) { + if (index<-size || index>=size) { return nullptr; } - return &elems[n>=0? n:n+size]; + return &elems[index>=0? index:index+size]; } std::ostream& operator<<(std::ostream& out, nas_vec& vec) { @@ -194,41 +194,41 @@ nas_val::nas_val(u8 val_type) { type = val_type; unmutable = 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_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_map: ptr.map = new nas_map; break; + case vm_obj: ptr.obj = new nas_ghost; break; + case vm_co: ptr.co = new nas_co; break; + case vm_map: ptr.map = new nas_map; break; } } nas_val::~nas_val() { switch(type) { - case vm_str: delete ptr.str; break; - case vm_vec: delete ptr.vec; break; - case vm_hash: delete ptr.hash; break; - case vm_func: delete ptr.func; break; - case vm_upval:delete ptr.upval;break; - case vm_obj: delete ptr.obj; break; - case vm_co: delete ptr.co; break; - case vm_map: delete ptr.map; break; + case vm_str: delete ptr.str; break; + case vm_vec: delete ptr.vec; break; + case vm_hash: delete ptr.hash; break; + case vm_func: delete ptr.func; break; + case vm_upval:delete ptr.upval; break; + case vm_obj: delete ptr.obj; break; + case vm_co: delete ptr.co; break; + case vm_map: delete ptr.map; break; } type=vm_nil; } void nas_val::clear() { switch(type) { - case vm_str: ptr.str->clear(); break; - case vm_vec: ptr.vec->elems.clear(); break; - case vm_hash: ptr.hash->elems.clear();break; - case vm_func: ptr.func->clear(); break; - case vm_upval:ptr.upval->clear(); break; - case vm_obj: ptr.obj->clear(); break; - case vm_co: ptr.co->clear(); break; - case vm_map: ptr.map->clear(); break; + case vm_str: ptr.str->clear(); break; + case vm_vec: ptr.vec->elems.clear(); break; + case vm_hash: ptr.hash->elems.clear(); break; + case vm_func: ptr.func->clear(); break; + case vm_upval:ptr.upval->clear(); break; + case vm_obj: ptr.obj->clear(); break; + case vm_co: ptr.co->clear(); break; + case vm_map: ptr.map->clear(); break; } } @@ -240,7 +240,7 @@ std::string var::to_str() { if (type==vm_str) { return str(); } else if (type==vm_num) { - std::string tmp=std::to_string(num()); + std::string tmp = std::to_string(num()); tmp.erase(tmp.find_last_not_of('0')+1, std::string::npos); tmp.erase(tmp.find_last_not_of('.')+1, std::string::npos); return tmp; @@ -257,7 +257,7 @@ std::ostream& operator<<(std::ostream& out, var& ref) { 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_obj: out << ref.ghost(); break; case vm_co: out << ref.co(); break; case vm_map: out << ref.map(); break; } @@ -265,7 +265,7 @@ std::ostream& operator<<(std::ostream& out, var& ref) { } bool var::object_check(const std::string& name) { - return type==vm_obj && obj().type_name==name && obj().pointer; + return type==vm_obj && ghost().type_name==name && ghost().pointer; } var var::none() { @@ -300,7 +300,7 @@ var* var::addr() { return val.addr; } -u32 var::ret() { +u32 var::ret() const { return val.ret; } @@ -308,7 +308,7 @@ i64& var::cnt() { return val.cnt; } -f64 var::num() { +f64 var::num() const { return val.num; } @@ -332,7 +332,7 @@ nas_upval& var::upval() { return *val.gcobj->ptr.upval; } -nas_ghost& var::obj() { +nas_ghost& var::ghost() { return *val.gcobj->ptr.obj; } diff --git a/src/nasal_type.h b/src/nasal_type.h index 37d7cf7..8bb589b 100644 --- a/src/nasal_type.h +++ b/src/nasal_type.h @@ -23,11 +23,13 @@ enum vm_type:u8 { vm_upval, // upvalue vm_obj, // ghost type vm_co, // coroutine - vm_map // for globals and namespaces + vm_map, // for globals and namespaces + /* mark type range */ + vm_type_size_max }; // size of gc object type -const u32 gc_type_size = vm_map-vm_str+1; +const u32 gc_type_size = vm_type_size_max-vm_str; // basic types struct nas_vec; // vector @@ -85,15 +87,15 @@ public: // get value var* addr(); - u32 ret(); + u32 ret() const; i64& cnt(); - f64 num(); + f64 num() const; std::string& str(); nas_vec& vec(); nas_hash& hash(); nas_func& func(); nas_upval& upval(); - nas_ghost& obj(); + nas_ghost& ghost(); nas_co& co(); nas_map& map(); }; diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index bc943ca..5b2bf10 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -93,7 +93,7 @@ void vm::value_info(var& val) { << " val}"; break; case vm_obj: std::clog << "| obj | <0x" << std::hex << p << "> obj:0x" - << reinterpret_cast(val.obj().pointer) + << reinterpret_cast(val.ghost().pointer) << std::dec; break; case vm_co: std::clog << "| co | <0x" << std::hex << p << std::dec << "> coroutine"; break; @@ -170,12 +170,12 @@ void vm::function_call_trace() { } void vm::trace_back() { - var* bottom = ctx.stack; - var* top = ctx.top; + // var* bottom = ctx.stack; + // var* top = ctx.top; // generate trace back std::stack ret; - for(var* i = bottom; i<=top; ++i) { + for(var* i = ctx.stack; i<=ctx.top; ++i) { if (i->type==vm_ret && i->ret()!=0) { ret.push(i->ret()); } @@ -401,7 +401,7 @@ void vm::die(const std::string& str) { } else { // in coroutine, shut down the coroutine and return to main context ctx.pc = 0; // mark coroutine 'dead' - ngc.ctxreserve(); // switch context to main + ngc.context_reserve(); // switch context to main ctx.top[0] = nil; // generate return value 'nil' } } diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 481627c..45ca5a3 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -1024,7 +1024,7 @@ inline void vm::o_ret() { // because there maybe another function call inside but return here // coroutine function ends with setting pc to 0 if (!ctx.pc) { - ngc.ctxreserve(); + ngc.context_reserve(); } } diff --git a/src/unix_lib.cpp b/src/unix_lib.cpp index 32e5f5f..eb37b4d 100644 --- a/src/unix_lib.cpp +++ b/src/unix_lib.cpp @@ -73,7 +73,7 @@ var builtin_opendir(context* ctx, gc* ngc) { } #endif var ret = ngc->alloc(vm_obj); - ret.obj().set(dir_type_name, dir_entry_destructor, p); + ret.ghost().set(dir_type_name, dir_entry_destructor, p); return ret; } @@ -84,12 +84,12 @@ var builtin_readdir(context* ctx, gc* ngc) { } #ifdef _MSC_VER WIN32_FIND_DATAA data; - if (!FindNextFileA(handle.obj().pointer, &data)) { + if (!FindNextFileA(handle.ghost().pointer, &data)) { return nil; } return ngc->newstr(data.cFileName); #else - dirent* p = readdir(static_cast(handle.obj().pointer)); + dirent* p = readdir(static_cast(handle.ghost().pointer)); return p? ngc->newstr(p->d_name):nil; #endif } @@ -99,7 +99,7 @@ var builtin_closedir(context* ctx, gc* ngc) { if (!handle.object_check(dir_type_name)) { return nas_err("unix::closedir", "not a valid dir handle"); } - handle.obj().clear(); + handle.ghost().clear(); return nil; } diff --git a/test/flush_screen.nas b/test/flush_screen.nas index 231bfda..2c24113 100644 --- a/test/flush_screen.nas +++ b/test/flush_screen.nas @@ -24,5 +24,5 @@ while(1) { res ~= "\n"; } print(res); - unix.sleep(1/20); + unix.sleep(1/15); } From 07a652cc3773816ede1bf1fb57350e04274cb432 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 22 Oct 2023 23:52:39 +0800 Subject: [PATCH 13/18] :bug: fix compilation error using CMake --- CMakeLists.txt | 1 + src/nasal_type.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 151e760..f623951 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,7 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/module) set(MODULE_USED_OBJECT_SOURCE_FILE ${CMAKE_SOURCE_DIR}/src/nasal_misc.cpp + ${CMAKE_SOURCE_DIR}/src/nasal_type.cpp ${CMAKE_SOURCE_DIR}/src/nasal_gc.cpp) add_library(module-used-object STATIC ${MODULE_USED_OBJECT_SOURCE_FILE}) diff --git a/src/nasal_type.cpp b/src/nasal_type.cpp index de42e25..410300d 100644 --- a/src/nasal_type.cpp +++ b/src/nasal_type.cpp @@ -1,5 +1,8 @@ #include "nasal_type.h" +#include +#include + namespace nasal { var nas_vec::get_value(const i32 index) { From f7f4a38b47359512bd25a120785a4b78e891f53b Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Mon, 23 Oct 2023 00:02:36 +0800 Subject: [PATCH 14/18] :bug: fix abnormal debugger output on windows --- src/nasal_err.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/nasal_err.cpp b/src/nasal_err.cpp index 3ff12c0..4f201ac 100644 --- a/src/nasal_err.cpp +++ b/src/nasal_err.cpp @@ -10,11 +10,8 @@ struct for_reset { for_reset() { GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &scr); } - static for_reset* singleton() { - static for_reset windows_set; - return &windows_set; - } }; +static for_reset windows_system_set; #endif std::ostream& back_white(std::ostream& s) { @@ -64,8 +61,10 @@ std::ostream& white(std::ostream& s) { std::ostream& reset(std::ostream& s) { #ifdef _WIN32 - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), - for_reset::singleton()->scr.wAttributes); + SetConsoleTextAttribute( + GetStdHandle(STD_OUTPUT_HANDLE), + windows_system_set.scr.wAttributes + ); #else s << "\033[0m"; #endif From 9f7484596ae6b7d1d3022c44080a08658dbe65af Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Tue, 24 Oct 2023 00:16:48 +0800 Subject: [PATCH 15/18] :bug: fix error report bug in import.cpp --- src/nasal.h | 1 + src/nasal_codegen.cpp | 4 ++-- src/nasal_import.cpp | 25 ++++++++++++++++--------- src/optimizer.h | 2 +- src/symbol_finder.h | 2 +- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/nasal.h b/src/nasal.h index 5b6b104..ad651b5 100644 --- a/src/nasal.h +++ b/src/nasal.h @@ -8,6 +8,7 @@ #include #include #include +#include #include // abbreviation of some useful basic type diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index 5be79a4..e82044a 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -1303,7 +1303,7 @@ void codegen::print(std::ostream& out) { out << std::hex << "<0x" << func_begin_stack.top() << std::dec << ">;\n"; // avoid two empty lines if (c.op!=op_newf) { - out<<"\n"; + out << "\n"; } func_begin_stack.pop(); func_end_stack.pop(); @@ -1322,7 +1322,7 @@ void codegen::print(std::ostream& out) { } // output bytecode - out << " " << codestream(c,i) << "\n"; + out << " " << codestream(c, i) << "\n"; } } diff --git a/src/nasal_import.cpp b/src/nasal_import.cpp index 3a5c2cf..f5b31f0 100644 --- a/src/nasal_import.cpp +++ b/src/nasal_import.cpp @@ -198,8 +198,10 @@ code_block* linker::import_regular_file(call_expr* node) { return new code_block({0, 0, 0, 0, filename}); } if (check_self_import(filename)) { - err.err("link", "self-referenced module <" + filename + ">:\n" + - " reference path: " + generate_self_import_path(filename)); + err.err("link", + "self-referenced module <" + filename + ">:\n" + + " reference path: " + generate_self_import_path(filename) + ); return new code_block({0, 0, 0, 0, filename}); } exist(filename); @@ -208,16 +210,19 @@ code_block* linker::import_regular_file(call_expr* node) { // start importing... if (lex.scan(filename).geterr()) { err.err("link", "error occurred when analysing <" + filename + ">"); + return new code_block({0, 0, 0, 0, filename}); } if (par.compile(lex).geterr()) { err.err("link", "error occurred when analysing <" + filename + ">"); + return new code_block({0, 0, 0, 0, filename}); } - auto tmp = par.swap(nullptr); - // check if tmp has 'import' - auto res = load(tmp, find(filename)); + auto parse_result = par.swap(nullptr); + + // check if parse result has 'import' + auto result = load(parse_result, find(filename)); module_load_stack.pop_back(); - return res; + return result; } code_block* linker::import_nasal_lib() { @@ -239,16 +244,18 @@ code_block* linker::import_nasal_lib() { err.err("link", "error occurred when analysing library <" + filename + ">" ); + return new code_block({0, 0, 0, 0, filename}); } if (par.compile(lex).geterr()) { err.err("link", "error occurred when analysing library <" + filename + ">" ); + return new code_block({0, 0, 0, 0, filename}); } - auto tmp = par.swap(nullptr); - // check if tmp has 'import' - return load(tmp, find(filename)); + auto parse_result = par.swap(nullptr); + // check if library has 'import' (in fact it should not) + return load(parse_result, find(filename)); } std::string linker::generate_module_name(const std::string& file_path) { diff --git a/src/optimizer.h b/src/optimizer.h index 3c33453..4a1d6a6 100644 --- a/src/optimizer.h +++ b/src/optimizer.h @@ -7,7 +7,7 @@ namespace nasal { -class optimizer:public ast_visitor { +class optimizer: public ast_visitor { private: void const_string(binary_operator*, string_literal*, string_literal*); void const_number(binary_operator*, number_literal*, number_literal*); diff --git a/src/symbol_finder.h b/src/symbol_finder.h index 3114179..aa7b0cf 100644 --- a/src/symbol_finder.h +++ b/src/symbol_finder.h @@ -9,7 +9,7 @@ namespace nasal { -class symbol_finder:public ast_visitor { +class symbol_finder: public ast_visitor { public: struct symbol_info { std::string name; From d56e1bff2c6f5184a0f5e7b2c4ae079597159d88 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Wed, 25 Oct 2023 00:32:42 +0800 Subject: [PATCH 16/18] :zap: change json.JSON to json --- std/json.nas | 48 ++++++++++++++++++++++++------------------------ test/json.nas | 42 +++++++++++++++++++++--------------------- test/jsonrpc.nas | 11 +++++------ 3 files changed, 50 insertions(+), 51 deletions(-) diff --git a/std/json.nas b/std/json.nas index e2ff68a..d656ed0 100644 --- a/std/json.nas +++ b/std/json.nas @@ -19,7 +19,7 @@ var _j_content = [ "identifier" ]; -var JSON = func() { +var parse = func() { var text = ""; var line = 1; @@ -66,7 +66,7 @@ var JSON = func() { var get = func(str) { init(); if (!size(str)) { - println("JSON.parse: empty string"); + println("json::parse: empty string"); str = "[]"; } text = str; @@ -147,7 +147,7 @@ var JSON = func() { var match = func(type) { if(token.type!=type) - println("JSON.parse: line ",line,": expect ",_j_content[type]," but get `",token.content,"`."); + println("json::parse: line ",line,": expect ",_j_content[type]," but get `",token.content,"`."); next(); return; } @@ -212,30 +212,30 @@ var JSON = func() { return vec; } - return { - parse:func(str) { - if(typeof(str)!="str") { - println("JSON.parse: must use string"); - return []; - } - get(str); - next(); - - if (token.type==_j_lbrkt) { - var res = vec_gen(); - } else { - var res = hash_gen(); - } - - init(); - return res; + return func(source) { + if(typeof(source)!="str") { + println("json::parse: must use string but get", typeof(str)); + return []; } - }; + + get(source); + next(); + + if (token.type==_j_lbrkt) { + var res = vec_gen(); + } else { + var res = hash_gen(); + } + + init(); + return res; + } }(); -JSON.stringify = func(object) { - if(typeof(object)!="hash" and typeof(object)!="vec") { - println("JSON.stringify: must use hashmap or vector"); +var stringify = func(object) { + var object_type = typeof(object); + if(object_type!="hash" and object_type!="vec" and object_type!="namespace") { + println("json::stringify: must use hashmap or vector, but get ", typeof(object)); return "[]"; } diff --git a/test/json.nas b/test/json.nas index fd04cdd..d5be934 100644 --- a/test/json.nas +++ b/test/json.nas @@ -1,9 +1,7 @@ import.std.json; import.std.process_bar; -var JSON = json.JSON; - -var ss=JSON.stringify({ +var ss = json.stringify({ vec:[0,1,2], hash:{ m1:0, @@ -17,10 +15,11 @@ var ss=JSON.stringify({ empty_an:[[[[[[{}]]]]]], function:func(){} }); -println(ss,"\n"); -println(JSON.parse(ss),"\n"); -var ss=JSON.stringify([{ +println(ss, "\n"); +println(json.parse(ss), "\n"); + +var ss = json.stringify([{ vec:[0,1,2,3], hash:{ m1:0, @@ -33,12 +32,13 @@ var ss=JSON.stringify([{ empty_an:[[[[[{}]]]]], function:func(){} }]); -println(ss,"\n"); -println(JSON.parse(ss),"\n"); + +println(ss, "\n"); +println(json.parse(ss), "\n"); func { - var bar=process_bar.high_resolution_bar(30); - var tmp=[ + var bar = process_bar.high_resolution_bar(30); + var tmp = [ {t0:nil}, {t1:nil}, {t2:nil}, @@ -50,18 +50,18 @@ func { ]; srand(); - foreach(var h;tmp) { - var name=keys(h)[0]; - h[name]=[]; - print("\e[1000D",bar.bar(0)); - for(var i=0;i<500;i+=1) { - append(h[name],{id:i,content:int(rand()*1e7)}); - print("\e[1000D",bar.bar((i+1)/500)); + foreach(var h; tmp) { + var name = keys(h)[0]; + h[name] = []; + print("\e[1000D", bar.bar(0)); + for(var i = 0; i<500; i+=1) { + append(h[name], {id:i, content:int(rand()*1e7)}); + print("\e[1000D", bar.bar((i+1)/500)); } - print("\e[1000D",bar.bar(1)," executing...\n"); + print("\e[1000D", bar.bar(1), " executing...\n"); } - print("\e[1000D","\e["~str(size(tmp))~"A"); - foreach(var h;JSON.parse(JSON.stringify(tmp))) { - println("\e[1000D",bar.bar(1)," parse done ",keys(h)[0]," ",size(h[keys(h)[0]])); + print("\e[1000D", "\e["~str(size(tmp))~"A"); + foreach(var h; json.parse(json.stringify(tmp))) { + println("\e[1000D", bar.bar(1), " parse done ", keys(h)[0], " ", size(h[keys(h)[0]])); } }(); \ No newline at end of file diff --git a/test/jsonrpc.nas b/test/jsonrpc.nas index 2b207dc..f976fc5 100644 --- a/test/jsonrpc.nas +++ b/test/jsonrpc.nas @@ -2,7 +2,6 @@ import.module.libsock; import.std.json; import.std.runtime; -var JSON = json.JSON; var socket = libsock.socket; var gettime=func(){ @@ -79,19 +78,19 @@ var server=func(ip,port) { while(1) { var data=jsonRPC.recv(client); if (data!=nil) { - data=JSON.parse(data); + data=json.parse(data); } else { break; } if (contains(methods,data.method)) { - jsonRPC.send(client, JSON.stringify({ + jsonRPC.send(client, json.stringify({ jsonrpc:2.0, id:data.id, error:"null", result:methods[data.method](data.params) })); } else { - jsonRPC.send(client, JSON.stringify({ + jsonRPC.send(client, json.stringify({ jsonrpc:2.0, id:data.id, error:"no such method \\\""~data.method~"\\\"", @@ -113,13 +112,13 @@ var client=func(ip,port) { var server=jsonRPC.connect(ip,port); while(1) { unix.sleep(5); - var data=JSON.stringify({jsonrpc:2.0, id:call_id, method:methods[rand()*size(methods)],params:params[rand()*size(params)]}); + var data=json.stringify({jsonrpc:2.0, id:call_id, method:methods[rand()*size(methods)],params:params[rand()*size(params)]}); jsonRPC.send(server, data); var respond=jsonRPC.recv(server); if (respond==nil) { break; } - println("[",gettime(),"] result: ",JSON.parse(respond).result); + println("[",gettime(),"] result: ",json.parse(respond).result); call_id+=1; } jsonRPC.disconnect(server); From bbed29eb65f804421c499ae18f48f8e6efdc5cd8 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Thu, 26 Oct 2023 00:04:20 +0800 Subject: [PATCH 17/18] :sparkles: add native function `ceil` --- src/nasal_builtin.cpp | 6 ++++++ src/nasal_builtin.h | 1 + std/json.nas | 45 ++++++++++++++++++++++++++----------------- std/lib.nas | 40 +++++++++++++++++++++++--------------- 4 files changed, 59 insertions(+), 33 deletions(-) diff --git a/src/nasal_builtin.cpp b/src/nasal_builtin.cpp index 6bdaf9c..47c13d6 100644 --- a/src/nasal_builtin.cpp +++ b/src/nasal_builtin.cpp @@ -157,6 +157,11 @@ var builtin_floor(context* ctx, gc* ngc) { return var::num(std::floor(value.num())); } +var builtin_ceil(context* ctx, gc* ngc) { + auto value = ctx->localr[1]; + return var::num(std::ceil(value.num())); +} + var builtin_num(context* ctx, gc* ngc) { auto val = ctx->localr[1]; if (val.type==vm_num) { @@ -653,6 +658,7 @@ nasal_builtin_table builtin[] = { {"__id", builtin_id}, {"__int", builtin_int}, {"__floor", builtin_floor}, + {"__ceil", builtin_ceil}, {"__num", builtin_num}, {"__pop", builtin_pop}, {"__str", builtin_str}, diff --git a/src/nasal_builtin.h b/src/nasal_builtin.h index 00f0878..d7c3dd5 100644 --- a/src/nasal_builtin.h +++ b/src/nasal_builtin.h @@ -42,6 +42,7 @@ var builtin_rand(context*, gc*); var builtin_id(context*, gc*); var builtin_int(context*, gc*); var builtin_floor(context*, gc*); +var builtin_ceil(context*, gc*); var builtin_num(context*, gc*); var builtin_pop(context*, gc*); var builtin_str(context*, gc*); diff --git a/std/json.nas b/std/json.nas index d656ed0..8327b55 100644 --- a/std/json.nas +++ b/std/json.nas @@ -2,8 +2,16 @@ # 2021 ValKmjolnir var ( - _j_eof, _j_lbrace, _j_rbrace, _j_lbrkt, _j_rbrkt, - _j_comma, _j_colon, _j_str, _j_num, _j_id + _j_eof, + _j_lbrace, + _j_rbrace, + _j_lbrkt, + _j_rbrkt, + _j_comma, + _j_colon, + _j_str, + _j_num, + _j_id ) = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9); var _j_content = [ @@ -146,28 +154,29 @@ var parse = func() { } var match = func(type) { - if(token.type!=type) + if(token.type!=type) { println("json::parse: line ",line,": expect ",_j_content[type]," but get `",token.content,"`."); + } next(); return; } var member = func(hash) { var name = token.content; - if(token.type==_j_rbrace) { + if (token.type==_j_rbrace) { return; } - if(token.type==_j_str) { + if (token.type==_j_str) { match(_j_str); } else { match(_j_id); } match(_j_colon); - if(token.type==_j_lbrace) { + if (token.type==_j_lbrace) { hash[name] = hash_gen(); - } elsif(token.type==_j_lbrkt) { + } elsif (token.type==_j_lbrkt) { hash[name] = vec_gen(); - } elsif(token.type==_j_str or token.type==_j_num) { + } elsif (token.type==_j_str or token.type==_j_num) { hash[name] = token.content; next(); } @@ -189,21 +198,21 @@ var parse = func() { var vec_gen = func() { var vec = []; match(_j_lbrkt); - if(token.type==_j_lbrace) { + if (token.type==_j_lbrace) { append(vec, hash_gen()); - } elsif(token.type==_j_lbrkt) { + } elsif (token.type==_j_lbrkt) { append(vec, vec_gen()); - } elsif(token.type==_j_str or token.type==_j_num) { + } elsif (token.type==_j_str or token.type==_j_num) { append(vec, token.content); next(); } while(token.type==_j_comma) { match(_j_comma); - if(token.type==_j_lbrace) { + if (token.type==_j_lbrace) { append(vec, hash_gen()); - } elsif(token.type==_j_lbrkt) { + } elsif (token.type==_j_lbrkt) { append(vec, vec_gen()); - } elsif(token.type==_j_str or token.type==_j_num) { + } elsif (token.type==_j_str or token.type==_j_num) { append(vec, token.content); next(); } @@ -242,13 +251,13 @@ var stringify = func(object) { var s = ""; var gen = func(elem) { var t = typeof(elem); - if(t=="num") { + if (t=="num") { s ~= str(elem); - } elsif(t=="str") { + } elsif (t=="str") { s ~= '"'~elem~'"'; - } elsif(t=="vec") { + } elsif (t=="vec") { vgen(elem); - } elsif(t=="hash") { + } elsif (t=="hash") { hgen(elem); } else { s ~= '"undefined"'; diff --git a/std/lib.nas b/std/lib.nas index 0bf6646..95cb4a6 100644 --- a/std/lib.nas +++ b/std/lib.nas @@ -75,6 +75,10 @@ var floor = func(val) { return __floor(val); } +var ceil = func(val) { + return __ceil(val); +} + # exit using std::exit var exit = func(val = -1) { return __exit(val); @@ -228,19 +232,21 @@ var println = func(elems...) { # sort function using quick sort # not very efficient... :( -var sort = func(){ +var sort = func() { srand(); # be aware! this causes global changes var quick_sort_core = func(vec, left, right, cmp) { if(left>=right) return nil; var base = left+int(rand()*(right-left)); (vec[left], vec[base]) = (vec[base], vec[left]); var (i, j, tmp) = (left, right, vec[left]); - while(i Date: Thu, 26 Oct 2023 22:40:20 +0800 Subject: [PATCH 18/18] :bug: fix error codegen in foreach/forindex loop undefined symbol was recognized as defined in symbol_finder, now it is fixed :) --- src/ast_dumper.cpp | 6 +++++- src/nasal_ast.h | 4 ++++ src/nasal_codegen.cpp | 11 ++++++++--- src/nasal_parse.cpp | 8 +++++++- src/repl.cpp | 5 ++++- src/symbol_finder.cpp | 2 +- test/scalar.nas | 15 ++++++++++++++- 7 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/ast_dumper.cpp b/src/ast_dumper.cpp index c46bfd0..525d42a 100644 --- a/src/ast_dumper.cpp +++ b/src/ast_dumper.cpp @@ -386,7 +386,11 @@ bool ast_dumper::visit_for_expr(for_expr* node) { bool ast_dumper::visit_iter_expr(iter_expr* node) { dump_indent(); - std::cout << "iterator"; + if (node->is_definition()) { + std::cout << "iterator_definition"; + } else { + std::cout << "iterator"; + } std::cout << format_location(node->get_location()); push_indent(); set_last(); diff --git a/src/nasal_ast.h b/src/nasal_ast.h index 55e91e8..4d8c6c1 100644 --- a/src/nasal_ast.h +++ b/src/nasal_ast.h @@ -560,18 +560,22 @@ public: class iter_expr: public expr { private: + bool is_iterator_definition; identifier* name; call_expr* call; public: iter_expr(const span& location): expr(location, expr_type::ast_iter), + is_iterator_definition(false), name(nullptr), call(nullptr) {} ~iter_expr() override; void set_name(identifier* node) {name = node;} void set_call(call_expr* node) {call = node;} + void set_is_definition(bool flag) {is_iterator_definition = flag;} identifier* get_name() {return name;} call_expr* get_call() {return call;} + bool is_definition() const {return is_iterator_definition;} void accept(ast_visitor*) override; }; diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index e82044a..bbb7971 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -89,7 +89,7 @@ void codegen::find_symbol(code_block* node) { experimental_namespace[i.location.file] = {}; } // if in global scope, load global symbol into this namespace - auto scope = experimental_namespace.at(i.location.file); + auto& scope = experimental_namespace.at(i.location.file); if (local.empty() && !scope.count(i.name)) { scope.insert(i.name); } @@ -835,13 +835,18 @@ void codegen::forei_gen(forei_expr* node) { } else { emit(op_feach, 0, node->get_location()); } - if (node->get_iterator()->get_name()) { + + auto iterator_node = node->get_iterator(); + if (iterator_node->is_definition()) { // define a new iterator - auto name_node = node->get_iterator()->get_name(); + const auto name_node = iterator_node->get_name(); const auto& str = name_node->get_name(); local.empty()? emit(op_loadg, global_symbol_find(str), name_node->get_location()): emit(op_loadl, local_symbol_find(str), name_node->get_location()); + } else if (!iterator_node->is_definition() && iterator_node->get_name()) { + mcall(node->get_iterator()->get_name()); + replace_left_assignment_with_load(node->get_iterator()->get_location()); } else { // use exist variable as the iterator mcall(node->get_iterator()->get_call()); diff --git a/src/nasal_parse.cpp b/src/nasal_parse.cpp index 82257e6..71111af 100644 --- a/src/nasal_parse.cpp +++ b/src/nasal_parse.cpp @@ -971,20 +971,26 @@ forei_expr* parse::forei_loop() { iter_expr* parse::iter_gen() { auto node = new iter_expr(toks[ptr].loc); + // definition if (lookahead(tok::var)) { match(tok::var); node->set_name(id()); + node->set_is_definition(true); update_location(node); return node; } + + // single symbol call auto id_node = id(); if (!is_call(toks[ptr].type)) { node->set_name(id_node); update_location(node); return node; } + + // call expression auto tmp = new call_expr(id_node->get_location()); - tmp->set_first(id()); + tmp->set_first(id_node); while(is_call(toks[ptr].type)) { tmp->add_call(call_scalar()); } diff --git a/src/repl.cpp b/src/repl.cpp index 2917361..2773700 100644 --- a/src/repl.cpp +++ b/src/repl.cpp @@ -111,7 +111,10 @@ void repl::execute() { info::instance()->in_repl_mode = true; std::cout << "[nasal-repl] Initializating enviroment...\n"; // run on pass for initializing basic modules, without output - run(); + if (!run()) { + std::cout << "[nasal-repl] Initialization failed.\n\n"; + std::exit(-1); + } // allow output now runtime.set_allow_repl_output_flag(true); std::cout << "[nasal-repl] Initialization complete.\n\n"; diff --git a/src/symbol_finder.cpp b/src/symbol_finder.cpp index c5105ae..404364b 100644 --- a/src/symbol_finder.cpp +++ b/src/symbol_finder.cpp @@ -29,7 +29,7 @@ bool symbol_finder::visit_function(function* node) { } bool symbol_finder::visit_iter_expr(iter_expr* node) { - if (node->get_name()) { + if (node->is_definition() && node->get_name()) { symbols.push_back({ node->get_name()->get_name(), node->get_name()->get_location() diff --git a/test/scalar.nas b/test/scalar.nas index afad81f..3e6039f 100644 --- a/test/scalar.nas +++ b/test/scalar.nas @@ -236,4 +236,17 @@ for(var a=0;a<16;a+=1) { print([0, 1, 2]~[3, 4, 5], "\n"); print(num("1.79769313486231570814527423731704357e+308"), "\n"); -print(num("4.94065645841246544176568792868e-324"), "\n"); \ No newline at end of file +print(num("4.94065645841246544176568792868e-324"), "\n"); + + +var test_call_iterator = {iter: 0}; + +foreach(test_call_iterator.iter; [0, 1, 2, 3]) { + println(test_call_iterator); +} + +var test_single_id_iterator = 0; + +foreach(test_single_id_iterator; [0, 1, 2, 3]) { + println(test_single_id_iterator); +} \ No newline at end of file