Merge pull request #41 from ValKmjolnir/develop
📝 adjust CI & improve maintainability
This commit is contained in:
commit
4f0afb31db
|
@ -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
|
||||
|
||||
|
|
19
README.md
19
README.md
|
@ -2,7 +2,6 @@
|
|||
|
||||
<img src="./doc/pic/header.png" style="width:600px"></img>
|
||||
|
||||

|
||||

|
||||
[](./LICENSE)
|
||||

|
||||
|
@ -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__
|
||||
|
||||

|
||||

|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
<img src="../doc/pic/header.png" style="width:600px"></img>
|
||||
|
||||

|
||||

|
||||
[](../LICENSE)
|
||||

|
||||
|
@ -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: [施工中...]
|
||||
|
||||
## __编译__
|
||||
|
||||
|
|
1
makefile
1
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
|
||||
|
|
|
@ -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<u64>(ptr) << std::dec << ") {\n";
|
||||
|
||||
delete static_cast<ghost_obj*>(ptr);
|
||||
|
||||
std::cout << " delete 0x" << std::hex;
|
||||
std::cout << reinterpret_cast<u64>(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<var>* bfs_queue) {
|
||||
std::cout << "ghost_for_test::mark (0x";
|
||||
std::cout << std::hex << reinterpret_cast<u64>(ptr) << std::dec << ") {\n";
|
||||
|
||||
bfs_queue->push_back(static_cast<ghost_obj*>(ptr)->test_string);
|
||||
|
||||
std::cout << " mark 0x" << std::hex;
|
||||
std::cout << reinterpret_cast<u64>(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<ghost_obj*>(res.ghost().pointer)->number = static_cast<u32>(num);
|
||||
std::cout << "set_new_ghost: successfully set ghost.number = " << num << "\n";
|
||||
|
||||
reinterpret_cast<ghost_obj*>(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;
|
||||
|
|
|
@ -9,9 +9,11 @@
|
|||
|
||||
namespace nasal {
|
||||
|
||||
class ast_dumper:public ast_visitor {
|
||||
class ast_dumper: public ast_visitor {
|
||||
private:
|
||||
std::vector<std::string> 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();
|
||||
}
|
||||
|
|
30
src/main.cpp
30
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<u32>(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<nasal::optimizer>(new nasal::optimizer);
|
||||
auto opt = std::make_unique<nasal::optimizer>();
|
||||
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<nasal::dbg>(new nasal::dbg);
|
||||
auto debugger = std::make_unique<nasal::dbg>();
|
||||
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<nasal::vm>(new nasal::vm);
|
||||
auto runtime = std::make_unique<nasal::vm>();
|
||||
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<f64>((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<nasal::repl::repl>(new nasal::repl::repl);
|
||||
auto repl = std::make_unique<nasal::repl::repl>();
|
||||
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<std::string, u32> cmdlst = {
|
||||
const std::unordered_map<std::string, u32> 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<std::string> vm_argv;
|
||||
for(i32 i = 1; i<argc; ++i) {
|
||||
if (cmdlst.count(argv[i])) {
|
||||
cmd |= cmdlst.at(argv[i]);
|
||||
if (command_list.count(argv[i])) {
|
||||
commands |= command_list.at(argv[i]);
|
||||
} else if (!filename.length()) {
|
||||
filename = argv[i];
|
||||
} else {
|
||||
|
@ -248,6 +251,7 @@ i32 main(i32 argc, const char* argv[]) {
|
|||
if (!filename.length()) {
|
||||
err();
|
||||
}
|
||||
execute(filename, vm_argv, cmd? cmd:VM_EXEC);
|
||||
|
||||
execute(filename, vm_argv, commands? commands:VM_EXEC);
|
||||
return 0;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef __nasver__
|
||||
#define __nasver__ "11.1"
|
||||
#define __nasver__ "11.2"
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
|
@ -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*);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<symbol_finder>(new symbol_finder);
|
||||
auto finder = std::make_unique<symbol_finder>();
|
||||
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; i<size-1; ++i, ++iter) {
|
||||
for(u64 i = 0; i<size-1; ++i, ++iter) {
|
||||
if (iter->count(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<u16>(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; i<size; ++i) {
|
||||
emit(op_callvi, i, node->get_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<i64>(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<tuple_expr*>(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; i<size; ++i) {
|
||||
for(i64 i = 0; i<size; ++i) {
|
||||
mcall(tuple[i]);
|
||||
// use load operands to avoid meq's pop operand
|
||||
// and this operation changes local and global value directly
|
||||
|
@ -773,13 +785,14 @@ void codegen::multi_assign_gen(multi_assign* node) {
|
|||
// generate multiple assignment: (a, b, c) = [1, 2, 3];
|
||||
calc_gen(value_node);
|
||||
auto& tuple = tuple_node->get_elements();
|
||||
for(i32 i = 0; i<size; ++i) {
|
||||
for(i64 i = 0; i<size; ++i) {
|
||||
emit(op_callvi, i, value_node->get_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<identifier*>(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<u32> func_begin_stack;
|
||||
std::stack<u32> func_end_stack;
|
||||
std::stack<u64> func_begin_stack;
|
||||
std::stack<u64> 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<code.size(); ++i) {
|
||||
|
||||
for(u64 i = 0; i<code.size(); ++i) {
|
||||
// print opcode index, opcode name, opcode immediate number
|
||||
const auto& c = code[i];
|
||||
if (!func_end_stack.empty() && i==func_end_stack.top()) {
|
||||
|
@ -1407,7 +1421,7 @@ void codegen::print(std::ostream& out) {
|
|||
// get function begin index and end index
|
||||
if (c.op==op_newf) {
|
||||
out << std::hex << "\nfunc <0x" << i << std::dec << ">:\n";
|
||||
for(u32 j = i; j<code.size(); ++j) {
|
||||
for(u64 j = i; j<code.size(); ++j) {
|
||||
if (code[j].op==op_jmp) {
|
||||
func_begin_stack.push(i);
|
||||
func_end_stack.push(code[j].num);
|
||||
|
@ -1422,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');
|
||||
|
|
|
@ -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<std::string> unsafe_system_api = {
|
||||
// builtin
|
||||
|
@ -67,8 +68,8 @@ private:
|
|||
std::vector<u32> in_foreach_loop_level;
|
||||
|
||||
// constant numbers and strings
|
||||
std::unordered_map<f64, u32> const_number_map;
|
||||
std::unordered_map<std::string, u32> const_string_map;
|
||||
std::unordered_map<f64, u64> const_number_map;
|
||||
std::unordered_map<std::string, u64> const_string_map;
|
||||
std::vector<f64> const_number_table;
|
||||
std::vector<std::string> const_string_table;
|
||||
|
||||
|
@ -82,17 +83,20 @@ private:
|
|||
std::vector<opcode> code;
|
||||
|
||||
// used to store jmp operands index, to fill the jump address back
|
||||
std::list<std::vector<i32>> continue_ptr;
|
||||
std::list<std::vector<i32>> break_ptr;
|
||||
std::list<std::vector<u64>> continue_ptr;
|
||||
std::list<std::vector<u64>> break_ptr;
|
||||
|
||||
// symbol table
|
||||
// global : max STACK_DEPTH-1 values
|
||||
std::unordered_map<std::string, i32> global;
|
||||
std::unordered_map<std::string, std::unordered_set<std::string>> experimental_namespace;
|
||||
// global : max VM_STACK_DEPTH-1 values
|
||||
std::unordered_map<std::string, u64> global;
|
||||
|
||||
// nasal namespace
|
||||
// stores all global symbols of each file
|
||||
std::unordered_map<std::string, std::unordered_set<std::string>> nasal_namespace;
|
||||
|
||||
// local : max 32768 upvalues 65536 values
|
||||
// but in fact local scope also has less than STACK_DEPTH value
|
||||
std::list<std::unordered_map<std::string, i32>> local;
|
||||
// but in fact local scope also has less than VM_STACK_DEPTH value
|
||||
std::list<std::unordered_map<std::string, u64>> 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;
|
||||
|
|
|
@ -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<std::string> dbg::parse(const std::string& cmd) {
|
|||
}
|
||||
|
||||
u16 dbg::file_index(const std::string& filename) const {
|
||||
for(u16 i = 0; i<fsize; ++i) {
|
||||
for(u16 i = 0; i<file_list_size; ++i) {
|
||||
if (filename==files[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 65535;
|
||||
return UINT16_MAX;
|
||||
}
|
||||
|
||||
void dbg::err() {
|
||||
void dbg::err() const {
|
||||
std::cerr
|
||||
<< "incorrect command\n"
|
||||
<< "input \'h\' to get help\n";
|
||||
}
|
||||
|
||||
void dbg::help() {
|
||||
void dbg::help() const {
|
||||
std::clog
|
||||
<< "<option>\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"
|
||||
<< "<option> <filename> <line>\n"
|
||||
|
@ -141,18 +141,20 @@ void dbg::help() {
|
|||
}
|
||||
|
||||
void dbg::list_file() const {
|
||||
for(usize i = 0; i<fsize; ++i) {
|
||||
for(usize i = 0; i<file_list_size; ++i) {
|
||||
std::clog << "[" << i << "] " << files[i] << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
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<end && i<src.size(); ++i) {
|
||||
for(u64 i = begin; i<end && i<src.size(); ++i) {
|
||||
std::clog << (i==line? back_white:reset);
|
||||
std::clog << (i==line? "--> ":" ") << src[i] << reset << "\n";
|
||||
}
|
||||
|
@ -160,15 +162,16 @@ 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<end && bytecode[i].op!=op_exit; ++i) {
|
||||
for(u64 i = begin; i<end && bytecode[i].op!=op_exit; ++i) {
|
||||
std::clog
|
||||
<< (i==ctx.pc? back_white:reset)
|
||||
<< (i==ctx.pc? "--> ":" ")
|
||||
<< codestream(bytecode[i], i)
|
||||
<< reset << "\n";
|
||||
}
|
||||
stack_info(10);
|
||||
stack_info(16);
|
||||
}
|
||||
|
||||
void dbg::interact() {
|
||||
|
@ -218,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;
|
||||
}
|
||||
|
@ -234,19 +237,19 @@ void dbg::interact() {
|
|||
}
|
||||
}
|
||||
|
||||
void dbg::run(
|
||||
const codegen& gen,
|
||||
const linker& linker,
|
||||
const std::vector<std::string>& argv,
|
||||
bool profile,
|
||||
bool show_all_prof_result) {
|
||||
void dbg::run(const codegen& gen,
|
||||
const linker& linker,
|
||||
const std::vector<std::string>& 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(
|
||||
file_list_size = file_list.size();
|
||||
|
||||
vm_init_enrty(
|
||||
gen.strs(),
|
||||
gen.nums(),
|
||||
gen.natives(),
|
||||
|
@ -257,10 +260,10 @@ void dbg::run(
|
|||
);
|
||||
counter.init(file_list);
|
||||
|
||||
std::vector<u32> code;
|
||||
std::vector<u8> code;
|
||||
std::vector<u16> code_file_index;
|
||||
std::vector<u32> code_line;
|
||||
for(auto& i : gen.codes()) {
|
||||
std::vector<u64> code_line;
|
||||
for(const auto& i : gen.codes()) {
|
||||
code.push_back(i.op);
|
||||
code_file_index.push_back(i.fidx);
|
||||
code_line.push_back(i.line);
|
||||
|
|
|
@ -140,9 +140,9 @@ private:
|
|||
|
||||
private:
|
||||
bool next;
|
||||
usize fsize;
|
||||
usize file_list_size;
|
||||
u16 break_file_index;
|
||||
u32 break_line;
|
||||
u64 break_line;
|
||||
error src;
|
||||
|
||||
private:
|
||||
|
@ -152,24 +152,21 @@ private:
|
|||
private:
|
||||
std::vector<std::string> 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) {}
|
||||
void run(
|
||||
const codegen&,
|
||||
const linker&,
|
||||
const std::vector<std::string>&,
|
||||
bool,
|
||||
bool
|
||||
);
|
||||
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<std::string>&,
|
||||
bool,
|
||||
bool);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -120,22 +120,23 @@ 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);
|
||||
|
||||
++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 +165,25 @@ void error::err(
|
|||
// output underline
|
||||
std::cerr << cyan << iden << " | " << reset;
|
||||
if (loc.begin_line==loc.end_line) {
|
||||
for(u32 i = 0; i<loc.begin_column; ++i) {
|
||||
for(u64 i = 0; i<loc.begin_column; ++i) {
|
||||
std::cerr << char(" \t"[code[i]=='\t']);
|
||||
}
|
||||
for(u32 i = loc.begin_column; i<loc.end_column; ++i) {
|
||||
for(u64 i = loc.begin_column; i<loc.end_column; ++i) {
|
||||
std::cerr << red << (code[i]=='\t'? "^^^^":"^") << reset;
|
||||
}
|
||||
} else if (line==loc.begin_line) {
|
||||
for(u32 i = 0; i<loc.begin_column; ++i) {
|
||||
for(u64 i = 0; i<loc.begin_column; ++i) {
|
||||
std::cerr << char(" \t"[code[i]=='\t']);
|
||||
}
|
||||
for(u32 i = loc.begin_column; i<code.size(); ++i) {
|
||||
for(u64 i = loc.begin_column; i<code.size(); ++i) {
|
||||
std::cerr << red << (code[i]=='\t'? "^^^^":"^") << reset;
|
||||
}
|
||||
} else if (loc.begin_line<line && line<loc.end_line) {
|
||||
for(u32 i = 0; i<code.size(); ++i) {
|
||||
for(u64 i = 0; i<code.size(); ++i) {
|
||||
std::cerr << red << (code[i]=='\t'? "^^^^":"^");
|
||||
}
|
||||
} else {
|
||||
for(u32 i = 0; i<loc.end_column; ++i) {
|
||||
for(u64 i = 0; i<loc.end_column; ++i) {
|
||||
std::cerr << red << (code[i]=='\t'? "^^^^":"^");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,11 +11,15 @@
|
|||
namespace nasal {
|
||||
|
||||
struct span {
|
||||
u32 begin_line;
|
||||
u32 begin_column;
|
||||
u32 end_line;
|
||||
u32 end_column;
|
||||
u64 begin_line;
|
||||
u64 begin_column;
|
||||
u64 end_line;
|
||||
u64 end_column;
|
||||
std::string file;
|
||||
|
||||
void dump_begin(std::ostream& out) const {
|
||||
out << file << ":" << begin_line << ":" << begin_column + 1;
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream& back_white(std::ostream&);
|
||||
|
@ -46,7 +50,7 @@ private:
|
|||
std::string identation(usize len) {
|
||||
return std::string(len, ' ');
|
||||
}
|
||||
std::string leftpad(u32 num, usize len) {
|
||||
std::string leftpad(u64 num, usize len) {
|
||||
auto tmp = std::to_string(num);
|
||||
while(tmp.length()<len) {
|
||||
tmp = " "+tmp;
|
||||
|
@ -65,7 +69,7 @@ public:
|
|||
std::exit(1);
|
||||
}
|
||||
}
|
||||
u32 geterr() const {return cnt;}
|
||||
auto geterr() const { return cnt; }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,10 @@ void gc::do_mark_sweep() {
|
|||
void gc::mark() {
|
||||
std::vector<var> bfs;
|
||||
mark_context_root(bfs);
|
||||
if (memory.size()>8192 && bfs.size()>4) {
|
||||
|
||||
// concurrent mark, experimental
|
||||
if (memory.size()>UINT16_MAX && bfs.size()>32) {
|
||||
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);
|
||||
|
@ -35,6 +38,7 @@ void gc::mark() {
|
|||
return;
|
||||
}
|
||||
|
||||
// normal mark
|
||||
while(!bfs.empty()) {
|
||||
var value = bfs.back();
|
||||
bfs.pop_back();
|
||||
|
@ -189,7 +193,7 @@ void gc::extend(const vm_type type) {
|
|||
const u8 index = static_cast<u8>(type)-static_cast<u8>(vm_type::vm_str);
|
||||
size[index] += incr[index];
|
||||
|
||||
for(u32 i = 0; i<incr[index]; ++i) {
|
||||
for(u64 i = 0; i<incr[index]; ++i) {
|
||||
// no need to check, will be killed if memory is not enough
|
||||
nas_val* tmp = new nas_val(type);
|
||||
|
||||
|
@ -197,14 +201,13 @@ void gc::extend(const vm_type type) {
|
|||
memory.push_back(tmp);
|
||||
unused[index].push_back(tmp);
|
||||
}
|
||||
|
||||
// if incr[index] = 1, this will always be 1
|
||||
incr[index] = incr[index]+incr[index]/2;
|
||||
}
|
||||
|
||||
void gc::init(
|
||||
const std::vector<std::string>& constant_strings,
|
||||
const std::vector<std::string>& argv
|
||||
) {
|
||||
void gc::init(const std::vector<std::string>& constant_strings,
|
||||
const std::vector<std::string>& argv) {
|
||||
// initialize counters
|
||||
worktime = 0;
|
||||
for(u8 i = 0; i<gc_type_size; ++i) {
|
||||
|
@ -216,25 +219,25 @@ void gc::init(
|
|||
|
||||
// init constant strings
|
||||
strs.resize(constant_strings.size());
|
||||
for(u32 i = 0; i<strs.size(); ++i) {
|
||||
for(u64 i = 0; i<strs.size(); ++i) {
|
||||
// incremental initialization, avoid memory leak in repl mode
|
||||
if (strs[i].is_str() && strs[i].str()==constant_strings[i]) {
|
||||
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];
|
||||
}
|
||||
|
||||
// record arguments
|
||||
env_argv.resize(argv.size());
|
||||
for(usize i = 0; i<argv.size(); ++i) {
|
||||
for(u64 i = 0; i<argv.size(); ++i) {
|
||||
// incremental initialization, avoid memory leak in repl mode
|
||||
if (env_argv[i].is_str() && env_argv[i].str()==argv[i]) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
@ -315,7 +318,7 @@ void gc::info() const {
|
|||
if (!gcnt[i] && !acnt[i] && !size[i]) {
|
||||
continue;
|
||||
}
|
||||
total += gcnt[i];
|
||||
total += static_cast<f64>(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];
|
||||
|
@ -341,6 +344,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";
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ struct gc {
|
|||
std::vector<nas_val*> 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
|
||||
|
@ -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;
|
||||
|
@ -115,7 +116,7 @@ public:
|
|||
// module function type
|
||||
typedef var (*module_func)(var*, usize, gc*);
|
||||
|
||||
// module function stores in tables with this type, end with {nullptr,nullptr}
|
||||
// module function stores in tables with this type, end with {nullptr, nullptr}
|
||||
struct module_func_info {
|
||||
const char* name;
|
||||
module_func fd;
|
||||
|
|
|
@ -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<fs::path> path_list = {filename};
|
||||
|
||||
|
@ -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<symbol_finder>(new symbol_finder);
|
||||
auto finder = std::make_unique<symbol_finder>();
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ void lexer::open(const std::string& file) {
|
|||
}
|
||||
|
||||
tok lexer::get_type(const std::string& str) {
|
||||
return typetbl.count(str)? typetbl.at(str):tok::null;
|
||||
return token_mapper.count(str)? token_mapper.at(str):tok::null;
|
||||
}
|
||||
|
||||
std::string lexer::utf8_gen() {
|
||||
|
@ -138,8 +138,8 @@ std::string lexer::utf8_gen() {
|
|||
}
|
||||
|
||||
token lexer::id_gen() {
|
||||
u32 begin_line = line;
|
||||
u32 begin_column = column;
|
||||
u64 begin_line = line;
|
||||
u64 begin_column = column;
|
||||
std::string str = "";
|
||||
while(ptr<res.size() && (is_id(res[ptr]) || is_dec(res[ptr]))) {
|
||||
if (res[ptr]<0) { // utf-8
|
||||
|
@ -157,8 +157,8 @@ token lexer::id_gen() {
|
|||
}
|
||||
|
||||
token lexer::num_gen() {
|
||||
u32 begin_line = line;
|
||||
u32 begin_column = column;
|
||||
u64 begin_line = line;
|
||||
u64 begin_column = column;
|
||||
// generate hex number
|
||||
if (ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='x') {
|
||||
std::string str = "0x";
|
||||
|
@ -239,8 +239,8 @@ token lexer::num_gen() {
|
|||
}
|
||||
|
||||
token lexer::str_gen() {
|
||||
u32 begin_line = line;
|
||||
u32 begin_column = column;
|
||||
u64 begin_line = line;
|
||||
u64 begin_column = column;
|
||||
std::string str = "";
|
||||
const char begin = res[ptr];
|
||||
++column;
|
||||
|
@ -298,8 +298,8 @@ token lexer::str_gen() {
|
|||
}
|
||||
|
||||
token lexer::single_opr() {
|
||||
u32 begin_line = line;
|
||||
u32 begin_column = column;
|
||||
u64 begin_line = line;
|
||||
u64 begin_column = column;
|
||||
std::string str(1, res[ptr]);
|
||||
++column;
|
||||
tok type = get_type(str);
|
||||
|
@ -314,8 +314,8 @@ token lexer::single_opr() {
|
|||
}
|
||||
|
||||
token lexer::dots() {
|
||||
u32 begin_line = line;
|
||||
u32 begin_column = column;
|
||||
u64 begin_line = line;
|
||||
u64 begin_column = column;
|
||||
std::string str = ".";
|
||||
if (ptr+2<res.size() && res[ptr+1]=='.' && res[ptr+2]=='.') {
|
||||
str += "..";
|
||||
|
@ -326,8 +326,8 @@ token lexer::dots() {
|
|||
}
|
||||
|
||||
token lexer::calc_opr() {
|
||||
u32 begin_line = line;
|
||||
u32 begin_column = column;
|
||||
u64 begin_line = line;
|
||||
u64 begin_column = column;
|
||||
// get calculation operator
|
||||
std::string str(1, res[ptr++]);
|
||||
if (ptr<res.size() && res[ptr]=='=') {
|
||||
|
|
|
@ -36,7 +36,7 @@ enum class tok:u32 {
|
|||
rif, // condition expression keyword if
|
||||
elsif, // condition expression keyword elsif
|
||||
relse, // condition expression keyword else
|
||||
tknil, // nil literal
|
||||
nil, // nil literal
|
||||
lcurve, // (
|
||||
rcurve, // )
|
||||
lbracket, // [
|
||||
|
@ -88,8 +88,8 @@ struct token {
|
|||
|
||||
class lexer {
|
||||
private:
|
||||
u32 line;
|
||||
u32 column;
|
||||
u64 line;
|
||||
u64 column;
|
||||
usize ptr;
|
||||
std::string filename;
|
||||
std::string res;
|
||||
|
@ -98,7 +98,7 @@ private:
|
|||
u64 invalid_char;
|
||||
std::vector<token> toks;
|
||||
|
||||
const std::unordered_map<std::string, tok> typetbl {
|
||||
const std::unordered_map<std::string, tok> token_mapper = {
|
||||
{"use" ,tok::use },
|
||||
{"true" ,tok::tktrue },
|
||||
{"false" ,tok::tkfalse },
|
||||
|
@ -114,7 +114,7 @@ private:
|
|||
{"if" ,tok::rif },
|
||||
{"elsif" ,tok::elsif },
|
||||
{"else" ,tok::relse },
|
||||
{"nil" ,tok::tknil },
|
||||
{"nil" ,tok::nil },
|
||||
{"(" ,tok::lcurve },
|
||||
{")" ,tok::rcurve },
|
||||
{"[" ,tok::lbracket},
|
||||
|
@ -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<token>& result() const {return toks;}
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace nasal {
|
||||
|
||||
const char* opname[] = {
|
||||
const char* oprand_name_table[] = {
|
||||
"exit ", "repl ", "intl ", "loadg ",
|
||||
"loadl ", "loadu ", "pnum ", "pnil ",
|
||||
"pstr ", "newv ", "newh ", "newf ",
|
||||
|
@ -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;
|
||||
|
@ -43,73 +42,115 @@ void codestream::dump(std::ostream& out) const {
|
|||
using std::setfill;
|
||||
using std::hex;
|
||||
using std::dec;
|
||||
auto op = code.op;
|
||||
auto num = code.num;
|
||||
|
||||
const auto op = code.op;
|
||||
const auto num = code.num;
|
||||
|
||||
// dump operand index and bytecode(hex format)
|
||||
out << hex << "0x"
|
||||
<< setw(6) << setfill('0') << index << " "
|
||||
<< setw(2) << setfill('0') << static_cast<u32>(op) << " "
|
||||
<< setw(2) << setfill('0') << ((num>>16)&0xff) << " "
|
||||
<< setw(2) << setfill('0') << ((num>>8)&0xff) << " "
|
||||
<< setw(2) << setfill('0') << (num&0xff) << " "
|
||||
<<opname[op]<<" "<<dec;
|
||||
<< setw(6) << setfill('0') << index << " "
|
||||
<< setw(2) << setfill('0') << static_cast<u32>(op) << ":" << dec;
|
||||
|
||||
// dump immediate number(hex format)
|
||||
for(i32 i = 64-8; i>=0; i -= 8) {
|
||||
out << hex << setw(2) << setfill('0') << ((num>>i)&0xff) << dec << " ";
|
||||
}
|
||||
|
||||
// dump operand name
|
||||
out << " " << oprand_name_table[op] << " ";
|
||||
|
||||
switch(op) {
|
||||
case op_addeq: case op_subeq:
|
||||
case op_muleq: case op_diveq:
|
||||
case op_lnkeq: case op_meq:
|
||||
case op_btandeq: case op_btoreq:
|
||||
case op_addeq:
|
||||
case op_subeq:
|
||||
case op_muleq:
|
||||
case op_diveq:
|
||||
case op_lnkeq:
|
||||
case op_meq:
|
||||
case op_btandeq:
|
||||
case op_btoreq:
|
||||
case op_btxoreq:
|
||||
out << hex << "0x" << num << dec << " sp-" << num; break;
|
||||
case op_addeqc: case op_subeqc:
|
||||
case op_muleqc:case op_diveqc:
|
||||
out << hex << "0x" << num << dec
|
||||
<< " (" << const_number[num] << ")"; break;
|
||||
out << hex << "0x" << num << dec << " sp-" << num;
|
||||
break;
|
||||
case op_addeqc:
|
||||
case op_subeqc:
|
||||
case op_muleqc:
|
||||
case op_diveqc:
|
||||
out << hex << "0x" << num << dec;
|
||||
out << " (" << const_number[num] << ")";
|
||||
break;
|
||||
case op_lnkeqc:
|
||||
out << hex << "0x" << num << dec
|
||||
<< " (" << rawstr(const_string[num], 16) << ")"; break;
|
||||
case op_addecp: case op_subecp:
|
||||
case op_mulecp: case op_divecp:
|
||||
out << hex << "0x" << num << dec
|
||||
<< " (" << const_number[num] << ") sp-1"; break;
|
||||
out << hex << "0x" << num << dec;
|
||||
out << " (" << rawstr(const_string[num], 16) << ")";
|
||||
break;
|
||||
case op_addecp:
|
||||
case op_subecp:
|
||||
case op_mulecp:
|
||||
case op_divecp:
|
||||
out << hex << "0x" << num << dec;
|
||||
out << " (" << const_number[num] << ") sp-1";
|
||||
break;
|
||||
case op_lnkecp:
|
||||
out << hex << "0x" << num << dec
|
||||
<< " (" << rawstr(const_string[num], 16) << ") sp-1"; break;
|
||||
case op_addc: case op_subc:
|
||||
case op_mulc: case op_divc:
|
||||
case op_lessc: case op_leqc:
|
||||
case op_grtc: case op_geqc:
|
||||
out << hex << "0x" << num << dec;
|
||||
out << " (" << rawstr(const_string[num], 16) << ") sp-1";
|
||||
break;
|
||||
case op_addc:
|
||||
case op_subc:
|
||||
case op_mulc:
|
||||
case op_divc:
|
||||
case op_lessc:
|
||||
case op_leqc:
|
||||
case op_grtc:
|
||||
case op_geqc:
|
||||
case op_pnum:
|
||||
out << hex << "0x" << num << dec
|
||||
<< " (" << const_number[num] << ")"; break;
|
||||
case op_callvi: case op_newv:
|
||||
case op_callfv: case op_repl:
|
||||
case op_intl: case op_findex:
|
||||
case op_feach: case op_newf:
|
||||
case op_jmp: case op_jt:
|
||||
case op_jf: case op_callg:
|
||||
case op_mcallg: case op_loadg:
|
||||
case op_calll: case op_mcalll:
|
||||
out << hex << "0x" << num << dec;
|
||||
out << " (" << const_number[num] << ")";
|
||||
break;
|
||||
case op_callvi:
|
||||
case op_newv:
|
||||
case op_callfv:
|
||||
case op_repl:
|
||||
case op_intl:
|
||||
case op_findex:
|
||||
case op_feach:
|
||||
case op_newf:
|
||||
case op_jmp:
|
||||
case op_jt:
|
||||
case op_jf:
|
||||
case op_callg:
|
||||
case op_mcallg:
|
||||
case op_loadg:
|
||||
case op_calll:
|
||||
case op_mcalll:
|
||||
case op_loadl:
|
||||
out << hex << "0x" << num << dec; break;
|
||||
case op_callb:
|
||||
out << hex << "0x" << num << " <" << natives[num].name
|
||||
<< "@0x" << reinterpret_cast<u64>(natives[num].func)
|
||||
<< dec << ">"; break;
|
||||
case op_upval: case op_mupval:
|
||||
case op_upval:
|
||||
case op_mupval:
|
||||
case op_loadu:
|
||||
out << hex << "0x" << ((num>>16)&0xffff)
|
||||
<< "[0x" << (num&0xffff) << "]" << dec; break;
|
||||
case op_happ: case op_pstr:
|
||||
case op_lnkc: case op_callh:
|
||||
case op_mcallh: case op_para:
|
||||
case op_deft: case op_dyn:
|
||||
out << hex << "0x" << num << dec
|
||||
<< " (" << rawstr(const_string[num], 16) << ")"; break;
|
||||
case op_happ:
|
||||
case op_pstr:
|
||||
case op_lnkc:
|
||||
case op_callh:
|
||||
case op_mcallh:
|
||||
case op_para:
|
||||
case op_deft:
|
||||
case op_dyn:
|
||||
out << hex << "0x" << num << dec;
|
||||
out << " (" << rawstr(const_string[num], 16) << ")";
|
||||
break;
|
||||
default:
|
||||
if (files) {
|
||||
out << hex << "0x" << num << dec;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// if file list is loaded, dump file location info
|
||||
if (files) {
|
||||
out << " (" << files[code.fidx] << ":" << code.line << ")";
|
||||
}
|
||||
|
|
|
@ -8,100 +8,100 @@
|
|||
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<i32>
|
||||
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<i32>
|
||||
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
|
||||
u32 line; // location line of source code
|
||||
u64 num; // immediate num
|
||||
u64 line; // location line of source code
|
||||
opcode() = default;
|
||||
opcode(const opcode&) = default;
|
||||
opcode& operator=(const opcode&) = default;
|
||||
|
@ -110,24 +110,23 @@ 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;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream&, const codestream&);
|
||||
|
||||
extern const char* opname[];
|
||||
extern const char* oprand_name_table[];
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
@ -156,8 +156,8 @@ 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;
|
||||
// special call means like this: function_name(a:1, b:2, c:3);
|
||||
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;
|
||||
|
@ -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::nil,
|
||||
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);
|
||||
|
@ -372,7 +372,7 @@ expr* parse::expression() {
|
|||
}
|
||||
switch(type) {
|
||||
case tok::use: return use_stmt_gen();
|
||||
case tok::tknil:
|
||||
case tok::nil:
|
||||
case tok::num:
|
||||
case tok::str:
|
||||
case tok::id:
|
||||
|
@ -637,9 +637,9 @@ unary_operator* parse::unary() {
|
|||
|
||||
expr* parse::scalar() {
|
||||
expr* node = nullptr;
|
||||
if (lookahead(tok::tknil)) {
|
||||
if (lookahead(tok::nil)) {
|
||||
node = nil();
|
||||
match(tok::tknil);
|
||||
match(tok::nil);
|
||||
} else if (lookahead(tok::num)) {
|
||||
node = num();
|
||||
} else if (lookahead(tok::str)) {
|
||||
|
@ -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::nil,
|
||||
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::nil,
|
||||
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::nil,
|
||||
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);
|
||||
|
@ -1069,7 +1070,7 @@ return_expr* parse::return_expression() {
|
|||
auto node = new return_expr(toks[ptr].loc);
|
||||
match(tok::ret);
|
||||
tok type = toks[ptr].type;
|
||||
if (type==tok::tknil || type==tok::num ||
|
||||
if (type==tok::nil || type==tok::num ||
|
||||
type==tok::str || type==tok::id ||
|
||||
type==tok::func || type==tok::sub ||
|
||||
type==tok::opnot || type==tok::lcurve ||
|
||||
|
|
|
@ -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;
|
||||
|
@ -37,7 +37,7 @@ private:
|
|||
{tok::rif ,"if" },
|
||||
{tok::elsif ,"elsif" },
|
||||
{tok::relse ,"else" },
|
||||
{tok::tknil ,"nil" },
|
||||
{tok::nil ,"nil" },
|
||||
{tok::lcurve ,"(" },
|
||||
{tok::rcurve ,")" },
|
||||
{tok::lbracket,"[" },
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -95,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<std::string> 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();
|
||||
|
@ -102,11 +129,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;
|
||||
|
@ -145,14 +171,14 @@ void nas_co::clear() {
|
|||
if (!ctx.stack) {
|
||||
return;
|
||||
}
|
||||
for(u32 i = 0; i<STACK_DEPTH; ++i) {
|
||||
for(u32 i = 0; i<VM_STACK_DEPTH; ++i) {
|
||||
ctx.stack[i] = var::nil();
|
||||
}
|
||||
|
||||
ctx.pc = 0;
|
||||
ctx.localr = nullptr;
|
||||
ctx.memr = nullptr;
|
||||
ctx.canary = ctx.stack+STACK_DEPTH-1;
|
||||
ctx.canary = ctx.stack+VM_STACK_DEPTH-1;
|
||||
ctx.top = ctx.stack;
|
||||
ctx.funcr = var::nil();
|
||||
ctx.upvalr = var::nil();
|
||||
|
@ -198,7 +224,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;
|
||||
|
@ -214,14 +240,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 +255,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;
|
||||
}
|
||||
}
|
||||
|
@ -254,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;
|
||||
|
@ -279,14 +308,14 @@ bool var::object_check(const std::string& name) {
|
|||
}
|
||||
|
||||
var var::none() {
|
||||
return {vm_type::vm_none, static_cast<u32>(0)};
|
||||
return {vm_type::vm_none, static_cast<u64>(0)};
|
||||
}
|
||||
|
||||
var var::nil() {
|
||||
return {vm_type::vm_nil, static_cast<u32>(0)};
|
||||
return {vm_type::vm_nil, static_cast<u64>(0)};
|
||||
}
|
||||
|
||||
var var::ret(u32 pc) {
|
||||
var var::ret(u64 pc) {
|
||||
return {vm_type::vm_ret, pc};
|
||||
}
|
||||
|
||||
|
@ -310,7 +339,7 @@ var* var::addr() {
|
|||
return val.addr;
|
||||
}
|
||||
|
||||
u32 var::ret() const {
|
||||
u64 var::ret() const {
|
||||
return val.ret;
|
||||
}
|
||||
|
||||
|
@ -355,7 +384,7 @@ nas_map& var::map() {
|
|||
}
|
||||
|
||||
var nas_err(const std::string& error_function_name, const std::string& info) {
|
||||
std::cerr << "[vm] " << error_function_name << ": " << info << "\n";
|
||||
std::cerr << "\n[vm] " << error_function_name << ": " << info << "\n";
|
||||
return var::none();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
@ -49,7 +51,7 @@ struct var {
|
|||
public:
|
||||
vm_type type = vm_type::vm_none;
|
||||
union {
|
||||
u32 ret;
|
||||
u64 ret;
|
||||
i64 cnt;
|
||||
f64 num;
|
||||
var* addr;
|
||||
|
@ -57,7 +59,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 +84,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 +93,7 @@ public:
|
|||
public:
|
||||
// get value
|
||||
var* addr();
|
||||
u32 ret() const;
|
||||
u64 ret() const;
|
||||
i64& cnt();
|
||||
f64 num() const;
|
||||
std::string& str();
|
||||
|
@ -143,19 +145,23 @@ 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<var> local; // local scope with default value(var)
|
||||
std::vector<var> upval; // closure
|
||||
|
||||
// parameter table, u32 begins from 1
|
||||
std::unordered_map<std::string, u32> 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();
|
||||
};
|
||||
|
||||
|
@ -163,7 +169,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 +213,7 @@ public:
|
|||
};
|
||||
|
||||
struct context {
|
||||
u32 pc = 0;
|
||||
u64 pc = 0;
|
||||
var* localr = nullptr;
|
||||
var* memr = nullptr;
|
||||
var funcr = var::nil();
|
||||
|
@ -228,7 +234,7 @@ struct nas_co {
|
|||
status status;
|
||||
|
||||
nas_co() {
|
||||
ctx.stack = new var[STACK_DEPTH];
|
||||
ctx.stack = new var[VM_STACK_DEPTH];
|
||||
clear();
|
||||
}
|
||||
~nas_co() {
|
||||
|
@ -250,7 +256,7 @@ struct nas_map {
|
|||
};
|
||||
|
||||
struct nas_val {
|
||||
enum class gc_status:u8 {
|
||||
enum class gc_status: u8 {
|
||||
uncollected = 0,
|
||||
collected,
|
||||
found
|
||||
|
@ -258,7 +264,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;
|
||||
|
@ -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&);
|
||||
|
|
|
@ -2,15 +2,13 @@
|
|||
|
||||
namespace nasal {
|
||||
|
||||
void vm::init(
|
||||
const std::vector<std::string>& strs,
|
||||
const std::vector<f64>& nums,
|
||||
const std::vector<nasal_builtin_table>& natives,
|
||||
const std::vector<opcode>& code,
|
||||
const std::unordered_map<std::string, i32>& global_symbol,
|
||||
const std::vector<std::string>& filenames,
|
||||
const std::vector<std::string>& argv
|
||||
) {
|
||||
void vm::vm_init_enrty(const std::vector<std::string>& strs,
|
||||
const std::vector<f64>& nums,
|
||||
const std::vector<nasal_builtin_table>& natives,
|
||||
const std::vector<opcode>& code,
|
||||
const std::unordered_map<std::string, u64>& global_symbol,
|
||||
const std::vector<std::string>& filenames,
|
||||
const std::vector<std::string>& argv) {
|
||||
const_number = nums.data();
|
||||
const_string = strs.data();
|
||||
bytecode = code.data();
|
||||
|
@ -51,14 +49,14 @@ void vm::context_and_global_init() {
|
|||
ctx.funcr = nil;
|
||||
ctx.upvalr = nil;
|
||||
|
||||
/* set canary = stack[STACK_DEPTH-1] */
|
||||
ctx.canary = ctx.stack+STACK_DEPTH-1;
|
||||
/* set canary = stack[VM_STACK_DEPTH-1] */
|
||||
ctx.canary = ctx.stack+VM_STACK_DEPTH-1;
|
||||
|
||||
/* nothing is on stack */
|
||||
ctx.top = ctx.stack - 1;
|
||||
|
||||
/* clear main stack and global */
|
||||
for(u32 i = 0; i<STACK_DEPTH; ++i) {
|
||||
for(u32 i = 0; i<VM_STACK_DEPTH; ++i) {
|
||||
ctx.stack[i] = nil;
|
||||
global[i] = nil;
|
||||
}
|
||||
|
@ -80,8 +78,8 @@ void vm::value_info(var& val) {
|
|||
<< "> " << rawstr(val.str(), 16)
|
||||
<< std::dec; break;
|
||||
case vm_type::vm_func: std::clog << "| func | <0x" << std::hex << p
|
||||
<< "> entry:0x" << val.func().entry
|
||||
<< std::dec; break;
|
||||
<< std::dec << "> " << val.func();
|
||||
break;
|
||||
case vm_type::vm_upval:std::clog << "| upval| <0x" << std::hex << p
|
||||
<< std::dec << "> [" << val.upval().size
|
||||
<< " val]"; break;
|
||||
|
@ -126,7 +124,7 @@ void vm::function_detail_info(const nas_func& func) {
|
|||
}
|
||||
if (func.dynamic_parameter_index>=0) {
|
||||
std::clog << (argument_list.size()? ", ":"");
|
||||
std::clog << const_string[func.dynamic_parameter_index] << "...";
|
||||
std::clog << func.dynamic_parameter_name << "...";
|
||||
}
|
||||
std::clog << ") ";
|
||||
const auto& code = bytecode[func.entry];
|
||||
|
@ -194,7 +192,7 @@ void vm::trace_back() {
|
|||
if (same) {
|
||||
std::clog << " 0x" << std::hex
|
||||
<< std::setw(6) << std::setfill('0')
|
||||
<< prev << std::dec << " "
|
||||
<< prev << std::dec << " "
|
||||
<< same << " same call(s)\n";
|
||||
same = 0;
|
||||
}
|
||||
|
@ -203,12 +201,15 @@ void vm::trace_back() {
|
|||
// the first called place has no same calls
|
||||
}
|
||||
|
||||
void vm::stack_info(const u32 limit = 10) {
|
||||
void vm::stack_info(const u64 limit = 16) {
|
||||
var* top = ctx.top;
|
||||
var* bottom = ctx.stack;
|
||||
std::clog << "\nstack (0x" << std::hex << reinterpret_cast<u64>(bottom);
|
||||
std::clog << std::dec << ", limit " << limit << ", total ";
|
||||
const auto stack_address = reinterpret_cast<u64>(bottom);
|
||||
|
||||
std::clog << "\nvm stack (0x" << std::hex << stack_address << std::dec;
|
||||
std::clog << ", limit " << limit << ", total ";
|
||||
std::clog << (top<bottom? 0:static_cast<i64>(top-bottom+1)) << ")\n";
|
||||
|
||||
for(u32 i = 0; i<limit && top>=bottom; ++i, --top) {
|
||||
std::clog << " 0x" << std::hex
|
||||
<< std::setw(6) << std::setfill('0')
|
||||
|
@ -390,7 +391,7 @@ std::string vm::type_name_string(const var& value) const {
|
|||
}
|
||||
|
||||
void vm::die(const std::string& str) {
|
||||
std::cerr << "[vm] error: " << str << "\n";
|
||||
std::cerr << "\n[vm] error: " << str << "\n";
|
||||
function_call_trace();
|
||||
trace_back();
|
||||
stack_info();
|
||||
|
@ -411,11 +412,10 @@ void vm::die(const std::string& str) {
|
|||
}
|
||||
}
|
||||
|
||||
void vm::run(
|
||||
const codegen& gen,
|
||||
const linker& linker,
|
||||
const std::vector<std::string>& argv) {
|
||||
init(
|
||||
void vm::run(const codegen& gen,
|
||||
const linker& linker,
|
||||
const std::vector<std::string>& argv) {
|
||||
vm_init_enrty(
|
||||
gen.strs(),
|
||||
gen.nums(),
|
||||
gen.natives(),
|
||||
|
@ -424,6 +424,7 @@ void vm::run(
|
|||
linker.get_file_list(),
|
||||
argv
|
||||
);
|
||||
|
||||
#ifndef _MSC_VER
|
||||
// using labels as values/computed goto
|
||||
const void* oprs[] = {
|
||||
|
@ -451,7 +452,7 @@ void vm::run(
|
|||
&&mcallv, &&mcallh, &&ret
|
||||
};
|
||||
std::vector<const void*> 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 +507,7 @@ void vm::run(
|
|||
&vm::o_ret
|
||||
};
|
||||
std::vector<nafunc> code;
|
||||
for(auto& i : gen.codes()) {
|
||||
for(const auto& i : gen.codes()) {
|
||||
code.push_back(oprs[i.op]);
|
||||
imm.push_back(i.num);
|
||||
}
|
||||
|
|
115
src/nasal_vm.h
115
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
|
||||
std::vector<u32> imm; // immediate number table
|
||||
const f64* const_number = nullptr;
|
||||
const std::string* const_string = nullptr;
|
||||
std::vector<u64> imm; // immediate number table
|
||||
|
||||
/* nasal native functions */
|
||||
std::vector<nasal_builtin_table> native_function;
|
||||
|
||||
/* garbage collector */
|
||||
|
@ -49,15 +51,13 @@ protected:
|
|||
bool flag_limited_mode = false;
|
||||
|
||||
/* vm initializing function */
|
||||
void init(
|
||||
const std::vector<std::string>&,
|
||||
const std::vector<f64>&,
|
||||
const std::vector<nasal_builtin_table>&,
|
||||
const std::vector<opcode>&,
|
||||
const std::unordered_map<std::string, i32>&,
|
||||
const std::vector<std::string>&,
|
||||
const std::vector<std::string>&
|
||||
);
|
||||
void vm_init_enrty(const std::vector<std::string>&,
|
||||
const std::vector<f64>&,
|
||||
const std::vector<nasal_builtin_table>&,
|
||||
const std::vector<opcode>&,
|
||||
const std::unordered_map<std::string, u64>&,
|
||||
const std::vector<std::string>&,
|
||||
const std::vector<std::string>&);
|
||||
void context_and_global_init();
|
||||
|
||||
/* debug functions */
|
||||
|
@ -66,7 +66,7 @@ protected:
|
|||
void function_detail_info(const nas_func&);
|
||||
void function_call_trace();
|
||||
void trace_back();
|
||||
void stack_info(const u32);
|
||||
void stack_info(const u64);
|
||||
void register_info();
|
||||
void global_state();
|
||||
void local_state();
|
||||
|
@ -79,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();
|
||||
|
@ -174,8 +176,8 @@ public:
|
|||
|
||||
/* constructor of vm instance */
|
||||
vm() {
|
||||
ctx.stack = new var[STACK_DEPTH];
|
||||
global = new var[STACK_DEPTH];
|
||||
ctx.stack = new var[VM_STACK_DEPTH];
|
||||
global = new var[VM_STACK_DEPTH];
|
||||
}
|
||||
~vm() {
|
||||
delete[] ctx.stack;
|
||||
|
@ -183,11 +185,9 @@ public:
|
|||
}
|
||||
|
||||
/* execution entry */
|
||||
void run(
|
||||
const codegen&, // get generated code
|
||||
const linker&, // get list of used files
|
||||
const std::vector<std::string>& // get arguments input by command line
|
||||
);
|
||||
void run(const codegen&, // get generated code
|
||||
const linker&, // get list of used files
|
||||
const std::vector<std::string>&); // get command line arguments
|
||||
|
||||
/* set detail report info flag */
|
||||
void set_detail_report_info(bool flag) {verbose = flag;}
|
||||
|
@ -251,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<imm[ctx.pc]; ++i) {
|
||||
ctx.top = ctx.top - imm[ctx.pc] + 1;
|
||||
|
||||
for(u64 i = 0; i<imm[ctx.pc]; ++i) {
|
||||
vec[i] = ctx.top[i];
|
||||
}
|
||||
ctx.top[0] = newv;
|
||||
|
@ -270,16 +271,21 @@ inline void vm::o_newf() {
|
|||
|
||||
/* this means you create a new function in local scope */
|
||||
if (ctx.localr) {
|
||||
// copy upval scope list from upper level function
|
||||
func.upval = ctx.funcr.func().upval;
|
||||
// function created in the same local scope shares one closure
|
||||
// so this size & stk setting has no problem
|
||||
|
||||
// function created in the same local scope shares same closure
|
||||
var upval = (ctx.upvalr.is_nil())?
|
||||
ngc.alloc(vm_type::vm_upval):
|
||||
ctx.upvalr;
|
||||
upval.upval().size = ctx.funcr.func().local_size;
|
||||
upval.upval().stack_frame_offset = ctx.localr;
|
||||
// if no upval scope exists, now it's time to create one
|
||||
if (ctx.upvalr.is_nil()) {
|
||||
upval.upval().size = ctx.funcr.func().local_size;
|
||||
upval.upval().stack_frame_offset = ctx.localr;
|
||||
ctx.upvalr = upval;
|
||||
}
|
||||
|
||||
func.upval.push_back(upval);
|
||||
ctx.upvalr = upval;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,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() {
|
||||
|
@ -669,7 +676,7 @@ inline void vm::o_callvi() {
|
|||
die("must use a vector but get "+type_name_string(val));
|
||||
return;
|
||||
}
|
||||
// cannot use operator[],because this may cause overflow
|
||||
// cannot use operator[], because this may cause overflow
|
||||
(++ctx.top)[0] = val.vec().get_value(imm[ctx.pc]);
|
||||
if (ctx.top[0].is_none()) {
|
||||
die(report_out_of_range(imm[ctx.pc], val.vec().size()));
|
||||
|
@ -683,6 +690,7 @@ inline void vm::o_callh() {
|
|||
die("must call a hash but get "+type_name_string(val));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& str = const_string[imm[ctx.pc]];
|
||||
if (val.is_hash()) {
|
||||
ctx.top[0] = val.hash().get_value(str);
|
||||
|
@ -700,7 +708,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 +727,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<parameter_size && func.local[argc+1].is_none()) {
|
||||
die(report_lack_arguments(argc, func));
|
||||
return;
|
||||
|
@ -730,16 +738,17 @@ inline void vm::o_callfv() {
|
|||
if (func.dynamic_parameter_index>=0) {
|
||||
// load dynamic argument
|
||||
dynamic = ngc.alloc(vm_type::vm_vec);
|
||||
for(u32 i = parameter_size; i<argc; ++i) {
|
||||
for(u64 i = parameter_size; i<argc; ++i) {
|
||||
dynamic.vec().elems.push_back(local[i]);
|
||||
}
|
||||
} else if (parameter_size<argc) {
|
||||
// load arguments to default dynamic argument "arg", located at stack+1
|
||||
dynamic = ngc.alloc(vm_type::vm_vec);
|
||||
for(u32 i = parameter_size; i<argc; ++i) {
|
||||
for(u64 i = parameter_size; i<argc; ++i) {
|
||||
dynamic.vec().elems.push_back(local[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// should reset stack top after allocating vector
|
||||
// because this may cause gc
|
||||
// then all the available values the vector needs
|
||||
|
@ -747,14 +756,18 @@ inline void vm::o_callfv() {
|
|||
// collected incorrectly
|
||||
ctx.top = local+func.local_size;
|
||||
|
||||
const u32 min_size = (std::min)(parameter_size, argc); // avoid error in MSVC
|
||||
for(u32 i = min_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; i<func.local_size; ++i) {
|
||||
for(u64 i = min_size+1; i<func.local_size; ++i) {
|
||||
local[i] = func.local[i];
|
||||
}
|
||||
// load dynamic argument
|
||||
|
@ -967,25 +980,31 @@ inline void vm::o_mcallv() {
|
|||
}
|
||||
|
||||
inline void vm::o_mcallh() {
|
||||
var hash = ctx.top[0]; // mcall hash, reserved on stack to avoid gc
|
||||
// mcall hash, reserved on stack to avoid gc, so do not do ctx.top--
|
||||
var hash = ctx.top[0];
|
||||
if (!hash.is_hash() && !hash.is_map()) {
|
||||
die("must call a hash/namespace but get "+type_name_string(hash));
|
||||
die("must call a hash/namespace but get " + type_name_string(hash));
|
||||
return;
|
||||
}
|
||||
const auto& str = const_string[imm[ctx.pc]];
|
||||
|
||||
const auto& key = const_string[imm[ctx.pc]];
|
||||
|
||||
// map is for nasal namespace type, for example `globals`
|
||||
if (hash.is_map()) {
|
||||
ctx.memr = hash.map().get_memory(str);
|
||||
ctx.memr = hash.map().get_memory(key);
|
||||
if (!ctx.memr) {
|
||||
die("cannot find symbol \"" + str + "\"");
|
||||
die("cannot find symbol \"" + key + "\"");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// call hash member
|
||||
auto& ref = hash.hash();
|
||||
ctx.memr = ref.get_memory(str);
|
||||
// create a new key
|
||||
ctx.memr = ref.get_memory(key);
|
||||
// create a new key if not exists
|
||||
if (!ctx.memr) {
|
||||
ref.elems[str] = nil;
|
||||
ctx.memr = ref.get_memory(str);
|
||||
ref.elems[key] = nil;
|
||||
ctx.memr = ref.get_memory(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1023,7 +1042,7 @@ inline void vm::o_ret() {
|
|||
auto size = func.func().local_size;
|
||||
upval.on_stack = false;
|
||||
upval.elems.resize(size);
|
||||
for(u32 i = 0; i<size; ++i) {
|
||||
for(u64 i = 0; i<size; ++i) {
|
||||
upval.elems[i] = local[i];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,14 +41,14 @@ var builtin_u32not(context* ctx, gc* ngc) {
|
|||
}
|
||||
|
||||
var builtin_fld(context* ctx, gc* ngc) {
|
||||
// bits.fld(s,0,3);
|
||||
// bits.fld(s, 0, 3);
|
||||
// if s stores 10100010(162)
|
||||
// will get 101(5)
|
||||
auto local = ctx->localr;
|
||||
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()) {
|
||||
|
@ -70,7 +70,7 @@ var builtin_fld(context* ctx, gc* ngc) {
|
|||
}
|
||||
|
||||
var builtin_sfld(context* ctx, gc* ngc) {
|
||||
// bits.sfld(s,0,3);
|
||||
// bits.sfld(s, 0, 3);
|
||||
// if s stores 10100010(162)
|
||||
// will get 101(5) then this will be signed extended to
|
||||
// 11111101(-3)
|
||||
|
@ -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()) {
|
||||
|
@ -103,7 +103,7 @@ var builtin_sfld(context* ctx, gc* ngc) {
|
|||
}
|
||||
|
||||
var builtin_setfld(context* ctx, gc* ngc) {
|
||||
// bits.setfld(s,0,8,69);
|
||||
// bits.setfld(s, 0, 8, 69);
|
||||
// set 01000101(69) to string will get this:
|
||||
// 10100010(162)
|
||||
// so s[0]=162
|
||||
|
@ -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()) {
|
||||
|
|
|
@ -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*>(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);
|
||||
}
|
||||
|
|
|
@ -204,16 +204,17 @@ var builtin_str(context* ctx, gc* ngc) {
|
|||
|
||||
var builtin_size(context* ctx, gc* ngc) {
|
||||
auto val = ctx->localr[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<f64>(num));
|
||||
}
|
||||
|
||||
var builtin_time(context* ctx, gc* ngc) {
|
||||
|
@ -323,7 +324,7 @@ var builtin_substr(context* ctx, gc* ngc) {
|
|||
if (begin>=str.str().length()) {
|
||||
return nas_err("susbtr", "begin index out of range: "+std::to_string(begin));
|
||||
}
|
||||
return ngc->newstr(str.str().substr(begin,length));
|
||||
return ngc->newstr(str.str().substr(begin, length));
|
||||
}
|
||||
|
||||
var builtin_streq(context* ctx, gc* ngc) {
|
||||
|
@ -339,6 +340,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 +357,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<i32>(len.num());
|
||||
i32 srclen = str.str().length();
|
||||
i32 srclen = static_cast<i32>(str.str().length());
|
||||
if (length>srclen) {
|
||||
length = srclen;
|
||||
}
|
||||
if (length<0) {
|
||||
length = 0;
|
||||
}
|
||||
|
||||
return ngc->newstr(str.str().substr(srclen-length, srclen));
|
||||
}
|
||||
|
||||
|
@ -387,22 +392,22 @@ var builtin_cmp(context* ctx, gc* ngc) {
|
|||
|
||||
var builtin_chr(context* ctx, gc* ngc) {
|
||||
const char* extend[] = {
|
||||
"€"," ","‚","ƒ","„","…","†","‡",
|
||||
"ˆ","‰","Š","‹","Œ"," ","Ž"," ",
|
||||
" ","‘","’","“","”","•","–","—",
|
||||
"˜","™","š","›","œ"," ","ž","Ÿ",
|
||||
" ","¡","¢","£","¤","¥","¦","§",
|
||||
"¨","©","ª","«","¬"," ","®","¯",
|
||||
"°","±","²","³","´","µ","¶","·",
|
||||
"¸","¹","º","»","¼","½","¾","¿",
|
||||
"À","Á","Â","Ã","Ä","Å","Æ","Ç",
|
||||
"È","É","Ê","Ë","Ì","Í","Î","Ï",
|
||||
"Ð","Ñ","Ò","Ó","Ô","Õ","Ö","×",
|
||||
"Ø","Ù","Ú","Û","Ü","Ý","Þ","ß",
|
||||
"à","á","â","ã","ä","å","æ","ç",
|
||||
"è","é","ê","ë","ì","í","î","ï",
|
||||
"ð","ñ","ò","ó","ô","õ","ö","÷",
|
||||
"ø","ù","ú","û","ü","ý","þ","ÿ"
|
||||
"€", " ", "‚", "ƒ", "„", "…", "†", "‡",
|
||||
"ˆ", "‰", "Š", "‹", "Œ", " ", "Ž", " ",
|
||||
" ", "‘", "’", "“", "”", "•", "–", "—",
|
||||
"˜", "™", "š", "›", "œ", " ", "ž", "Ÿ",
|
||||
" ", "¡", "¢", "£", "¤", "¥", "¦", "§",
|
||||
"¨", "©", "ª", "«", "¬", " ", "®", "¯",
|
||||
"°", "±", "²", "³", "´", "µ", "¶", "·",
|
||||
"¸", "¹", "º", "»", "¼", "½", "¾", "¿",
|
||||
"À", "Á", "Â", "Ã", "Ä", "Å", "Æ", "Ç",
|
||||
"È", "É", "Ê", "Ë", "Ì", "Í", "Î", "Ï",
|
||||
"Ð", "Ñ", "Ò", "Ó", "Ô", "Õ", "Ö", "×",
|
||||
"Ø", "Ù", "Ú", "Û", "Ü", "Ý", "Þ", "ß",
|
||||
"à", "á", "â", "ã", "ä", "å", "æ", "ç",
|
||||
"è", "é", "ê", "ë", "ì", "í", "î", "ï",
|
||||
"ð", "ñ", "ò", "ó", "ô", "õ", "ö", "÷",
|
||||
"ø", "ù", "ú", "û", "ü", "ý", "þ", "ÿ"
|
||||
};
|
||||
auto num = static_cast<i32>(ctx->localr[1].num());
|
||||
if (0<=num && num<128) {
|
||||
|
@ -479,7 +484,7 @@ std::string md5(const std::string& src) {
|
|||
std::vector<u32> buff;
|
||||
usize num = ((src.length()+8)>>6)+1;
|
||||
usize buffsize = num<<4;
|
||||
buff.resize(buffsize,0);
|
||||
buff.resize(buffsize, 0);
|
||||
for(usize i = 0; i<src.length(); i++) {
|
||||
buff[i>>2] |= (static_cast<u8>(src[i]))<<((i&0x3)<<3);
|
||||
}
|
||||
|
@ -489,37 +494,45 @@ std::string md5(const std::string& src) {
|
|||
|
||||
// u32(abs(sin(i+1))*(2pow32))
|
||||
const u32 k[] = {
|
||||
0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,
|
||||
0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,0xa679438e,0x49b40821,
|
||||
0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
|
||||
0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a,
|
||||
0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70,
|
||||
0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,
|
||||
0xf4292244,0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1,
|
||||
0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391
|
||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
|
||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
|
||||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
|
||||
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
|
||||
};
|
||||
|
||||
// left shift bits
|
||||
const u32 s[] = {
|
||||
7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
|
||||
5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
|
||||
4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
|
||||
6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
|
||||
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
||||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
||||
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
|
||||
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
|
||||
};
|
||||
|
||||
// index
|
||||
const u32 idx[] = {
|
||||
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, // g=i
|
||||
1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12, // g=(5*i+1)%16;
|
||||
5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2, // g=(3*i+5)%16;
|
||||
0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9 // g=(7*i)%16;
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // g=i
|
||||
1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, // g=(5*i+1)%16;
|
||||
5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, // g=(3*i+5)%16;
|
||||
0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 // g=(7*i)%16;
|
||||
};
|
||||
|
||||
#define shift(x,n) (((x)<<(n))|((x)>>(32-(n)))) // cycle left shift
|
||||
#define md5f(x,y,z) (((x)&(y))|((~x)&(z)))
|
||||
#define md5g(x,y,z) (((x)&(z))|((y)&(~z)))
|
||||
#define md5h(x,y,z) ((x)^(y)^(z))
|
||||
#define md5i(x,y,z) ((y)^((x)|(~z)))
|
||||
#define shift(x, n) (((x)<<(n))|((x)>>(32-(n)))) // cycle left shift
|
||||
#define md5f(x, y, z) (((x)&(y))|((~x)&(z)))
|
||||
#define md5g(x, y, z) (((x)&(z))|((y)&(~z)))
|
||||
#define md5h(x, y, z) ((x)^(y)^(z))
|
||||
#define md5i(x, y, z) ((y)^((x)|(~z)))
|
||||
|
||||
u32 atmp = 0x67452301, btmp = 0xefcdab89;
|
||||
u32 ctmp = 0x98badcfe, dtmp = 0x10325476;
|
||||
|
@ -533,7 +546,7 @@ std::string md5(const std::string& src) {
|
|||
u32 tmp = d;
|
||||
d = c;
|
||||
c = b;
|
||||
b = b+shift((a+f+k[j]+buff[i+idx[j]]),s[j]);
|
||||
b = b+shift((a+f+k[j]+buff[i+idx[j]]), s[j]);
|
||||
a = tmp;
|
||||
}
|
||||
atmp += a;
|
||||
|
@ -565,13 +578,13 @@ public:
|
|||
stamp = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
f64 elapsed_milliseconds() {
|
||||
auto duration = std::chrono::high_resolution_clock::now() - stamp;
|
||||
auto elapsed_milliseconds() const {
|
||||
const auto duration = std::chrono::high_resolution_clock::now() - stamp;
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
|
||||
}
|
||||
|
||||
f64 elapsed_microseconds() {
|
||||
auto duration = std::chrono::high_resolution_clock::now() - stamp;
|
||||
auto elapsed_microseconds() const {
|
||||
const auto duration = std::chrono::high_resolution_clock::now() - stamp;
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
|
||||
}
|
||||
};
|
||||
|
@ -607,7 +620,7 @@ var builtin_elapsed_millisecond(context* ctx, gc* ngc) {
|
|||
return var::num(-1);
|
||||
}
|
||||
auto stamp = static_cast<time_stamp*>(object.ghost().pointer);
|
||||
return var::num(stamp->elapsed_milliseconds());
|
||||
return var::num(static_cast<f64>(stamp->elapsed_milliseconds()));
|
||||
}
|
||||
|
||||
var builtin_elapsed_microsecond(context* ctx, gc* ngc) {
|
||||
|
@ -616,7 +629,7 @@ var builtin_elapsed_microsecond(context* ctx, gc* ngc) {
|
|||
return var::num(-1);
|
||||
}
|
||||
auto stamp = static_cast<time_stamp*>(object.ghost().pointer);
|
||||
return var::num(stamp->elapsed_microseconds());
|
||||
return var::num(static_cast<f64>(stamp->elapsed_microseconds()));
|
||||
}
|
||||
|
||||
var builtin_gcextend(context* ctx, gc* ngc) {
|
||||
|
@ -644,20 +657,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; i<gc_type_size; ++i) {
|
||||
total += ngc->gcnt[i];
|
||||
total += static_cast<f64>(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<f64>(ngc->worktime);
|
||||
const auto max_time = static_cast<f64>(ngc->max_time);
|
||||
const auto max_mark_time = static_cast<f64>(ngc->max_mark_time);
|
||||
const auto max_sweep_time = static_cast<f64>(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;
|
||||
}
|
||||
|
||||
|
@ -682,9 +702,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<u64>(arg.ghost().pointer));
|
||||
std::stringstream ss;
|
||||
ss << "0x" << std::hex;
|
||||
ss << reinterpret_cast<u64>(arg.ghost().pointer) << std::dec;
|
||||
return ngc->newstr(ss.str());
|
||||
}
|
||||
return ngc->newstr(name);
|
||||
}
|
||||
|
|
|
@ -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*);
|
||||
|
@ -80,7 +82,7 @@ var builtin_logtime(context*, gc*);
|
|||
var builtin_ghosttype(context*, gc*);
|
||||
|
||||
// register builtin function's name and it's address here in this table below
|
||||
// this table must end with {nullptr,nullptr}
|
||||
// this table must end with {nullptr, nullptr}
|
||||
struct nasal_builtin_table {
|
||||
const char* name;
|
||||
var (*func)(context*, gc*);
|
||||
|
|
12
src/repl.cpp
12
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<lexer>(new lexer);
|
||||
auto nasal_lexer = std::make_unique<lexer>();
|
||||
if (nasal_lexer->scan("<nasal-repl>").geterr()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -77,11 +77,11 @@ void repl::help() {
|
|||
}
|
||||
|
||||
bool repl::run() {
|
||||
auto nasal_lexer = std::unique_ptr<lexer>(new lexer);
|
||||
auto nasal_parser = std::unique_ptr<parse>(new parse);
|
||||
auto nasal_linker = std::unique_ptr<linker>(new linker);
|
||||
auto nasal_opt = std::unique_ptr<optimizer>(new optimizer);
|
||||
auto nasal_codegen = std::unique_ptr<codegen>(new codegen);
|
||||
auto nasal_lexer = std::make_unique<lexer>();
|
||||
auto nasal_parser = std::make_unique<parse>();
|
||||
auto nasal_linker = std::make_unique<linker>();
|
||||
auto nasal_opt = std::make_unique<optimizer>();
|
||||
auto nasal_codegen = std::make_unique<codegen>();
|
||||
|
||||
update_temp_file();
|
||||
if (nasal_lexer->scan("<nasal-repl>").geterr()) {
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
var student = func(n,a) {
|
||||
var student = func(n, a) {
|
||||
return {
|
||||
print_info:func println(n,' ',a),
|
||||
set_age: func(age) a=age,
|
||||
get_age: func return a,
|
||||
set_name: func(name) n=name,
|
||||
get_name: func return n
|
||||
print_info: func println(n,' ',a),
|
||||
set_age: func(age) a=age,
|
||||
get_age: func return a,
|
||||
set_name: func(name) n=name,
|
||||
get_name: func return n
|
||||
};
|
||||
}
|
||||
|
||||
var s=student('valk',24);
|
||||
s.print_info();
|
||||
println(s.get_age(),' ',s.get_name());
|
||||
|
@ -18,6 +19,7 @@ s.set_age(20);
|
|||
s.set_name('Sidi Liang');
|
||||
s.print_info();
|
||||
println(s.get_age(),' ',s.get_name());
|
||||
|
||||
# flightgear nasal-console cannot use this kind of object initializing
|
||||
var m = func() {
|
||||
var (_1,_2)=(0,1);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -251,3 +251,19 @@ var test_single_id_iterator = 0;
|
|||
foreach(test_single_id_iterator; [0, 1, 2, 3]) {
|
||||
println(test_single_id_iterator);
|
||||
}
|
||||
|
||||
# simple closure test, make sure two functions share the same closure
|
||||
var closure_tester = func() {
|
||||
var b = 0;
|
||||
return [
|
||||
func { b += 1; },
|
||||
func { return b; }
|
||||
];
|
||||
}();
|
||||
|
||||
for(var i = 1; i<=10; i += 1) {
|
||||
closure_tester[0]();
|
||||
if (closure_tester[1]()!=i) {
|
||||
die("test failed: expect " ~ i ~ ", but get " ~ closure_tester[1]());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,6 @@ import os
|
|||
import platform
|
||||
import shutil
|
||||
|
||||
|
||||
nasal_version = "11.1"
|
||||
|
||||
build_directory = pathlib.Path("build")
|
||||
if not os.path.exists(build_directory):
|
||||
print("pack binaries failed: build directory not found")
|
||||
|
@ -47,20 +44,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()
|
||||
|
|
Loading…
Reference in New Issue