From a34f90cbd137748440d652ff2b37fbd5e459ef1f Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 12 May 2024 00:21:18 +0800 Subject: [PATCH 01/21] :memo: fix typo: `unmutable` -> `immutable` --- src/main.cpp | 16 +++++++++------- src/nasal.h | 2 +- src/nasal_gc.cpp | 4 ++-- src/nasal_lexer.h | 3 ++- src/nasal_type.cpp | 2 +- src/nasal_type.h | 4 ++-- src/natives/bits_lib.cpp | 6 +++--- src/natives/io_lib.cpp | 4 ++-- 8 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0955be9..40223ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -166,7 +166,7 @@ void execute(const std::string& file, } // run - auto start = clk::now(); + const auto start = clk::now(); if (cmd&VM_DEBUG) { auto debugger = std::unique_ptr(new nasal::dbg); debugger->run(gen, ld, argv, cmd&VM_PROFILE, cmd&VM_PROF_ALL); @@ -178,7 +178,7 @@ void execute(const std::string& file, } // get running time - auto end = clk::now(); + const auto end = clk::now(); if (cmd&VM_TIME) { std::clog << "process exited after "; std::clog << (end-start).count()*1.0/den << "s.\n\n"; @@ -211,7 +211,7 @@ i32 main(i32 argc, const char* argv[]) { } // execute with arguments - const std::unordered_map cmdlst = { + const std::unordered_map command_list = { {"--raw-ast", VM_RAW_AST}, {"--ast", VM_AST}, {"-a", VM_AST}, @@ -233,12 +233,13 @@ i32 main(i32 argc, const char* argv[]) { {"--ref-file", VM_REF_FILE}, {"--limit", VM_LIMIT|VM_EXEC} }; - u32 cmd = 0; + + u32 commands = 0; std::string filename = ""; std::vector vm_argv; for(i32 i = 1; i diff --git a/src/nasal_gc.cpp b/src/nasal_gc.cpp index e402447..215c08a 100644 --- a/src/nasal_gc.cpp +++ b/src/nasal_gc.cpp @@ -222,7 +222,7 @@ void gc::init( continue; } strs[i] = var::gcobj(new nas_val(vm_type::vm_str)); - strs[i].val.gcobj->unmutable = 1; + strs[i].val.gcobj->immutable = 1; strs[i].str() = constant_strings[i]; } @@ -234,7 +234,7 @@ void gc::init( continue; } env_argv[i] = var::gcobj(new nas_val(vm_type::vm_str)); - env_argv[i].val.gcobj->unmutable = 1; + env_argv[i].val.gcobj->immutable = 1; env_argv[i].str() = argv[i]; } } diff --git a/src/nasal_lexer.h b/src/nasal_lexer.h index 4c57f8e..bd0a778 100644 --- a/src/nasal_lexer.h +++ b/src/nasal_lexer.h @@ -177,7 +177,8 @@ private: token dots(); token calc_opr(); public: - lexer(): line(1), column(0), ptr(0), filename(""), res(""), invalid_char(0) {} + lexer(): line(1), column(0), ptr(0), + filename(""), res(""), invalid_char(0) {} const error& scan(const std::string&); const std::vector& result() const {return toks;} }; diff --git a/src/nasal_type.cpp b/src/nasal_type.cpp index 0587f27..5b3cf20 100644 --- a/src/nasal_type.cpp +++ b/src/nasal_type.cpp @@ -198,7 +198,7 @@ std::ostream& operator<<(std::ostream& out, nas_map& mp) { nas_val::nas_val(vm_type val_type) { mark = gc_status::collected; type = val_type; - unmutable = 0; + immutable = 0; switch(val_type) { case vm_type::vm_str: ptr.str = new std::string; break; case vm_type::vm_vec: ptr.vec = new nas_vec; break; diff --git a/src/nasal_type.h b/src/nasal_type.h index a217996..7cd3f17 100644 --- a/src/nasal_type.h +++ b/src/nasal_type.h @@ -250,7 +250,7 @@ struct nas_map { }; struct nas_val { - enum class gc_status:u8 { + enum class gc_status: u8 { uncollected = 0, collected, found @@ -258,7 +258,7 @@ struct nas_val { gc_status mark; vm_type type; // value type - u8 unmutable; // used to mark if a string is unmutable + u8 immutable; // used to mark if a string is immutable union { std::string* str; nas_vec* vec; diff --git a/src/natives/bits_lib.cpp b/src/natives/bits_lib.cpp index 1ccfe6d..61576c5 100644 --- a/src/natives/bits_lib.cpp +++ b/src/natives/bits_lib.cpp @@ -48,7 +48,7 @@ var builtin_fld(context* ctx, gc* ngc) { auto str = local[1]; auto startbit = local[2]; auto length = local[3]; - if (!str.is_str() || str.val.gcobj->unmutable) { + if (!str.is_str() || str.val.gcobj->immutable) { return nas_err("bits::fld", "\"str\" must be mutable string"); } if (!startbit.is_num() || !length.is_num()) { @@ -78,7 +78,7 @@ var builtin_sfld(context* ctx, gc* ngc) { auto str = local[1]; auto startbit = local[2]; auto length = local[3]; - if (!str.is_str() || str.val.gcobj->unmutable) { + if (!str.is_str() || str.val.gcobj->immutable) { return nas_err("bits::sfld", "\"str\" must be mutable string"); } if (!startbit.is_num() || !length.is_num()) { @@ -112,7 +112,7 @@ var builtin_setfld(context* ctx, gc* ngc) { auto startbit = local[2]; auto length = local[3]; auto value = local[4]; - if (!str.is_str() || str.val.gcobj->unmutable) { + if (!str.is_str() || str.val.gcobj->immutable) { return nas_err("bits::setfld", "\"str\" must be mutable string"); } if (!startbit.is_num() || !length.is_num() || !value.is_num()) { diff --git a/src/natives/io_lib.cpp b/src/natives/io_lib.cpp index 9fb4cfc..7f9b469 100644 --- a/src/natives/io_lib.cpp +++ b/src/natives/io_lib.cpp @@ -84,7 +84,7 @@ var builtin_read(context* ctx, gc* ngc) { if (!file_descriptor.object_check(file_type_name)) { return nas_err("io::read", "not a valid filehandle"); } - if (!buffer.is_str() || buffer.val.gcobj->unmutable) { + if (!buffer.is_str() || buffer.val.gcobj->immutable) { return nas_err("io::read", "\"buf\" must be mutable string"); } if (!length.is_num()) { @@ -102,7 +102,7 @@ var builtin_read(context* ctx, gc* ngc) { static_cast(file_descriptor.ghost().pointer) ); buffer.str() = temp_buffer; - buffer.val.gcobj->unmutable = true; + buffer.val.gcobj->immutable = true; delete []temp_buffer; return var::num(read_size); } From ac1960ea2784aebfc4b97e1bde68a7d25375fe1b Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 12 May 2024 11:51:28 +0800 Subject: [PATCH 02/21] :memo: adjust CI --- .github/workflows/c-cpp.yml | 19 +++++++++---------- tools/pack.py | 8 ++++++-- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 33a290b..65a76a5 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -1,4 +1,4 @@ -name: C/C++ CI +name: Nasal Interpreter Build/Test/Package CI on: schedule: @@ -20,9 +20,10 @@ jobs: cd module make all -j4 cd .. - make test - tar -czf nasal-mac-nightly.tgz . - python3 tools/pack.py + - name: test + run: make test + - name: package + run: python3 tools/pack.py - name: Release file # You may pin to the exact commit or the version. # uses: djnicholson/release-action@e9a535b3eced09c460e07a84118fb74ae9b53236 @@ -36,7 +37,6 @@ jobs: automatic_release_tag: next_macOS # File to release files: | - nasal-mac-nightly.tgz nasal-Darwin.tar linux-x86_64-build: @@ -49,10 +49,10 @@ jobs: cd module make all -j4 cd .. - make test - touch nasal-linux-x86_64-nightly.tgz - tar -czf nasal-linux-x86_64-nightly.tgz --exclude=nasal-linux-x86_64-nightly.tgz . - python3 tools/pack.py + - name: test + run: make test + - name: package + run: python3 tools/pack.py - name: Release file # You may pin to the exact commit or the version. # uses: djnicholson/release-action@e9a535b3eced09c460e07a84118fb74ae9b53236 @@ -66,6 +66,5 @@ jobs: automatic_release_tag: next_linux_x86_64 # File to release files: | - nasal-linux-x86_64-nightly.tgz nasal-Linux.tar diff --git a/tools/pack.py b/tools/pack.py index 7fddd11..63aa477 100644 --- a/tools/pack.py +++ b/tools/pack.py @@ -4,8 +4,7 @@ import os import platform import shutil - -nasal_version = "11.1" +nasal_version = "11.2" build_directory = pathlib.Path("build") if not os.path.exists(build_directory): @@ -47,20 +46,25 @@ for m in ["libfib", "libkey", "libmat", "libnasock"]: tar_file_name = "nasal-{}".format(platform.system()) + # create package directory in build directory and copy files needed package_directory = build_directory.joinpath(tar_file_name) if not os.path.exists(package_directory): os.mkdir(package_directory) os.mkdir(package_directory.joinpath("module")) + print("pack nasal executable") shutil.copy(nasal_executable, package_directory.joinpath(nasal_executable)) + print("pack nasal standard library") shutil.copytree(nasal_standard_library, package_directory.joinpath(nasal_standard_library)) + for m in nasal_modules: print("pack nasal module:", m) shutil.copy(m, package_directory.joinpath(m)) file = tarfile.open(name=tar_file_name + ".tar", mode="w") file.add(package_directory) + print("pack succeeded") file.close() From eed59cfe0722ed0bd7df6ae8c523fcc6956b9445 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 12 May 2024 12:11:31 +0800 Subject: [PATCH 03/21] :memo: update README: add download links --- README.md | 18 ++++++++++++++---- doc/README_zh.md | 23 +++++++++++++++++------ 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 82ac078..a90f40c 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,8 @@ ## __Contents__ * [__Introduction__](#introduction) -* [__Compile__](#how-to-compile) +* [__Download__](#download) +* [__Compile__](#compile) * [__Usage__](#how-to-use) * [__Tutorial__](./doc/tutorial.md) * [__Release Notes__](./doc/dev.md#release-notes) @@ -42,11 +43,10 @@ __Contact us if having great ideas to share!__ [Nasal](http://wiki.flightgear.org/Nasal_scripting_language) is an ECMAscript-like language used in [FlightGear](https://www.flightgear.org/). The designer is [Andy Ross](https://github.com/andyross). - This interpreter is rewritten by [ValKmjolnir](https://github.com/ValKmjolnir) using `C++`(`-std=c++17`). We really appreciate that Andy created this amazing programming language: [Andy Ross's nasal interpreter](https://github.com/andyross/nasal). -This project uses __MIT license__ (2019/7 ~ 2021/5/4 ~ 2023/5), __GPL v2 license__ (since 2023/6). +Old version of this project uses __MIT license__ (2019/7 ~ 2021/5/4 ~ 2023/5). Now it uses __GPL v2 license__ (since 2023/6). ### __Why writing this Nasal interpreter?__ @@ -64,7 +64,17 @@ interesting programs and run them without the lib of Flightgear. You could add your own modules to make the interpreter a useful tool in your own projects. -## __How to Compile__ +## __Download__ + +Nightly build could be found here. +Windows nightly build is not supported yet, +please wait or just compile it by yourself, a Cmake file is given for Visual Studio to compile this project easily: + +* [macOS-nightly-build](https://github.com/ValKmjolnir/Nasal-Interpreter/releases/tag/next_macOS) +* [linux-nightly-build](https://github.com/ValKmjolnir/Nasal-Interpreter/releases/tag/next_linux_x86_64) +* windows-nightly-build: [WIP] + +## __Compile__ ![g++](https://img.shields.io/badge/GNU-g++-A42E2B?style=flat-square&logo=GNU) ![clang++](https://img.shields.io/badge/LLVM-clang++-262D3A?style=flat-square&logo=LLVM) diff --git a/doc/README_zh.md b/doc/README_zh.md index ddb213f..1e2a96b 100644 --- a/doc/README_zh.md +++ b/doc/README_zh.md @@ -13,6 +13,7 @@ ## __目录__ * [__简介__](#简介) +* [__下载__](#下载) * [__编译__](#编译) * [__使用方法__](#使用方法) * [__教程__](../doc/tutorial_zh.md) @@ -42,18 +43,28 @@ __如果有好的意见或建议,欢迎联系我们!__ [Nasal](http://wiki.flightgear.org/Nasal_scripting_language) 是一款语法与 ECMAscript 相似的编程语言,并作为脚本语言被著名开源飞行模拟器 [FlightGear](https://www.flightgear.org/) 所使用。 该语言的设计者为 [Andy Ross](https://github.com/andyross)。 +该解释器由 [ValKmjolnir](https://github.com/ValKmjolnir) 使用 `C++`(`-std=c++17`)重新实现。非常感谢 Andy 为我们设计了这个神奇且简洁的编程语言: [Andy Ross 的 nasal 解释器](https://github.com/andyross/nasal)。 -该解释器项目由 [ValKmjolnir](https://github.com/ValKmjolnir) 使用 `C++`(`-std=c++17`)重新实现,我们非常感谢Andy为我们带来了这样一个神奇且简洁的编程语言: [Andy Ross 的 nasal 解释器](https://github.com/andyross/nasal)。 +该项目旧版本使用 __MIT__ 协议开源 (2019/7 ~ 2021/5/4 ~ 2023/5),从 2023/6 开始新版本使用 __GPL v2__ 协议。 -该项目使用 __MIT__ 协议开源 (2019/7 ~ 2021/5/4 ~ 2023/5),从 2023/6 开始使用 __GPL v2__ 协议。 +### __为什么重新写 Nasal 解释器?__ -### __我们为什么想要重新写一个 Nasal 解释器?__ +2019 年暑假,[FGPRC](https://www.fgprc.org.cn/) 的成员告诉我,在 Flightgear 中提供的 nasal 控制台窗口中进行调试很不方便,仅仅是想检查语法错误,也得花时间打开软件等待加载进去后进行调试。所以我就写了一个全新的解释器来帮助他们检查语法错误以及运行时错误。 -2019年暑假,[FGPRC](https://www.fgprc.org.cn/) 的成员告诉我,在Flightgear中提供的nasal控制台窗口中进行调试很不方便,仅仅是想检查语法错误,也得花时间打开软件等待加载进去后进行调试。所以我就写了一个全新的解释器来帮助他们检查语法错误以及运行时错误。 +我编写了 nasal 的词法分析器和语法分析器,以及一个全新的字节码虚拟机,并用这个运行时来进行 nasal 程序的调试。我们发现使用这个解释器来检测语法和运行时错误极大的提高了效率。 -我编写了nasal的词法分析器和语法分析器,以及一个全新的字节码虚拟机,并用这个运行时来进行nasal程序的调试。我们发现使用这个解释器来检测语法和运行时错误极大的提高了效率。 +你也可以使用这个语言来写一些与 Flightgear 运行环境无关的有趣的程序,并用这个解释器来执行。你也可以让解释器来调用你自己编写的模块,使它成为项目中一个非常有用的工具。 -你也可以使用这个语言来写一些与Flightgear运行环境无关的有趣的程序,并用这个解释器来执行。你也可以让解释器来调用你自己编写的模块,使它成为项目中一个非常有用的工具。 +## __下载__ + +现在支持下载预览版(Nightly Build)。 +Windows 平台的预览版解释器现在还没配置相关流水线, +请耐心等候或者直接在本地编译。 +我们提供了一份 Cmake 文件,可以很方便地在 Visual Studio 中编译: + +* [macOS-nightly-build](https://github.com/ValKmjolnir/Nasal-Interpreter/releases/tag/next_macOS) +* [linux-nightly-build](https://github.com/ValKmjolnir/Nasal-Interpreter/releases/tag/next_linux_x86_64) +* windows-nightly-build: [施工中...] ## __编译__ From 8e38764df0a68eea1e4ed0160269b0f199ff775d Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 12 May 2024 19:34:05 +0800 Subject: [PATCH 04/21] :memo: change span data from u32 to u64 --- README.md | 1 - doc/README_zh.md | 1 - module/fib.cpp | 6 ++++++ src/ast_dumper.h | 3 +-- src/nasal_ast.h | 10 +++++----- src/nasal_dbg.cpp | 2 +- src/nasal_err.cpp | 22 +++++++++++----------- src/nasal_err.h | 16 ++++++++++------ src/nasal_lexer.cpp | 26 +++++++++++++------------- src/nasal_lexer.h | 6 +++--- src/nasal_opcode.h | 2 +- src/nasal_parse.cpp | 4 ++-- src/nasal_parse.h | 6 +++--- src/nasal_vm.cpp | 4 ++-- src/natives/nasal_builtin.cpp | 10 +++++++--- src/natives/nasal_builtin.h | 2 ++ tools/pack.py | 2 -- 17 files changed, 67 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index a90f40c..f5a72e8 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ -![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) [![license](https://img.shields.io/badge/license-GPLv2-green?style=flat-square&logo=github)](./LICENSE) ![downloads](https://img.shields.io/github/downloads/ValKmjolnir/Nasal-Interpreter/total.svg?style=flat-square&logo=github) diff --git a/doc/README_zh.md b/doc/README_zh.md index 1e2a96b..2f655e9 100644 --- a/doc/README_zh.md +++ b/doc/README_zh.md @@ -2,7 +2,6 @@ -![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) [![license](https://img.shields.io/badge/license-GPLv2-green?style=flat-square&logo=github)](../LICENSE) ![downloads](https://img.shields.io/github/downloads/ValKmjolnir/Nasal-Interpreter/total.svg?style=flat-square&logo=github) diff --git a/module/fib.cpp b/module/fib.cpp index 68e7264..d618a37 100644 --- a/module/fib.cpp +++ b/module/fib.cpp @@ -53,7 +53,9 @@ struct ghost_obj { void ghost_for_test_destructor(void* ptr) { std::cout << "ghost_for_test::destructor (0x"; std::cout << std::hex << reinterpret_cast(ptr) << std::dec << ") {\n"; + delete static_cast(ptr); + std::cout << " delete 0x" << std::hex; std::cout << reinterpret_cast(ptr) << std::dec << ";\n"; std::cout << "}\n"; @@ -62,7 +64,9 @@ void ghost_for_test_destructor(void* ptr) { void ghost_for_test_gc_marker(void* ptr, std::vector* bfs_queue) { std::cout << "ghost_for_test::mark (0x"; std::cout << std::hex << reinterpret_cast(ptr) << std::dec << ") {\n"; + bfs_queue->push_back(static_cast(ptr)->test_string); + std::cout << " mark 0x" << std::hex; std::cout << reinterpret_cast(ptr) << std::dec << "->test_string;\n"; std::cout << "}\n"; @@ -86,8 +90,10 @@ var set_new_ghost(var* args, usize size, gc* ngc) { return nil; } f64 num = args[1].num(); + reinterpret_cast(res.ghost().pointer)->number = static_cast(num); std::cout << "set_new_ghost: successfully set ghost.number = " << num << "\n"; + reinterpret_cast(res.ghost().pointer)->test_string = ngc->newstr("just for test"); std::cout << "set_new_ghost: successfully set ghost.test_string = just for test\n"; return nil; diff --git a/src/ast_dumper.h b/src/ast_dumper.h index e20f5c4..2049044 100644 --- a/src/ast_dumper.h +++ b/src/ast_dumper.h @@ -35,8 +35,7 @@ private: std::string format_location(const span& location) { std::stringstream ss; ss << " -> "; - ss << location.file << ":"; - ss << location.begin_line << ":" << location.begin_column + 1; + location.dump_begin(ss); ss << "\n"; return ss.str(); } diff --git a/src/nasal_ast.h b/src/nasal_ast.h index 2d2a88c..3913ff9 100644 --- a/src/nasal_ast.h +++ b/src/nasal_ast.h @@ -8,7 +8,7 @@ namespace nasal { -enum class expr_type: u32 { +enum class expr_type { ast_null = 0, // null node ast_use, // use statement ast_block, // code block @@ -65,13 +65,13 @@ public: expr(const span& location, expr_type node_type): nd_loc(location), nd_type(node_type) {} virtual ~expr() = default; - void set_begin(u32 line, u32 column) { + void set_begin(u64 line, u64 column) { nd_loc.begin_line = line; nd_loc.begin_column = column; } - const span& get_location() const {return nd_loc;} - const u32 get_line() const {return nd_loc.begin_line;} - expr_type get_type() const {return nd_type;} + const auto& get_location() const { return nd_loc; } + const auto get_line() const { return nd_loc.begin_line; } + auto get_type() const { return nd_type; } void update_location(const span& location) { nd_loc.end_line = location.end_line; nd_loc.end_column = location.end_column; diff --git a/src/nasal_dbg.cpp b/src/nasal_dbg.cpp index 38c9e39..0975d3b 100644 --- a/src/nasal_dbg.cpp +++ b/src/nasal_dbg.cpp @@ -260,7 +260,7 @@ void dbg::run( std::vector code; std::vector code_file_index; std::vector code_line; - for(auto& i : gen.codes()) { + for(const auto& i : gen.codes()) { code.push_back(i.op); code_file_index.push_back(i.fidx); code_line.push_back(i.line); diff --git a/src/nasal_err.cpp b/src/nasal_err.cpp index 4f201ac..42a71d3 100644 --- a/src/nasal_err.cpp +++ b/src/nasal_err.cpp @@ -127,15 +127,15 @@ void error::err( ++cnt; - std::cerr - << red << stage << ": " << white << info << reset << "\n" << cyan << " --> " - << red << loc.file << ":" << loc.begin_line << ":" << loc.begin_column+1 - << reset << "\n"; + std::cerr << red << stage << ": " << white << info << reset << "\n"; + std::cerr << cyan << " --> " << red; + loc.dump_begin(std::cerr); + std::cerr << reset << "\n"; const usize maxlen = std::to_string(loc.end_line).length(); const std::string iden = identation(maxlen); - for(u32 line = loc.begin_line; line<=loc.end_line; ++line) { + for(u64 line = loc.begin_line; line<=loc.end_line; ++line) { // skip line 0 if (!line) { continue; @@ -164,25 +164,25 @@ void error::err( // output underline std::cerr << cyan << iden << " | " << reset; if (loc.begin_line==loc.end_line) { - for(u32 i = 0; i toks; - const std::unordered_map typetbl { + const std::unordered_map token_mapper = { {"use" ,tok::use }, {"true" ,tok::tktrue }, {"false" ,tok::tkfalse }, diff --git a/src/nasal_opcode.h b/src/nasal_opcode.h index 687a32c..9a3b835 100644 --- a/src/nasal_opcode.h +++ b/src/nasal_opcode.h @@ -101,7 +101,7 @@ struct opcode { u8 op; // opcode u16 fidx; // source code file index u32 num; // immediate num - u32 line; // location line of source code + u64 line; // location line of source code opcode() = default; opcode(const opcode&) = default; opcode& operator=(const opcode&) = default; diff --git a/src/nasal_parse.cpp b/src/nasal_parse.cpp index 06e40a1..dc3b1a2 100644 --- a/src/nasal_parse.cpp +++ b/src/nasal_parse.cpp @@ -105,7 +105,7 @@ bool parse::check_comma(const tok* panic_set) { } bool parse::check_tuple() { - u32 check_ptr=ptr, curve=1, bracket=0, brace=0; + u64 check_ptr = ptr, curve = 1, bracket = 0, brace = 0; while(toks[++check_ptr].type!=tok::eof && curve) { switch(toks[check_ptr].type) { case tok::lcurve: ++curve; break; @@ -157,7 +157,7 @@ bool parse::check_in_curve_multi_definition() { bool parse::check_special_call() { // special call means like this: function_name(a:1,b:2,c:3); - u32 check_ptr = ptr, curve = 1, bracket = 0, brace = 0; + u64 check_ptr = ptr, curve = 1, bracket = 0, brace = 0; while(toks[++check_ptr].type!=tok::eof && curve) { switch(toks[check_ptr].type) { case tok::lcurve: ++curve; break; diff --git a/src/nasal_parse.h b/src/nasal_parse.h index f662770..2d8ff27 100644 --- a/src/nasal_parse.h +++ b/src/nasal_parse.h @@ -15,9 +15,9 @@ class parse { #define prevspan (ptr!=0? toks[ptr-1].loc:toks[ptr].loc) private: - u32 ptr; - u32 in_func; // count function block - u32 in_loop; // count loop block + u64 ptr; + u64 in_func; // count function block + u64 in_loop; // count loop block const token* toks; code_block* root; error err; diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index 68f8031..496155f 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -451,7 +451,7 @@ void vm::run( &&mcallv, &&mcallh, &&ret }; std::vector code; - for(auto& i : gen.codes()) { + for(const auto& i : gen.codes()) { code.push_back(oprs[i.op]); imm.push_back(i.num); } @@ -506,7 +506,7 @@ void vm::run( &vm::o_ret }; std::vector code; - for(auto& i : gen.codes()) { + for(const auto& i : gen.codes()) { code.push_back(oprs[i.op]); imm.push_back(i.num); } diff --git a/src/natives/nasal_builtin.cpp b/src/natives/nasal_builtin.cpp index 04e695b..15af44a 100644 --- a/src/natives/nasal_builtin.cpp +++ b/src/natives/nasal_builtin.cpp @@ -339,6 +339,7 @@ var builtin_left(context* ctx, gc* ngc) { auto local = ctx->localr; var str = local[1]; var len = local[2]; + if (!str.is_str()) { return nas_err("left", "\"string\" must be string"); } @@ -355,20 +356,23 @@ var builtin_right(context* ctx, gc* ngc) { auto local = ctx->localr; var str = local[1]; var len = local[2]; + if (!str.is_str()) { return nas_err("right", "\"string\" must be string"); } if (!len.is_num()) { return nas_err("right", "\"length\" must be number"); } + i32 length = static_cast(len.num()); - i32 srclen = str.str().length(); + i32 srclen = static_cast(str.str().length()); if (length>srclen) { length = srclen; } if (length<0) { length = 0; } + return ngc->newstr(str.str().substr(srclen-length, srclen)); } @@ -566,12 +570,12 @@ public: } f64 elapsed_milliseconds() { - auto duration = std::chrono::high_resolution_clock::now() - stamp; + const auto duration = std::chrono::high_resolution_clock::now() - stamp; return std::chrono::duration_cast(duration).count(); } f64 elapsed_microseconds() { - auto duration = std::chrono::high_resolution_clock::now() - stamp; + const auto duration = std::chrono::high_resolution_clock::now() - stamp; return std::chrono::duration_cast(duration).count(); } }; diff --git a/src/natives/nasal_builtin.h b/src/natives/nasal_builtin.h index 9ca7503..28674cd 100644 --- a/src/natives/nasal_builtin.h +++ b/src/natives/nasal_builtin.h @@ -66,10 +66,12 @@ 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(context*, gc*); + var builtin_maketimestamp(context*, gc*); var builtin_time_stamp(context*, gc*); var builtin_elapsed_millisecond(context*, gc*); diff --git a/tools/pack.py b/tools/pack.py index 63aa477..3be7d00 100644 --- a/tools/pack.py +++ b/tools/pack.py @@ -4,8 +4,6 @@ import os import platform import shutil -nasal_version = "11.2" - build_directory = pathlib.Path("build") if not os.path.exists(build_directory): print("pack binaries failed: build directory not found") From 96731d180febf52bd1311af90810e8d88ef77433 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 12 May 2024 22:33:51 +0800 Subject: [PATCH 05/21] :sparkles: append code size from u32 to u64 --- makefile | 2 +- src/ast_dumper.h | 4 +- src/main.cpp | 6 +- src/nasal_codegen.cpp | 50 +++++---- src/nasal_codegen.h | 19 ++-- src/nasal_dbg.cpp | 30 +++--- src/nasal_gc.cpp | 15 ++- src/nasal_gc.h | 2 +- src/nasal_opcode.cpp | 11 +- src/nasal_opcode.h | 189 +++++++++++++++++----------------- src/nasal_type.cpp | 8 +- src/nasal_type.h | 18 ++-- src/nasal_vm.cpp | 26 +++-- src/nasal_vm.h | 47 ++++----- src/natives/nasal_builtin.cpp | 50 ++++++--- 15 files changed, 252 insertions(+), 225 deletions(-) diff --git a/makefile b/makefile index 7bbc56c..aae7741 100644 --- a/makefile +++ b/makefile @@ -6,7 +6,7 @@ endif ifeq ($(OS), Darwin) CXXFLAGS = -std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15 -I src else - CXXFLAGS = -std=$(STD) -c -O3 -fPIC -I src + CXXFLAGS = -std=$(STD) -c -O3 -fPIC -I src -Wconversion -Wno-float-conversion endif NASAL_HEADER = \ diff --git a/src/ast_dumper.h b/src/ast_dumper.h index 2049044..c762f79 100644 --- a/src/ast_dumper.h +++ b/src/ast_dumper.h @@ -9,9 +9,11 @@ namespace nasal { -class ast_dumper:public ast_visitor { +class ast_dumper: public ast_visitor { private: std::vector indent; + +private: void push_indent() { if (indent.size()) { if (indent.back()=="|--") { diff --git a/src/main.cpp b/src/main.cpp index 40223ec..42d12f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -95,7 +95,8 @@ std::ostream& logo(std::ostream& out) { } std::ostream& version(std::ostream& out) { - std::srand(std::time(nullptr)); + std::srand(static_cast(std::time(nullptr))); + f64 num = 0; for(u32 i = 0; i<5; ++i) { num = (num+rand())*(1.0/(RAND_MAX+1.0)); @@ -103,6 +104,7 @@ std::ostream& version(std::ostream& out) { if (num<0.01) { nasal::parse::easter_egg(); } + out << "nasal interpreter version " << __nasver__; out << " " << nasal::get_platform() << " " << nasal::get_arch(); out << " (" << __DATE__ << " " << __TIME__ << ")\n"; @@ -181,7 +183,7 @@ void execute(const std::string& file, const auto end = clk::now(); if (cmd&VM_TIME) { std::clog << "process exited after "; - std::clog << (end-start).count()*1.0/den << "s.\n\n"; + std::clog << static_cast((end-start).count())/den << "s.\n\n"; } } diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index cfc84ab..81ec3ae 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -70,7 +70,8 @@ void codegen::regist_number(const f64 num) { if (const_number_map.count(num)) { return; } - u32 size = const_number_map.size(); + + auto size = const_number_map.size(); const_number_map[num] = size; const_number_table.push_back(num); } @@ -79,7 +80,8 @@ void codegen::regist_string(const std::string& str) { if (const_string_map.count(str)) { return; } - u32 size = const_string_map.size(); + + auto size = const_string_map.size(); const_string_map[str] = size; const_string_table.push_back(str); } @@ -107,18 +109,20 @@ void codegen::find_symbol(code_block* node) { } void codegen::regist_symbol(const std::string& name) { + // regist global if local scope list is empty if (local.empty()) { if (global.count(name)) { return; } - i32 index = global.size(); + auto index = global.size(); global[name] = index; return; } + if (local.back().count(name)) { return; } - i32 index = local.back().size(); + auto index = local.back().size(); local.back()[name] = index; } @@ -149,7 +153,7 @@ i32 codegen::upvalue_symbol_find(const std::string& name) { return index; } -void codegen::emit(u8 operation_code, u32 immediate_num, const span& location) { +void codegen::emit(u8 operation_code, u64 immediate_num, const span& location) { code.push_back({ operation_code, static_cast(file_map.at(location.file)), @@ -505,7 +509,7 @@ void codegen::single_def(definition_expr* node) { const auto& str = node->get_variable_name()->get_name(); calc_gen(node->get_value()); // only generate in repl mode and in global scope - if (need_repl_output && local.empty()) { + if (flag_need_repl_output && local.empty()) { emit(op_repl, 0, node->get_location()); } if (local.empty()) { @@ -752,16 +756,16 @@ void codegen::multi_assign_gen(multi_assign* node) { } } - i32 size = tuple_node->get_elements().size(); + i64 size = static_cast(tuple_node->get_elements().size()); // generate multiple assignment: (a, b, c) = (1, 2, 3); if (value_node->get_type()==expr_type::ast_tuple) { const auto& value_tuple = reinterpret_cast(value_node) ->get_elements(); - for(i32 i = size-1; i>=0; --i) { + for(i64 i = size-1; i>=0; --i) { calc_gen(value_tuple[i]); } auto& tuple = tuple_node->get_elements(); - for(i32 i = 0; iget_elements(); - for(i32 i = 0; iget_location()); mcall(tuple[i]); // use load operands to avoid meq's pop operand // and this operation changes local and global value directly replace_left_assignment_with_load(tuple[i]->get_location()); } + // pop source vector emit(op_pop, 0, node->get_location()); } @@ -834,7 +839,7 @@ void codegen::loop_gen(expr* node) { } } -void codegen::load_continue_break(i32 continue_place, i32 break_place) { +void codegen::load_continue_break(u64 continue_place, u64 break_place) { for(auto i : continue_ptr.front()) { code[i].num = continue_place; } @@ -943,7 +948,7 @@ void codegen::statement_generation(expr* node) { case expr_type::ast_ternary: calc_gen(node); // only generate in repl mode and in global scope - if (need_repl_output && local.empty()) { + if (flag_need_repl_output && local.empty()) { emit(op_repl, 0, node->get_location()); } emit(op_pop, 0, node->get_location()); @@ -1254,7 +1259,7 @@ void codegen::block_gen(code_block* node) { break; case expr_type::ast_null: break; case expr_type::ast_id: - if (need_repl_output && local.empty()) { + if (flag_need_repl_output && local.empty()) { repl_mode_info_output_gen(tmp); } else { check_id_exist(reinterpret_cast(tmp)); @@ -1264,7 +1269,7 @@ void codegen::block_gen(code_block* node) { case expr_type::ast_num: case expr_type::ast_str: case expr_type::ast_bool: - if (need_repl_output && local.empty()) { + if (flag_need_repl_output && local.empty()) { repl_mode_info_output_gen(tmp); } break; @@ -1313,7 +1318,7 @@ const error& codegen::compile(parse& parse, linker& import, bool repl_flag, bool limit_mode) { - need_repl_output = repl_flag; + flag_need_repl_output = repl_flag; flag_limited_mode = limit_mode; init_native_function(); init_file_map(import.get_file_list()); @@ -1334,13 +1339,13 @@ const error& codegen::compile(parse& parse, emit(op_exit, 0, parse.tree()->get_location()); // size out of bound check - if (const_number_table.size()>0xffffff) { + if (const_number_table.size()>INT64_MAX) { err.err("code", "too many constant numbers: " + std::to_string(const_number_table.size()) ); } - if (const_string_table.size()>0xffffff) { + if (const_string_table.size()>INT64_MAX) { err.err("code", "too many constant strings: " + std::to_string(const_string_table.size()) @@ -1356,7 +1361,7 @@ const error& codegen::compile(parse& parse, } // check generated code size - if (code.size()>0xffffff) { + if (code.size()>INT64_MAX) { err.err("code", "bytecode size overflow: " + std::to_string(code.size()) @@ -1367,8 +1372,8 @@ const error& codegen::compile(parse& parse, void codegen::print(std::ostream& out) { // func end stack, reserved for code print - std::stack func_begin_stack; - std::stack func_end_stack; + std::stack func_begin_stack; + std::stack func_end_stack; // print const numbers for(auto num : const_number_table) { @@ -1391,7 +1396,8 @@ void codegen::print(std::ostream& out) { const_string_table.data(), native_function.data() ); - for(u32 i = 0; i:\n"; - for(u32 j = i; j unsafe_system_api = { // builtin @@ -67,8 +68,8 @@ private: std::vector in_foreach_loop_level; // constant numbers and strings - std::unordered_map const_number_map; - std::unordered_map const_string_map; + std::unordered_map const_number_map; + std::unordered_map const_string_map; std::vector const_number_table; std::vector const_string_table; @@ -82,17 +83,17 @@ private: std::vector code; // used to store jmp operands index, to fill the jump address back - std::list> continue_ptr; - std::list> break_ptr; + std::list> continue_ptr; + std::list> break_ptr; // symbol table // global : max STACK_DEPTH-1 values - std::unordered_map global; + std::unordered_map global; std::unordered_map> experimental_namespace; // local : max 32768 upvalues 65536 values // but in fact local scope also has less than STACK_DEPTH value - std::list> local; + std::list> local; void check_id_exist(identifier*); @@ -108,7 +109,7 @@ private: i32 global_symbol_find(const std::string&); i32 upvalue_symbol_find(const std::string&); - void emit(u8, u32, const span&); + void emit(u8, u64, const span&); void number_gen(number_literal*); void string_gen(string_literal*); @@ -135,7 +136,7 @@ private: void multi_assign_gen(multi_assign*); void cond_gen(condition_expr*); void loop_gen(expr*); - void load_continue_break(i32, i32); + void load_continue_break(u64, u64); void while_gen(while_expr*); void for_gen(for_expr*); void forei_gen(forei_expr*); diff --git a/src/nasal_dbg.cpp b/src/nasal_dbg.cpp index 0975d3b..c835817 100644 --- a/src/nasal_dbg.cpp +++ b/src/nasal_dbg.cpp @@ -147,12 +147,14 @@ void dbg::list_file() const { } void dbg::step_info() { - u32 line = bytecode[ctx.pc].line==0? 0:bytecode[ctx.pc].line-1; - u32 begin = (line>>3)==0? 0:((line>>3)<<3); - u32 end = (1+(line>>3))<<3; + u64 line = bytecode[ctx.pc].line==0? 0:bytecode[ctx.pc].line-1; + u64 begin = (line>>3)==0? 0:((line>>3)<<3); + u64 end = (1+(line>>3))<<3; + src.load(files[bytecode[ctx.pc].fidx]); + std::clog << "\nsource code:\n"; - for(u32 i = begin; i ":" ") << src[i] << reset << "\n"; } @@ -160,8 +162,9 @@ 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 << "\nnext bytecode:\n"; - for(u32 i = begin; i ":" ") @@ -234,19 +237,18 @@ void dbg::interact() { } } -void dbg::run( - const codegen& gen, - const linker& linker, - const std::vector& argv, - bool profile, - bool show_all_prof_result) { +void dbg::run(const codegen& gen, + const linker& linker, + const std::vector& argv, + bool profile, + bool show_all_prof_result) { set_detail_report_info(true); do_operand_count = profile || show_all_prof_result; const auto& file_list = linker.get_file_list(); fsize = file_list.size(); - init( + vm_init_enrty( gen.strs(), gen.nums(), gen.natives(), @@ -257,9 +259,9 @@ void dbg::run( ); counter.init(file_list); - std::vector code; + std::vector code; std::vector code_file_index; - std::vector code_line; + std::vector code_line; for(const auto& i : gen.codes()) { code.push_back(i.op); code_file_index.push_back(i.fidx); diff --git a/src/nasal_gc.cpp b/src/nasal_gc.cpp index 215c08a..bbbf3b0 100644 --- a/src/nasal_gc.cpp +++ b/src/nasal_gc.cpp @@ -189,7 +189,7 @@ void gc::extend(const vm_type type) { const u8 index = static_cast(type)-static_cast(vm_type::vm_str); size[index] += incr[index]; - for(u32 i = 0; i& constant_strings, - const std::vector& argv -) { +void gc::init(const std::vector& constant_strings, + const std::vector& argv) { // initialize counters worktime = 0; for(u8 i = 0; i(gcnt[i]); std::clog << " " << left << setw(indent) << setfill(' ') << name[i]; std::clog << " | " << left << setw(indent) << setfill(' ') << gcnt[i]; std::clog << " | " << left << setw(indent) << setfill(' ') << acnt[i]; diff --git a/src/nasal_gc.h b/src/nasal_gc.h index 63df51a..daf5fa9 100644 --- a/src/nasal_gc.h +++ b/src/nasal_gc.h @@ -41,7 +41,7 @@ struct gc { std::vector unused[gc_type_size]; // gc free list /* heap increase size */ - u32 incr[gc_type_size] = { + u64 incr[gc_type_size] = { 128, // vm_str 128, // vm_vec 64, // vm_hash diff --git a/src/nasal_opcode.cpp b/src/nasal_opcode.cpp index 6b8a36c..1678a20 100644 --- a/src/nasal_opcode.cpp +++ b/src/nasal_opcode.cpp @@ -27,11 +27,10 @@ const char* opname[] = { "mcallv", "mcallh", "ret " }; -void codestream::set( - const f64* number_list, - const std::string* string_list, - const nasal_builtin_table* native_table, - const std::string* file_list) { +void codestream::set(const f64* number_list, + const std::string* string_list, + const nasal_builtin_table* native_table, + const std::string* file_list) { const_number = number_list; const_string = string_list; natives = native_table; @@ -110,6 +109,8 @@ void codestream::dump(std::ostream& out) const { } break; } + + // if file list is loaded, dump file location info if (files) { out << " (" << files[code.fidx] << ":" << code.line << ")"; } diff --git a/src/nasal_opcode.h b/src/nasal_opcode.h index 9a3b835..ace9497 100644 --- a/src/nasal_opcode.h +++ b/src/nasal_opcode.h @@ -8,99 +8,99 @@ namespace nasal { enum op_code_type: u8 { - op_exit, // stop the virtual machine - op_repl, // in repl mode: print value on stack top - op_intl, // local scope size - op_loadg, // load global value - op_loadl, // load local value - op_loadu, // load upvalue - op_pnum, // push constant number to the stack - op_pnil, // push constant nil to the stack - op_pstr, // push constant std::string to the stack - op_newv, // push new vector with initial values from stack - op_newh, // push new hash to the stack - op_newf, // push new function to the stack - op_happ, // hash append - op_para, // normal parameter - op_deft, // default parameter - op_dyn, // dynamic parameter - op_lnot, // ! logical negation - op_usub, // - negation - op_bnot, // ~ bitwise not static_cast - op_btor, // | bitwise or - op_btxor, // ^ bitwise xor - op_btand, // & bitwise and - op_add, // + - op_sub, // - - op_mul, // * - op_div, // / - op_lnk, // ~ - op_addc, // + const - op_subc, // - const - op_mulc, // * const - op_divc, // / const - op_lnkc, // ~ const - op_addeq, // += maybe pop stack top - op_subeq, // -= maybe pop stack top - op_muleq, // *= maybe pop stack top - op_diveq, // /= maybe pop stack top - op_lnkeq, // ~= maybe pop stack top - op_btandeq,// &= maybe pop stack top - op_btoreq, // |= maybe pop stack top - op_btxoreq,// ^= maybe pop stack top - op_addeqc, // += const don't pop stack top - op_subeqc, // -= const don't pop stack top - op_muleqc, // *= const don't pop stack top - op_diveqc, // /= const don't pop stack top - op_lnkeqc, // ~= const don't pop stack top - op_addecp, // += const and pop stack top - op_subecp, // -= const and pop stack top - op_mulecp, // *= const and pop stack top - op_divecp, // /= const and pop stack top - op_lnkecp, // ~= concat const std::string and pop stack top - op_meq, // = maybe pop stack top - op_eq, // == compare operator - op_neq, // != compare operator - op_less, // < compare operator - op_leq, // <= compare operator - op_grt, // > compare operator - op_geq, // >= compare operator - op_lessc, // < const compare operator - op_leqc, // <= const compare operator - op_grtc, // > const compare operator - op_geqc, // >= const compare operator - op_pop, // pop a value out of stack top - op_jmp, // jump absolute address with no condition - op_jt, // used in operator and/or,jmp when condition is true and DO NOT POP - op_jf, // used in conditional/loop,jmp when condition is false and POP STACK - op_cnt, // add counter for forindex/foreach - op_findex, // index counter on the top of forindex_stack plus 1 - op_feach, // index counter on the top of forindex_stack plus 1 and get the value in vector - op_callg, // get value in global scope - op_calll, // get value in local scope - op_upval, // get value in closure, high 16 as the index of upval, low 16 as the index of local - op_callv, // call vec[index] - op_callvi, // call vec[immediate] (used in multi-assign/multi-define) - op_callh, // call hash.label - op_callfv, // call function(vector as parameters) - op_callfh, // call function(hash as parameters) - op_callb, // call native functions - op_slcbeg, // begin of slice like: vec[1, 2, 3:6, 0, -1] - op_slcend, // end of slice - op_slc, // slice like vec[1] - op_slc2, // slice like vec[nil:10] - op_mcallg, // get memory space of value in global scope - op_mcalll, // get memory space of value in local scope - op_mupval, // get memory space of value in closure - op_mcallv, // get memory space of vec[index] - op_mcallh, // get memory space of hash.label - op_ret // return + op_exit, // stop the virtual machine + op_repl, // in repl mode: print value on stack top + op_intl, // local scope size + op_loadg, // load global value + op_loadl, // load local value + op_loadu, // load upvalue + op_pnum, // push constant number to the stack + op_pnil, // push constant nil to the stack + op_pstr, // push constant std::string to the stack + op_newv, // push new vector with initial values from stack + op_newh, // push new hash to the stack + op_newf, // push new function to the stack + op_happ, // hash append + op_para, // normal parameter + op_deft, // default parameter + op_dyn, // dynamic parameter + op_lnot, // ! logical negation + op_usub, // - negation + op_bnot, // ~ bitwise not static_cast + op_btor, // | bitwise or + op_btxor, // ^ bitwise xor + op_btand, // & bitwise and + op_add, // + + op_sub, // - + op_mul, // * + op_div, // / + op_lnk, // ~ + op_addc, // + const + op_subc, // - const + op_mulc, // * const + op_divc, // / const + op_lnkc, // ~ const + op_addeq, // += maybe pop stack top + op_subeq, // -= maybe pop stack top + op_muleq, // *= maybe pop stack top + op_diveq, // /= maybe pop stack top + op_lnkeq, // ~= maybe pop stack top + op_btandeq, // &= maybe pop stack top + op_btoreq, // |= maybe pop stack top + op_btxoreq, // ^= maybe pop stack top + op_addeqc, // += const don't pop stack top + op_subeqc, // -= const don't pop stack top + op_muleqc, // *= const don't pop stack top + op_diveqc, // /= const don't pop stack top + op_lnkeqc, // ~= const don't pop stack top + op_addecp, // += const and pop stack top + op_subecp, // -= const and pop stack top + op_mulecp, // *= const and pop stack top + op_divecp, // /= const and pop stack top + op_lnkecp, // ~= concat const std::string and pop stack top + op_meq, // = maybe pop stack top + op_eq, // == compare operator + op_neq, // != compare operator + op_less, // < compare operator + op_leq, // <= compare operator + op_grt, // > compare operator + op_geq, // >= compare operator + op_lessc, // < const compare operator + op_leqc, // <= const compare operator + op_grtc, // > const compare operator + op_geqc, // >= const compare operator + op_pop, // pop a value out of stack top + op_jmp, // jump absolute address with no condition + op_jt, // used in operator and/or,jmp when condition is true and DO NOT POP + op_jf, // used in conditional/loop,jmp when condition is false and POP STACK + op_cnt, // add counter for forindex/foreach + op_findex, // index counter on the top of forindex_stack plus 1 + op_feach, // index counter on the top of forindex_stack plus 1 and get the value in vector + op_callg, // get value in global scope + op_calll, // get value in local scope + op_upval, // get value in closure, high 16 as the index of upval, low 16 as the index of local + op_callv, // call vec[index] + op_callvi, // call vec[immediate] (used in multi-assign/multi-define) + op_callh, // call hash.label + op_callfv, // call function(vector as parameters) + op_callfh, // call function(hash as parameters) + op_callb, // call native functions + op_slcbeg, // begin of slice like: vec[1, 2, 3:6, 0, -1] + op_slcend, // end of slice + op_slc, // slice like vec[1] + op_slc2, // slice like vec[nil:10] + op_mcallg, // get memory space of value in global scope + op_mcalll, // get memory space of value in local scope + op_mupval, // get memory space of value in closure + op_mcallv, // get memory space of vec[index] + op_mcallh, // get memory space of hash.label + op_ret // return }; struct opcode { u8 op; // opcode u16 fidx; // source code file index - u32 num; // immediate num + u64 num; // immediate num u64 line; // location line of source code opcode() = default; opcode(const opcode&) = default; @@ -110,19 +110,18 @@ struct opcode { class codestream { private: opcode code; - const u32 index; + const u64 index; 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; public: - codestream(const opcode& c, const u32 i): code(c), index(i) {} - static void set( - const f64*, const std::string*, - const nasal_builtin_table*, - const std::string* file_list = nullptr - ); + codestream(const opcode& c, const u64 i): code(c), index(i) {} + static void set(const f64*, + const std::string*, + const nasal_builtin_table*, + const std::string* file_list = nullptr); void dump(std::ostream&) const; }; diff --git a/src/nasal_type.cpp b/src/nasal_type.cpp index 5b3cf20..bef537c 100644 --- a/src/nasal_type.cpp +++ b/src/nasal_type.cpp @@ -279,14 +279,14 @@ bool var::object_check(const std::string& name) { } var var::none() { - return {vm_type::vm_none, static_cast(0)}; + return {vm_type::vm_none, static_cast(0)}; } var var::nil() { - return {vm_type::vm_nil, static_cast(0)}; + return {vm_type::vm_nil, static_cast(0)}; } -var var::ret(u32 pc) { +var var::ret(u64 pc) { return {vm_type::vm_ret, pc}; } @@ -310,7 +310,7 @@ var* var::addr() { return val.addr; } -u32 var::ret() const { +u64 var::ret() const { return val.ret; } diff --git a/src/nasal_type.h b/src/nasal_type.h index 7cd3f17..b802066 100644 --- a/src/nasal_type.h +++ b/src/nasal_type.h @@ -49,7 +49,7 @@ struct var { public: vm_type type = vm_type::vm_none; union { - u32 ret; + u64 ret; i64 cnt; f64 num; var* addr; @@ -57,7 +57,7 @@ public: } val; private: - var(vm_type t, u32 pc) {type = t; val.ret = pc;} + var(vm_type t, u64 pc) {type = t; val.ret = pc;} var(vm_type t, i64 ct) {type = t; val.cnt = ct;} var(vm_type t, f64 n) {type = t; val.num = n;} var(vm_type t, var* p) {type = t; val.addr = p;} @@ -82,7 +82,7 @@ public: // create new var object static var none(); static var nil(); - static var ret(u32); + static var ret(u64); static var cnt(i64); static var num(f64); static var gcobj(nas_val*); @@ -91,7 +91,7 @@ public: public: // get value var* addr(); - u32 ret() const; + u64 ret() const; i64& cnt(); f64 num() const; std::string& str(); @@ -143,10 +143,10 @@ struct nas_hash { }; 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 + i64 dynamic_parameter_index; // dynamic parameter name index in hash. + u64 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 + u64 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 @@ -163,7 +163,7 @@ struct nas_upval { public: /* on stack, use these variables */ bool on_stack; - u32 size; + u64 size; var* stack_frame_offset; /* not on stack, use this */ @@ -207,7 +207,7 @@ public: }; struct context { - u32 pc = 0; + u64 pc = 0; var* localr = nullptr; var* memr = nullptr; var funcr = var::nil(); diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index 496155f..0de18a2 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -2,15 +2,13 @@ namespace nasal { -void vm::init( - const std::vector& strs, - const std::vector& nums, - const std::vector& natives, - const std::vector& code, - const std::unordered_map& global_symbol, - const std::vector& filenames, - const std::vector& argv -) { +void vm::vm_init_enrty(const std::vector& strs, + const std::vector& nums, + const std::vector& natives, + const std::vector& code, + const std::unordered_map& global_symbol, + const std::vector& filenames, + const std::vector& argv) { const_number = nums.data(); const_string = strs.data(); bytecode = code.data(); @@ -411,11 +409,10 @@ void vm::die(const std::string& str) { } } -void vm::run( - const codegen& gen, - const linker& linker, - const std::vector& argv) { - init( +void vm::run(const codegen& gen, + const linker& linker, + const std::vector& argv) { + vm_init_enrty( gen.strs(), gen.nums(), gen.natives(), @@ -424,6 +421,7 @@ void vm::run( linker.get_file_list(), argv ); + #ifndef _MSC_VER // using labels as values/computed goto const void* oprs[] = { diff --git a/src/nasal_vm.h b/src/nasal_vm.h index bfe5cc6..ea175f7 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -26,7 +26,7 @@ protected: /* constants */ 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 imm; // immediate number table std::vector native_function; /* garbage collector */ @@ -49,15 +49,13 @@ protected: bool flag_limited_mode = false; /* vm initializing function */ - void init( - const std::vector&, - const std::vector&, - const std::vector&, - const std::vector&, - const std::unordered_map&, - const std::vector&, - const std::vector& - ); + void vm_init_enrty(const std::vector&, + const std::vector&, + const std::vector&, + const std::vector&, + const std::unordered_map&, + const std::vector&, + const std::vector&); void context_and_global_init(); /* debug functions */ @@ -183,11 +181,9 @@ public: } /* execution entry */ - void run( - const codegen&, // get generated code - const linker&, // get list of used files - const std::vector& // get arguments input by command line - ); + void run(const codegen&, // get generated code + const linker&, // get list of used files + const std::vector&); // get command line arguments /* set detail report info flag */ void set_detail_report_info(bool flag) {verbose = flag;} @@ -700,7 +696,7 @@ inline void vm::o_callh() { } inline void vm::o_callfv() { - const u32 argc = imm[ctx.pc]; // arguments counter + const auto argc = imm[ctx.pc]; // arguments counter var* local = ctx.top-argc+1; // arguments begin address if (!local[-1].is_func()) { die("must call a function but get "+type_name_string(local[-1])); @@ -719,7 +715,7 @@ inline void vm::o_callfv() { return; } // parameter size is func->psize-1, 1 is reserved for "me" - const u32 parameter_size = func.parameter_size-1; + const u64 parameter_size = func.parameter_size-1; if (argc=0) { // load dynamic argument dynamic = ngc.alloc(vm_type::vm_vec); - for(u32 i = parameter_size; i=1; --i) { // load arguments + // use (std::min) to avoid compilation error in MSVC + // MSVC windows.h uses macro std::min + const u64 min_size = (std::min)(parameter_size, argc); + + // load arguments + for(u64 i = min_size; i>=1; --i) { local[i] = local[i-1]; } - local[0] = func.local[0];// load "me" + local[0] = func.local[0]; // load "me" // load local scope & default arguments - for(u32 i = min_size+1; ilocalr[1]; - f64 num = 0; + + usize num = 0; switch(val.type) { - case vm_type::vm_num: num = val.num(); break; + case vm_type::vm_num: return val; case vm_type::vm_str: num = val.str().length(); break; case vm_type::vm_vec: num = val.vec().size(); break; case vm_type::vm_hash: num = val.hash().size(); break; case vm_type::vm_map: num = val.map().mapper.size(); break; default: break; } - return var::num(num); + return var::num(static_cast(num)); } var builtin_time(context* ctx, gc* ngc) { @@ -569,12 +570,12 @@ public: stamp = std::chrono::high_resolution_clock::now(); } - f64 elapsed_milliseconds() { + auto elapsed_milliseconds() const { const auto duration = std::chrono::high_resolution_clock::now() - stamp; return std::chrono::duration_cast(duration).count(); } - f64 elapsed_microseconds() { + auto elapsed_microseconds() const { const auto duration = std::chrono::high_resolution_clock::now() - stamp; return std::chrono::duration_cast(duration).count(); } @@ -611,7 +612,7 @@ var builtin_elapsed_millisecond(context* ctx, gc* ngc) { return var::num(-1); } auto stamp = static_cast(object.ghost().pointer); - return var::num(stamp->elapsed_milliseconds()); + return var::num(static_cast(stamp->elapsed_milliseconds())); } var builtin_elapsed_microsecond(context* ctx, gc* ngc) { @@ -620,7 +621,7 @@ var builtin_elapsed_microsecond(context* ctx, gc* ngc) { return var::num(-1); } auto stamp = static_cast(object.ghost().pointer); - return var::num(stamp->elapsed_microseconds()); + return var::num(static_cast(stamp->elapsed_microseconds())); } var builtin_gcextend(context* ctx, gc* ngc) { @@ -648,20 +649,27 @@ var builtin_gcextend(context* ctx, gc* ngc) { } var builtin_gcinfo(context* ctx, gc* ngc) { - auto den = std::chrono::high_resolution_clock::duration::period::den; + const auto den = std::chrono::high_resolution_clock::duration::period::den; var res = ngc->alloc(vm_type::vm_hash); - double total = 0; + f64 total = 0; for(u32 i = 0; igcnt[i]; + total += static_cast(ngc->gcnt[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); + const auto worktime = static_cast(ngc->worktime); + const auto max_time = static_cast(ngc->max_time); + const auto max_mark_time = static_cast(ngc->max_mark_time); + const auto max_sweep_time = static_cast(ngc->max_sweep_time); + + // using ms + map["total"] = var::num(worktime/den*1000); + map["average"] = var::num(worktime/den*1000/total); + map["max_gc"] = var::num(max_time/den*1000); + map["max_mark"] = var::num(max_mark_time/den*1000); + map["max_sweep"] = var::num(max_sweep_time/den*1000); return res; } @@ -686,9 +694,17 @@ var builtin_ghosttype(context* ctx, gc* ngc) { if (!arg.is_ghost()) { return nas_err("ghosttype", "this is not a ghost object."); } + const auto& name = arg.ghost().get_ghost_name(); + + // https://wiki.flightgear.org/Nasal_library#ghosttype() + // tolds us if no name has been set, + // return a unique id (the pointer to the instance) if (!name.length()) { - return var::num(reinterpret_cast(arg.ghost().pointer)); + std::stringstream ss; + ss << "0x" << std::hex; + ss << reinterpret_cast(arg.ghost().pointer) << std::dec; + return ngc->newstr(ss.str()); } return ngc->newstr(name); } From a11e0726bba8bfc1f5587f8044a2ac2fd7fe638c Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 12 May 2024 23:29:48 +0800 Subject: [PATCH 06/21] :fire: add check for imported files' quantity --- makefile | 2 +- src/main.cpp | 10 +++++----- src/nasal_codegen.cpp | 36 ++++++++++++++++++++++-------------- src/nasal_codegen.h | 14 +++++++------- src/nasal_dbg.cpp | 4 ++-- src/nasal_dbg.h | 2 +- src/nasal_import.cpp | 9 ++++++++- src/repl.cpp | 12 ++++++------ 8 files changed, 52 insertions(+), 37 deletions(-) diff --git a/makefile b/makefile index aae7741..7bbc56c 100644 --- a/makefile +++ b/makefile @@ -6,7 +6,7 @@ endif ifeq ($(OS), Darwin) CXXFLAGS = -std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15 -I src else - CXXFLAGS = -std=$(STD) -c -O3 -fPIC -I src -Wconversion -Wno-float-conversion + CXXFLAGS = -std=$(STD) -c -O3 -fPIC -I src endif NASAL_HEADER = \ diff --git a/src/main.cpp b/src/main.cpp index 42d12f0..422cd27 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -95,7 +95,7 @@ std::ostream& logo(std::ostream& out) { } std::ostream& version(std::ostream& out) { - std::srand(static_cast(std::time(nullptr))); + std::srand(static_cast(std::time(nullptr))); f64 num = 0; for(u32 i = 0; i<5; ++i) { @@ -152,7 +152,7 @@ void execute(const std::string& file, } // optimizer does simple optimization on ast - auto opt = std::unique_ptr(new nasal::optimizer); + auto opt = std::make_unique(); opt->do_optimization(parse.tree()); if (cmd&VM_AST) { nasal::ast_dumper().dump(parse.tree()); @@ -170,10 +170,10 @@ void execute(const std::string& file, // run const auto start = clk::now(); if (cmd&VM_DEBUG) { - auto debugger = std::unique_ptr(new nasal::dbg); + auto debugger = std::make_unique(); debugger->run(gen, ld, argv, cmd&VM_PROFILE, cmd&VM_PROF_ALL); } else if (cmd&VM_TIME || cmd&VM_EXEC) { - auto runtime = std::unique_ptr(new nasal::vm); + auto runtime = std::make_unique(); runtime->set_detail_report_info(cmd&VM_DETAIL); runtime->set_limit_mode_flag(cmd&VM_LIMIT); runtime->run(gen, ld, argv); @@ -202,7 +202,7 @@ i32 main(i32 argc, const char* argv[]) { } else if (s=="-v" || s=="--version") { std::clog << version; } else if (s=="-r" || s=="--repl") { - auto repl = std::unique_ptr(new nasal::repl::repl); + auto repl = std::make_unique(); repl->execute(); } else if (s[0]!='-') { execute(s, {}, VM_EXEC); diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index 81ec3ae..ad94ff5 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -87,7 +87,7 @@ void codegen::regist_string(const std::string& str) { } void codegen::find_symbol(code_block* node) { - auto finder = std::unique_ptr(new symbol_finder); + auto finder = std::make_unique(); for(const auto& i : finder->do_find(node)) { // check if symbol conflicts with native function name if (native_function_mapper.count(i.name)) { @@ -95,11 +95,11 @@ void codegen::find_symbol(code_block* node) { continue; } // create new namespace with checking existence of location file - if (!experimental_namespace.count(i.location.file)) { - experimental_namespace[i.location.file] = {}; + if (!nasal_namespace.count(i.location.file)) { + nasal_namespace[i.location.file] = {}; } // if in global scope, load global symbol into this namespace - auto& scope = experimental_namespace.at(i.location.file); + auto& scope = nasal_namespace.at(i.location.file); if (local.empty() && !scope.count(i.name)) { scope.insert(i.name); } @@ -126,26 +126,30 @@ void codegen::regist_symbol(const std::string& name) { local.back()[name] = index; } -i32 codegen::local_symbol_find(const std::string& name) { +i64 codegen::local_symbol_find(const std::string& name) { if (local.empty()) { return -1; } return local.back().count(name)? local.back().at(name):-1; } -i32 codegen::global_symbol_find(const std::string& name) { +i64 codegen::global_symbol_find(const std::string& name) { return global.count(name)? global.at(name):-1; } -i32 codegen::upvalue_symbol_find(const std::string& name) { +i64 codegen::upvalue_symbol_find(const std::string& name) { // 32768 level 65536 upvalues - i32 index = -1; + // may cause some errors if local scope depth is too deep or + // local scope's symbol list size is greater than 65536, + // but we check the local size in codegen::func_gen + i64 index = -1; usize size = local.size(); if (size<=1) { return -1; } + auto iter = local.begin(); - for(u32 i = 0; icount(name)) { index = ((i<<16)|(*iter).at(name)); } @@ -301,10 +305,14 @@ void codegen::func_gen(function* node) { block_gen(block); in_foreach_loop_level.pop_back(); + // we must check the local scope symbol list size + // the local scope should not cause stack overflow + // and should not greater than upvalue's max size(65536) code[lsize].num = local.back().size(); - if (local.back().size()>=STACK_DEPTH) { + if (local.back().size()>=STACK_DEPTH || local.back().size()>=UINT16_MAX) { die("too many local variants: " + - std::to_string(local.back().size()), block->get_location() + std::to_string(local.back().size()), + block->get_location() ); } local.pop_back(); @@ -350,7 +358,7 @@ void codegen::call_identifier(identifier* node) { return; } - i32 index; + i64 index; if ((index = local_symbol_find(name))>=0) { emit(op_calll, index, node->get_location()); return; @@ -470,7 +478,7 @@ void codegen::mcall_identifier(identifier* node) { return; } - i32 index; + i64 index; if ((index = local_symbol_find(name))>=0) { emit(op_mcalll, index, node->get_location()); return; @@ -1428,7 +1436,7 @@ void codegen::print(std::ostream& out) { } void codegen::symbol_dump(std::ostream& out) const { - for(const auto& domain : experimental_namespace) { + for(const auto& domain : nasal_namespace) { out << "<" << domain.first << ">\n"; for(const auto& i : domain.second) { out << " 0x" << std::setw(4) << std::setfill('0'); diff --git a/src/nasal_codegen.h b/src/nasal_codegen.h index 2b3e817..e171f83 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -89,7 +89,10 @@ private: // symbol table // global : max STACK_DEPTH-1 values std::unordered_map global; - std::unordered_map> experimental_namespace; + + // nasal namespace + // stores all global symbols of each file + std::unordered_map> nasal_namespace; // local : max 32768 upvalues 65536 values // but in fact local scope also has less than STACK_DEPTH value @@ -105,9 +108,9 @@ private: void regist_string(const std::string&); void find_symbol(code_block*); void regist_symbol(const std::string&); - i32 local_symbol_find(const std::string&); - i32 global_symbol_find(const std::string&); - i32 upvalue_symbol_find(const std::string&); + i64 local_symbol_find(const std::string&); + i64 global_symbol_find(const std::string&); + i64 upvalue_symbol_find(const std::string&); void emit(u8, u64, const span&); @@ -157,9 +160,6 @@ public: const auto& natives() const {return native_function;} const auto& codes() const {return code;} const auto& globals() const {return global;} - const auto& get_experimental_namespace() const { - return experimental_namespace; - } public: codegen() = default; diff --git a/src/nasal_dbg.cpp b/src/nasal_dbg.cpp index c835817..a1afd3d 100644 --- a/src/nasal_dbg.cpp +++ b/src/nasal_dbg.cpp @@ -113,7 +113,7 @@ u16 dbg::file_index(const std::string& filename) const { return i; } } - return 65535; + return UINT16_MAX; } void dbg::err() { @@ -221,7 +221,7 @@ void dbg::interact() { } else if (res.size()==3 && get_cmd_type(res[0])==cmd_kind::cmd_break_point) { break_file_index = file_index(res[1]); - if (break_file_index==65535) { + if (break_file_index==UINT16_MAX) { std::clog << "cannot find file named `" << res[1] << "`\n"; continue; } diff --git a/src/nasal_dbg.h b/src/nasal_dbg.h index 13c392e..2aa1b0c 100644 --- a/src/nasal_dbg.h +++ b/src/nasal_dbg.h @@ -142,7 +142,7 @@ private: bool next; usize fsize; u16 break_file_index; - u32 break_line; + u64 break_line; error src; private: diff --git a/src/nasal_import.cpp b/src/nasal_import.cpp index 123f956..9d94777 100644 --- a/src/nasal_import.cpp +++ b/src/nasal_import.cpp @@ -316,7 +316,7 @@ std::string linker::generate_module_name(const std::string& file_path) { } return_expr* linker::generate_module_return(code_block* block) { - auto finder = std::unique_ptr(new symbol_finder); + auto finder = std::make_unique(); auto result = new return_expr(block->get_location()); auto value = new hash_expr(block->get_location()); result->set_value(value); @@ -406,6 +406,13 @@ const error& linker::link(parse& parse, bool spath = false) { merge_tree(library, parse.tree()); // swap tree root, and delete old root delete parse.swap(library); + + if (imported_files.size()>=UINT16_MAX) { + err.err("link", + "too many imported files: " + + std::to_string(imported_files.size()) + ); + } return err; } diff --git a/src/repl.cpp b/src/repl.cpp index 1883f6d..e0118c5 100644 --- a/src/repl.cpp +++ b/src/repl.cpp @@ -37,7 +37,7 @@ void repl::update_temp_file() { bool repl::check_need_more_input() { while(true) { update_temp_file(); - auto nasal_lexer = std::unique_ptr(new lexer); + auto nasal_lexer = std::make_unique(); if (nasal_lexer->scan("").geterr()) { return false; } @@ -77,11 +77,11 @@ void repl::help() { } bool repl::run() { - auto nasal_lexer = std::unique_ptr(new lexer); - auto nasal_parser = std::unique_ptr(new parse); - auto nasal_linker = std::unique_ptr(new linker); - auto nasal_opt = std::unique_ptr(new optimizer); - auto nasal_codegen = std::unique_ptr(new codegen); + auto nasal_lexer = std::make_unique(); + auto nasal_parser = std::make_unique(); + auto nasal_linker = std::make_unique(); + auto nasal_opt = std::make_unique(); + auto nasal_codegen = std::make_unique(); update_temp_file(); if (nasal_lexer->scan("").geterr()) { From 230848a6e18015a3c4501f0b368ac73b167edc60 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Mon, 13 May 2024 00:06:37 +0800 Subject: [PATCH 07/21] :memo: improve maintainability --- src/nasal_type.cpp | 64 ++++++++++++++++++++++++---------------------- src/nasal_vm.h | 59 +++++++++++++++++++++++++++--------------- test/class.nas | 14 +++++----- test/scalar.nas | 18 ++++++++++++- 4 files changed, 96 insertions(+), 59 deletions(-) diff --git a/src/nasal_type.cpp b/src/nasal_type.cpp index bef537c..537db2f 100644 --- a/src/nasal_type.cpp +++ b/src/nasal_type.cpp @@ -42,6 +42,7 @@ var nas_hash::get_value(const std::string& key) { } else if (!elems.count("parents")) { return var::none(); } + auto ret = var::none(); auto& val = elems.at("parents"); if (!val.is_vec()) { @@ -64,12 +65,14 @@ var* nas_hash::get_memory(const std::string& key) { } else if (!elems.count("parents")) { return nullptr; } + var* addr = nullptr; var& val = elems.at("parents"); if (!val.is_vec()) { return addr; } for(auto& i : val.vec().elems) { + // recursively search key in `parents` if (i.is_hash()) { addr = i.hash().get_memory(key); } @@ -102,11 +105,10 @@ void nas_func::clear() { keys.clear(); } -void nas_ghost::set( - const std::string& ghost_type_name, - destructor destructor_pointer, - marker gc_marker_pointer, - void* ghost_pointer) { +void nas_ghost::set(const std::string& ghost_type_name, + destructor destructor_pointer, + marker gc_marker_pointer, + void* ghost_pointer) { type_name = ghost_type_name; destructor_function = destructor_pointer; gc_mark_function = gc_marker_pointer; @@ -214,14 +216,14 @@ nas_val::nas_val(vm_type val_type) { nas_val::~nas_val() { switch(type) { - case vm_type::vm_str: delete ptr.str; break; - case vm_type::vm_vec: delete ptr.vec; break; - case vm_type::vm_hash: delete ptr.hash; break; - case vm_type::vm_func: delete ptr.func; break; - case vm_type::vm_upval:delete ptr.upval; break; - case vm_type::vm_ghost:delete ptr.obj; break; - case vm_type::vm_co: delete ptr.co; break; - case vm_type::vm_map: delete ptr.map; break; + case vm_type::vm_str: delete ptr.str; break; + case vm_type::vm_vec: delete ptr.vec; break; + case vm_type::vm_hash: delete ptr.hash; break; + case vm_type::vm_func: delete ptr.func; break; + case vm_type::vm_upval: delete ptr.upval; break; + case vm_type::vm_ghost: delete ptr.obj; break; + case vm_type::vm_co: delete ptr.co; break; + case vm_type::vm_map: delete ptr.map; break; default: break; } type = vm_type::vm_nil; @@ -229,14 +231,14 @@ nas_val::~nas_val() { void nas_val::clear() { switch(type) { - case vm_type::vm_str: ptr.str->clear(); break; - case vm_type::vm_vec: ptr.vec->elems.clear(); break; - case vm_type::vm_hash: ptr.hash->elems.clear(); break; - case vm_type::vm_func: ptr.func->clear(); break; - case vm_type::vm_upval:ptr.upval->clear(); break; - case vm_type::vm_ghost:ptr.obj->clear(); break; - case vm_type::vm_co: ptr.co->clear(); break; - case vm_type::vm_map: ptr.map->clear(); break; + case vm_type::vm_str: ptr.str->clear(); break; + case vm_type::vm_vec: ptr.vec->elems.clear(); break; + case vm_type::vm_hash: ptr.hash->elems.clear(); break; + case vm_type::vm_func: ptr.func->clear(); break; + case vm_type::vm_upval: ptr.upval->clear(); break; + case vm_type::vm_ghost: ptr.obj->clear(); break; + case vm_type::vm_co: ptr.co->clear(); break; + case vm_type::vm_map: ptr.map->clear(); break; default: break; } } @@ -259,16 +261,16 @@ std::string var::to_str() { std::ostream& operator<<(std::ostream& out, var& ref) { switch(ref.type) { - case vm_type::vm_none: out << "undefined"; break; - case vm_type::vm_nil: out << "nil"; break; - case vm_type::vm_num: out << ref.val.num; break; - case vm_type::vm_str: out << ref.str(); break; - case vm_type::vm_vec: out << ref.vec(); break; - case vm_type::vm_hash: out << ref.hash(); break; - case vm_type::vm_func: out << "func(..) {..}"; break; - case vm_type::vm_ghost:out << ref.ghost(); break; - case vm_type::vm_co: out << ref.co(); break; - case vm_type::vm_map: out << ref.map(); break; + case vm_type::vm_none: out << "undefined"; break; + case vm_type::vm_nil: out << "nil"; break; + case vm_type::vm_num: out << ref.val.num; break; + case vm_type::vm_str: out << ref.str(); break; + case vm_type::vm_vec: out << ref.vec(); break; + case vm_type::vm_hash: out << ref.hash(); break; + case vm_type::vm_func: out << "func(..) {..}"; break; + case vm_type::vm_ghost: out << ref.ghost(); break; + case vm_type::vm_co: out << ref.co(); break; + case vm_type::vm_map: out << ref.map(); break; default: break; } return out; diff --git a/src/nasal_vm.h b/src/nasal_vm.h index ea175f7..2286b01 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -20,13 +20,15 @@ namespace nasal { class vm { protected: - /* registers of vm */ - context ctx; // running context + /* vm context */ + context ctx; /* constants */ - const f64* const_number = nullptr; // constant numbers - const std::string* const_string = nullptr; // constant symbols and strings + const f64* const_number = nullptr; + const std::string* const_string = nullptr; std::vector imm; // immediate number table + + /* nasal native functions */ std::vector native_function; /* garbage collector */ @@ -77,9 +79,11 @@ protected: std::string type_name_string(const var&) const; void die(const std::string&); +protected: /* vm calculation functions*/ inline bool cond(var&); +protected: /* vm operands */ inline void o_repl(); inline void o_intl(); @@ -247,8 +251,9 @@ inline void vm::o_newv() { auto& vec = newv.vec().elems; vec.resize(imm[ctx.pc]); // use top-=imm[pc]-1 here will cause error if imm[pc] is 0 - ctx.top = ctx.top-imm[ctx.pc]+1; - for(u32 i = 0; i Date: Mon, 13 May 2024 21:59:05 +0800 Subject: [PATCH 08/21] :sparkles: `str()` can be used on complex types --- src/nasal_dbg.h | 12 +++++------ src/nasal_err.cpp | 5 +++-- src/nasal_import.cpp | 4 ++-- src/nasal_parse.cpp | 47 +++++++++++++++++++++--------------------- src/nasal_type.cpp | 49 ++++++++++++++++++++++++++++++++++---------- src/nasal_type.h | 9 +++++++- src/nasal_vm.h | 1 + 7 files changed, 81 insertions(+), 46 deletions(-) diff --git a/src/nasal_dbg.h b/src/nasal_dbg.h index 2aa1b0c..0fd2b93 100644 --- a/src/nasal_dbg.h +++ b/src/nasal_dbg.h @@ -163,13 +163,11 @@ public: next(true), fsize(0), break_file_index(0), break_line(0), do_operand_count(false) {} - void run( - const codegen&, - const linker&, - const std::vector&, - bool, - bool - ); + void run(const codegen&, + const linker&, + const std::vector&, + bool, + bool); }; } diff --git a/src/nasal_err.cpp b/src/nasal_err.cpp index 42a71d3..c57aa20 100644 --- a/src/nasal_err.cpp +++ b/src/nasal_err.cpp @@ -120,8 +120,9 @@ void error::warn(const std::string& stage, const std::string& info) { std::clog << orange << stage << ": " << white << info << reset << "\n\n"; } -void error::err( - const std::string& stage, const span& loc, const std::string& info) { +void error::err(const std::string& stage, + const span& loc, + const std::string& info) { // load error occurred file into string lines load(loc.file); diff --git a/src/nasal_import.cpp b/src/nasal_import.cpp index 9d94777..b5273e5 100644 --- a/src/nasal_import.cpp +++ b/src/nasal_import.cpp @@ -41,8 +41,8 @@ std::string linker::get_path(expr* node) { return content->get_content(); } -std::string linker::find_real_file_path( - const std::string& filename, const span& location) { +std::string linker::find_real_file_path(const std::string& filename, + const span& location) { // first add file name itself into the file path std::vector path_list = {filename}; diff --git a/src/nasal_parse.cpp b/src/nasal_parse.cpp index dc3b1a2..c0f3f98 100644 --- a/src/nasal_parse.cpp +++ b/src/nasal_parse.cpp @@ -254,11 +254,11 @@ vector_expr* parse::vec() { // panic set for this token is not ',' // this is the FIRST set of calculation // array end with tok::null=0 - const tok panic[]={ - tok::id,tok::str,tok::num,tok::tktrue, - tok::tkfalse,tok::opnot,tok::sub,tok::tknil, - tok::func,tok::var,tok::lcurve,tok::floater, - tok::lbrace,tok::lbracket,tok::null + const tok panic[] = { + tok::id, tok::str, tok::num, tok::tktrue, + tok::tkfalse, tok::opnot, tok::sub, tok::tknil, + tok::func, tok::var, tok::lcurve, tok::floater, + tok::lbrace, tok::lbracket, tok::null }; auto node = new vector_expr(toks[ptr].loc); match(tok::lbracket); @@ -713,11 +713,11 @@ call_vector* parse::callv() { // panic set for this token is not ',' // this is the FIRST set of subvec // array end with tok::null=0 - const tok panic[]={ - tok::id,tok::str,tok::num,tok::tktrue, - tok::tkfalse,tok::opnot,tok::sub,tok::tknil, - tok::func,tok::var,tok::lcurve,tok::floater, - tok::lbrace,tok::lbracket,tok::colon,tok::null + const tok panic[] = { + tok::id, tok::str, tok::num, tok::tktrue, + tok::tkfalse, tok::opnot, tok::sub, tok::tknil, + tok::func, tok::var, tok::lcurve, tok::floater, + tok::lbrace, tok::lbracket, tok::colon, tok::null }; auto node = new call_vector(toks[ptr].loc); match(tok::lbracket); @@ -743,11 +743,11 @@ call_function* parse::callf() { // panic set for this token is not ',' // this is the FIRST set of calculation/hashmember // array end with tok::null=0 - const tok panic[]={ - tok::id,tok::str,tok::num,tok::tktrue, - tok::tkfalse,tok::opnot,tok::sub,tok::tknil, - tok::func,tok::var,tok::lcurve,tok::floater, - tok::lbrace,tok::lbracket,tok::null + const tok panic[] = { + tok::id, tok::str,tok::num, tok::tktrue, + tok::tkfalse, tok::opnot, tok::sub, tok::tknil, + tok::func, tok::var, tok::lcurve, tok::floater, + tok::lbrace, tok::lbracket, tok::null }; auto node = new call_function(toks[ptr].loc); bool special_call=check_special_call(); @@ -802,7 +802,7 @@ expr* parse::definition() { } multi_identifier* parse::incurve_def() { - const auto& loc=toks[ptr].loc; + const auto& loc = toks[ptr].loc; match(tok::lcurve); match(tok::var); auto node = multi_id(); @@ -813,7 +813,7 @@ multi_identifier* parse::incurve_def() { } multi_identifier* parse::outcurve_def() { - const auto& loc=toks[ptr].loc; + const auto& loc = toks[ptr].loc; match(tok::lcurve); auto node = multi_id(); update_location(node); @@ -840,12 +840,13 @@ multi_identifier* parse::multi_id() { } tuple_expr* parse::multi_scalar() { - // if check_call_memory is true,we will check if value called here can reach a memory space - const tok panic[]={ - tok::id,tok::str,tok::num,tok::tktrue, - tok::tkfalse,tok::opnot,tok::sub,tok::tknil, - tok::func,tok::var,tok::lcurve,tok::floater, - tok::lbrace,tok::lbracket,tok::null + // if check_call_memory is true, + // we will check if value called here can reach a memory space + const tok panic[] = { + tok::id, tok::str,tok::num, tok::tktrue, + tok::tkfalse, tok::opnot, tok::sub, tok::tknil, + tok::func, tok::var, tok::lcurve, tok::floater, + tok::lbrace, tok::lbracket, tok::null }; auto node = new tuple_expr(toks[ptr].loc); match(tok::lcurve); diff --git a/src/nasal_type.cpp b/src/nasal_type.cpp index 537db2f..70324f7 100644 --- a/src/nasal_type.cpp +++ b/src/nasal_type.cpp @@ -98,6 +98,30 @@ std::ostream& operator<<(std::ostream& out, nas_hash& hash) { return out; } +std::ostream& operator<<(std::ostream& out, nas_func& func) { + out << "func("; + + std::vector argument_list = {}; + argument_list.resize(func.keys.size()); + for(const auto& key : func.keys) { + argument_list[key.second-1] = key.first; + } + + for(const auto& key : argument_list) { + out << key; + if (key != argument_list.back()) { + out << ", "; + } + } + if (func.dynamic_parameter_index>=0) { + out << (argument_list.size()? ", ":""); + out << func.dynamic_parameter_name << "..."; + } + + out << ") {..}"; + return out; +} + void nas_func::clear() { dynamic_parameter_index = -1; local.clear(); @@ -256,21 +280,24 @@ std::string var::to_str() { tmp.erase(tmp.find_last_not_of('.')+1, std::string::npos); return tmp; } - return ""; + + std::stringstream ss; + ss << *this; + return ss.str(); } std::ostream& operator<<(std::ostream& out, var& ref) { switch(ref.type) { - case vm_type::vm_none: out << "undefined"; break; - case vm_type::vm_nil: out << "nil"; break; - case vm_type::vm_num: out << ref.val.num; break; - case vm_type::vm_str: out << ref.str(); break; - case vm_type::vm_vec: out << ref.vec(); break; - case vm_type::vm_hash: out << ref.hash(); break; - case vm_type::vm_func: out << "func(..) {..}"; break; - case vm_type::vm_ghost: out << ref.ghost(); break; - case vm_type::vm_co: out << ref.co(); break; - case vm_type::vm_map: out << ref.map(); break; + case vm_type::vm_none: out << "undefined"; break; + case vm_type::vm_nil: out << "nil"; break; + case vm_type::vm_num: out << ref.val.num; break; + case vm_type::vm_str: out << ref.str(); break; + case vm_type::vm_vec: out << ref.vec(); break; + case vm_type::vm_hash: out << ref.hash(); break; + case vm_type::vm_func: out << ref.func(); break; + case vm_type::vm_ghost: out << ref.ghost(); break; + case vm_type::vm_co: out << ref.co(); break; + case vm_type::vm_map: out << ref.map(); break; default: break; } return out; diff --git a/src/nasal_type.h b/src/nasal_type.h index b802066..d7e3b9d 100644 --- a/src/nasal_type.h +++ b/src/nasal_type.h @@ -15,6 +15,7 @@ enum class vm_type: u8 { vm_ret, // return addres(program counter) vm_nil, // nil vm_num, // number + /* gc object */ vm_str, // string vm_vec, // vector @@ -24,6 +25,7 @@ enum class vm_type: u8 { vm_ghost, // ghost type vm_co, // coroutine vm_map, // for globals and namespaces + /* mark type range */ vm_type_size_max }; @@ -153,9 +155,13 @@ struct nas_func { // parameter table, u32 begins from 1 std::unordered_map keys; + // dynamic parameter name + std::string dynamic_parameter_name; + nas_func(): dynamic_parameter_index(-1), entry(0), - parameter_size(0), local_size(0) {} + parameter_size(0), local_size(0), + dynamic_parameter_name("") {} void clear(); }; @@ -277,6 +283,7 @@ struct nas_val { std::ostream& operator<<(std::ostream&, nas_vec&); std::ostream& operator<<(std::ostream&, nas_hash&); +std::ostream& operator<<(std::ostream&, nas_func&); std::ostream& operator<<(std::ostream&, nas_map&); std::ostream& operator<<(std::ostream&, const nas_ghost&); std::ostream& operator<<(std::ostream&, const nas_co&); diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 2286b01..d6daddb 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -311,6 +311,7 @@ inline void vm::o_deft() { inline void vm::o_dyn() { ctx.top[0].func().dynamic_parameter_index = imm[ctx.pc]; + ctx.top[0].func().dynamic_parameter_name = const_string[imm[ctx.pc]]; } inline void vm::o_lnot() { From 9b168b5d5222954626ce35741a0dcf3242729908 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Tue, 14 May 2024 00:16:02 +0800 Subject: [PATCH 09/21] :memo: move andy_gc_test to test dir --- makefile | 1 + src/nasal_dbg.cpp | 11 ++++++----- src/nasal_dbg.h | 13 ++++++------- src/nasal_gc.cpp | 11 +++++++++-- src/nasal_gc.h | 1 + {tools => test}/andy_gc_test.nas | 0 test/gc_test.nas | 2 +- 7 files changed, 24 insertions(+), 15 deletions(-) rename {tools => test}/andy_gc_test.nas (100%) diff --git a/makefile b/makefile index 7bbc56c..47c12b4 100644 --- a/makefile +++ b/makefile @@ -255,6 +255,7 @@ clean: .PHONY: test test:nasal + @ ./nasal -t -d test/andy_gc_test.nas @ ./nasal test/argparse_test.nas @ ./nasal -e test/ascii-art.nas @ ./nasal -t -d test/bfs.nas diff --git a/src/nasal_dbg.cpp b/src/nasal_dbg.cpp index a1afd3d..8ac3489 100644 --- a/src/nasal_dbg.cpp +++ b/src/nasal_dbg.cpp @@ -108,7 +108,7 @@ std::vector dbg::parse(const std::string& cmd) { } u16 dbg::file_index(const std::string& filename) const { - for(u16 i = 0; i\n" << " h, help | get help\n" @@ -141,7 +141,7 @@ void dbg::help() { } void dbg::list_file() const { - for(usize i = 0; i parse(const std::string&); u16 file_index(const std::string&) const; - void err(); - void help(); + void err() const; + void help() const; void list_file() const; void step_info(); void interact(); public: - dbg(): - next(true), fsize(0), - break_file_index(0), break_line(0), - do_operand_count(false) {} + dbg(): next(true), file_list_size(0), + break_file_index(0), break_line(0), + do_operand_count(false) {} void run(const codegen&, const linker&, const std::vector&, diff --git a/src/nasal_gc.cpp b/src/nasal_gc.cpp index bbbf3b0..d5a06ee 100644 --- a/src/nasal_gc.cpp +++ b/src/nasal_gc.cpp @@ -1,4 +1,5 @@ #include "nasal_gc.h" +#include namespace nasal { @@ -22,7 +23,10 @@ void gc::do_mark_sweep() { void gc::mark() { std::vector bfs; mark_context_root(bfs); - if (memory.size()>8192 && bfs.size()>4) { + + // concurrent mark, experimental + if (memory.size()>UINT16_MAX && bfs.size()>8192) { + flag_concurrent_mark_triggered = true; usize size = bfs.size(); std::thread t0(&gc::concurrent_mark, this, std::ref(bfs), 0, size/4); std::thread t1(&gc::concurrent_mark, this, std::ref(bfs), size/4, size/2); @@ -34,7 +38,8 @@ void gc::mark() { t3.join(); return; } - + + // normal mark while(!bfs.empty()) { var value = bfs.back(); bfs.pop_back(); @@ -340,6 +345,8 @@ void gc::info() const { std::clog << " | " << max_mark_time*1.0/den*1000 << " ms\n"; std::clog << " " << left << setw(indent) << setfill(' ') << "max sweep"; std::clog << " | " << max_sweep_time*1.0/den*1000 << " ms\n"; + std::clog << " " << left << setw(indent) << setfill(' ') << "concurrent"; + std::clog << " | " << (flag_concurrent_mark_triggered? "true\n":"false\n"); std::clog << last_line << "\n"; } diff --git a/src/nasal_gc.h b/src/nasal_gc.h index daf5fa9..3daee2b 100644 --- a/src/nasal_gc.h +++ b/src/nasal_gc.h @@ -60,6 +60,7 @@ struct gc { i64 max_time = 0; i64 max_mark_time = 0; i64 max_sweep_time = 0; + bool flag_concurrent_mark_triggered = false; void set(context* _ctx, var* _global, usize _size) { running_context = _ctx; diff --git a/tools/andy_gc_test.nas b/test/andy_gc_test.nas similarity index 100% rename from tools/andy_gc_test.nas rename to test/andy_gc_test.nas diff --git a/test/gc_test.nas b/test/gc_test.nas index 8263c77..804fe00 100644 --- a/test/gc_test.nas +++ b/test/gc_test.nas @@ -17,7 +17,7 @@ var test_func = func(test_processes...) { info = runtime.gc.info(); println("[", os.time(), "] ", duration, " ms, gc ", (info.total-gc_total)*100/duration, "%, ", - int(1000/duration), " cps"); + 1000/duration, " cps"); gc_total = info.total; } From 8759d12eda5ccdc60249b547e1d722fc79162dcd Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Tue, 14 May 2024 00:23:00 +0800 Subject: [PATCH 10/21] :bug: delete omp.h header --- src/nasal_gc.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/nasal_gc.cpp b/src/nasal_gc.cpp index d5a06ee..2d71359 100644 --- a/src/nasal_gc.cpp +++ b/src/nasal_gc.cpp @@ -1,5 +1,4 @@ #include "nasal_gc.h" -#include namespace nasal { From 00a655a9fc6379fe044477cc9a67e833924a9335 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Wed, 15 May 2024 00:27:31 +0800 Subject: [PATCH 11/21] :memo: change opcode dump format --- module/fib.cpp | 2 +- src/nasal_codegen.cpp | 4 +- src/nasal_dbg.cpp | 6 +- src/nasal_gc.cpp | 2 +- src/nasal_gc.h | 2 +- src/nasal_opcode.cpp | 134 ++++++++++++++++++++++------------ src/nasal_opcode.h | 6 +- src/nasal_parse.cpp | 6 +- src/nasal_type.cpp | 2 +- src/nasal_vm.cpp | 19 +++-- src/nasal_vm.h | 4 +- src/natives/bits_lib.cpp | 6 +- src/natives/nasal_builtin.cpp | 88 ++++++++++++---------- src/natives/nasal_builtin.h | 2 +- 14 files changed, 167 insertions(+), 116 deletions(-) diff --git a/module/fib.cpp b/module/fib.cpp index d618a37..dace56b 100644 --- a/module/fib.cpp +++ b/module/fib.cpp @@ -25,7 +25,7 @@ var fib(var* args, usize size, gc* ngc) { var quick_fib(var* args, usize size, gc* ngc) { if (!size) { - return nas_err("quick_fib","lack arguments"); + return nas_err("quick_fib", "lack arguments"); } double num = args[0].to_num(); if (num<2) { diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index ad94ff5..86fb620 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -530,7 +530,7 @@ void codegen::single_def(definition_expr* node) { void codegen::multi_def(definition_expr* node) { auto& identifiers = node->get_variables()->get_variables(); usize size = identifiers.size(); - // (var a,b,c) = (c,b,a); + // (var a, b, c) = (c, b, a); if (node->get_tuple()) { auto& vals = node->get_tuple()->get_elements(); if (identifiers.size()>vals.size()) { @@ -557,7 +557,7 @@ void codegen::multi_def(definition_expr* node) { } return; } - // (var a,b,c) = [0,1,2]; + // (var a, b, c) = [0, 1, 2]; calc_gen(node->get_value()); for(usize i = 0; iget_value()->get_location()); diff --git a/src/nasal_dbg.cpp b/src/nasal_dbg.cpp index 8ac3489..64d911c 100644 --- a/src/nasal_dbg.cpp +++ b/src/nasal_dbg.cpp @@ -46,7 +46,7 @@ void operand_line_counter::dump_operand_count() const { if (!rate) { break; } - std::clog << " " << opname[i.first] << " : "; + std::clog << " " << oprand_name_table[i.first] << " : "; std::clog << i.second << " (" << rate << "%)\n"; } std::clog << " total : " << total << '\n'; @@ -133,7 +133,7 @@ void dbg::help() const { << " l, local | see local values\n" << " u, upval | see upvalue\n" << " r, register | show vm register detail\n" - << " a, all | show global,local and upvalue\n" + << " a, all | show global, local and upvalue\n" << " n, next | execute next bytecode\n" << " q, exit | exit debugger\n" << "