diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 33a290b..1b10782 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -1,4 +1,4 @@ -name: C/C++ CI +name: Build/Test/Package CI on: schedule: @@ -10,62 +10,48 @@ on: workflow_dispatch: jobs: - mac-build: + mac-aarch64-build: runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - name: make + - uses: actions/checkout@v4 + - name: Build run: | make -j4 cd module make all -j4 cd .. - make test - tar -czf nasal-mac-nightly.tgz . - python3 tools/pack.py - - name: Release file - # You may pin to the exact commit or the version. - # uses: djnicholson/release-action@e9a535b3eced09c460e07a84118fb74ae9b53236 - uses: marvinpinto/action-automatic-releases@v1.2.1 + - name: Test + run: make test + - name: Package + run: python3 tools/pack.py + - name: Release + uses: softprops/action-gh-release@v2.0.5 with: - # GitHub auth token - repo_token: ${{ secrets.GITHUB_TOKEN }} - # Name of Release to add file to - title: macOS Nightly build - # Name of the tag for the release (will be associated with current branch) - automatic_release_tag: next_macOS - # File to release + name: macOS nightly build + tag_name: next_macOS + prerelease: true files: | - nasal-mac-nightly.tgz nasal-Darwin.tar linux-x86_64-build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: make + - uses: actions/checkout@v4 + - name: Build run: | make -j4 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: Release file - # You may pin to the exact commit or the version. - # uses: djnicholson/release-action@e9a535b3eced09c460e07a84118fb74ae9b53236 - uses: marvinpinto/action-automatic-releases@v1.2.1 + - name: Test + run: make test + - name: Package + run: python3 tools/pack.py + - name: Release + uses: softprops/action-gh-release@v2.0.5 with: - # GitHub auth token - repo_token: ${{ secrets.GITHUB_TOKEN }} - # Name of Release to add file to - title: Linux Nightly build - # Name of the tag for the release (will be associated with current branch) - automatic_release_tag: next_linux_x86_64 - # File to release + name: linux nightly build + tag_name: next_linux_x86_64 + prerelease: true files: | - nasal-linux-x86_64-nightly.tgz nasal-Linux.tar - diff --git a/README.md b/README.md index 82ac078..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) @@ -13,7 +12,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 +42,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 +63,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..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) @@ -13,6 +12,7 @@ ## __目录__ * [__简介__](#简介) +* [__下载__](#下载) * [__编译__](#编译) * [__使用方法__](#使用方法) * [__教程__](../doc/tutorial_zh.md) @@ -42,18 +42,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: [施工中...] ## __编译__ 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/module/fib.cpp b/module/fib.cpp index 68e7264..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) { @@ -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..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()=="|--") { @@ -35,8 +37,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/main.cpp b/src/main.cpp index 0955be9..422cd27 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"; @@ -150,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()); @@ -166,22 +168,22 @@ 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); + 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); } // 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"; + std::clog << static_cast((end-start).count())/den << "s.\n\n"; } } @@ -200,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); @@ -211,7 +213,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 +235,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 @@ -38,7 +38,7 @@ const char* get_platform(); const char* get_arch(); // virtual machine stack depth, both global depth and value stack depth -const u32 STACK_DEPTH = 4096; +const u32 VM_STACK_DEPTH = UINT16_MAX; f64 hex_to_f64(const char*); f64 oct_to_f64(const char*); 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_codegen.cpp b/src/nasal_codegen.cpp index cfc84ab..ab5e42e 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,13 +80,14 @@ 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); } 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)) { @@ -93,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); } @@ -107,41 +109,47 @@ 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; } -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)); } @@ -149,7 +157,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)), @@ -297,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()>=VM_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(); @@ -346,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; @@ -466,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; @@ -505,7 +517,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()) { @@ -518,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()) { @@ -545,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()); @@ -752,16 +764,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 +847,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 +956,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 +1267,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 +1277,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 +1326,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 +1347,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()) @@ -1348,7 +1361,7 @@ const error& codegen::compile(parse& parse, } // check global variables size - if (global.size()>=STACK_DEPTH/2) { + if (global.size()>=VM_STACK_DEPTH) { err.err("code", "too many global variables: " + std::to_string(global.size()) @@ -1356,7 +1369,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 +1380,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 +1404,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\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 024a0d1..2b4ba53 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -37,10 +37,11 @@ private: error err; // repl output flag, will generate op_repl to output stack top value if true - bool need_repl_output = false; + bool flag_need_repl_output = false; // limit mode flag bool flag_limited_mode = false; + // under limited mode, unsafe system api will be banned const std::unordered_set 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,20 @@ 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> experimental_namespace; + // global : max VM_STACK_DEPTH-1 values + std::unordered_map global; + + // 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 - std::list> local; + // but in fact local scope also has less than VM_STACK_DEPTH value + std::list> local; void check_id_exist(identifier*); @@ -104,11 +108,11 @@ 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, u32, const span&); + void emit(u8, u64, const span&); void number_gen(number_literal*); void string_gen(string_literal*); @@ -135,7 +139,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*); @@ -156,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 38c9e39..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'; @@ -108,21 +108,21 @@ 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" @@ -133,7 +133,7 @@ void dbg::help() { << " 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" << "