🔥 change class name.

nasal_lexer -> lexer
nasal_parse -> parse
nasal_codegen -> codegen
nasal_vm -> vm
nasal_gc -> gc
nasal_dbg -> debugger
nasal_import -> linker
nas_ref -> var
This commit is contained in:
ValKmjolnir 2022-10-21 01:29:29 +08:00
parent 025ff49ffc
commit 3fd1b25f79
19 changed files with 1070 additions and 1068 deletions

View File

@ -182,7 +182,7 @@ var f=func(args...){
} }
``` ```
__`upval`__ is used to store upvalues, used in __`nasal_vm`__ to make sure closure runs correctly. __`upval`__ is used to store upvalues, used in __`vm`__ to make sure closure runs correctly.
__`obj`__ is used to store other complex `C/C++` data types. __`obj`__ is used to store other complex `C/C++` data types.
This type is created by native-function of nasal. If want to define a new data type, see how to add native-functions by editing code. This type is created by native-function of nasal. If want to define a new data type, see how to add native-functions by editing code.
@ -490,11 +490,11 @@ nas_native(builtin_print);
Then complete this function using C++: Then complete this function using C++:
```C++ ```C++
nas_ref builtin_print(nas_ref* local,nasal_gc& gc) var builtin_print(var* local,nasal_gc& gc)
{ {
// find value with index begin from 1 // find value with index begin from 1
// because local[0] is reserved for value 'me' // because local[0] is reserved for value 'me'
nas_ref vec=local[1]; var vec=local[1];
// main process // main process
// also check number of arguments and type here // also check number of arguments and type here
// if get an error,use nas_err // if get an error,use nas_err
@ -524,13 +524,13 @@ The value got before will be collected, but stil in use in this builtin function
So use `gc::temp` in builtin functions to temprorarily store the gc-managed value that you want to return later. Like this: So use `gc::temp` in builtin functions to temprorarily store the gc-managed value that you want to return later. Like this:
```C++ ```C++
nas_ref builtin_keys(nas_ref* local,nasal_gc& gc) var builtin_keys(var* local,nasal_gc& gc)
{ {
nas_ref hash=local[1]; var hash=local[1];
if(hash.type!=vm_hash) if(hash.type!=vm_hash)
return nas_err("keys","\"hash\" must be hash"); return nas_err("keys","\"hash\" must be hash");
// use gc.temp to store the gc-managed-value, to avoid being sweeped // use gc.temp to store the gc-managed-value, to avoid being sweeped
nas_ref res=gc.temp=gc.alloc(vm_vec); var res=gc.temp=gc.alloc(vm_vec);
auto& vec=res.vec().elems; auto& vec=res.vec().elems;
for(auto& iter:hash.hash().elems) for(auto& iter:hash.hash().elems)
vec.push_back(gc.newstr(iter.first)); vec.push_back(gc.newstr(iter.first));
@ -545,7 +545,7 @@ After that, register the built-in function's name(in nasal) and the function's p
struct func struct func
{ {
const char* name; const char* name;
nas_ref (*func)(nas_ref*,nasal_gc&); var (*func)(var*,nasal_gc&);
} builtin[]= } builtin[]=
{ {
{"__print",builtin_print}, {"__print",builtin_print},
@ -617,10 +617,10 @@ double fibonaci(double x){
} }
// remember to use extern "C", // remember to use extern "C",
// so you could search the symbol quickly // so you could search the symbol quickly
extern "C" nas_ref fib(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var fib(std::vector<var>& args,nasal_gc& gc){
// the arguments are generated into a vm_vec: args // the arguments are generated into a vm_vec: args
// get values from the vector that must be used here // get values from the vector that must be used here
nas_ref num=args[0]; var num=args[0];
// if you want your function safer, try this // if you want your function safer, try this
// nas_err will print the error info on screen // nas_err will print the error info on screen
// and return vm_null for runtime to interrupt // and return vm_null for runtime to interrupt

View File

@ -168,7 +168,7 @@ var f=func(args...){
} }
``` ```
__`upval`__ 是存储闭包数据的特殊类型, 在 __`nasal_vm`__ 中使用,以确保闭包功能正常。 __`upval`__ 是存储闭包数据的特殊类型, 在 __`vm`__ 中使用,以确保闭包功能正常。
__`obj`__ 是用来存储`C/C++`的一些复杂数据结构。这种类型的数据由内置函数生成。如果想为nasal添加新的数据结构, 可以看下文如何通过修改本项目来添加内置函数。 __`obj`__ 是用来存储`C/C++`的一些复杂数据结构。这种类型的数据由内置函数生成。如果想为nasal添加新的数据结构, 可以看下文如何通过修改本项目来添加内置函数。
@ -469,11 +469,11 @@ nas_native(builtin_print);
然后用C++完成这个函数的函数体: 然后用C++完成这个函数的函数体:
```C++ ```C++
nas_ref builtin_print(nas_ref* local,nasal_gc& gc) var builtin_print(var* local,nasal_gc& gc)
{ {
// 局部变量的下标其实是从1开始的 // 局部变量的下标其实是从1开始的
// 因为local[0]是保留给'me'的空间 // 因为local[0]是保留给'me'的空间
nas_ref vec=local[1]; var vec=local[1];
// 主要部分 // 主要部分
// 一些必要的类型检查和输入合法性检测也要在这里写出 // 一些必要的类型检查和输入合法性检测也要在这里写出
// 如果检测到问题用builtin_err函数来返回vm_null // 如果检测到问题用builtin_err函数来返回vm_null
@ -504,13 +504,13 @@ nas_ref builtin_print(nas_ref* local,nasal_gc& gc)
可以使用`gc::temp`来暂时存储一个会被返回的需要gc管理的变量这样可以防止内部所有的申请错误触发垃圾回收。如下所示 可以使用`gc::temp`来暂时存储一个会被返回的需要gc管理的变量这样可以防止内部所有的申请错误触发垃圾回收。如下所示
```C++ ```C++
nas_ref builtin_keys(nas_ref* local,nasal_gc& gc) var builtin_keys(var* local,nasal_gc& gc)
{ {
nas_ref hash=local[1]; var hash=local[1];
if(hash.type!=vm_hash) if(hash.type!=vm_hash)
return nas_err("keys","\"hash\" must be hash"); return nas_err("keys","\"hash\" must be hash");
// 使用gc.temp来存储gc管理的变量防止错误的回收 // 使用gc.temp来存储gc管理的变量防止错误的回收
nas_ref res=gc.temp=gc.alloc(vm_vec); var res=gc.temp=gc.alloc(vm_vec);
auto& vec=res.vec().elems; auto& vec=res.vec().elems;
for(auto& iter:hash.hash().elems) for(auto& iter:hash.hash().elems)
vec.push_back(gc.newstr(iter.first)); vec.push_back(gc.newstr(iter.first));
@ -525,7 +525,7 @@ nas_ref builtin_keys(nas_ref* local,nasal_gc& gc)
struct func struct func
{ {
const char* name; const char* name;
nas_ref (*func)(nas_ref*,nasal_gc&); var (*func)(var*,nasal_gc&);
} builtin[]= } builtin[]=
{ {
{"__print",builtin_print}, {"__print",builtin_print},
@ -592,9 +592,9 @@ double fibonaci(double x){
} }
// 记得用extern "C" // 记得用extern "C"
// 这样找符号会更加快速便捷不要在意编译时的warning // 这样找符号会更加快速便捷不要在意编译时的warning
extern "C" nas_ref fib(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var fib(std::vector<var>& args,nasal_gc& gc){
// 传参会被送到一个vm_vec类型中送过来而不是上文中那种指针直接指向局部作用域 // 传参会被送到一个vm_vec类型中送过来而不是上文中那种指针直接指向局部作用域
nas_ref num=args[0]; var num=args[0];
// 如果你想让这个函数有更强的稳定性,那么一定要进行合法性检查 // 如果你想让这个函数有更强的稳定性,那么一定要进行合法性检查
// builtin_err会输出错误信息并返回错误类型让虚拟机终止执行 // builtin_err会输出错误信息并返回错误类型让虚拟机终止执行
if(num.type!=vm_num) if(num.type!=vm_num)

View File

@ -337,8 +337,8 @@ As you could see from the bytecode above,
And because of the new structure of `mcall`, And because of the new structure of `mcall`,
`addr_stack`, a stack used to store the memory address, `addr_stack`, a stack used to store the memory address,
is deleted from `nasal_vm`, is deleted from `vm`,
and now `nasal_vm` use `nas_val** mem_addr` to store the memory address. and now `vm` use `nas_val** mem_addr` to store the memory address.
This will not cause fatal errors because the memory address is used __immediately__ after getting it. This will not cause fatal errors because the memory address is used __immediately__ after getting it.
### version 7.0 vm (last update 2021/10/8) ### version 7.0 vm (last update 2021/10/8)
@ -347,7 +347,7 @@ This will not cause fatal errors because the memory address is used __immediatel
Instruction dispatch is changed from call-threading to computed-goto(with inline function). Instruction dispatch is changed from call-threading to computed-goto(with inline function).
After changing the way of instruction dispatch, After changing the way of instruction dispatch,
there is a great improvement in nasal_vm. there is a great improvement in `vm`.
Now vm can run test/bigloop and test/pi in 0.2s! Now vm can run test/bigloop and test/pi in 0.2s!
And vm runs test/fib in 0.8s on linux. And vm runs test/fib in 0.8s on linux.
You could see the time use data below, You could see the time use data below,
@ -550,37 +550,37 @@ __We will explain how resume and yield work here:__
When `op_callb` is called, the stack frame is like this: When `op_callb` is called, the stack frame is like this:
```C++ ```C++
+--------------------------+(main stack) +----------------------+(main stack)
| old pc(vm_ret) | <- top[0] | old pc(vm_ret) | <- top[0]
+--------------------------+ +----------------------+
| old localr(vm_addr) | <- top[-1] | old localr(vm_addr) | <- top[-1]
+--------------------------+ +----------------------+
| old upvalr(vm_upval) | <- top[-2] | old upvalr(vm_upval) | <- top[-2]
+--------------------------+ +----------------------+
| local scope(nas_ref) | | local scope(var) |
| ... | | ... |
+--------------------------+ <- local pointer stored in localr +----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr | old funcr(vm_func) | <- old function stored in funcr
+--------------------------+ +----------------------+
``` ```
In `op_callb`'s progress, next step the stack frame is: In `op_callb`'s progress, next step the stack frame is:
```C++ ```C++
+--------------------------+(main stack) +----------------------+(main stack)
| nil(vm_nil) | <- push nil | nil(vm_nil) | <- push nil
+--------------------------+ +----------------------+
| old pc(vm_ret) | | old pc(vm_ret) |
+--------------------------+ +----------------------+
| old localr(vm_addr) | | old localr(vm_addr) |
+--------------------------+ +----------------------+
| old upvalr(vm_upval) | | old upvalr(vm_upval) |
+--------------------------+ +----------------------+
| local scope(nas_ref) | | local scope(var) |
| ... | | ... |
+--------------------------+ <- local pointer stored in localr +----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr | old funcr(vm_func) | <- old function stored in funcr
+--------------------------+ +----------------------+
``` ```
Then we call `resume`, this function will change stack. Then we call `resume`, this function will change stack.
@ -591,9 +591,9 @@ So for safe running, `resume` will return `gc.top[0]`.
`op_callb` will do `top[0]=resume()`, so the value does not change. `op_callb` will do `top[0]=resume()`, so the value does not change.
```C++ ```C++
+--------------------------+(coroutine stack) +----------------------+(coroutine stack)
| pc:0(vm_ret) | <- now gc.top[0] | pc:0(vm_ret) | <- now gc.top[0]
+--------------------------+ +----------------------+
``` ```
When we call `yield`, the function will do like this. When we call `yield`, the function will do like this.
@ -601,40 +601,40 @@ And we find that `op_callb` has put the `nil` at the top.
but where is the returned `local[1]` sent? but where is the returned `local[1]` sent?
```C++ ```C++
+--------------------------+(coroutine stack) +----------------------+(coroutine stack)
| nil(vm_nil) | <- push nil | nil(vm_nil) | <- push nil
+--------------------------+ +----------------------+
| old pc(vm_ret) | | old pc(vm_ret) |
+--------------------------+ +----------------------+
| old localr(vm_addr) | | old localr(vm_addr) |
+--------------------------+ +----------------------+
| old upvalr(vm_upval) | | old upvalr(vm_upval) |
+--------------------------+ +----------------------+
| local scope(nas_ref) | | local scope(var) |
| ... | | ... |
+--------------------------+ <- local pointer stored in localr +----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr | old funcr(vm_func) | <- old function stored in funcr
+--------------------------+ +----------------------+
``` ```
When `builtin_coyield` is finished, the stack is set to main stack, When `builtin_coyield` is finished, the stack is set to main stack,
and the returned `local[1]` in fact is set to the top of the main stack by `op_callb`: and the returned `local[1]` in fact is set to the top of the main stack by `op_callb`:
```C++ ```C++
+--------------------------+(main stack) +----------------------+(main stack)
| return_value(nas_ref) | | return_value(var) |
+--------------------------+ +----------------------+
| old pc(vm_ret) | | old pc(vm_ret) |
+--------------------------+ +----------------------+
| old localr(vm_addr) | | old localr(vm_addr) |
+--------------------------+ +----------------------+
| old upvalr(vm_upval) | | old upvalr(vm_upval) |
+--------------------------+ +----------------------+
| local scope(nas_ref) | | local scope(var) |
| ... | | ... |
+--------------------------+ <- local pointer stored in localr +----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr | old funcr(vm_func) | <- old function stored in funcr
+--------------------------+ +----------------------+
``` ```
so the main progress feels the value on the top is the returned value of `resume`. so the main progress feels the value on the top is the returned value of `resume`.

View File

@ -305,7 +305,7 @@ m(0)._=m(1)._=10;
从上面这些字节码可以看出,`mcall`/`mcallv`/`mcallh`指令的使用频率比以前减小了一些,而`call`/`callv`/`callh`/`callfv`/`callfh`则相反。 从上面这些字节码可以看出,`mcall`/`mcallv`/`mcallh`指令的使用频率比以前减小了一些,而`call`/`callv`/`callh`/`callfv`/`callfh`则相反。
并且因为新的数据结构,`mcall`指令以及`addr_stack`,一个曾用来存储指针的栈,从`nasal_vm`中被移除。现在`nasal_vm`使用`nas_val** mem_addr`来暂存获取的内存地址。这不会导致严重的问题,因为内存空间是 __获取即使用__ 的。 并且因为新的数据结构,`mcall`指令以及`addr_stack`,一个曾用来存储指针的栈,从`vm`中被移除。现在`vm`使用`nas_val** mem_addr`来暂存获取的内存地址。这不会导致严重的问题,因为内存空间是 __获取即使用__ 的。
### version 7.0 vm (last update 2021/10/8) ### version 7.0 vm (last update 2021/10/8)
@ -491,37 +491,37 @@ __接下来我们解释这个协程的运行原理:__
当`op_callb`被执行时,栈帧如下所示: 当`op_callb`被执行时,栈帧如下所示:
```C++ ```C++
+--------------------------+(主操作数栈) +----------------------+(主操作数栈)
| old pc(vm_ret) | <- top[0] | old pc(vm_ret) | <- top[0]
+--------------------------+ +----------------------+
| old localr(vm_addr) | <- top[-1] | old localr(vm_addr) | <- top[-1]
+--------------------------+ +----------------------+
| old upvalr(vm_upval) | <- top[-2] | old upvalr(vm_upval) | <- top[-2]
+--------------------------+ +----------------------+
| local scope(nas_ref) | | local scope(var) |
| ... | | ... |
+--------------------------+ <- local pointer stored in localr +----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr | old funcr(vm_func) | <- old function stored in funcr
+--------------------------+ +----------------------+
``` ```
在`op_callb`执行过程中,下一步的栈帧如下: 在`op_callb`执行过程中,下一步的栈帧如下:
```C++ ```C++
+--------------------------+(主操作数栈) +----------------------+(主操作数栈)
| nil(vm_nil) | <- push nil | nil(vm_nil) | <- push nil
+--------------------------+ +----------------------+
| old pc(vm_ret) | | old pc(vm_ret) |
+--------------------------+ +----------------------+
| old localr(vm_addr) | | old localr(vm_addr) |
+--------------------------+ +----------------------+
| old upvalr(vm_upval) | | old upvalr(vm_upval) |
+--------------------------+ +----------------------+
| local scope(nas_ref) | | local scope(var) |
| ... | | ... |
+--------------------------+ <- local pointer stored in localr +----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr | old funcr(vm_func) | <- old function stored in funcr
+--------------------------+ +----------------------+
``` ```
接着我们调用`resume`,这个函数会替换操作数栈。我们会看到,协程的操作数栈上已经保存了一些数据,但是我们首次进入协程执行时,这个操作数栈的栈顶将会是`vm_ret`,并且返回的`pc`值是`0`。 接着我们调用`resume`,这个函数会替换操作数栈。我们会看到,协程的操作数栈上已经保存了一些数据,但是我们首次进入协程执行时,这个操作数栈的栈顶将会是`vm_ret`,并且返回的`pc`值是`0`。
@ -529,47 +529,47 @@ __接下来我们解释这个协程的运行原理:__
为了保证栈顶的数据不会被破坏,`resume`会返回`gc.top[0]`。`op_callb`将会执行`top[0]=resume()`,所以栈顶的数据虽然被覆盖了一次,但是实际上还是原来的数据。 为了保证栈顶的数据不会被破坏,`resume`会返回`gc.top[0]`。`op_callb`将会执行`top[0]=resume()`,所以栈顶的数据虽然被覆盖了一次,但是实际上还是原来的数据。
```C++ ```C++
+--------------------------+(协程操作数栈) +----------------------+(协程操作数栈)
| pc:0(vm_ret) | <- now gc.top[0] | pc:0(vm_ret) | <- now gc.top[0]
+--------------------------+ +----------------------+
``` ```
当我们调用`yield`的时候,该函数会执行出这个情况,我们发现`op_callb` 已经把`nil`放在的栈顶。但是应该返回的`local[1]`到底发送到哪里去了? 当我们调用`yield`的时候,该函数会执行出这个情况,我们发现`op_callb` 已经把`nil`放在的栈顶。但是应该返回的`local[1]`到底发送到哪里去了?
```C++ ```C++
+--------------------------+(协程操作数栈) +----------------------+(协程操作数栈)
| nil(vm_nil) | <- push nil | nil(vm_nil) | <- push nil
+--------------------------+ +----------------------+
| old pc(vm_ret) | | old pc(vm_ret) |
+--------------------------+ +----------------------+
| old localr(vm_addr) | | old localr(vm_addr) |
+--------------------------+ +----------------------+
| old upvalr(vm_upval) | | old upvalr(vm_upval) |
+--------------------------+ +----------------------+
| local scope(nas_ref) | | local scope(var) |
| ... | | ... |
+--------------------------+ <- local pointer stored in localr +----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr | old funcr(vm_func) | <- old function stored in funcr
+--------------------------+ +----------------------+
``` ```
当`builtin_coyield`执行完毕之后,栈又切换到了主操作数栈上,这时可以看到返回的`local[1]`实际上被`op_callb`放在了这里的栈顶: 当`builtin_coyield`执行完毕之后,栈又切换到了主操作数栈上,这时可以看到返回的`local[1]`实际上被`op_callb`放在了这里的栈顶:
```C++ ```C++
+--------------------------+(主操作数栈) +----------------------+(主操作数栈)
| return_value(nas_ref) | | return_value(var) |
+--------------------------+ +----------------------+
| old pc(vm_ret) | | old pc(vm_ret) |
+--------------------------+ +----------------------+
| old localr(vm_addr) | | old localr(vm_addr) |
+--------------------------+ +----------------------+
| old upvalr(vm_upval) | | old upvalr(vm_upval) |
+--------------------------+ +----------------------+
| local scope(nas_ref) | | local scope(var) |
| ... | | ... |
+--------------------------+ <- local pointer stored in localr +----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr | old funcr(vm_func) | <- old function stored in funcr
+--------------------------+ +----------------------+
``` ```
所以主程序会认为顶部这个返回值好像是`resume`返回的。而实际上`resume`的返回值在协程的操作数栈顶。综上所述: 所以主程序会认为顶部这个返回值好像是`resume`返回的。而实际上`resume`的返回值在协程的操作数栈顶。综上所述:

View File

@ -10,6 +10,7 @@
#include "nasal_codegen.h" #include "nasal_codegen.h"
#include "nasal_vm.h" #include "nasal_vm.h"
#include "nasal_dbg.h" #include "nasal_dbg.h"
#include <unordered_map> #include <unordered_map>
const u32 VM_TOKEN =0x01; const u32 VM_TOKEN =0x01;
@ -82,13 +83,13 @@ void err()
void execute(const string& file,const std::vector<string>& argv,const u32 cmd) void execute(const string& file,const std::vector<string>& argv,const u32 cmd)
{ {
// front end use the same error module // front end use the same error module
nasal_err nerr; error err;
nasal_lexer lex(nerr); lexer lex(err);
nasal_parse parse(nerr); parse parse(err);
nasal_import ld(nerr); linker ld(err);
nasal_codegen gen(nerr); codegen gen(err);
// back end // back end
nasal_vm vm; vm rt;
// lexer scans file to get tokens // lexer scans file to get tokens
lex.scan(file); lex.scan(file);
@ -112,16 +113,16 @@ void execute(const string& file,const std::vector<string>& argv,const u32 cmd)
// run // run
if(cmd&VM_DEBUG) if(cmd&VM_DEBUG)
nasal_dbg(nerr).run(gen,ld,argv); debugger(err).run(gen,ld,argv);
else if(cmd&VM_TIME) else if(cmd&VM_TIME)
{ {
auto start=std::chrono::high_resolution_clock::now(); auto start=std::chrono::high_resolution_clock::now();
vm.run(gen,ld,argv,cmd&VM_DETAIL); rt.run(gen,ld,argv,cmd&VM_DETAIL);
auto end=std::chrono::high_resolution_clock::now(); auto end=std::chrono::high_resolution_clock::now();
std::clog<<"process exited after "<<(end-start).count()*1.0/std::chrono::high_resolution_clock::duration::period::den<<"s.\n"; std::clog<<"process exited after "<<(end-start).count()*1.0/std::chrono::high_resolution_clock::duration::period::den<<"s.\n";
} }
else if(cmd&VM_EXEC) else if(cmd&VM_EXEC)
vm.run(gen,ld,argv,cmd&VM_DETAIL); rt.run(gen,ld,argv,cmd&VM_DETAIL);
} }
i32 main(i32 argc,const char* argv[]) i32 main(i32 argc,const char* argv[])

View File

@ -6,20 +6,20 @@ double fibonaci(double x){
return x; return x;
return fibonaci(x-1)+fibonaci(x-2); return fibonaci(x-1)+fibonaci(x-2);
} }
extern "C" nas_ref fib(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var fib(std::vector<var>& args,gc& ngc){
std::cout<<"[mod] this is the first test module of nasal\n"; std::cout<<"[mod] this is the first test module of nasal\n";
if(!args.size()) if(!args.size())
return nas_err("fib","lack arguments"); return nas_err("fib","lack arguments");
nas_ref num=args[0]; var num=args[0];
if(num.type!=vm_num) if(num.type!=vm_num)
return nas_err("extern_fib","\"num\" must be number"); return nas_err("extern_fib","\"num\" must be number");
return {vm_num,fibonaci(num.tonum())}; return {vm_num,fibonaci(num.tonum())};
} }
extern "C" nas_ref quick_fib(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var quick_fib(std::vector<var>& args,gc& ngc){
std::cout<<"[mod] this is the first test module of nasal\n"; std::cout<<"[mod] this is the first test module of nasal\n";
if(!args.size()) if(!args.size())
return nas_err("fib","lack arguments"); return nas_err("fib","lack arguments");
nas_ref num=args[0]; var num=args[0];
if(num.type!=vm_num) if(num.type!=vm_num)
return nas_err("extern_quick_fib","\"num\" must be number"); return nas_err("extern_quick_fib","\"num\" must be number");
if(num.num()<2) if(num.num()<2)

View File

@ -71,13 +71,13 @@ public:
}; };
noecho_input this_window; noecho_input this_window;
extern "C" nas_ref nas_getch(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_getch(std::vector<var>& args,gc& ngc){
return {vm_num,(double)this_window.noecho_getch()}; return {vm_num,(double)this_window.noecho_getch()};
} }
extern "C" nas_ref nas_kbhit(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_kbhit(std::vector<var>& args,gc& ngc){
return {vm_num,(double)this_window.noecho_kbhit()}; return {vm_num,(double)this_window.noecho_kbhit()};
} }
extern "C" nas_ref nas_noblock(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_noblock(std::vector<var>& args,gc& ngc){
if(this_window.noecho_kbhit()) if(this_window.noecho_kbhit())
return {vm_num,(double)this_window.noecho_getch()}; return {vm_num,(double)this_window.noecho_getch()};
return nil; return nil;

View File

@ -30,7 +30,8 @@ libnasock.dll: nasocket.cpp
del nasocket.o del nasocket.o
clean: clean:
rm *.so *.dll *.dylib -@ rm *.so *.dll *.dylib
@ echo "done"
all: libfib.so libkey.so libnasock.so all: libfib.so libkey.so libnasock.so
@ echo "build done" @ echo "build done"
mingw-all: libfib.dll libkey.dll libnasock.dll mingw-all: libfib.dll libkey.dll libnasock.dll

View File

@ -25,14 +25,14 @@ static WSAmanager win;
#include <netinet/in.h> #include <netinet/in.h>
#endif #endif
extern "C" nas_ref nas_socket(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_socket(std::vector<var>& args,gc& ngc){
if(args[0].type!=vm_num || args[1].type!=vm_num || args[2].type!=vm_num) if(args[0].type!=vm_num || args[1].type!=vm_num || args[2].type!=vm_num)
return nas_err("socket","\"af\", \"type\", \"protocol\" should be number"); return nas_err("socket","\"af\", \"type\", \"protocol\" should be number");
int sd=socket(args[0].num(),args[1].num(),args[2].num()); int sd=socket(args[0].num(),args[1].num(),args[2].num());
return {vm_num,(double)sd}; return {vm_num,(double)sd};
} }
extern "C" nas_ref nas_closesocket(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_closesocket(std::vector<var>& args,gc& ngc){
if(args[0].type!=vm_num) if(args[0].type!=vm_num)
return nas_err("closesocket","\"\" should be number"); return nas_err("closesocket","\"\" should be number");
#ifdef _WIN32 #ifdef _WIN32
@ -42,7 +42,7 @@ extern "C" nas_ref nas_closesocket(std::vector<nas_ref>& args,nasal_gc& gc){
#endif #endif
} }
extern "C" nas_ref nas_shutdown(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_shutdown(std::vector<var>& args,gc& ngc){
if(args[0].type!=vm_num) if(args[0].type!=vm_num)
return nas_err("shutdown","\"sd\" must be a number"); return nas_err("shutdown","\"sd\" must be a number");
if(args[1].type!=vm_num) if(args[1].type!=vm_num)
@ -50,7 +50,7 @@ extern "C" nas_ref nas_shutdown(std::vector<nas_ref>& args,nasal_gc& gc){
return {vm_num,(double)shutdown(args[0].num(),args[1].num())}; return {vm_num,(double)shutdown(args[0].num(),args[1].num())};
} }
extern "C" nas_ref nas_bind(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_bind(std::vector<var>& args,gc& ngc){
if(args[0].type!=vm_num) if(args[0].type!=vm_num)
return nas_err("bind","\"sd\" muse be a number"); return nas_err("bind","\"sd\" muse be a number");
if(args[1].type!=vm_str) if(args[1].type!=vm_str)
@ -65,7 +65,7 @@ extern "C" nas_ref nas_bind(std::vector<nas_ref>& args,nasal_gc& gc){
return {vm_num,(double)bind(args[0].num(),(sockaddr*)&server,sizeof(server))}; return {vm_num,(double)bind(args[0].num(),(sockaddr*)&server,sizeof(server))};
} }
extern "C" nas_ref nas_listen(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_listen(std::vector<var>& args,gc& ngc){
if(args[0].type!=vm_num) if(args[0].type!=vm_num)
return nas_err("listen","\"sd\" must be a number"); return nas_err("listen","\"sd\" must be a number");
if(args[1].type!=vm_num) if(args[1].type!=vm_num)
@ -73,7 +73,7 @@ extern "C" nas_ref nas_listen(std::vector<nas_ref>& args,nasal_gc& gc){
return{vm_num,(double)listen(args[0].num(),args[1].num())}; return{vm_num,(double)listen(args[0].num(),args[1].num())};
} }
extern "C" nas_ref nas_connect(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_connect(std::vector<var>& args,gc& ngc){
if(args[0].type!=vm_num) if(args[0].type!=vm_num)
return nas_err("connect","\"sd\" must be a number"); return nas_err("connect","\"sd\" must be a number");
if(args[1].type!=vm_str) if(args[1].type!=vm_str)
@ -89,7 +89,7 @@ extern "C" nas_ref nas_connect(std::vector<nas_ref>& args,nasal_gc& gc){
return {vm_num,(double)connect(args[0].num(),(sockaddr*)&addr,sizeof(sockaddr_in))}; return {vm_num,(double)connect(args[0].num(),(sockaddr*)&addr,sizeof(sockaddr_in))};
} }
extern "C" nas_ref nas_accept(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_accept(std::vector<var>& args,gc& ngc){
if(args[0].type!=vm_num) if(args[0].type!=vm_num)
return nas_err("accept","\"sd\" must be a number"); return nas_err("accept","\"sd\" must be a number");
sockaddr_in client; sockaddr_in client;
@ -99,15 +99,15 @@ extern "C" nas_ref nas_accept(std::vector<nas_ref>& args,nasal_gc& gc){
#else #else
int client_sd=accept(args[0].num(),(sockaddr*)&client,(socklen_t*)&socklen); int client_sd=accept(args[0].num(),(sockaddr*)&client,(socklen_t*)&socklen);
#endif #endif
nas_ref res=gc.temp=gc.alloc(vm_hash); var res=ngc.temp=ngc.alloc(vm_hash);
auto& hash=res.hash().elems; auto& hash=res.hash().elems;
hash["sd"]={vm_num,(double)client_sd}; hash["sd"]={vm_num,(double)client_sd};
hash["ip"]=gc.newstr(inet_ntoa(client.sin_addr)); hash["ip"]=ngc.newstr(inet_ntoa(client.sin_addr));
gc.temp=nil; ngc.temp=nil;
return res; return res;
} }
extern "C" nas_ref nas_send(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_send(std::vector<var>& args,gc& ngc){
if(args[0].type!=vm_num) if(args[0].type!=vm_num)
return nas_err("send","\"sd\" must be a number"); return nas_err("send","\"sd\" must be a number");
if(args[1].type!=vm_str) if(args[1].type!=vm_str)
@ -117,7 +117,7 @@ extern "C" nas_ref nas_send(std::vector<nas_ref>& args,nasal_gc& gc){
return {vm_num,(double)send(args[0].num(),args[1].str().c_str(),args[1].str().length(),args[2].num())}; return {vm_num,(double)send(args[0].num(),args[1].str().c_str(),args[1].str().length(),args[2].num())};
} }
extern "C" nas_ref nas_sendto(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_sendto(std::vector<var>& args,gc& ngc){
if(args[0].type!=vm_num) if(args[0].type!=vm_num)
return nas_err("sendto","\"sd\" must be a number"); return nas_err("sendto","\"sd\" must be a number");
if(args[1].type!=vm_str) if(args[1].type!=vm_str)
@ -137,7 +137,7 @@ extern "C" nas_ref nas_sendto(std::vector<nas_ref>& args,nasal_gc& gc){
return {vm_num,(double)sendto(args[0].num(),args[3].str().c_str(),args[3].str().length(),args[4].num(),(sockaddr*)&addr,sizeof(sockaddr_in))}; return {vm_num,(double)sendto(args[0].num(),args[3].str().c_str(),args[3].str().length(),args[4].num(),(sockaddr*)&addr,sizeof(sockaddr_in))};
} }
extern "C" nas_ref nas_recv(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_recv(std::vector<var>& args,gc& ngc){
if(args[0].type!=vm_num) if(args[0].type!=vm_num)
return nas_err("recv","\"sd\" must be a number"); return nas_err("recv","\"sd\" must be a number");
if(args[1].type!=vm_num) if(args[1].type!=vm_num)
@ -146,17 +146,17 @@ extern "C" nas_ref nas_recv(std::vector<nas_ref>& args,nasal_gc& gc){
return nas_err("recv","\"len\" out of range"); return nas_err("recv","\"len\" out of range");
if(args[2].type!=vm_num) if(args[2].type!=vm_num)
return nas_err("recv","\"flags\" muse be a number"); return nas_err("recv","\"flags\" muse be a number");
nas_ref res=gc.temp=gc.alloc(vm_hash); var res=ngc.temp=ngc.alloc(vm_hash);
auto& hash=res.hash().elems; auto& hash=res.hash().elems;
char* buf=new char[(int)args[1].num()]; char* buf=new char[(int)args[1].num()];
hash["size"]={vm_num,(double)recv(args[0].num(),buf,args[1].num(),args[2].num())}; hash["size"]={vm_num,(double)recv(args[0].num(),buf,args[1].num(),args[2].num())};
hash["str"]=gc.newstr(buf); hash["str"]=ngc.newstr(buf);
delete[] buf; delete[] buf;
gc.temp=nil; ngc.temp=nil;
return res; return res;
} }
extern "C" nas_ref nas_recvfrom(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_recvfrom(std::vector<var>& args,gc& ngc){
if(args[0].type!=vm_num) if(args[0].type!=vm_num)
return nas_err("recvfrom","\"sd\" must be a number"); return nas_err("recvfrom","\"sd\" must be a number");
if(args[1].type!=vm_num) if(args[1].type!=vm_num)
@ -167,7 +167,7 @@ extern "C" nas_ref nas_recvfrom(std::vector<nas_ref>& args,nasal_gc& gc){
return nas_err("recvfrom","\"flags\" muse be a number"); return nas_err("recvfrom","\"flags\" muse be a number");
sockaddr_in addr; sockaddr_in addr;
int socklen=sizeof(sockaddr_in); int socklen=sizeof(sockaddr_in);
nas_ref res=gc.temp=gc.alloc(vm_hash); var res=ngc.temp=ngc.alloc(vm_hash);
auto& hash=res.hash().elems; auto& hash=res.hash().elems;
char* buf=new char[(int)args[1].num()+1]; char* buf=new char[(int)args[1].num()+1];
#ifdef _WIN32 #ifdef _WIN32
@ -176,13 +176,13 @@ extern "C" nas_ref nas_recvfrom(std::vector<nas_ref>& args,nasal_gc& gc){
hash["size"]={vm_num,(double)recvfrom(args[0].num(),buf,args[1].num(),args[2].num(),(sockaddr*)&addr,(socklen_t*)&socklen)}; hash["size"]={vm_num,(double)recvfrom(args[0].num(),buf,args[1].num(),args[2].num(),(sockaddr*)&addr,(socklen_t*)&socklen)};
#endif #endif
buf[(int)hash["size"].num()]=0; buf[(int)hash["size"].num()]=0;
hash["str"]=gc.newstr(buf); hash["str"]=ngc.newstr(buf);
delete[] buf; delete[] buf;
hash["fromip"]=gc.newstr(inet_ntoa(addr.sin_addr)); hash["fromip"]=ngc.newstr(inet_ntoa(addr.sin_addr));
gc.temp=nil; ngc.temp=nil;
return res; return res;
} }
extern "C" nas_ref nas_errno(std::vector<nas_ref>& args,nasal_gc& gc){ extern "C" var nas_errno(std::vector<var>& args,gc& ngc){
return gc.newstr(strerror(errno)); return ngc.newstr(strerror(errno));
} }

View File

@ -150,6 +150,6 @@ string rawstr(const string& str,const usize maxlen=0)
return ret; return ret;
} }
#include "nasal_gc.h" // declarations of nas_ref and nasal_gc #include "nasal_gc.h" // declarations of var and nasal_gc
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -198,11 +198,11 @@ public:
} }
}; };
class nasal_codegen class codegen
{ {
private: private:
u16 fileindex; u16 fileindex;
nasal_err& nerr; error& err;
const string* file; const string* file;
std::stack<u32> in_iterloop; std::stack<u32> in_iterloop;
std::unordered_map<f64,u32> num_table; std::unordered_map<f64,u32> num_table;
@ -264,24 +264,24 @@ private:
void singleop(const u32); void singleop(const u32);
public: public:
nasal_codegen(nasal_err& e):fileindex(0),nerr(e),file(nullptr){} codegen(error& e):fileindex(0),err(e),file(nullptr){}
void compile(const nasal_parse&,const nasal_import&); void compile(const parse&,const linker&);
void print(); void print();
const std::vector<string>& strs() const {return str_res;} const std::vector<string>& strs() const {return str_res;}
const std::vector<f64>& nums() const {return num_res;} const std::vector<f64>& nums() const {return num_res;}
const std::vector<opcode>& codes() const {return code;} const std::vector<opcode>& codes() const {return code;}
}; };
void nasal_codegen::die(const string& info,const u32 line,const u32 col) void codegen::die(const string& info,const u32 line,const u32 col)
{ {
nerr.load(file[fileindex]); err.load(file[fileindex]);
if(col) if(col)
nerr.err("code",line,col,info); err.err("code",line,col,info);
else else
nerr.err("code",line,info); err.err("code",line,info);
} }
void nasal_codegen::regist_num(const f64 num) void codegen::regist_num(const f64 num)
{ {
if(!num_table.count(num)) if(!num_table.count(num))
{ {
@ -291,7 +291,7 @@ void nasal_codegen::regist_num(const f64 num)
} }
} }
void nasal_codegen::regist_str(const string& str) void codegen::regist_str(const string& str)
{ {
if(!str_table.count(str)) if(!str_table.count(str))
{ {
@ -301,7 +301,7 @@ void nasal_codegen::regist_str(const string& str)
} }
} }
void nasal_codegen::find_symbol(const ast& node) void codegen::find_symbol(const ast& node)
{ {
// symbol definition checked here // symbol definition checked here
// if find a function, return // if find a function, return
@ -326,7 +326,7 @@ void nasal_codegen::find_symbol(const ast& node)
find_symbol(i); find_symbol(i);
} }
void nasal_codegen::add_sym(const string& name) void codegen::add_sym(const string& name)
{ {
if(local.empty()) if(local.empty())
{ {
@ -342,19 +342,19 @@ void nasal_codegen::add_sym(const string& name)
local.back()[name]=index; local.back()[name]=index;
} }
i32 nasal_codegen::local_find(const string& name) i32 codegen::local_find(const string& name)
{ {
if(local.empty()) if(local.empty())
return -1; return -1;
return local.back().count(name)?local.back()[name]:-1; return local.back().count(name)?local.back()[name]:-1;
} }
i32 nasal_codegen::global_find(const string& name) i32 codegen::global_find(const string& name)
{ {
return global.count(name)?global[name]:-1; return global.count(name)?global[name]:-1;
} }
i32 nasal_codegen::upvalue_find(const string& name) i32 codegen::upvalue_find(const string& name)
{ {
// 32768 level 65536 upvalues // 32768 level 65536 upvalues
i32 index=-1; i32 index=-1;
@ -368,32 +368,32 @@ i32 nasal_codegen::upvalue_find(const string& name)
return index; return index;
} }
void nasal_codegen::gen(u8 op,u32 num,u32 line) void codegen::gen(u8 op,u32 num,u32 line)
{ {
code.push_back({op,fileindex,num,line}); code.push_back({op,fileindex,num,line});
} }
void nasal_codegen::num_gen(const ast& node) void codegen::num_gen(const ast& node)
{ {
f64 num=node.num(); f64 num=node.num();
regist_num(num); regist_num(num);
gen(op_pnum,num_table[num],node.line()); gen(op_pnum,num_table[num],node.line());
} }
void nasal_codegen::str_gen(const ast& node) void codegen::str_gen(const ast& node)
{ {
regist_str(node.str()); regist_str(node.str());
gen(op_pstr,str_table[node.str()],node.line()); gen(op_pstr,str_table[node.str()],node.line());
} }
void nasal_codegen::vec_gen(const ast& node) void codegen::vec_gen(const ast& node)
{ {
for(auto& child:node.child()) for(auto& child:node.child())
calc_gen(child); calc_gen(child);
gen(op_newv,node.size(),node.line()); gen(op_newv,node.size(),node.line());
} }
void nasal_codegen::hash_gen(const ast& node) void codegen::hash_gen(const ast& node)
{ {
gen(op_newh,0,node.line()); gen(op_newh,0,node.line());
for(auto& child:node.child()) for(auto& child:node.child())
@ -405,7 +405,7 @@ void nasal_codegen::hash_gen(const ast& node)
} }
} }
void nasal_codegen::func_gen(const ast& node) void codegen::func_gen(const ast& node)
{ {
usize newf=code.size(); usize newf=code.size();
gen(op_newf,0,node.line()); gen(op_newf,0,node.line());
@ -462,7 +462,7 @@ void nasal_codegen::func_gen(const ast& node)
code[jmp_ptr].num=code.size(); code[jmp_ptr].num=code.size();
} }
void nasal_codegen::call_gen(const ast& node) void codegen::call_gen(const ast& node)
{ {
calc_gen(node[0]); calc_gen(node[0]);
if(code.back().op==op_callb) if(code.back().op==op_callb)
@ -479,7 +479,7 @@ void nasal_codegen::call_gen(const ast& node)
} }
} }
void nasal_codegen::call_id(const ast& node) void codegen::call_id(const ast& node)
{ {
const string& str=node.str(); const string& str=node.str();
for(u32 i=0;builtin[i].name;++i) for(u32 i=0;builtin[i].name;++i)
@ -509,13 +509,13 @@ void nasal_codegen::call_id(const ast& node)
die("undefined symbol \""+str+"\"",node.line(),node.col()); die("undefined symbol \""+str+"\"",node.line(),node.col());
} }
void nasal_codegen::call_hash(const ast& node) void codegen::call_hash(const ast& node)
{ {
regist_str(node.str()); regist_str(node.str());
gen(op_callh,str_table[node.str()],node.line()); gen(op_callh,str_table[node.str()],node.line());
} }
void nasal_codegen::call_vec(const ast& node) void codegen::call_vec(const ast& node)
{ {
// maybe this place can use callv-const if ast's first child is ast_num // maybe this place can use callv-const if ast's first child is ast_num
if(node.size()==1 && node[0].type()!=ast_subvec) if(node.size()==1 && node[0].type()!=ast_subvec)
@ -542,7 +542,7 @@ void nasal_codegen::call_vec(const ast& node)
gen(op_slcend,0,node.line()); gen(op_slcend,0,node.line());
} }
void nasal_codegen::call_func(const ast& node) void codegen::call_func(const ast& node)
{ {
if(!node.size()) if(!node.size())
gen(op_callfv,0,node.line()); gen(op_callfv,0,node.line());
@ -565,9 +565,9 @@ void nasal_codegen::call_func(const ast& node)
* at this time the value including the memory space can must be found alive. * at this time the value including the memory space can must be found alive.
* BUT in fact this method does not make much safety. * BUT in fact this method does not make much safety.
* so we use another way to avoid gc-caused SIGSEGV: reserve m-called value on stack. * so we use another way to avoid gc-caused SIGSEGV: reserve m-called value on stack.
* you could see the notes in `nasal_vm::opr_mcallv()`. * you could see the notes in `vm::opr_mcallv()`.
*/ */
void nasal_codegen::mcall(const ast& node) void codegen::mcall(const ast& node)
{ {
if(node.type()==ast_id) if(node.type()==ast_id)
{ {
@ -597,7 +597,7 @@ void nasal_codegen::mcall(const ast& node)
mcall_vec(tmp); mcall_vec(tmp);
} }
void nasal_codegen::mcall_id(const ast& node) void codegen::mcall_id(const ast& node)
{ {
const string& str=node.str(); const string& str=node.str();
for(u32 i=0;builtin[i].name;++i) for(u32 i=0;builtin[i].name;++i)
@ -625,19 +625,19 @@ void nasal_codegen::mcall_id(const ast& node)
die("undefined symbol \""+str+"\"",node.line(),node.col()); die("undefined symbol \""+str+"\"",node.line(),node.col());
} }
void nasal_codegen::mcall_vec(const ast& node) void codegen::mcall_vec(const ast& node)
{ {
calc_gen(node[0]); calc_gen(node[0]);
gen(op_mcallv,0,node.line()); gen(op_mcallv,0,node.line());
} }
void nasal_codegen::mcall_hash(const ast& node) void codegen::mcall_hash(const ast& node)
{ {
regist_str(node.str()); regist_str(node.str());
gen(op_mcallh,str_table[node.str()],node.line()); gen(op_mcallh,str_table[node.str()],node.line());
} }
void nasal_codegen::single_def(const ast& node) void codegen::single_def(const ast& node)
{ {
const string& str=node[0].str(); const string& str=node[0].str();
calc_gen(node[1]); calc_gen(node[1]);
@ -645,7 +645,7 @@ void nasal_codegen::single_def(const ast& node)
gen(op_loadg,global_find(str),node.line()): gen(op_loadg,global_find(str),node.line()):
gen(op_loadl,local_find(str),node.line()); gen(op_loadl,local_find(str),node.line());
} }
void nasal_codegen::multi_def(const ast& node) void codegen::multi_def(const ast& node)
{ {
auto& ids=node[0].child(); auto& ids=node[0].child();
usize size=ids.size(); usize size=ids.size();
@ -676,12 +676,12 @@ void nasal_codegen::multi_def(const ast& node)
} }
} }
void nasal_codegen::def_gen(const ast& node) void codegen::def_gen(const ast& node)
{ {
node[0].type()==ast_id?single_def(node):multi_def(node); node[0].type()==ast_id?single_def(node):multi_def(node);
} }
void nasal_codegen::multi_assign_gen(const ast& node) void codegen::multi_assign_gen(const ast& node)
{ {
i32 size=node[0].size(); i32 size=node[0].size();
if(node[1].type()==ast_multi_scalar) if(node[1].type()==ast_multi_scalar)
@ -725,7 +725,7 @@ void nasal_codegen::multi_assign_gen(const ast& node)
} }
} }
void nasal_codegen::conditional_gen(const ast& node) void codegen::conditional_gen(const ast& node)
{ {
std::vector<usize> jmp_label; std::vector<usize> jmp_label;
for(auto& tmp:node.child()) for(auto& tmp:node.child())
@ -754,7 +754,7 @@ void nasal_codegen::conditional_gen(const ast& node)
code[i].num=code.size(); code[i].num=code.size();
} }
void nasal_codegen::loop_gen(const ast& node) void codegen::loop_gen(const ast& node)
{ {
continue_ptr.push_front(std::vector<i32>()); continue_ptr.push_front(std::vector<i32>());
break_ptr.push_front(std::vector<i32>()); break_ptr.push_front(std::vector<i32>());
@ -767,7 +767,7 @@ void nasal_codegen::loop_gen(const ast& node)
} }
} }
void nasal_codegen::load_continue_break(i32 continue_place,i32 break_place) void codegen::load_continue_break(i32 continue_place,i32 break_place)
{ {
for(auto i:continue_ptr.front()) for(auto i:continue_ptr.front())
code[i].num=continue_place; code[i].num=continue_place;
@ -777,7 +777,7 @@ void nasal_codegen::load_continue_break(i32 continue_place,i32 break_place)
break_ptr.pop_front(); break_ptr.pop_front();
} }
void nasal_codegen::while_gen(const ast& node) void codegen::while_gen(const ast& node)
{ {
usize loop_ptr=code.size(); usize loop_ptr=code.size();
calc_gen(node[0]); calc_gen(node[0]);
@ -790,7 +790,7 @@ void nasal_codegen::while_gen(const ast& node)
load_continue_break(code.size()-1,code.size()); load_continue_break(code.size()-1,code.size());
} }
void nasal_codegen::for_gen(const ast& node) void codegen::for_gen(const ast& node)
{ {
switch(node[0].type()) switch(node[0].type())
{ {
@ -915,7 +915,7 @@ void nasal_codegen::for_gen(const ast& node)
load_continue_break(continue_place,code.size()); load_continue_break(continue_place,code.size());
} }
void nasal_codegen::forindex_gen(const ast& node) void codegen::forindex_gen(const ast& node)
{ {
calc_gen(node[1]); calc_gen(node[1]);
gen(op_cnt,0,node[1].line()); gen(op_cnt,0,node[1].line());
@ -949,7 +949,7 @@ void nasal_codegen::forindex_gen(const ast& node)
gen(op_pop,0,node[1].line());// pop vector gen(op_pop,0,node[1].line());// pop vector
gen(op_pop,0,node.line());// pop iterator gen(op_pop,0,node.line());// pop iterator
} }
void nasal_codegen::foreach_gen(const ast& node) void codegen::foreach_gen(const ast& node)
{ {
calc_gen(node[1]); calc_gen(node[1]);
gen(op_cnt,0,node.line()); gen(op_cnt,0,node.line());
@ -984,7 +984,7 @@ void nasal_codegen::foreach_gen(const ast& node)
gen(op_pop,0,node.line());// pop iterator gen(op_pop,0,node.line());// pop iterator
} }
void nasal_codegen::or_gen(const ast& node) void codegen::or_gen(const ast& node)
{ {
calc_gen(node[0]); calc_gen(node[0]);
usize l1=code.size(); usize l1=code.size();
@ -1001,7 +1001,7 @@ void nasal_codegen::or_gen(const ast& node)
code[l1].num=code[l2].num=code.size(); code[l1].num=code[l2].num=code.size();
} }
void nasal_codegen::and_gen(const ast& node) void codegen::and_gen(const ast& node)
{ {
calc_gen(node[0]); calc_gen(node[0]);
gen(op_jt,code.size()+2,node[0].line()); gen(op_jt,code.size()+2,node[0].line());
@ -1019,7 +1019,7 @@ void nasal_codegen::and_gen(const ast& node)
//jt jumps here //jt jumps here
} }
void nasal_codegen::trino_gen(const ast& node) void codegen::trino_gen(const ast& node)
{ {
calc_gen(node[0]); calc_gen(node[0]);
usize lfalse=code.size(); usize lfalse=code.size();
@ -1032,7 +1032,7 @@ void nasal_codegen::trino_gen(const ast& node)
code[lexit].num=code.size(); code[lexit].num=code.size();
} }
void nasal_codegen::calc_gen(const ast& node) void codegen::calc_gen(const ast& node)
{ {
switch(node.type()) switch(node.type())
{ {
@ -1137,7 +1137,7 @@ void nasal_codegen::calc_gen(const ast& node)
} }
} }
void nasal_codegen::block_gen(const ast& node) void codegen::block_gen(const ast& node)
{ {
for(auto& tmp:node.child()) for(auto& tmp:node.child())
switch(tmp.type()) switch(tmp.type())
@ -1222,7 +1222,7 @@ void nasal_codegen::block_gen(const ast& node)
} }
} }
void nasal_codegen::ret_gen(const ast& node) void codegen::ret_gen(const ast& node)
{ {
for(u32 i=0;i<in_iterloop.top();++i) for(u32 i=0;i<in_iterloop.top();++i)
{ {
@ -1236,7 +1236,7 @@ void nasal_codegen::ret_gen(const ast& node)
gen(op_ret,0,node.line()); gen(op_ret,0,node.line());
} }
void nasal_codegen::compile(const nasal_parse& parse,const nasal_import& import) void codegen::compile(const parse& parse,const linker& import)
{ {
fileindex=0; fileindex=0;
file=import.filelist().data(); file=import.filelist().data();
@ -1249,10 +1249,10 @@ void nasal_codegen::compile(const nasal_parse& parse,const nasal_import& import)
die("too many global variants: "+std::to_string(global.size()),0,0); die("too many global variants: "+std::to_string(global.size()),0,0);
if(code.size()>0xffffffff) if(code.size()>0xffffffff)
die("too large generated bytecode file: "+std::to_string(code.size()),0,0); die("too large generated bytecode file: "+std::to_string(code.size()),0,0);
nerr.chkerr(); err.chkerr();
} }
void nasal_codegen::singleop(const u32 index) void codegen::singleop(const u32 index)
{ {
// print opcode index,opcode name,opcode immediate number // print opcode index,opcode name,opcode immediate number
const opcode& c=code[index]; const opcode& c=code[index];
@ -1278,7 +1278,7 @@ void nasal_codegen::singleop(const u32 index)
std::cout<<" "<<codestream(c,index,num_res.data(),str_res.data())<<"\n"; std::cout<<" "<<codestream(c,index,num_res.data(),str_res.data())<<"\n";
} }
void nasal_codegen::print() void codegen::print()
{ {
for(auto& num:num_res) for(auto& num:num_res)
std::cout<<" .number "<<num<<"\n"; std::cout<<" .number "<<num<<"\n";

View File

@ -5,14 +5,14 @@
#include "nasal_vm.h" #include "nasal_vm.h"
#include <algorithm> #include <algorithm>
class nasal_dbg:public nasal_vm class debugger:public vm
{ {
private: private:
bool next; bool next;
usize fsize; usize fsize;
u16 bk_fidx; u16 bk_fidx;
u32 bk_line; u32 bk_line;
nasal_err& src; error& src;
std::vector<string> parse(const string&); std::vector<string> parse(const string&);
u16 fileindex(const string&); u16 fileindex(const string&);
@ -22,18 +22,18 @@ private:
void stepinfo(); void stepinfo();
void interact(); void interact();
public: public:
nasal_dbg(nasal_err& nerr): debugger(error& err):
next(false),fsize(0), next(false),fsize(0),
bk_fidx(0),bk_line(0), bk_fidx(0),bk_line(0),
src(nerr){} src(err){}
void run( void run(
const nasal_codegen&, const codegen&,
const nasal_import&, const linker&,
const std::vector<string>& const std::vector<string>&
); );
}; };
std::vector<string> nasal_dbg::parse(const string& cmd) std::vector<string> debugger::parse(const string& cmd)
{ {
std::vector<string> res; std::vector<string> res;
usize last=0,pos=cmd.find(" ",0); usize last=0,pos=cmd.find(" ",0);
@ -49,7 +49,7 @@ std::vector<string> nasal_dbg::parse(const string& cmd)
return res; return res;
} }
u16 nasal_dbg::fileindex(const string& filename) u16 debugger::fileindex(const string& filename)
{ {
for(u16 i=0;i<fsize;++i) for(u16 i=0;i<fsize;++i)
if(filename==files[i]) if(filename==files[i])
@ -57,14 +57,14 @@ u16 nasal_dbg::fileindex(const string& filename)
return 65535; return 65535;
} }
void nasal_dbg::err() void debugger::err()
{ {
std::cerr std::cerr
<<"incorrect command\n" <<"incorrect command\n"
<<"input \'h\' to get help\n"; <<"input \'h\' to get help\n";
} }
void nasal_dbg::help() void debugger::help()
{ {
std::cout std::cout
<<"<option>\n" <<"<option>\n"
@ -83,7 +83,7 @@ void nasal_dbg::help()
<<"\tbk, break | set break point\n"; <<"\tbk, break | set break point\n";
} }
void nasal_dbg::callsort(const u64* arr) void debugger::callsort(const u64* arr)
{ {
typedef std::pair<u32,u64> op; typedef std::pair<u32,u64> op;
std::vector<op> opcall; std::vector<op> opcall;
@ -111,7 +111,7 @@ void nasal_dbg::callsort(const u64* arr)
std::clog<<"\n total : "<<total<<'\n'; std::clog<<"\n total : "<<total<<'\n';
} }
void nasal_dbg::stepinfo() void debugger::stepinfo()
{ {
u32 line=bytecode[pc].line==0?0:bytecode[pc].line-1; u32 line=bytecode[pc].line==0?0:bytecode[pc].line-1;
u32 begin=(line>>3)==0?0:((line>>3)<<3); u32 begin=(line>>3)==0?0:((line>>3)<<3);
@ -131,7 +131,7 @@ void nasal_dbg::stepinfo()
stackinfo(10); stackinfo(10);
} }
void nasal_dbg::interact() void debugger::interact()
{ {
// special operand // special operand
if(bytecode[pc].op==op_intg) if(bytecode[pc].op==op_intg)
@ -207,9 +207,9 @@ void nasal_dbg::interact()
} }
} }
void nasal_dbg::run( void debugger::run(
const nasal_codegen& gen, const codegen& gen,
const nasal_import& linker, const linker& linker,
const std::vector<string>& argv) const std::vector<string>& argv)
{ {
detail_info=true; detail_info=true;
@ -248,47 +248,47 @@ void nasal_dbg::run(
// goto the first operand // goto the first operand
goto *code[pc]; goto *code[pc];
#else #else
typedef void (nasal_dbg::*nafunc)(); typedef void (debugger::*nafunc)();
const nafunc oprs[]= const nafunc oprs[]=
{ {
nullptr, &nasal_dbg::o_intg, nullptr, &debugger::o_intg,
&nasal_dbg::o_intl, &nasal_dbg::o_loadg, &debugger::o_intl, &debugger::o_loadg,
&nasal_dbg::o_loadl, &nasal_dbg::o_loadu, &debugger::o_loadl, &debugger::o_loadu,
&nasal_dbg::o_pnum, &nasal_dbg::o_pnil, &debugger::o_pnum, &debugger::o_pnil,
&nasal_dbg::o_pstr, &nasal_dbg::o_newv, &debugger::o_pstr, &debugger::o_newv,
&nasal_dbg::o_newh, &nasal_dbg::o_newf, &debugger::o_newh, &debugger::o_newf,
&nasal_dbg::o_happ, &nasal_dbg::o_para, &debugger::o_happ, &debugger::o_para,
&nasal_dbg::o_deft, &nasal_dbg::o_dyn, &debugger::o_deft, &debugger::o_dyn,
&nasal_dbg::o_unot, &nasal_dbg::o_usub, &debugger::o_unot, &debugger::o_usub,
&nasal_dbg::o_add, &nasal_dbg::o_sub, &debugger::o_add, &debugger::o_sub,
&nasal_dbg::o_mul, &nasal_dbg::o_div, &debugger::o_mul, &debugger::o_div,
&nasal_dbg::o_lnk, &nasal_dbg::o_addc, &debugger::o_lnk, &debugger::o_addc,
&nasal_dbg::o_subc, &nasal_dbg::o_mulc, &debugger::o_subc, &debugger::o_mulc,
&nasal_dbg::o_divc, &nasal_dbg::o_lnkc, &debugger::o_divc, &debugger::o_lnkc,
&nasal_dbg::o_addeq, &nasal_dbg::o_subeq, &debugger::o_addeq, &debugger::o_subeq,
&nasal_dbg::o_muleq, &nasal_dbg::o_diveq, &debugger::o_muleq, &debugger::o_diveq,
&nasal_dbg::o_lnkeq, &nasal_dbg::o_addeqc, &debugger::o_lnkeq, &debugger::o_addeqc,
&nasal_dbg::o_subeqc, &nasal_dbg::o_muleqc, &debugger::o_subeqc, &debugger::o_muleqc,
&nasal_dbg::o_diveqc, &nasal_dbg::o_lnkeqc, &debugger::o_diveqc, &debugger::o_lnkeqc,
&nasal_dbg::o_meq, &nasal_dbg::o_eq, &debugger::o_meq, &debugger::o_eq,
&nasal_dbg::o_neq, &nasal_dbg::o_less, &debugger::o_neq, &debugger::o_less,
&nasal_dbg::o_leq, &nasal_dbg::o_grt, &debugger::o_leq, &debugger::o_grt,
&nasal_dbg::o_geq, &nasal_dbg::o_lessc, &debugger::o_geq, &debugger::o_lessc,
&nasal_dbg::o_leqc, &nasal_dbg::o_grtc, &debugger::o_leqc, &debugger::o_grtc,
&nasal_dbg::o_geqc, &nasal_dbg::o_pop, &debugger::o_geqc, &debugger::o_pop,
&nasal_dbg::o_jmp, &nasal_dbg::o_jt, &debugger::o_jmp, &debugger::o_jt,
&nasal_dbg::o_jf, &nasal_dbg::o_cnt, &debugger::o_jf, &debugger::o_cnt,
&nasal_dbg::o_findex, &nasal_dbg::o_feach, &debugger::o_findex, &debugger::o_feach,
&nasal_dbg::o_callg, &nasal_dbg::o_calll, &debugger::o_callg, &debugger::o_calll,
&nasal_dbg::o_upval, &nasal_dbg::o_callv, &debugger::o_upval, &debugger::o_callv,
&nasal_dbg::o_callvi, &nasal_dbg::o_callh, &debugger::o_callvi, &debugger::o_callh,
&nasal_dbg::o_callfv, &nasal_dbg::o_callfh, &debugger::o_callfv, &debugger::o_callfh,
&nasal_dbg::o_callb, &nasal_dbg::o_slcbeg, &debugger::o_callb, &debugger::o_slcbeg,
&nasal_dbg::o_slcend, &nasal_dbg::o_slc, &debugger::o_slcend, &debugger::o_slc,
&nasal_dbg::o_slc2, &nasal_dbg::o_mcallg, &debugger::o_slc2, &debugger::o_mcallg,
&nasal_dbg::o_mcalll, &nasal_dbg::o_mupval, &debugger::o_mcalll, &debugger::o_mupval,
&nasal_dbg::o_mcallv, &nasal_dbg::o_mcallh, &debugger::o_mcallv, &debugger::o_mcallh,
&nasal_dbg::o_ret &debugger::o_ret
}; };
std::vector<u32> code; std::vector<u32> code;
for(auto& i:gen.codes()) for(auto& i:gen.codes())
@ -308,7 +308,7 @@ void nasal_dbg::run(
vmexit: vmexit:
callsort(count); callsort(count);
gc.clear(); ngc.clear();
imm.clear(); imm.clear();
std::cout<<bold_cyan<<"[debug] "<<reset<<"debugger exited\n"; std::cout<<bold_cyan<<"[debug] "<<reset<<"debugger exited\n";
return; return;

View File

@ -101,10 +101,10 @@ public:
usize size(){return res.size();} usize size(){return res.size();}
}; };
class nasal_err:public fstreamline class error:public fstreamline
{ {
private: private:
u32 error; u32 cnt;
string identation(usize len) string identation(usize len)
{ {
string tmp=""; string tmp="";
@ -112,16 +112,16 @@ private:
return tmp; return tmp;
} }
public: public:
nasal_err():error(0){} error():cnt(0){}
void err(const char* stage,const string& info) void err(const char* stage,const string& info)
{ {
++error; ++cnt;
std::cerr<<bold_red<<stage<<": " std::cerr<<bold_red<<stage<<": "
<<bold_white<<info<<reset<<"\n\n"; <<bold_white<<info<<reset<<"\n\n";
} }
void err(const char* stage,u32 line,u32 column,const string& info) void err(const char* stage,u32 line,u32 column,const string& info)
{ {
++error; ++cnt;
const string& code=res[line-1]; const string& code=res[line-1];
const string ident=identation(std::to_string(line).length()); const string ident=identation(std::to_string(line).length());
std::cerr<<bold_red<<stage<<": " std::cerr<<bold_red<<stage<<": "
@ -142,7 +142,7 @@ public:
} }
void err(const char* stage,u32 line,const string& info) void err(const char* stage,u32 line,const string& info)
{ {
++error; ++cnt;
const string ident=identation(std::to_string(line).length()); const string ident=identation(std::to_string(line).length());
std::cerr<<bold_red<<stage<<": " std::cerr<<bold_red<<stage<<": "
<<bold_white<<info<<reset<<"\n" <<bold_white<<info<<reset<<"\n"
@ -157,7 +157,7 @@ public:
<<bold_cyan<<line<<" | "<<reset<<res[line-1]<<"\n" <<bold_cyan<<line<<" | "<<reset<<res[line-1]<<"\n"
<<bold_cyan<<ident<<" | "<<reset<<"\n\n"; <<bold_cyan<<ident<<" | "<<reset<<"\n\n";
} }
void chkerr(){if(error)std::exit(1);} void chkerr(){if(cnt)std::exit(1);}
}; };
#endif #endif

View File

@ -55,7 +55,7 @@ struct nas_obj; // special objects
struct nas_co; // coroutine struct nas_co; // coroutine
struct nas_val; // nas_val includes gc-managed types struct nas_val; // nas_val includes gc-managed types
struct nas_ref struct var
{ {
u8 type; u8 type;
union union
@ -63,32 +63,32 @@ struct nas_ref
u32 ret; u32 ret;
i64 cnt; i64 cnt;
f64 num; f64 num;
nas_ref* addr; var* addr;
nas_val* gcobj; nas_val* gcobj;
} val; } val;
// vm_none/vm_nil // vm_none/vm_nil
nas_ref(const u8 t=vm_none):type(t){} var(const u8 t=vm_none):type(t){}
// vm_ret // vm_ret
nas_ref(const u8 t,const u32 n):type(t){val.ret=n;} var(const u8 t,const u32 n):type(t){val.ret=n;}
// vm_cnt // vm_cnt
nas_ref(const u8 t,const i64 n):type(t){val.cnt=n;} var(const u8 t,const i64 n):type(t){val.cnt=n;}
// vm_num // vm_num
nas_ref(const u8 t,const f64 n):type(t){val.num=n;} var(const u8 t,const f64 n):type(t){val.num=n;}
// nas_val // nas_val
nas_ref(const u8 t,nas_val* n):type(t){val.gcobj=n;} var(const u8 t,nas_val* n):type(t){val.gcobj=n;}
// vm_addr // vm_addr
nas_ref(const u8 t,nas_ref* n):type(t){val.addr=n;} var(const u8 t,var* n):type(t){val.addr=n;}
// copy // copy
nas_ref(const nas_ref& nr):type(nr.type),val(nr.val){} var(const var& nr):type(nr.type),val(nr.val){}
bool operator==(const nas_ref& nr){return type==nr.type && val.gcobj==nr.val.gcobj;} bool operator==(const var& nr){return type==nr.type && val.gcobj==nr.val.gcobj;}
bool operator!=(const nas_ref& nr){return type!=nr.type || val.gcobj!=nr.val.gcobj;} bool operator!=(const var& nr){return type!=nr.type || val.gcobj!=nr.val.gcobj;}
// number and string can be translated to each other // number and string can be translated to each other
f64 tonum(); f64 tonum();
string tostr(); string tostr();
friend std::ostream& operator<<(std::ostream&,nas_ref&); friend std::ostream& operator<<(std::ostream&,var&);
bool objchk(u32); bool objchk(u32);
inline nas_ref* addr(); inline var* addr();
inline u32 ret (); inline u32 ret ();
inline i64& cnt (); inline i64& cnt ();
inline f64 num (); inline f64 num ();
@ -104,25 +104,25 @@ struct nas_ref
struct nas_vec struct nas_vec
{ {
bool printed; bool printed;
std::vector<nas_ref> elems; std::vector<var> elems;
nas_vec():printed(false){} nas_vec():printed(false){}
friend std::ostream& operator<<(std::ostream&,nas_vec&); friend std::ostream& operator<<(std::ostream&,nas_vec&);
usize size(){return elems.size();} usize size(){return elems.size();}
nas_ref get_val(const i32); var get_val(const i32);
nas_ref* get_mem(const i32); var* get_mem(const i32);
}; };
struct nas_hash struct nas_hash
{ {
bool printed; bool printed;
std::unordered_map<string,nas_ref> elems; std::unordered_map<string,var> elems;
nas_hash():printed(false){} nas_hash():printed(false){}
friend std::ostream& operator<<(std::ostream&,nas_hash&); friend std::ostream& operator<<(std::ostream&,nas_hash&);
usize size(){return elems.size();} usize size(){return elems.size();}
nas_ref get_val(const string&); var get_val(const string&);
nas_ref* get_mem(const string&); var* get_mem(const string&);
}; };
struct nas_func struct nas_func
@ -131,8 +131,8 @@ struct nas_func
u32 entry; // pc will set to entry-1 to call this function u32 entry; // pc will set to entry-1 to call this function
u32 psize; // used to load default parameters to a new function u32 psize; // used to load default parameters to a new function
u32 lsize; // used to expand memory space for local values on stack u32 lsize; // used to expand memory space for local values on stack
std::vector<nas_ref> local; // local scope with default value(nas_ref) std::vector<var> local; // local scope with default value(var)
std::vector<nas_ref> upval; // closure std::vector<var> upval; // closure
std::unordered_map<u32,u32> keys; // parameter table, u32 begins from 1 std::unordered_map<u32,u32> keys; // parameter table, u32 begins from 1
nas_func():dpara(-1),entry(0),psize(0),lsize(0){} nas_func():dpara(-1),entry(0),psize(0),lsize(0){}
@ -142,12 +142,12 @@ struct nas_func
struct nas_upval struct nas_upval
{ {
bool onstk; bool onstk;
u32 size; u32 size;
nas_ref* stk; var* stk;
std::vector<nas_ref> elems; std::vector<var> elems;
nas_upval(){onstk=true;stk=nullptr;size=0;} nas_upval(){onstk=true;stk=nullptr;size=0;}
nas_ref& operator[](usize n){return onstk?stk[n]:elems[n];} var& operator[](usize n){return onstk?stk[n]:elems[n];}
void clear(){onstk=true;elems.clear();size=0;} void clear(){onstk=true;elems.clear();size=0;}
}; };
@ -195,15 +195,15 @@ struct nas_co
running, running,
dead dead
}; };
nas_ref stack[STACK_DEPTH]; var stack[STACK_DEPTH];
u32 pc; u32 pc;
nas_ref* top; var* top;
nas_ref* canary; var* canary;
nas_ref* localr; var* localr;
nas_ref* memr; var* memr;
nas_ref funcr; var funcr;
nas_ref upvalr; var upvalr;
u32 status; u32 status;
nas_co(): nas_co():
@ -248,20 +248,20 @@ struct nas_val
nas_upval* upval; nas_upval* upval;
nas_obj* obj; nas_obj* obj;
nas_co* co; nas_co* co;
}ptr; } ptr;
nas_val(u8); nas_val(u8);
~nas_val(); ~nas_val();
}; };
nas_ref nas_vec::get_val(const i32 n) var nas_vec::get_val(const i32 n)
{ {
i32 size=elems.size(); i32 size=elems.size();
if(n<-size || n>=size) if(n<-size || n>=size)
return {vm_none}; return {vm_none};
return elems[n>=0?n:n+size]; return elems[n>=0?n:n+size];
} }
nas_ref* nas_vec::get_mem(const i32 n) var* nas_vec::get_mem(const i32 n)
{ {
i32 size=elems.size(); i32 size=elems.size();
if(n<-size || n>=size) if(n<-size || n>=size)
@ -284,14 +284,14 @@ std::ostream& operator<<(std::ostream& out,nas_vec& vec)
return out; return out;
} }
nas_ref nas_hash::get_val(const string& key) var nas_hash::get_val(const string& key)
{ {
if(elems.count(key)) if(elems.count(key))
return elems[key]; return elems[key];
else if(elems.count("parents")) else if(elems.count("parents"))
{ {
nas_ref ret(vm_none); var ret(vm_none);
nas_ref val=elems["parents"]; var val=elems["parents"];
if(val.type==vm_vec) if(val.type==vm_vec)
for(auto& i:val.vec().elems) for(auto& i:val.vec().elems)
{ {
@ -303,14 +303,14 @@ nas_ref nas_hash::get_val(const string& key)
} }
return {vm_none}; return {vm_none};
} }
nas_ref* nas_hash::get_mem(const string& key) var* nas_hash::get_mem(const string& key)
{ {
if(elems.count(key)) if(elems.count(key))
return &elems[key]; return &elems[key];
else if(elems.count("parents")) else if(elems.count("parents"))
{ {
nas_ref* addr=nullptr; var* addr=nullptr;
nas_ref val=elems["parents"]; var val=elems["parents"];
if(val.type==vm_vec) if(val.type==vm_vec)
for(auto& i:val.vec().elems) for(auto& i:val.vec().elems)
{ {
@ -376,11 +376,11 @@ nas_val::~nas_val()
} }
type=vm_nil; type=vm_nil;
} }
f64 nas_ref::tonum() f64 var::tonum()
{ {
return type!=vm_str?val.num:str2num(str().c_str()); return type!=vm_str?val.num:str2num(str().c_str());
} }
string nas_ref::tostr() string var::tostr()
{ {
if(type==vm_str) if(type==vm_str)
return str(); return str();
@ -393,7 +393,7 @@ string nas_ref::tostr()
} }
return ""; return "";
} }
std::ostream& operator<<(std::ostream& out,nas_ref& ref) std::ostream& operator<<(std::ostream& out,var& ref)
{ {
switch(ref.type) switch(ref.type)
{ {
@ -409,56 +409,56 @@ std::ostream& operator<<(std::ostream& out,nas_ref& ref)
} }
return out; return out;
} }
bool nas_ref::objchk(u32 objtype) bool var::objchk(u32 objtype)
{ {
return type==vm_obj && obj().type==objtype && obj().ptr; return type==vm_obj && obj().type==objtype && obj().ptr;
} }
inline nas_ref* nas_ref::addr (){return val.addr; } inline var* var::addr (){return val.addr; }
inline u32 nas_ref::ret (){return val.ret; } inline u32 var::ret (){return val.ret; }
inline i64& nas_ref::cnt (){return val.cnt; } inline i64& var::cnt (){return val.cnt; }
inline f64 nas_ref::num (){return val.num; } inline f64 var::num (){return val.num; }
inline string& nas_ref::str (){return *val.gcobj->ptr.str; } inline string& var::str (){return *val.gcobj->ptr.str; }
inline nas_vec& nas_ref::vec (){return *val.gcobj->ptr.vec; } inline nas_vec& var::vec (){return *val.gcobj->ptr.vec; }
inline nas_hash& nas_ref::hash (){return *val.gcobj->ptr.hash; } inline nas_hash& var::hash (){return *val.gcobj->ptr.hash; }
inline nas_func& nas_ref::func (){return *val.gcobj->ptr.func; } inline nas_func& var::func (){return *val.gcobj->ptr.func; }
inline nas_upval& nas_ref::upval(){return *val.gcobj->ptr.upval;} inline nas_upval& var::upval(){return *val.gcobj->ptr.upval;}
inline nas_obj& nas_ref::obj (){return *val.gcobj->ptr.obj; } inline nas_obj& var::obj (){return *val.gcobj->ptr.obj; }
inline nas_co& nas_ref::co (){return *val.gcobj->ptr.co; } inline nas_co& var::co (){return *val.gcobj->ptr.co; }
const nas_ref zero={vm_num,(f64)0}; const var zero={vm_num,(f64)0};
const nas_ref one ={vm_num,(f64)1}; const var one ={vm_num,(f64)1};
const nas_ref nil ={vm_nil,(f64)0}; const var nil ={vm_nil,(f64)0};
struct nasal_gc struct gc
{ {
/* main context */ /* main context */
struct struct
{ {
u32 pc; u32 pc;
nas_ref* top; var* top;
nas_ref* localr; var* localr;
nas_ref* memr; var* memr;
nas_ref funcr; var funcr;
nas_ref upvalr; var upvalr;
nas_ref* canary; var* canary;
nas_ref* stack; var* stack;
} mctx; } mctx;
/* runtime context */ /* runtime context */
u32& pc; // program counter u32& pc; // program counter
nas_ref*& localr;// local scope register var*& localr;// local scope register
nas_ref*& memr; // used for mem_call var*& memr; // used for mem_call
nas_ref& funcr; // function register var& funcr; // function register
nas_ref& upvalr;// upvalue register var& upvalr;// upvalue register
nas_ref*& canary;// avoid stackoverflow var*& canary;// avoid stackoverflow
nas_ref*& top; // stack top var*& top; // stack top
nas_ref* stack; // stack pointer var* stack; // stack pointer
nas_co* cort; // running coroutine nas_co* cort;// running coroutine
nas_ref temp; // temporary place used in builtin/module functions var temp; // temporary place used in builtin/module functions
/* constants and memory pool */ /* constants and memory pool */
std::vector<nas_ref> strs; // reserved address for const vm_str std::vector<var> strs; // reserved address for const vm_str
std::vector<nas_ref> env_argv; // command line arguments std::vector<var> env_argv; // command line arguments
std::vector<nas_val*> memory; // gc memory std::vector<nas_val*> memory; // gc memory
std::queue<nas_val*> unused[gc_tsize]; // gc free list std::queue<nas_val*> unused[gc_tsize]; // gc free list
@ -466,46 +466,42 @@ struct nasal_gc
u64 size[gc_tsize]; u64 size[gc_tsize];
u64 count[gc_tsize]; u64 count[gc_tsize];
u64 allocc[gc_tsize]; u64 allocc[gc_tsize];
nasal_gc( gc(
u32& _pc, u32& _pc, var*& _localr,
nas_ref*& _localr, var*& _memr, var& _funcr,
nas_ref*& _memr, var& _upvalr, var*& _canary,
nas_ref& _funcr, var*& _top, var* _stk):
nas_ref& _upvalr,
nas_ref*& _canary,
nas_ref*& _top,
nas_ref* _stk):
pc(_pc),localr(_localr),memr(_memr),funcr(_funcr),upvalr(_upvalr), pc(_pc),localr(_localr),memr(_memr),funcr(_funcr),upvalr(_upvalr),
canary(_canary),top(_top),stack(_stk),cort(nullptr),temp(nil){} canary(_canary),top(_top),stack(_stk),cort(nullptr),temp(nil){}
void mark(); void mark();
void sweep(); void sweep();
void init(const std::vector<string>&,const std::vector<string>&); void init(const std::vector<string>&,const std::vector<string>&);
void clear(); void clear();
void info(); void info();
nas_ref alloc(const u8); var alloc(const u8);
nas_ref newstr(char); var newstr(char);
nas_ref newstr(const char*); var newstr(const char*);
nas_ref newstr(const string&); var newstr(const string&);
void ctxchg(nas_co&); void ctxchg(nas_co&);
void ctxreserve(); void ctxreserve();
}; };
/* gc functions */ /* gc functions */
void nasal_gc::mark() void gc::mark()
{ {
std::queue<nas_ref> bfs; std::queue<var> bfs;
// scan coroutine process stack when coroutine ptr is not null // scan coroutine process stack when coroutine ptr is not null
// scan main process stack when coroutine ptr is null // scan main process stack when coroutine ptr is null
// this scan process must execute because when running coroutine, // this scan process must execute because when running coroutine,
// the nas_co related to it will not update it's context(like `top`) until the coroutine suspends or exits. // the nas_co related to it will not update it's context(like `top`) until the coroutine suspends or exits.
for(nas_ref* i=stack;i<=top;++i) for(var* i=stack;i<=top;++i)
bfs.push(*i); bfs.push(*i);
bfs.push(funcr); bfs.push(funcr);
bfs.push(upvalr); bfs.push(upvalr);
bfs.push(temp); bfs.push(temp);
if(cort) // scan main process stack if(cort) // scan main process stack
{ {
for(nas_ref* i=mctx.stack;i<=mctx.top;++i) for(var* i=mctx.stack;i<=mctx.top;++i)
bfs.push(*i); bfs.push(*i);
bfs.push(mctx.funcr); bfs.push(mctx.funcr);
bfs.push(mctx.upvalr); bfs.push(mctx.upvalr);
@ -513,7 +509,7 @@ void nasal_gc::mark()
while(!bfs.empty()) while(!bfs.empty())
{ {
nas_ref tmp=bfs.front(); var tmp=bfs.front();
bfs.pop(); bfs.pop();
if(tmp.type<=vm_num || tmp.val.gcobj->mark) continue; if(tmp.type<=vm_num || tmp.val.gcobj->mark) continue;
tmp.val.gcobj->mark=GC_FOUND; tmp.val.gcobj->mark=GC_FOUND;
@ -540,13 +536,13 @@ void nasal_gc::mark()
case vm_co: case vm_co:
bfs.push(tmp.co().funcr); bfs.push(tmp.co().funcr);
bfs.push(tmp.co().upvalr); bfs.push(tmp.co().upvalr);
for(nas_ref* i=tmp.co().stack;i<=tmp.co().top;++i) for(var* i=tmp.co().stack;i<=tmp.co().top;++i)
bfs.push(*i); bfs.push(*i);
break; break;
} }
} }
} }
void nasal_gc::sweep() void gc::sweep()
{ {
for(auto i:memory) for(auto i:memory)
{ {
@ -569,7 +565,7 @@ void nasal_gc::sweep()
i->mark=GC_UNCOLLECTED; i->mark=GC_UNCOLLECTED;
} }
} }
void nasal_gc::init(const std::vector<string>& s,const std::vector<string>& argv) void gc::init(const std::vector<string>& s,const std::vector<string>& argv)
{ {
// initiaize function register // initiaize function register
funcr=nil; funcr=nil;
@ -601,7 +597,7 @@ void nasal_gc::init(const std::vector<string>& s,const std::vector<string>& argv
env_argv[i].str()=argv[i]; env_argv[i].str()=argv[i];
} }
} }
void nasal_gc::clear() void gc::clear()
{ {
for(auto i:memory) for(auto i:memory)
delete i; delete i;
@ -614,7 +610,7 @@ void nasal_gc::clear()
strs.clear(); strs.clear();
env_argv.clear(); env_argv.clear();
} }
void nasal_gc::info() void gc::info()
{ {
const char* name[]={"str ","vec ","hash ","func ","upval","obj ","co "}; const char* name[]={"str ","vec ","hash ","func ","upval","obj ","co "};
std::cout<<"\ngarbage collector info(gc/alloc)\n"; std::cout<<"\ngarbage collector info(gc/alloc)\n";
@ -626,7 +622,7 @@ void nasal_gc::info()
if(ini[i] || size[i]) if(ini[i] || size[i])
std::cout<<" "<<name[i]<<" | "<<ini[i]+size[i]*incr[i]<<" (+"<<size[i]<<")\n"; std::cout<<" "<<name[i]<<" | "<<ini[i]+size[i]*incr[i]<<" (+"<<size[i]<<")\n";
} }
nas_ref nasal_gc::alloc(u8 type) var gc::alloc(u8 type)
{ {
const u8 index=type-vm_str; const u8 index=type-vm_str;
++allocc[index]; ++allocc[index];
@ -646,30 +642,30 @@ nas_ref nasal_gc::alloc(u8 type)
unused[index].push(tmp); unused[index].push(tmp);
} }
} }
nas_ref ret={type,unused[index].front()}; var ret={type,unused[index].front()};
ret.val.gcobj->mark=GC_UNCOLLECTED; ret.val.gcobj->mark=GC_UNCOLLECTED;
unused[index].pop(); unused[index].pop();
return ret; return ret;
} }
nas_ref nasal_gc::newstr(char c) var gc::newstr(char c)
{ {
nas_ref s=alloc(vm_str); var s=alloc(vm_str);
s.str()=c; s.str()=c;
return s; return s;
} }
nas_ref nasal_gc::newstr(const char* buff) var gc::newstr(const char* buff)
{ {
nas_ref s=alloc(vm_str); var s=alloc(vm_str);
s.str()=buff; s.str()=buff;
return s; return s;
} }
nas_ref nasal_gc::newstr(const string& buff) var gc::newstr(const string& buff)
{ {
nas_ref s=alloc(vm_str); var s=alloc(vm_str);
s.str()=buff; s.str()=buff;
return s; return s;
} }
void nasal_gc::ctxchg(nas_co& ctx) void gc::ctxchg(nas_co& ctx)
{ {
mctx.pc=pc; mctx.pc=pc;
mctx.top=top; mctx.top=top;
@ -692,7 +688,7 @@ void nasal_gc::ctxchg(nas_co& ctx)
cort->status=nas_co::running; cort->status=nas_co::running;
} }
void nasal_gc::ctxreserve() void gc::ctxreserve()
{ {
// pc=0 means this coroutine is finished // pc=0 means this coroutine is finished
cort->status=pc?nas_co::suspended:nas_co::dead; cort->status=pc?nas_co::suspended:nas_co::dead;
@ -716,7 +712,7 @@ void nasal_gc::ctxreserve()
} }
// use to print error log and return error value // use to print error log and return error value
nas_ref nas_err(const string& err_f,const string& info) var nas_err(const string& err_f,const string& info)
{ {
std::cerr<<"[vm] "<<err_f<<": "<<info<<"\n"; std::cerr<<"[vm] "<<err_f<<": "<<info<<"\n";
return {vm_none}; return {vm_none};

View File

@ -13,29 +13,29 @@
#define F_OK 0 #define F_OK 0
#endif #endif
class nasal_import class linker
{ {
private: private:
bool show_path; bool show_path;
bool lib_loaded; bool lib_loaded;
nasal_err& nerr; error& err;
std::vector<string> files; std::vector<string> files;
std::vector<string> envpath; std::vector<string> envpath;
bool imptchk(const ast&); bool imptchk(const ast&);
bool exist(const string&); bool exist(const string&);
void linker(ast&,ast&&); void link(ast&,ast&&);
string path(const ast&); string path(const ast&);
string findf(const string&); string findf(const string&);
ast fimpt(ast&); ast fimpt(ast&);
ast libimpt(); ast libimpt();
ast load(ast&,u16); ast load(ast&,u16);
public: public:
nasal_import(nasal_err&); linker(error&);
void link(nasal_parse&,const string&,bool); void link(parse&,const string&,bool);
const std::vector<string>& filelist() const {return files;} const std::vector<string>& filelist() const {return files;}
}; };
nasal_import::nasal_import(nasal_err& e):lib_loaded(false),nerr(e){ linker::linker(error& e):lib_loaded(false),err(e){
#ifdef _WIN32 #ifdef _WIN32
char sep=';'; char sep=';';
#else #else
@ -55,7 +55,7 @@ nasal_import::nasal_import(nasal_err& e):lib_loaded(false),nerr(e){
envpath.push_back(PATH.substr(last)); envpath.push_back(PATH.substr(last));
} }
string nasal_import::path(const ast& node) string linker::path(const ast& node)
{ {
if(node[1].type()==ast_callf) if(node[1].type()==ast_callf)
return node[1][0].str(); return node[1][0].str();
@ -69,7 +69,7 @@ string nasal_import::path(const ast& node)
return fpath+".nas"; return fpath+".nas";
} }
string nasal_import::findf(const string& fname) string linker::findf(const string& fname)
{ {
std::vector<string> filepath={fname}; std::vector<string> filepath={fname};
for(auto&p:envpath) for(auto&p:envpath)
@ -91,17 +91,17 @@ string nasal_import::findf(const string& fname)
#endif #endif
if(!show_path) if(!show_path)
{ {
nerr.err("link","cannot find file <"+fname+">"); err.err("link","cannot find file <"+fname+">");
return ""; return "";
} }
string paths=""; string paths="";
for(auto& i:filepath) for(auto& i:filepath)
paths+=" "+i+"\n"; paths+=" "+i+"\n";
nerr.err("link","cannot find file <"+fname+"> in these paths:\n"+paths); err.err("link","cannot find file <"+fname+"> in these paths:\n"+paths);
return ""; return "";
} }
bool nasal_import::imptchk(const ast& node) bool linker::imptchk(const ast& node)
{ {
// only these two kinds of node can be recognized as 'import': // only these two kinds of node can be recognized as 'import':
/* /*
@ -133,7 +133,7 @@ bool nasal_import::imptchk(const ast& node)
); );
} }
bool nasal_import::exist(const string& file) bool linker::exist(const string& file)
{ {
// avoid importing the same file // avoid importing the same file
for(auto& fname:files) for(auto& fname:files)
@ -143,17 +143,17 @@ bool nasal_import::exist(const string& file)
return false; return false;
} }
void nasal_import::linker(ast& root,ast&& add_root) void linker::link(ast& root,ast&& add_root)
{ {
// add children of add_root to the back of root // add children of add_root to the back of root
for(auto& i:add_root.child()) for(auto& i:add_root.child())
root.add(std::move(i)); root.add(std::move(i));
} }
ast nasal_import::fimpt(ast& node) ast linker::fimpt(ast& node)
{ {
nasal_lexer lex(nerr); lexer lex(err);
nasal_parse par(nerr); parse par(err);
// get filename and set node to ast_null // get filename and set node to ast_null
string filename=path(node); string filename=path(node);
node.clear(); node.clear();
@ -171,10 +171,10 @@ ast nasal_import::fimpt(ast& node)
return load(tmp,files.size()-1); return load(tmp,files.size()-1);
} }
ast nasal_import::libimpt() ast linker::libimpt()
{ {
nasal_lexer lex(nerr); lexer lex(err);
nasal_parse par(nerr); parse par(err);
string filename=findf("lib.nas"); string filename=findf("lib.nas");
if(!filename.length()) if(!filename.length())
return {0,0,ast_root}; return {0,0,ast_root};
@ -191,18 +191,18 @@ ast nasal_import::libimpt()
return load(tmp,files.size()-1); return load(tmp,files.size()-1);
} }
ast nasal_import::load(ast& root,u16 fileindex) ast linker::load(ast& root,u16 fileindex)
{ {
ast new_root(0,0,ast_root); ast new_root(0,0,ast_root);
if(!lib_loaded) if(!lib_loaded)
{ {
linker(new_root,libimpt()); link(new_root,libimpt());
lib_loaded=true; lib_loaded=true;
} }
for(auto& i:root.child()) for(auto& i:root.child())
{ {
if(imptchk(i)) if(imptchk(i))
linker(new_root,fimpt(i)); link(new_root,fimpt(i));
else else
break; break;
} }
@ -210,11 +210,11 @@ ast nasal_import::load(ast& root,u16 fileindex)
ast file_head(0,0,ast_file); ast file_head(0,0,ast_file);
file_head.set_num(fileindex); file_head.set_num(fileindex);
new_root.add(std::move(file_head)); new_root.add(std::move(file_head));
linker(new_root,std::move(root)); link(new_root,std::move(root));
return new_root; return new_root;
} }
void nasal_import::link(nasal_parse& parse,const string& self,bool spath=false) void linker::link(parse& parse,const string& self,bool spath=false)
{ {
show_path=spath; show_path=spath;
// initializing // initializing
@ -222,7 +222,7 @@ void nasal_import::link(nasal_parse& parse,const string& self,bool spath=false)
// scan root and import files,then generate a new ast and return to import_ast // scan root and import files,then generate a new ast and return to import_ast
// the main file's index is 0 // the main file's index is 0
parse.tree()=load(parse.tree(),0); parse.tree()=load(parse.tree(),0);
nerr.chkerr(); err.chkerr();
} }
#endif #endif

View File

@ -115,54 +115,52 @@ struct token
} }
}; };
class nasal_lexer class lexer
{ {
private: private:
u32 line; u32 line;
u32 column; u32 column;
usize ptr; usize ptr;
string res; string res;
nasal_err& nerr; error& err;
std::vector<token> tokens; std::vector<token> tokens;
u32 get_type(const string&); u32 get_type(const string&);
void die(const string& info){nerr.err("lexer",line,column,info);} void die(const string& info){err.err("lexer",line,column,info);}
void open(const string&); void open(const string&);
string utf8_gen(); string utf8_gen();
string id_gen(); string id_gen();
string num_gen(); string num_gen();
string str_gen(); string str_gen();
public: public:
nasal_lexer(nasal_err& e): lexer(error& e):
line(1), line(1),column(0),
column(0), ptr(0),res(""),
ptr(0), err(e){}
res(""),
nerr(e){}
void scan(const string&); void scan(const string&);
void print(); void print();
const std::vector<token>& result() const {return tokens;} const std::vector<token>& result() const {return tokens;}
}; };
void nasal_lexer::open(const string& file) void lexer::open(const string& file)
{ {
struct stat buffer; struct stat buffer;
if(stat(file.c_str(),&buffer)==0 && !S_ISREG(buffer.st_mode)) if(stat(file.c_str(),&buffer)==0 && !S_ISREG(buffer.st_mode))
{ {
nerr.err("lexer","<"+file+"> is not a regular file"); err.err("lexer","<"+file+"> is not a regular file");
nerr.chkerr(); err.chkerr();
} }
std::ifstream fin(file,std::ios::binary); std::ifstream fin(file,std::ios::binary);
if(fin.fail()) if(fin.fail())
nerr.err("lexer","failed to open <"+file+">"); err.err("lexer","failed to open <"+file+">");
else else
nerr.load(file); err.load(file);
std::stringstream ss; std::stringstream ss;
ss<<fin.rdbuf(); ss<<fin.rdbuf();
res=ss.str(); res=ss.str();
} }
u32 nasal_lexer::get_type(const string& str) u32 lexer::get_type(const string& str)
{ {
for(u32 i=0;tok_table[i].str;++i) for(u32 i=0;tok_table[i].str;++i)
if(str==tok_table[i].str) if(str==tok_table[i].str)
@ -170,7 +168,7 @@ u32 nasal_lexer::get_type(const string& str)
return tok_null; return tok_null;
} }
string nasal_lexer::utf8_gen() string lexer::utf8_gen()
{ {
string str=""; string str="";
while(ptr<res.size() && res[ptr]<0) while(ptr<res.size() && res[ptr]<0)
@ -204,7 +202,7 @@ string nasal_lexer::utf8_gen()
return str; return str;
} }
string nasal_lexer::id_gen() string lexer::id_gen()
{ {
string str=""; string str="";
while(ptr<res.size() && (ID(res[ptr])||DIGIT(res[ptr]))) while(ptr<res.size() && (ID(res[ptr])||DIGIT(res[ptr])))
@ -220,7 +218,7 @@ string nasal_lexer::id_gen()
return str; return str;
} }
string nasal_lexer::num_gen() string lexer::num_gen()
{ {
// generate hex number // generate hex number
if(ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='x') if(ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='x')
@ -283,7 +281,7 @@ string nasal_lexer::num_gen()
return str; return str;
} }
string nasal_lexer::str_gen() string lexer::str_gen()
{ {
string str=""; string str="";
const char begin=res[ptr]; const char begin=res[ptr];
@ -333,7 +331,7 @@ string nasal_lexer::str_gen()
return str; return str;
} }
void nasal_lexer::scan(const string& file) void lexer::scan(const string& file)
{ {
line=1; line=1;
column=0; column=0;
@ -409,10 +407,10 @@ void nasal_lexer::scan(const string& file)
} }
tokens.push_back({line,column,tok_eof,"eof"}); tokens.push_back({line,column,tok_eof,"eof"});
res=""; res="";
nerr.chkerr(); err.chkerr();
} }
void nasal_lexer::print() void lexer::print()
{ {
for(auto& tok:tokens) for(auto& tok:tokens)
std::cout<<"("<<tok.line<<" | "<<rawstr(tok.str,128)<<")\n"; std::cout<<"("<<tok.line<<" | "<<rawstr(tok.str,128)<<")\n";

View File

@ -38,7 +38,7 @@
`"` `"` `"` `"`
*/ */
class nasal_parse class parse
{ {
#define error_line (tokens[ptr].line) #define error_line (tokens[ptr].line)
#define is_call(type) ((type)==tok_lcurve || (type)==tok_lbracket || (type)==tok_dot) #define is_call(type) ((type)==tok_lcurve || (type)==tok_lbracket || (type)==tok_dot)
@ -46,12 +46,13 @@ private:
u32 ptr; u32 ptr;
u32 in_func; // count function block u32 in_func; // count function block
u32 in_loop; // count loop block u32 in_loop; // count loop block
const token* tokens;// ref from nasal_lexer const token* tokens;// ref from lexer
ast root; ast root;
nasal_err& nerr; error& err;
void die(u32,string,bool); void die(u32,string,bool);
void match(u32 type,const char* info=nullptr); void match(u32 type,const char* info=nullptr);
bool lookahead(u32 type);
bool check_comma(const u32*); bool check_comma(const u32*);
bool check_multi_scalar(); bool check_multi_scalar();
bool check_func_end(const ast&); bool check_func_end(const ast&);
@ -100,46 +101,47 @@ private:
ast break_expr(); ast break_expr();
ast ret_expr(); ast ret_expr();
public: public:
nasal_parse(nasal_err& e): parse(error& e):
ptr(0),in_func(0),in_loop(0), ptr(0),in_func(0),in_loop(0),
tokens(nullptr),root(0,0,ast_root),nerr(e){} tokens(nullptr),root(0,0,ast_root),
err(e){}
void print(){root.print_tree();} void print(){root.print_tree();}
void compile(const nasal_lexer&); void compile(const lexer&);
ast& tree(){return root;} ast& tree(){return root;}
const ast& tree() const {return root;} const ast& tree() const {return root;}
}; };
void nasal_parse::compile(const nasal_lexer& lexer) void parse::compile(const lexer& lexer)
{ {
tokens=lexer.result().data(); tokens=lexer.result().data();
ptr=in_func=in_loop=0; ptr=in_func=in_loop=0;
root={0,0,ast_root}; root={0,0,ast_root};
while(tokens[ptr].type!=tok_eof) while(!lookahead(tok_eof))
{ {
root.add(expr()); root.add(expr());
if(tokens[ptr].type==tok_semi) if(lookahead(tok_semi))
match(tok_semi); match(tok_semi);
// the last expression can be recognized without semi // the last expression can be recognized without semi
else if(need_semi_check(root.child().back()) && tokens[ptr].type!=tok_eof) else if(need_semi_check(root.child().back()) && !lookahead(tok_eof))
die(error_line,"expected \";\"",true); die(error_line,"expected \";\"",true);
} }
nerr.chkerr(); err.chkerr();
} }
void nasal_parse::die(u32 line,string info,bool report_prev=false) void parse::die(u32 line,string info,bool report_prev=false)
{ {
i32 col=(i32)tokens[ptr].col-(tokens[ptr].type==tok_eof?0:(i32)tokens[ptr].str.length()); i32 col=(i32)tokens[ptr].col-(lookahead(tok_eof)?0:(i32)tokens[ptr].str.length());
if(tokens[ptr].type==tok_str) if(lookahead(tok_str))
col-=2; // tok_str's str has no \" col-=2; // tok_str's str has no \"
if(report_prev && ptr) // used to report lack of ',' ';' if(report_prev && ptr) // used to report lack of ',' ';'
{ {
line=tokens[ptr-1].line; line=tokens[ptr-1].line;
col=tokens[ptr-1].col+1; col=tokens[ptr-1].col+1;
} }
nerr.err("parse",line,col<0?0:col,info); err.err("parse",line,col<0?0:col,info);
} }
void nasal_parse::match(u32 type,const char* info) void parse::match(u32 type,const char* info)
{ {
if(tokens[ptr].type!=type) if(!lookahead(type))
{ {
if(info) if(info)
{ {
@ -155,21 +157,25 @@ void nasal_parse::match(u32 type,const char* info)
} }
return; return;
} }
if(tokens[ptr].type==tok_eof) if(lookahead(tok_eof))
return; return;
++ptr; ++ptr;
} }
bool nasal_parse::check_comma(const u32* panic_set) bool parse::lookahead(u32 type)
{
return tokens[ptr].type==type;
}
bool parse::check_comma(const u32* panic_set)
{ {
for(u32 i=0;panic_set[i];++i) for(u32 i=0;panic_set[i];++i)
if(tokens[ptr].type==panic_set[i]) if(lookahead(panic_set[i]))
{ {
die(error_line,"expected ',' between scalars",true); die(error_line,"expected ',' between scalars",true);
return true; return true;
} }
return false; return false;
} }
bool nasal_parse::check_multi_scalar() bool parse::check_multi_scalar()
{ {
u32 check_ptr=ptr,curve=1,bracket=0,brace=0; u32 check_ptr=ptr,curve=1,bracket=0,brace=0;
while(tokens[++check_ptr].type!=tok_eof && curve) while(tokens[++check_ptr].type!=tok_eof && curve)
@ -188,7 +194,7 @@ bool nasal_parse::check_multi_scalar()
} }
return false; return false;
} }
bool nasal_parse::check_func_end(const ast& node) bool parse::check_func_end(const ast& node)
{ {
u32 type=node.type(); u32 type=node.type();
if(type==ast_func) if(type==ast_func)
@ -212,7 +218,7 @@ bool nasal_parse::check_func_end(const ast& node)
return check_func_end(node.child().back()); return check_func_end(node.child().back());
return false; return false;
} }
bool nasal_parse::check_special_call() bool parse::check_special_call()
{ {
// special call means like this: function_name(a:1,b:2,c:3); // special call means like this: function_name(a:1,b:2,c:3);
u32 check_ptr=ptr,curve=1,bracket=0,brace=0; u32 check_ptr=ptr,curve=1,bracket=0,brace=0;
@ -235,14 +241,14 @@ bool nasal_parse::check_special_call()
} }
return false; return false;
} }
bool nasal_parse::need_semi_check(const ast& node) bool parse::need_semi_check(const ast& node)
{ {
u32 type=node.type(); u32 type=node.type();
if(type==ast_for || type==ast_foreach || type==ast_forindex || type==ast_while || type==ast_conditional) if(type==ast_for || type==ast_foreach || type==ast_forindex || type==ast_while || type==ast_conditional)
return false; return false;
return !check_func_end(node); return !check_func_end(node);
} }
void nasal_parse::check_memory_reachable(const ast& node) void parse::check_memory_reachable(const ast& node)
{ {
if(node.type()==ast_call) if(node.type()==ast_call)
{ {
@ -255,36 +261,36 @@ void nasal_parse::check_memory_reachable(const ast& node)
else if(node.type()!=ast_id) else if(node.type()!=ast_id)
die(node.line(),"bad left-value"); die(node.line(),"bad left-value");
} }
ast nasal_parse::null() ast parse::null()
{ {
return {tokens[ptr].line,tokens[ptr].col,ast_null}; return {tokens[ptr].line,tokens[ptr].col,ast_null};
} }
ast nasal_parse::nil() ast parse::nil()
{ {
return {tokens[ptr].line,tokens[ptr].col,ast_nil}; return {tokens[ptr].line,tokens[ptr].col,ast_nil};
} }
ast nasal_parse::num() ast parse::num()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_num); ast node(tokens[ptr].line,tokens[ptr].col,ast_num);
node.set_num(str2num(tokens[ptr].str.c_str())); node.set_num(str2num(tokens[ptr].str.c_str()));
match(tok_num); match(tok_num);
return node; return node;
} }
ast nasal_parse::str() ast parse::str()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_str); ast node(tokens[ptr].line,tokens[ptr].col,ast_str);
node.set_str(tokens[ptr].str); node.set_str(tokens[ptr].str);
match(tok_str); match(tok_str);
return node; return node;
} }
ast nasal_parse::id() ast parse::id()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_id); ast node(tokens[ptr].line,tokens[ptr].col,ast_id);
node.set_str(tokens[ptr].str); node.set_str(tokens[ptr].str);
match(tok_id); match(tok_id);
return node; return node;
} }
ast nasal_parse::vec() ast parse::vec()
{ {
// panic set for this token is not ',' // panic set for this token is not ','
// this is the FIRST set of calculation // this is the FIRST set of calculation
@ -297,29 +303,29 @@ ast nasal_parse::vec()
}; };
ast node(tokens[ptr].line,tokens[ptr].col,ast_vec); ast node(tokens[ptr].line,tokens[ptr].col,ast_vec);
match(tok_lbracket); match(tok_lbracket);
while(tokens[ptr].type!=tok_rbracket) while(!lookahead(tok_rbracket))
{ {
node.add(calc()); node.add(calc());
if(tokens[ptr].type==tok_comma) if(lookahead(tok_comma))
match(tok_comma); match(tok_comma);
else if(tokens[ptr].type==tok_eof) else if(lookahead(tok_eof))
break; break;
else if(tokens[ptr].type!=tok_rbracket && !check_comma(panic_set)) else if(!lookahead(tok_rbracket) && !check_comma(panic_set))
break; break;
} }
match(tok_rbracket,"expected ']' when generating vector"); match(tok_rbracket,"expected ']' when generating vector");
return node; return node;
} }
ast nasal_parse::hash() ast parse::hash()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_hash); ast node(tokens[ptr].line,tokens[ptr].col,ast_hash);
match(tok_lbrace); match(tok_lbrace);
while(tokens[ptr].type!=tok_rbrace) while(!lookahead(tok_rbrace))
{ {
node.add(pair()); node.add(pair());
if(tokens[ptr].type==tok_comma) if(lookahead(tok_comma))
match(tok_comma); match(tok_comma);
else if(tokens[ptr].type==tok_id || tokens[ptr].type==tok_str)// first set of hashmember else if(lookahead(tok_id) || lookahead(tok_str))// first set of hashmember
die(error_line,"expected ',' between hash members",true); die(error_line,"expected ',' between hash members",true);
else else
break; break;
@ -327,12 +333,12 @@ ast nasal_parse::hash()
match(tok_rbrace,"expected '}' when generating hash"); match(tok_rbrace,"expected '}' when generating hash");
return node; return node;
} }
ast nasal_parse::pair() ast parse::pair()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_pair); ast node(tokens[ptr].line,tokens[ptr].col,ast_pair);
if(tokens[ptr].type==tok_id) if(lookahead(tok_id))
node.add(id()); node.add(id());
else if(tokens[ptr].type==tok_str) else if(lookahead(tok_str))
node.add(str()); node.add(str());
else else
match(tok_id,"expected hashmap key"); match(tok_id,"expected hashmap key");
@ -340,12 +346,12 @@ ast nasal_parse::pair()
node.add(calc()); node.add(calc());
return node; return node;
} }
ast nasal_parse::func() ast parse::func()
{ {
++in_func; ++in_func;
ast node(tokens[ptr].line,tokens[ptr].col,ast_func); ast node(tokens[ptr].line,tokens[ptr].col,ast_func);
match(tok_func); match(tok_func);
if(tokens[ptr].type==tok_lcurve) if(lookahead(tok_lcurve))
node.add(args()); node.add(args());
else else
node.add(null()); node.add(null());
@ -353,17 +359,17 @@ ast nasal_parse::func()
--in_func; --in_func;
return node; return node;
} }
ast nasal_parse::args() ast parse::args()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_args); ast node(tokens[ptr].line,tokens[ptr].col,ast_args);
match(tok_lcurve); match(tok_lcurve);
while(tokens[ptr].type!=tok_rcurve) while(!lookahead(tok_rcurve))
{ {
ast tmp=id(); ast tmp=id();
if(tokens[ptr].type==tok_eq || tokens[ptr].type==tok_ellipsis) if(lookahead(tok_eq) || lookahead(tok_ellipsis))
{ {
ast special_arg(tokens[ptr].line,tokens[ptr].col,ast_null); ast special_arg(tokens[ptr].line,tokens[ptr].col,ast_null);
if(tokens[ptr].type==tok_eq) if(lookahead(tok_eq))
{ {
match(tok_eq); match(tok_eq);
special_arg=std::move(tmp); special_arg=std::move(tmp);
@ -380,9 +386,9 @@ ast nasal_parse::args()
} }
else else
node.add(std::move(tmp)); node.add(std::move(tmp));
if(tokens[ptr].type==tok_comma) if(lookahead(tok_comma))
match(tok_comma); match(tok_comma);
else if(tokens[ptr].type==tok_id)// first set of identifier else if(lookahead(tok_id))// first set of identifier
die(error_line,"expected ',' between identifiers",true); die(error_line,"expected ',' between identifiers",true);
else else
break; break;
@ -430,13 +436,13 @@ ast nasal_parse::args()
} }
return node; return node;
} }
ast nasal_parse::lcurve_expr() ast parse::lcurve_expr()
{ {
if(tokens[ptr+1].type==tok_var) if(tokens[ptr+1].type==tok_var)
return definition(); return definition();
return check_multi_scalar()?multi_assgin():calc(); return check_multi_scalar()?multi_assgin():calc();
} }
ast nasal_parse::expr() ast parse::expr()
{ {
u32 type=tokens[ptr].type; u32 type=tokens[ptr].type;
if((type==tok_break || type==tok_continue) && !in_loop) if((type==tok_break || type==tok_continue) && !in_loop)
@ -472,24 +478,24 @@ ast nasal_parse::expr()
} }
return {tokens[ptr].line,tokens[ptr].col,ast_null}; return {tokens[ptr].line,tokens[ptr].col,ast_null};
} }
ast nasal_parse::exprs() ast parse::exprs()
{ {
if(tokens[ptr].type==tok_eof) if(lookahead(tok_eof))
{ {
die(error_line,"expected expression block"); die(error_line,"expected expression block");
return null(); return null();
} }
ast node(tokens[ptr].line,tokens[ptr].col,ast_block); ast node(tokens[ptr].line,tokens[ptr].col,ast_block);
if(tokens[ptr].type==tok_lbrace) if(lookahead(tok_lbrace))
{ {
match(tok_lbrace); match(tok_lbrace);
while(tokens[ptr].type!=tok_rbrace && tokens[ptr].type!=tok_eof) while(!lookahead(tok_rbrace) && !lookahead(tok_eof))
{ {
node.add(expr()); node.add(expr());
if(tokens[ptr].type==tok_semi) if(lookahead(tok_semi))
match(tok_semi); match(tok_semi);
// the last expression can be recognized without semi // the last expression can be recognized without semi
else if(need_semi_check(node.child().back()) && tokens[ptr].type!=tok_rbrace) else if(need_semi_check(node.child().back()) && !lookahead(tok_rbrace))
die(error_line,"expected ';'",true); die(error_line,"expected ';'",true);
} }
match(tok_rbrace,"expected '}' when generating expressions"); match(tok_rbrace,"expected '}' when generating expressions");
@ -497,15 +503,15 @@ ast nasal_parse::exprs()
else else
{ {
node.add(expr()); node.add(expr());
if(tokens[ptr].type==tok_semi) if(lookahead(tok_semi))
match(tok_semi); match(tok_semi);
} }
return node; return node;
} }
ast nasal_parse::calc() ast parse::calc()
{ {
ast node=or_expr(); ast node=or_expr();
if(tokens[ptr].type==tok_quesmark) if(lookahead(tok_quesmark))
{ {
// trinocular calculation // trinocular calculation
ast tmp(tokens[ptr].line,tokens[ptr].col,ast_trino); ast tmp(tokens[ptr].line,tokens[ptr].col,ast_trino);
@ -528,10 +534,10 @@ ast nasal_parse::calc()
} }
return node; return node;
} }
ast nasal_parse::or_expr() ast parse::or_expr()
{ {
ast node=and_expr(); ast node=and_expr();
while(tokens[ptr].type==tok_or) while(lookahead(tok_or))
{ {
ast tmp(tokens[ptr].line,tokens[ptr].col,ast_or); ast tmp(tokens[ptr].line,tokens[ptr].col,ast_or);
tmp.add(std::move(node)); tmp.add(std::move(node));
@ -541,10 +547,10 @@ ast nasal_parse::or_expr()
} }
return node; return node;
} }
ast nasal_parse::and_expr() ast parse::and_expr()
{ {
ast node=cmp_expr(); ast node=cmp_expr();
while(tokens[ptr].type==tok_and) while(lookahead(tok_and))
{ {
ast tmp(tokens[ptr].line,tokens[ptr].col,ast_and); ast tmp(tokens[ptr].line,tokens[ptr].col,ast_and);
tmp.add(std::move(node)); tmp.add(std::move(node));
@ -554,7 +560,7 @@ ast nasal_parse::and_expr()
} }
return node; return node;
} }
ast nasal_parse::cmp_expr() ast parse::cmp_expr()
{ {
ast node=additive_expr(); ast node=additive_expr();
while(tok_cmpeq<=tokens[ptr].type && tokens[ptr].type<=tok_geq) while(tok_cmpeq<=tokens[ptr].type && tokens[ptr].type<=tok_geq)
@ -568,10 +574,10 @@ ast nasal_parse::cmp_expr()
} }
return node; return node;
} }
ast nasal_parse::additive_expr() ast parse::additive_expr()
{ {
ast node=multive_expr(); ast node=multive_expr();
while(tokens[ptr].type==tok_add || tokens[ptr].type==tok_sub || tokens[ptr].type==tok_link) while(lookahead(tok_add) || lookahead(tok_sub) || lookahead(tok_link))
{ {
ast tmp(tokens[ptr].line,tokens[ptr].col,ast_null); ast tmp(tokens[ptr].line,tokens[ptr].col,ast_null);
switch(tokens[ptr].type) switch(tokens[ptr].type)
@ -587,20 +593,20 @@ ast nasal_parse::additive_expr()
} }
return node; return node;
} }
ast nasal_parse::multive_expr() ast parse::multive_expr()
{ {
ast node=(tokens[ptr].type==tok_sub || tokens[ptr].type==tok_not)?unary():scalar(); ast node=(lookahead(tok_sub) || lookahead(tok_not))?unary():scalar();
while(tokens[ptr].type==tok_mult || tokens[ptr].type==tok_div) while(lookahead(tok_mult) || lookahead(tok_div))
{ {
ast tmp(tokens[ptr].line,tokens[ptr].col,tokens[ptr].type-tok_mult+ast_mult); ast tmp(tokens[ptr].line,tokens[ptr].col,tokens[ptr].type-tok_mult+ast_mult);
tmp.add(std::move(node)); tmp.add(std::move(node));
match(tokens[ptr].type); match(tokens[ptr].type);
tmp.add((tokens[ptr].type==tok_sub || tokens[ptr].type==tok_not)?unary():scalar()); tmp.add((lookahead(tok_sub) || lookahead(tok_not))?unary():scalar());
node=std::move(tmp); node=std::move(tmp);
} }
return node; return node;
} }
ast nasal_parse::unary() ast parse::unary()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_null); ast node(tokens[ptr].line,tokens[ptr].col,ast_null);
switch(tokens[ptr].type) switch(tokens[ptr].type)
@ -608,26 +614,26 @@ ast nasal_parse::unary()
case tok_sub:node.set_type(ast_neg);match(tok_sub);break; case tok_sub:node.set_type(ast_neg);match(tok_sub);break;
case tok_not:node.set_type(ast_not);match(tok_not);break; case tok_not:node.set_type(ast_not);match(tok_not);break;
} }
node.add((tokens[ptr].type==tok_sub || tokens[ptr].type==tok_not)?unary():scalar()); node.add((lookahead(tok_sub) || lookahead(tok_not))?unary():scalar());
return node; return node;
} }
ast nasal_parse::scalar() ast parse::scalar()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_null); ast node(tokens[ptr].line,tokens[ptr].col,ast_null);
if(tokens[ptr].type==tok_nil) {node=nil();match(tok_nil);} if(lookahead(tok_nil)) {node=nil();match(tok_nil);}
else if(tokens[ptr].type==tok_num) node=num(); else if(lookahead(tok_num)) node=num();
else if(tokens[ptr].type==tok_str) node=str(); else if(lookahead(tok_str)) node=str();
else if(tokens[ptr].type==tok_id) node=id(); else if(lookahead(tok_id)) node=id();
else if(tokens[ptr].type==tok_func) node=func(); else if(lookahead(tok_func)) node=func();
else if(tokens[ptr].type==tok_lbracket) node=vec(); else if(lookahead(tok_lbracket)) node=vec();
else if(tokens[ptr].type==tok_lbrace) node=hash(); else if(lookahead(tok_lbrace)) node=hash();
else if(tokens[ptr].type==tok_lcurve) else if(lookahead(tok_lcurve))
{ {
match(tok_lcurve); match(tok_lcurve);
node=calc(); node=calc();
match(tok_rcurve); match(tok_rcurve);
} }
else if(tokens[ptr].type==tok_var) else if(lookahead(tok_var))
{ {
match(tok_var); match(tok_var);
node.set_type(ast_def); node.set_type(ast_def);
@ -641,7 +647,7 @@ ast nasal_parse::scalar()
return node; return node;
} }
// check call and avoid ambiguous syntax // check call and avoid ambiguous syntax
if(is_call(tokens[ptr].type) && !(tokens[ptr].type==tok_lcurve && tokens[ptr+1].type==tok_var)) if(is_call(tokens[ptr].type) && !(lookahead(tok_lcurve) && tokens[ptr+1].type==tok_var))
{ {
ast tmp=std::move(node); ast tmp=std::move(node);
node={tokens[ptr].line,tokens[ptr].col,ast_call}; node={tokens[ptr].line,tokens[ptr].col,ast_call};
@ -651,7 +657,7 @@ ast nasal_parse::scalar()
} }
return node; return node;
} }
ast nasal_parse::call_scalar() ast parse::call_scalar()
{ {
switch(tokens[ptr].type) switch(tokens[ptr].type)
{ {
@ -662,7 +668,7 @@ ast nasal_parse::call_scalar()
// should never run this expression // should never run this expression
return {tokens[ptr].line,tokens[ptr].col,ast_nil}; return {tokens[ptr].line,tokens[ptr].col,ast_nil};
} }
ast nasal_parse::callh() ast parse::callh()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_callh); ast node(tokens[ptr].line,tokens[ptr].col,ast_callh);
match(tok_dot); match(tok_dot);
@ -670,7 +676,7 @@ ast nasal_parse::callh()
match(tok_id,"expected hashmap key"); // get key match(tok_id,"expected hashmap key"); // get key
return node; return node;
} }
ast nasal_parse::callv() ast parse::callv()
{ {
// panic set for this token is not ',' // panic set for this token is not ','
// this is the FIRST set of subvec // this is the FIRST set of subvec
@ -684,14 +690,14 @@ ast nasal_parse::callv()
}; };
ast node(tokens[ptr].line,tokens[ptr].col,ast_callv); ast node(tokens[ptr].line,tokens[ptr].col,ast_callv);
match(tok_lbracket); match(tok_lbracket);
while(tokens[ptr].type!=tok_rbracket) while(!lookahead(tok_rbracket))
{ {
node.add(subvec()); node.add(subvec());
if(tokens[ptr].type==tok_comma) if(lookahead(tok_comma))
match(tok_comma); match(tok_comma);
else if(tokens[ptr].type==tok_eof) else if(lookahead(tok_eof))
break; break;
else if(tokens[ptr].type!=tok_rbracket && !check_comma(panic_set)) else if(!lookahead(tok_rbracket) && !check_comma(panic_set))
break; break;
} }
if(node.size()==0) if(node.size()==0)
@ -699,7 +705,7 @@ ast nasal_parse::callv()
match(tok_rbracket,"expected ']' when calling vector"); match(tok_rbracket,"expected ']' when calling vector");
return node; return node;
} }
ast nasal_parse::callf() ast parse::callf()
{ {
// panic set for this token is not ',' // panic set for this token is not ','
// this is the FIRST set of calculation/hashmember // this is the FIRST set of calculation/hashmember
@ -713,36 +719,36 @@ ast nasal_parse::callf()
ast node(tokens[ptr].line,tokens[ptr].col,ast_callf); ast node(tokens[ptr].line,tokens[ptr].col,ast_callf);
bool special_call=check_special_call(); bool special_call=check_special_call();
match(tok_lcurve); match(tok_lcurve);
while(tokens[ptr].type!=tok_rcurve) while(!lookahead(tok_rcurve))
{ {
node.add(special_call?pair():calc()); node.add(special_call?pair():calc());
if(tokens[ptr].type==tok_comma) if(lookahead(tok_comma))
match(tok_comma); match(tok_comma);
else if(tokens[ptr].type==tok_eof) else if(lookahead(tok_eof))
break; break;
else if(tokens[ptr].type!=tok_rcurve && !check_comma(panic_set)) else if(!lookahead(tok_rcurve) && !check_comma(panic_set))
break; break;
} }
match(tok_rcurve,"expected ')' when calling function"); match(tok_rcurve,"expected ')' when calling function");
return node; return node;
} }
ast nasal_parse::subvec() ast parse::subvec()
{ {
ast node=tokens[ptr].type==tok_colon?nil():calc(); ast node=lookahead(tok_colon)?nil():calc();
if(tokens[ptr].type==tok_colon) if(lookahead(tok_colon))
{ {
ast tmp(node.line(),node.col(),ast_subvec); ast tmp(node.line(),node.col(),ast_subvec);
match(tok_colon); match(tok_colon);
tmp.add(std::move(node)); tmp.add(std::move(node));
tmp.add((tokens[ptr].type==tok_comma || tokens[ptr].type==tok_rbracket)?nil():calc()); tmp.add((lookahead(tok_comma) || lookahead(tok_rbracket))?nil():calc());
node=std::move(tmp); node=std::move(tmp);
} }
return node; return node;
} }
ast nasal_parse::definition() ast parse::definition()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_def); ast node(tokens[ptr].line,tokens[ptr].col,ast_def);
if(tokens[ptr].type==tok_var) if(lookahead(tok_var))
{ {
match(tok_var); match(tok_var);
switch(tokens[ptr].type) switch(tokens[ptr].type)
@ -752,10 +758,10 @@ ast nasal_parse::definition()
default: die(error_line,"expected identifier");break; default: die(error_line,"expected identifier");break;
} }
} }
else if(tokens[ptr].type==tok_lcurve) else if(lookahead(tok_lcurve))
node.add(incurve_def()); node.add(incurve_def());
match(tok_eq); match(tok_eq);
if(tokens[ptr].type==tok_lcurve) if(lookahead(tok_lcurve))
node.add(check_multi_scalar()?multi_scalar(false):calc()); node.add(check_multi_scalar()?multi_scalar(false):calc());
else else
node.add(calc()); node.add(calc());
@ -765,7 +771,7 @@ ast nasal_parse::definition()
die(node[0].line(),"too much or lack values in multi-definition"); die(node[0].line(),"too much or lack values in multi-definition");
return node; return node;
} }
ast nasal_parse::incurve_def() ast parse::incurve_def()
{ {
match(tok_lcurve); match(tok_lcurve);
match(tok_var); match(tok_var);
@ -773,17 +779,17 @@ ast nasal_parse::incurve_def()
match(tok_rcurve); match(tok_rcurve);
return node; return node;
} }
ast nasal_parse::outcurve_def() ast parse::outcurve_def()
{ {
match(tok_lcurve); match(tok_lcurve);
ast node=multi_id(); ast node=multi_id();
match(tok_rcurve); match(tok_rcurve);
return node; return node;
} }
ast nasal_parse::multi_id() ast parse::multi_id()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_multi_id); ast node(tokens[ptr].line,tokens[ptr].col,ast_multi_id);
while(tokens[ptr].type!=tok_eof) while(!lookahead(tok_eof))
{ {
node.add(id()); node.add(id());
if(is_call(tokens[ptr].type)) if(is_call(tokens[ptr].type))
@ -791,16 +797,16 @@ ast nasal_parse::multi_id()
call_scalar();// recognize calls but this is still a syntax error call_scalar();// recognize calls but this is still a syntax error
die(error_line,"cannot call identifier in multi-definition"); die(error_line,"cannot call identifier in multi-definition");
} }
if(tokens[ptr].type==tok_comma) if(lookahead(tok_comma))
match(tok_comma); match(tok_comma);
else if(tokens[ptr].type==tok_id)// first set of identifier else if(lookahead(tok_id))// first set of identifier
die(error_line,"expected ',' between identifiers",true); die(error_line,"expected ',' between identifiers",true);
else else
break; break;
} }
return node; return node;
} }
ast nasal_parse::multi_scalar(bool check_call_memory) ast parse::multi_scalar(bool check_call_memory)
{ {
// if check_call_memory is true,we will check if value called here can reach a memory space // if check_call_memory is true,we will check if value called here can reach a memory space
const u32 panic_set[]={ const u32 panic_set[]={
@ -811,32 +817,32 @@ ast nasal_parse::multi_scalar(bool check_call_memory)
}; };
ast node(tokens[ptr].line,tokens[ptr].col,ast_multi_scalar); ast node(tokens[ptr].line,tokens[ptr].col,ast_multi_scalar);
match(tok_lcurve); match(tok_lcurve);
while(tokens[ptr].type!=tok_rcurve) while(!lookahead(tok_rcurve))
{ {
node.add(calc()); node.add(calc());
if(check_call_memory) if(check_call_memory)
check_memory_reachable(node.child().back()); check_memory_reachable(node.child().back());
if(tokens[ptr].type==tok_comma) if(lookahead(tok_comma))
match(tok_comma); match(tok_comma);
else if(tokens[ptr].type==tok_eof) else if(lookahead(tok_eof))
break; break;
else if(tokens[ptr].type!=tok_rcurve && !check_comma(panic_set)) else if(!lookahead(tok_rcurve) && !check_comma(panic_set))
break; break;
} }
match(tok_rcurve,"expected ')' after multi-scalar"); match(tok_rcurve,"expected ')' after multi-scalar");
return node; return node;
} }
ast nasal_parse::multi_assgin() ast parse::multi_assgin()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_multi_assign); ast node(tokens[ptr].line,tokens[ptr].col,ast_multi_assign);
node.add(multi_scalar(true)); node.add(multi_scalar(true));
match(tok_eq); match(tok_eq);
if(tokens[ptr].type==tok_eof) if(lookahead(tok_eof))
{ {
die(error_line,"expected value list"); die(error_line,"expected value list");
return node; return node;
} }
if(tokens[ptr].type==tok_lcurve) if(lookahead(tok_lcurve))
node.add(check_multi_scalar()?multi_scalar(false):calc()); node.add(check_multi_scalar()?multi_scalar(false):calc());
else else
node.add(calc()); node.add(calc());
@ -845,7 +851,7 @@ ast nasal_parse::multi_assgin()
die(node[0].line(),"too much or lack values in multi-assignment"); die(node[0].line(),"too much or lack values in multi-assignment");
return node; return node;
} }
ast nasal_parse::loop() ast parse::loop()
{ {
++in_loop; ++in_loop;
ast node(0,0,ast_null); ast node(0,0,ast_null);
@ -859,7 +865,7 @@ ast nasal_parse::loop()
--in_loop; --in_loop;
return node; return node;
} }
ast nasal_parse::while_loop() ast parse::while_loop()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_while); ast node(tokens[ptr].line,tokens[ptr].col,ast_while);
match(tok_while); match(tok_while);
@ -869,35 +875,35 @@ ast nasal_parse::while_loop()
node.add(exprs()); node.add(exprs());
return node; return node;
} }
ast nasal_parse::for_loop() ast parse::for_loop()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_for); ast node(tokens[ptr].line,tokens[ptr].col,ast_for);
match(tok_for); match(tok_for);
match(tok_lcurve); match(tok_lcurve);
// first expression // first expression
if(tokens[ptr].type==tok_eof) if(lookahead(tok_eof))
die(error_line,"expected definition"); die(error_line,"expected definition");
if(tokens[ptr].type==tok_semi) if(lookahead(tok_semi))
node.add(null()); node.add(null());
else if(tokens[ptr].type==tok_var) else if(lookahead(tok_var))
node.add(definition()); node.add(definition());
else if(tokens[ptr].type==tok_lcurve) else if(lookahead(tok_lcurve))
node.add(lcurve_expr()); node.add(lcurve_expr());
else else
node.add(calc()); node.add(calc());
match(tok_semi,"expected ';' in for(;;)"); match(tok_semi,"expected ';' in for(;;)");
// conditional expression // conditional expression
if(tokens[ptr].type==tok_eof) if(lookahead(tok_eof))
die(error_line,"expected conditional expr"); die(error_line,"expected conditional expr");
if(tokens[ptr].type==tok_semi) if(lookahead(tok_semi))
node.add(null()); node.add(null());
else else
node.add(calc()); node.add(calc());
match(tok_semi,"expected ';' in for(;;)"); match(tok_semi,"expected ';' in for(;;)");
//after loop expression //after loop expression
if(tokens[ptr].type==tok_eof) if(lookahead(tok_eof))
die(error_line,"expected calculation"); die(error_line,"expected calculation");
if(tokens[ptr].type==tok_rcurve) if(lookahead(tok_rcurve))
node.add(null()); node.add(null());
else else
node.add(calc()); node.add(calc());
@ -905,7 +911,7 @@ ast nasal_parse::for_loop()
node.add(exprs()); node.add(exprs());
return node; return node;
} }
ast nasal_parse::forei_loop() ast parse::forei_loop()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_null); ast node(tokens[ptr].line,tokens[ptr].col,ast_null);
switch(tokens[ptr].type) switch(tokens[ptr].type)
@ -916,21 +922,21 @@ ast nasal_parse::forei_loop()
match(tok_lcurve); match(tok_lcurve);
// first expression // first expression
// foreach/forindex must have an iterator to loop through // foreach/forindex must have an iterator to loop through
if(tokens[ptr].type!=tok_var && tokens[ptr].type!=tok_id) if(!lookahead(tok_var) && !lookahead(tok_id))
die(error_line,"expected iterator"); die(error_line,"expected iterator");
node.add(iter_gen()); node.add(iter_gen());
match(tok_semi,"expected ';' in foreach/forindex(iter;vector)"); match(tok_semi,"expected ';' in foreach/forindex(iter;vector)");
if(tokens[ptr].type==tok_eof) if(lookahead(tok_eof))
die(error_line,"expected vector"); die(error_line,"expected vector");
node.add(calc()); node.add(calc());
match(tok_rcurve); match(tok_rcurve);
node.add(exprs()); node.add(exprs());
return node; return node;
} }
ast nasal_parse::iter_gen() ast parse::iter_gen()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_null); ast node(tokens[ptr].line,tokens[ptr].col,ast_null);
if(tokens[ptr].type==tok_var) if(lookahead(tok_var))
{ {
match(tok_var); match(tok_var);
node.set_type(ast_iter); node.set_type(ast_iter);
@ -946,7 +952,7 @@ ast nasal_parse::iter_gen()
} }
return node; return node;
} }
ast nasal_parse::conditional() ast parse::conditional()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_conditional); ast node(tokens[ptr].line,tokens[ptr].col,ast_conditional);
ast ifnode(tokens[ptr].line,tokens[ptr].col,ast_if); ast ifnode(tokens[ptr].line,tokens[ptr].col,ast_if);
@ -956,7 +962,7 @@ ast nasal_parse::conditional()
match(tok_rcurve); match(tok_rcurve);
ifnode.add(exprs()); ifnode.add(exprs());
node.add(std::move(ifnode)); node.add(std::move(ifnode));
while(tokens[ptr].type==tok_elsif) while(lookahead(tok_elsif))
{ {
ast elsifnode(tokens[ptr].line,tokens[ptr].col,ast_elsif); ast elsifnode(tokens[ptr].line,tokens[ptr].col,ast_elsif);
match(tok_elsif); match(tok_elsif);
@ -966,7 +972,7 @@ ast nasal_parse::conditional()
elsifnode.add(exprs()); elsifnode.add(exprs());
node.add(std::move(elsifnode)); node.add(std::move(elsifnode));
} }
if(tokens[ptr].type==tok_else) if(lookahead(tok_else))
{ {
ast elsenode(tokens[ptr].line,tokens[ptr].col,ast_else); ast elsenode(tokens[ptr].line,tokens[ptr].col,ast_else);
match(tok_else); match(tok_else);
@ -975,19 +981,19 @@ ast nasal_parse::conditional()
} }
return node; return node;
} }
ast nasal_parse::continue_expr() ast parse::continue_expr()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_continue); ast node(tokens[ptr].line,tokens[ptr].col,ast_continue);
match(tok_continue); match(tok_continue);
return node; return node;
} }
ast nasal_parse::break_expr() ast parse::break_expr()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_break); ast node(tokens[ptr].line,tokens[ptr].col,ast_break);
match(tok_break); match(tok_break);
return node; return node;
} }
ast nasal_parse::ret_expr() ast parse::ret_expr()
{ {
ast node(tokens[ptr].line,tokens[ptr].col,ast_ret); ast node(tokens[ptr].line,tokens[ptr].col,ast_ret);
match(tok_ret); match(tok_ret);

View File

@ -5,29 +5,29 @@
#include <stack> #include <stack>
#include "nasal_codegen.h" #include "nasal_codegen.h"
class nasal_vm class vm
{ {
protected: protected:
/* registers and constants of nasal_vm */ /* registers and constants of vm */
u32 pc; // program counter u32 pc; // program counter
nas_ref* localr; // local scope register var* localr; // local scope register
nas_ref* memr; // used for mem_call var* memr; // used for mem_call
nas_ref funcr; // function register var funcr; // function register
nas_ref upvalr; // upvalue register var upvalr; // upvalue register
nas_ref* canary; // avoid stackoverflow var* canary; // avoid stackoverflow
nas_ref* top; // stack top var* top; // stack top
const f64* num_table;// const numbers, ref from nasal_codegen const f64* num_table;// const numbers, ref from codegen
const string* str_table;// const symbols, ref from nasal_codegen const string* str_table;// const symbols, ref from codegen
std::vector<u32> imm; // immediate number std::vector<u32> imm; // immediate number
/* garbage collector */ /* garbage collector */
nasal_gc gc; gc ngc;
/* main stack */ /* main stack */
nas_ref stack[STACK_DEPTH]; var stack[STACK_DEPTH];
/* values used for debugger */ /* values used for debugger */
const string* files; // ref from nasal_import const string* files; // ref from linker
const opcode* bytecode; // ref from nasal_codegen const opcode* bytecode; // ref from codegen
void init( void init(
const std::vector<string>&, const std::vector<string>&,
@ -37,7 +37,7 @@ protected:
const std::vector<string>&); const std::vector<string>&);
/* debug functions */ /* debug functions */
bool detail_info; bool detail_info;
void valinfo(nas_ref&); void valinfo(var&);
void traceback(); void traceback();
void stackinfo(const u32); void stackinfo(const u32);
void reginfo(); void reginfo();
@ -48,7 +48,7 @@ protected:
void die(const string&); void die(const string&);
#define vm_error(info) {die(info);return;} #define vm_error(info) {die(info);return;}
/* vm calculation functions*/ /* vm calculation functions*/
bool condition(nas_ref); bool condition(var);
/* vm operands */ /* vm operands */
void o_intg(); void o_intg();
void o_intl(); void o_intl();
@ -125,26 +125,26 @@ protected:
void o_mcallh(); void o_mcallh();
void o_ret(); void o_ret();
public: public:
nasal_vm():pc(0),localr(nullptr),memr(nullptr),funcr(nil), vm():pc(0),localr(nullptr),memr(nullptr),funcr(nil),
upvalr(nil),canary(nullptr),top(stack), upvalr(nil),canary(nullptr),top(stack),
num_table(nullptr),str_table(nullptr), num_table(nullptr),str_table(nullptr),
gc(pc,localr,memr,funcr,upvalr,canary,top,stack), ngc(pc,localr,memr,funcr,upvalr,canary,top,stack),
files(nullptr),bytecode(nullptr),detail_info(false){} files(nullptr),bytecode(nullptr),detail_info(false){}
void run( void run(
const nasal_codegen&, const codegen&,
const nasal_import&, const linker&,
const std::vector<string>&, const std::vector<string>&,
const bool); const bool);
}; };
void nasal_vm::init( void vm::init(
const std::vector<string>& strs, const std::vector<string>& strs,
const std::vector<f64>& nums, const std::vector<f64>& nums,
const std::vector<opcode>& code, const std::vector<opcode>& code,
const std::vector<string>& filenames, const std::vector<string>& filenames,
const std::vector<string>& argv) const std::vector<string>& argv)
{ {
gc.init(strs,argv); ngc.init(strs,argv);
num_table=nums.data(); num_table=nums.data();
str_table=strs.data(); str_table=strs.data();
bytecode=code.data(); bytecode=code.data();
@ -161,7 +161,7 @@ void nasal_vm::init(
for(u32 i=0;i<STACK_DEPTH;++i) for(u32 i=0;i<STACK_DEPTH;++i)
stack[i]=nil; stack[i]=nil;
} }
void nasal_vm::valinfo(nas_ref& val) void vm::valinfo(var& val)
{ {
const nas_val* p=val.val.gcobj; const nas_val* p=val.val.gcobj;
std::cout<<"\t"; std::cout<<"\t";
@ -199,17 +199,17 @@ void nasal_vm::valinfo(nas_ref& val)
} }
std::cout<<"\n"; std::cout<<"\n";
} }
void nasal_vm::traceback() void vm::traceback()
{ {
/* bytecode[0].num is the global size */ /* bytecode[0].num is the global size */
nas_ref* bottom=gc.stack==stack?stack+bytecode[0].num:gc.stack; var* bottom=ngc.stack==stack?stack+bytecode[0].num:ngc.stack;
nas_ref* ctx_top=gc.stack==stack?top:gc.top; var* ctx_top=ngc.stack==stack?top:ngc.top;
std::stack<u32> ret; std::stack<u32> ret;
for(nas_ref* i=bottom;i<=ctx_top;++i) for(var* i=bottom;i<=ctx_top;++i)
if(i->type==vm_ret && i->ret()!=0) if(i->type==vm_ret && i->ret()!=0)
ret.push(i->ret()); ret.push(i->ret());
ret.push(pc); // store the position program crashed ret.push(pc); // store the position program crashed
std::cout<<"trace back ("<<(gc.stack==stack?"main":"coroutine")<<")\n"; std::cout<<"trace back ("<<(ngc.stack==stack?"main":"coroutine")<<")\n";
for(u32 p=0,same=0,prev=0xffffffff;!ret.empty();prev=p,ret.pop()) for(u32 p=0,same=0,prev=0xffffffff;!ret.empty();prev=p,ret.pop())
{ {
if((p=ret.top())==prev) if((p=ret.top())==prev)
@ -226,12 +226,12 @@ void nasal_vm::traceback()
} }
// the first called place has no same calls // the first called place has no same calls
} }
void nasal_vm::stackinfo(const u32 limit=10) void vm::stackinfo(const u32 limit=10)
{ {
/* bytecode[0].num is the global size */ /* bytecode[0].num is the global size */
const u32 gsize=gc.stack==stack?bytecode[0].num:0; const u32 gsize=ngc.stack==stack?bytecode[0].num:0;
nas_ref* t=top; var* t=top;
nas_ref* bottom=gc.stack+gsize; var* bottom=ngc.stack+gsize;
std::cout<<"vm stack (0x"<<std::hex<<(u64)bottom<<std::dec std::cout<<"vm stack (0x"<<std::hex<<(u64)bottom<<std::dec
<<" <sp+"<<gsize<<">, limit "<<limit<<", total " <<" <sp+"<<gsize<<">, limit "<<limit<<", total "
<<(t<bottom? 0:(i64)(t-bottom+1))<<")\n"; <<(t<bottom? 0:(i64)(t-bottom+1))<<")\n";
@ -239,13 +239,13 @@ void nasal_vm::stackinfo(const u32 limit=10)
{ {
std::cout<<" 0x"<<std::hex std::cout<<" 0x"<<std::hex
<<std::setw(8)<<std::setfill('0') <<std::setw(8)<<std::setfill('0')
<<(u64)(t-gc.stack)<<std::dec; <<(u64)(t-ngc.stack)<<std::dec;
valinfo(t[0]); valinfo(t[0]);
} }
} }
void nasal_vm::reginfo() void vm::reginfo()
{ {
std::cout<<"registers ("<<(gc.cort?"coroutine":"main")<<")\n"<<std::hex std::cout<<"registers ("<<(ngc.cort?"coroutine":"main")<<")\n"<<std::hex
<<" [ pc ] | pc | 0x"<<pc<<"\n" <<" [ pc ] | pc | 0x"<<pc<<"\n"
<<" [ global ] | addr | 0x"<<(u64)stack<<"\n" <<" [ global ] | addr | 0x"<<(u64)stack<<"\n"
<<" [ localr ] | addr | 0x"<<(u64)localr<<"\n" <<" [ localr ] | addr | 0x"<<(u64)localr<<"\n"
@ -256,7 +256,7 @@ void nasal_vm::reginfo()
std::cout<<" [ funcr ]";valinfo(funcr); std::cout<<" [ funcr ]";valinfo(funcr);
std::cout<<" [ upvalr ]";valinfo(upvalr); std::cout<<" [ upvalr ]";valinfo(upvalr);
} }
void nasal_vm::gstate() void vm::gstate()
{ {
if(!bytecode[0].num || stack[0].type==vm_none) // bytecode[0].op is op_intg if(!bytecode[0].num || stack[0].type==vm_none) // bytecode[0].op is op_intg
return; return;
@ -268,13 +268,13 @@ void nasal_vm::gstate()
valinfo(stack[i]); valinfo(stack[i]);
} }
} }
void nasal_vm::lstate() void vm::lstate()
{ {
if(!localr || !funcr.func().lsize) if(!localr || !funcr.func().lsize)
return; return;
const u32 lsize=funcr.func().lsize; const u32 lsize=funcr.func().lsize;
std::cout<<"local (0x"<<std::hex<<(u64)localr std::cout<<"local (0x"<<std::hex<<(u64)localr
<<" <sp+"<<(u64)(localr-gc.stack)<<">)\n"<<std::dec; <<" <sp+"<<(u64)(localr-ngc.stack)<<">)\n"<<std::dec;
for(u32 i=0;i<lsize;++i) for(u32 i=0;i<lsize;++i)
{ {
std::cout<<" 0x"<<std::hex<<std::setw(8) std::cout<<" 0x"<<std::hex<<std::setw(8)
@ -282,7 +282,7 @@ void nasal_vm::lstate()
valinfo(localr[i]); valinfo(localr[i]);
} }
} }
void nasal_vm::ustate() void vm::ustate()
{ {
if(funcr.type==vm_nil || funcr.func().upval.empty()) if(funcr.type==vm_nil || funcr.func().upval.empty())
return; return;
@ -300,29 +300,29 @@ void nasal_vm::ustate()
} }
} }
} }
void nasal_vm::detail() void vm::detail()
{ {
reginfo(); reginfo();
gstate(); gstate();
lstate(); lstate();
ustate(); ustate();
} }
void nasal_vm::die(const string& str) void vm::die(const string& str)
{ {
std::cout<<"[vm] error: "<<str<<"\n"; std::cout<<"[vm] error: "<<str<<"\n";
traceback(); traceback();
stackinfo(); stackinfo();
if(detail_info) if(detail_info)
detail(); detail();
if(gc.stack==stack){ if(ngc.stack==stack){
std::exit(1); std::exit(1);
}else{ }else{
pc=0; // mark coroutine 'dead' pc=0; // mark coroutine 'dead'
gc.ctxreserve(); ngc.ctxreserve();
top[0]=nil; top[0]=nil;
} }
} }
inline bool nasal_vm::condition(nas_ref val) inline bool vm::condition(var val)
{ {
if(val.type==vm_num) if(val.type==vm_num)
return val.num(); return val.num();
@ -333,45 +333,45 @@ inline bool nasal_vm::condition(nas_ref val)
} }
return false; return false;
} }
inline void nasal_vm::o_intg() inline void vm::o_intg()
{ {
// global values store on stack // global values store on stack
top+=imm[pc]; top+=imm[pc];
--top;// point to the top --top;// point to the top
} }
inline void nasal_vm::o_intl() inline void vm::o_intl()
{ {
top[0].func().local.resize(imm[pc],nil); top[0].func().local.resize(imm[pc],nil);
top[0].func().lsize=imm[pc]; top[0].func().lsize=imm[pc];
} }
inline void nasal_vm::o_loadg() inline void vm::o_loadg()
{ {
stack[imm[pc]]=(top--)[0]; stack[imm[pc]]=(top--)[0];
} }
inline void nasal_vm::o_loadl() inline void vm::o_loadl()
{ {
localr[imm[pc]]=(top--)[0]; localr[imm[pc]]=(top--)[0];
} }
inline void nasal_vm::o_loadu() inline void vm::o_loadu()
{ {
funcr.func().upval[(imm[pc]>>16)&0xffff] funcr.func().upval[(imm[pc]>>16)&0xffff]
.upval()[imm[pc]&0xffff]=(top--)[0]; .upval()[imm[pc]&0xffff]=(top--)[0];
} }
inline void nasal_vm::o_pnum() inline void vm::o_pnum()
{ {
(++top)[0]={vm_num,num_table[imm[pc]]}; (++top)[0]={vm_num,num_table[imm[pc]]};
} }
inline void nasal_vm::o_pnil() inline void vm::o_pnil()
{ {
(++top)[0]=nil; (++top)[0]=nil;
} }
inline void nasal_vm::o_pstr() inline void vm::o_pstr()
{ {
(++top)[0]=gc.strs[imm[pc]]; (++top)[0]=ngc.strs[imm[pc]];
} }
inline void nasal_vm::o_newv() inline void vm::o_newv()
{ {
nas_ref newv=gc.alloc(vm_vec); var newv=ngc.alloc(vm_vec);
auto& vec=newv.vec().elems; auto& vec=newv.vec().elems;
vec.resize(imm[pc]); vec.resize(imm[pc]);
// use top-=imm[pc]-1 here will cause error if imm[pc] is 0 // use top-=imm[pc]-1 here will cause error if imm[pc] is 0
@ -380,13 +380,13 @@ inline void nasal_vm::o_newv()
vec[i]=top[i]; vec[i]=top[i];
top[0]=newv; top[0]=newv;
} }
inline void nasal_vm::o_newh() inline void vm::o_newh()
{ {
(++top)[0]=gc.alloc(vm_hash); (++top)[0]=ngc.alloc(vm_hash);
} }
inline void nasal_vm::o_newf() inline void vm::o_newf()
{ {
(++top)[0]=gc.alloc(vm_func); (++top)[0]=ngc.alloc(vm_func);
nas_func& func=top[0].func(); nas_func& func=top[0].func();
func.entry=imm[pc]; func.entry=imm[pc];
func.psize=1; func.psize=1;
@ -395,40 +395,40 @@ inline void nasal_vm::o_newf()
if(localr) if(localr)
{ {
func.upval=funcr.func().upval; func.upval=funcr.func().upval;
nas_ref upval=(upvalr.type==vm_nil)?gc.alloc(vm_upval):upvalr; var upval=(upvalr.type==vm_nil)?ngc.alloc(vm_upval):upvalr;
upval.upval().size=funcr.func().lsize; upval.upval().size=funcr.func().lsize;
upval.upval().stk=localr; upval.upval().stk=localr;
func.upval.push_back(upval); func.upval.push_back(upval);
upvalr=upval; upvalr=upval;
} }
} }
inline void nasal_vm::o_happ() inline void vm::o_happ()
{ {
top[-1].hash().elems[str_table[imm[pc]]]=top[0]; top[-1].hash().elems[str_table[imm[pc]]]=top[0];
--top; --top;
} }
inline void nasal_vm::o_para() inline void vm::o_para()
{ {
nas_func& func=top[0].func(); nas_func& func=top[0].func();
// func->size has 1 place reserved for "me" // func->size has 1 place reserved for "me"
func.keys[imm[pc]]=func.psize; func.keys[imm[pc]]=func.psize;
func.local[func.psize++]={vm_none}; func.local[func.psize++]={vm_none};
} }
inline void nasal_vm::o_deft() inline void vm::o_deft()
{ {
nas_ref val=top[0]; var val=top[0];
nas_func& func=(--top)[0].func(); nas_func& func=(--top)[0].func();
// func->size has 1 place reserved for "me" // func->size has 1 place reserved for "me"
func.keys[imm[pc]]=func.psize; func.keys[imm[pc]]=func.psize;
func.local[func.psize++]=val; func.local[func.psize++]=val;
} }
inline void nasal_vm::o_dyn() inline void vm::o_dyn()
{ {
top[0].func().dpara=imm[pc]; top[0].func().dpara=imm[pc];
} }
inline void nasal_vm::o_unot() inline void vm::o_unot()
{ {
nas_ref val=top[0]; var val=top[0];
switch(val.type) switch(val.type)
{ {
case vm_nil:top[0]=one;break; case vm_nil:top[0]=one;break;
@ -444,7 +444,7 @@ inline void nasal_vm::o_unot()
default:vm_error("incorrect value type");break; default:vm_error("incorrect value type");break;
} }
} }
inline void nasal_vm::o_usub() inline void vm::o_usub()
{ {
top[0]={vm_num,-top[0].tonum()}; top[0]={vm_num,-top[0].tonum()};
} }
@ -453,26 +453,26 @@ inline void nasal_vm::o_usub()
top[-1]={vm_num,top[-1].tonum() type top[0].tonum()};\ top[-1]={vm_num,top[-1].tonum() type top[0].tonum()};\
--top; --top;
inline void nasal_vm::o_add(){op_calc(+);} inline void vm::o_add(){op_calc(+);}
inline void nasal_vm::o_sub(){op_calc(-);} inline void vm::o_sub(){op_calc(-);}
inline void nasal_vm::o_mul(){op_calc(*);} inline void vm::o_mul(){op_calc(*);}
inline void nasal_vm::o_div(){op_calc(/);} inline void vm::o_div(){op_calc(/);}
inline void nasal_vm::o_lnk() inline void vm::o_lnk()
{ {
top[-1]=gc.newstr(top[-1].tostr()+top[0].tostr()); top[-1]=ngc.newstr(top[-1].tostr()+top[0].tostr());
--top; --top;
} }
#define op_calc_const(type)\ #define op_calc_const(type)\
top[0]={vm_num,top[0].tonum() type num_table[imm[pc]]}; top[0]={vm_num,top[0].tonum() type num_table[imm[pc]]};
inline void nasal_vm::o_addc(){op_calc_const(+);} inline void vm::o_addc(){op_calc_const(+);}
inline void nasal_vm::o_subc(){op_calc_const(-);} inline void vm::o_subc(){op_calc_const(-);}
inline void nasal_vm::o_mulc(){op_calc_const(*);} inline void vm::o_mulc(){op_calc_const(*);}
inline void nasal_vm::o_divc(){op_calc_const(/);} inline void vm::o_divc(){op_calc_const(/);}
inline void nasal_vm::o_lnkc() inline void vm::o_lnkc()
{ {
top[0]=gc.newstr(top[0].tostr()+str_table[imm[pc]]); top[0]=ngc.newstr(top[0].tostr()+str_table[imm[pc]]);
} }
#define op_calc_eq(type)\ #define op_calc_eq(type)\
@ -480,13 +480,13 @@ inline void nasal_vm::o_lnkc()
memr=nullptr;\ memr=nullptr;\
top-=imm[pc]+1; top-=imm[pc]+1;
inline void nasal_vm::o_addeq(){op_calc_eq(+);} inline void vm::o_addeq(){op_calc_eq(+);}
inline void nasal_vm::o_subeq(){op_calc_eq(-);} inline void vm::o_subeq(){op_calc_eq(-);}
inline void nasal_vm::o_muleq(){op_calc_eq(*);} inline void vm::o_muleq(){op_calc_eq(*);}
inline void nasal_vm::o_diveq(){op_calc_eq(/);} inline void vm::o_diveq(){op_calc_eq(/);}
inline void nasal_vm::o_lnkeq() inline void vm::o_lnkeq()
{ {
top[-1]=memr[0]=gc.newstr(memr[0].tostr()+top[-1].tostr()); top[-1]=memr[0]=ngc.newstr(memr[0].tostr()+top[-1].tostr());
memr=nullptr; memr=nullptr;
top-=imm[pc]+1; top-=imm[pc]+1;
} }
@ -496,18 +496,18 @@ inline void nasal_vm::o_lnkeq()
memr=nullptr;\ memr=nullptr;\
top-=(imm[pc]>>31); top-=(imm[pc]>>31);
inline void nasal_vm::o_addeqc(){op_calc_eq_const(+);} inline void vm::o_addeqc(){op_calc_eq_const(+);}
inline void nasal_vm::o_subeqc(){op_calc_eq_const(-);} inline void vm::o_subeqc(){op_calc_eq_const(-);}
inline void nasal_vm::o_muleqc(){op_calc_eq_const(*);} inline void vm::o_muleqc(){op_calc_eq_const(*);}
inline void nasal_vm::o_diveqc(){op_calc_eq_const(/);} inline void vm::o_diveqc(){op_calc_eq_const(/);}
inline void nasal_vm::o_lnkeqc() inline void vm::o_lnkeqc()
{ {
top[0]=memr[0]=gc.newstr(memr[0].tostr()+str_table[imm[pc]&0x7fffffff]); top[0]=memr[0]=ngc.newstr(memr[0].tostr()+str_table[imm[pc]&0x7fffffff]);
memr=nullptr; memr=nullptr;
top-=(imm[pc]>>31); top-=(imm[pc]>>31);
} }
inline void nasal_vm::o_meq() inline void vm::o_meq()
{ {
// pop old memr[0] and replace it // pop old memr[0] and replace it
// the reason why we should get memr and push the old value on stack // the reason why we should get memr and push the old value on stack
@ -518,10 +518,10 @@ inline void nasal_vm::o_meq()
memr=nullptr; memr=nullptr;
top-=imm[pc]+1; top-=imm[pc]+1;
} }
inline void nasal_vm::o_eq() inline void vm::o_eq()
{ {
nas_ref val2=top[0]; var val2=top[0];
nas_ref val1=(--top)[0]; var val1=(--top)[0];
if(val1.type==vm_nil && val2.type==vm_nil) if(val1.type==vm_nil && val2.type==vm_nil)
top[0]=one; top[0]=one;
else if(val1.type==vm_str && val2.type==vm_str) else if(val1.type==vm_str && val2.type==vm_str)
@ -532,10 +532,10 @@ inline void nasal_vm::o_eq()
else else
top[0]=(val1==val2)?one:zero; top[0]=(val1==val2)?one:zero;
} }
inline void nasal_vm::o_neq() inline void vm::o_neq()
{ {
nas_ref val2=top[0]; var val2=top[0];
nas_ref val1=(--top)[0]; var val1=(--top)[0];
if(val1.type==vm_nil && val2.type==vm_nil) if(val1.type==vm_nil && val2.type==vm_nil)
top[0]=zero; top[0]=zero;
else if(val1.type==vm_str && val2.type==vm_str) else if(val1.type==vm_str && val2.type==vm_str)
@ -551,45 +551,45 @@ inline void nasal_vm::o_neq()
--top;\ --top;\
top[0]=(top[0].tonum() type top[1].tonum())?one:zero; top[0]=(top[0].tonum() type top[1].tonum())?one:zero;
inline void nasal_vm::o_less(){op_cmp(<);} inline void vm::o_less(){op_cmp(<);}
inline void nasal_vm::o_leq(){op_cmp(<=);} inline void vm::o_leq(){op_cmp(<=);}
inline void nasal_vm::o_grt(){op_cmp(>);} inline void vm::o_grt(){op_cmp(>);}
inline void nasal_vm::o_geq(){op_cmp(>=);} inline void vm::o_geq(){op_cmp(>=);}
#define op_cmp_const(type)\ #define op_cmp_const(type)\
top[0]=(top[0].tonum() type num_table[imm[pc]])?one:zero; top[0]=(top[0].tonum() type num_table[imm[pc]])?one:zero;
inline void nasal_vm::o_lessc(){op_cmp_const(<);} inline void vm::o_lessc(){op_cmp_const(<);}
inline void nasal_vm::o_leqc(){op_cmp_const(<=);} inline void vm::o_leqc(){op_cmp_const(<=);}
inline void nasal_vm::o_grtc(){op_cmp_const(>);} inline void vm::o_grtc(){op_cmp_const(>);}
inline void nasal_vm::o_geqc(){op_cmp_const(>=);} inline void vm::o_geqc(){op_cmp_const(>=);}
inline void nasal_vm::o_pop() inline void vm::o_pop()
{ {
--top; --top;
} }
inline void nasal_vm::o_jmp() inline void vm::o_jmp()
{ {
pc=imm[pc]-1; pc=imm[pc]-1;
} }
inline void nasal_vm::o_jt() inline void vm::o_jt()
{ {
if(condition(top[0])) if(condition(top[0]))
pc=imm[pc]-1; pc=imm[pc]-1;
} }
inline void nasal_vm::o_jf() inline void vm::o_jf()
{ {
if(!condition(top[0])) if(!condition(top[0]))
pc=imm[pc]-1; pc=imm[pc]-1;
--top; --top;
} }
inline void nasal_vm::o_cnt() inline void vm::o_cnt()
{ {
if(top[0].type!=vm_vec) if(top[0].type!=vm_vec)
vm_error("must use vector in forindex/foreach"); vm_error("must use vector in forindex/foreach");
(++top)[0]={vm_cnt,(i64)-1}; (++top)[0]={vm_cnt,(i64)-1};
} }
inline void nasal_vm::o_findex() inline void vm::o_findex()
{ {
if((usize)(++top[0].cnt())>=top[-1].vec().size()) if((usize)(++top[0].cnt())>=top[-1].vec().size())
{ {
@ -599,9 +599,9 @@ inline void nasal_vm::o_findex()
top[1]={vm_num,(f64)top[0].cnt()}; top[1]={vm_num,(f64)top[0].cnt()};
++top; ++top;
} }
inline void nasal_vm::o_feach() inline void vm::o_feach()
{ {
std::vector<nas_ref>& ref=top[-1].vec().elems; std::vector<var>& ref=top[-1].vec().elems;
if((usize)(++top[0].cnt())>=ref.size()) if((usize)(++top[0].cnt())>=ref.size())
{ {
pc=imm[pc]-1; pc=imm[pc]-1;
@ -610,23 +610,23 @@ inline void nasal_vm::o_feach()
top[1]=ref[top[0].cnt()]; top[1]=ref[top[0].cnt()];
++top; ++top;
} }
inline void nasal_vm::o_callg() inline void vm::o_callg()
{ {
(++top)[0]=stack[imm[pc]]; (++top)[0]=stack[imm[pc]];
} }
inline void nasal_vm::o_calll() inline void vm::o_calll()
{ {
(++top)[0]=localr[imm[pc]]; (++top)[0]=localr[imm[pc]];
} }
inline void nasal_vm::o_upval() inline void vm::o_upval()
{ {
(++top)[0]=funcr.func().upval[(imm[pc]>>16)&0xffff] (++top)[0]=funcr.func().upval[(imm[pc]>>16)&0xffff]
.upval()[imm[pc]&0xffff]; .upval()[imm[pc]&0xffff];
} }
inline void nasal_vm::o_callv() inline void vm::o_callv()
{ {
nas_ref val=top[0]; var val=top[0];
nas_ref vec=(--top)[0]; var vec=(--top)[0];
if(vec.type==vm_vec) if(vec.type==vm_vec)
{ {
top[0]=vec.vec().get_val(val.tonum()); top[0]=vec.vec().get_val(val.tonum());
@ -655,9 +655,9 @@ inline void nasal_vm::o_callv()
else else
vm_error("must call a vector/hash/string"); vm_error("must call a vector/hash/string");
} }
inline void nasal_vm::o_callvi() inline void vm::o_callvi()
{ {
nas_ref val=top[0]; var val=top[0];
if(val.type!=vm_vec) if(val.type!=vm_vec)
vm_error("must use a vector"); vm_error("must use a vector");
// cannot use operator[],because this may cause overflow // cannot use operator[],because this may cause overflow
@ -665,9 +665,9 @@ inline void nasal_vm::o_callvi()
if(top[0].type==vm_none) if(top[0].type==vm_none)
vm_error("index out of range:"+std::to_string(imm[pc])); vm_error("index out of range:"+std::to_string(imm[pc]));
} }
inline void nasal_vm::o_callh() inline void vm::o_callh()
{ {
nas_ref val=top[0]; var val=top[0];
if(val.type!=vm_hash) if(val.type!=vm_hash)
vm_error("must call a hash"); vm_error("must call a hash");
top[0]=val.hash().get_val(str_table[imm[pc]]); top[0]=val.hash().get_val(str_table[imm[pc]]);
@ -676,14 +676,14 @@ inline void nasal_vm::o_callh()
if(top[0].type==vm_func) if(top[0].type==vm_func)
top[0].func().local[0]=val;// 'me' top[0].func().local[0]=val;// 'me'
} }
inline void nasal_vm::o_callfv() inline void vm::o_callfv()
{ {
u32 argc=imm[pc]; // arguments counter u32 argc=imm[pc]; // arguments counter
nas_ref* local=top-argc+1; // arguments begin address var* local=top-argc+1; // arguments begin address
if(local[-1].type!=vm_func) if(local[-1].type!=vm_func)
vm_error("must call a function"); vm_error("must call a function");
auto& func=local[-1].func(); auto& func=local[-1].func();
nas_ref tmp=local[-1]; var tmp=local[-1];
local[-1]=funcr; local[-1]=funcr;
funcr=tmp; funcr=tmp;
// top-argc+lsize(local) +1(old pc) +1(old localr) +1(old upvalr) // top-argc+lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
@ -694,11 +694,11 @@ inline void nasal_vm::o_callfv()
if(argc<psize && func.local[argc+1].type==vm_none) if(argc<psize && func.local[argc+1].type==vm_none)
vm_error("lack argument(s)"); vm_error("lack argument(s)");
nas_ref dynamic=nil; var dynamic=nil;
top=local+func.lsize; top=local+func.lsize;
if(func.dpara>=0)// load dynamic arguments if(func.dpara>=0)// load dynamic arguments
{ {
dynamic=gc.alloc(vm_vec); dynamic=ngc.alloc(vm_vec);
for(u32 i=psize;i<argc;++i) for(u32 i=psize;i<argc;++i)
dynamic.vec().elems.push_back(local[i]); dynamic.vec().elems.push_back(local[i]);
} }
@ -723,13 +723,13 @@ inline void nasal_vm::o_callfv()
localr=local; localr=local;
upvalr=nil; upvalr=nil;
} }
inline void nasal_vm::o_callfh() inline void vm::o_callfh()
{ {
auto& hash=top[0].hash().elems; auto& hash=top[0].hash().elems;
if(top[-1].type!=vm_func) if(top[-1].type!=vm_func)
vm_error("must call a function"); vm_error("must call a function");
auto& func=top[-1].func(); auto& func=top[-1].func();
nas_ref tmp=top[-1]; var tmp=top[-1];
top[-1]=funcr; top[-1]=funcr;
funcr=tmp; funcr=tmp;
// top -1(hash) +lsize(local) +1(old pc) +1(old localr) +1(old upvalr) // top -1(hash) +lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
@ -738,7 +738,7 @@ inline void nasal_vm::o_callfh()
if(func.dpara>=0) if(func.dpara>=0)
vm_error("special call cannot use dynamic argument"); vm_error("special call cannot use dynamic argument");
nas_ref* local=top; var* local=top;
top+=func.lsize; top+=func.lsize;
for(u32 i=0;i<func.lsize;++i) for(u32 i=0;i<func.lsize;++i)
local[i]=func.local[i]; local[i]=func.local[i];
@ -759,7 +759,7 @@ inline void nasal_vm::o_callfh()
localr=local; localr=local;
upvalr=nil; upvalr=nil;
} }
inline void nasal_vm::o_callb() inline void vm::o_callb()
{ {
// reserve place for builtin function return, // reserve place for builtin function return,
// in fact this code is changed because of coroutine // in fact this code is changed because of coroutine
@ -767,40 +767,40 @@ inline void nasal_vm::o_callb()
// this ++top should not be used like: (++top)[0] here // this ++top should not be used like: (++top)[0] here
// because if running a builtin function about coroutine // because if running a builtin function about coroutine
// (top) will be set to another context.top, instead of main_context.top // (top) will be set to another context.top, instead of main_context.top
top[0]=(*builtin[imm[pc]].func)(localr,gc); top[0]=(*builtin[imm[pc]].func)(localr,ngc);
if(top[0].type==vm_none) if(top[0].type==vm_none)
vm_error("native function error"); vm_error("native function error");
} }
inline void nasal_vm::o_slcbeg() inline void vm::o_slcbeg()
{ {
// +--------------+ // +--------------+
// | slice_vector | <-- top[0] // | slice_vector | <-- top[0]
// +--------------+ // +--------------+
// | resource_vec | <-- top[-1] // | resource_vec | <-- top[-1]
// +--------------+ // +--------------+
(++top)[0]=gc.alloc(vm_vec); (++top)[0]=ngc.alloc(vm_vec);
if(top[-1].type!=vm_vec) if(top[-1].type!=vm_vec)
vm_error("must slice a vector"); vm_error("must slice a vector");
} }
inline void nasal_vm::o_slcend() inline void vm::o_slcend()
{ {
top[-1]=top[0]; top[-1]=top[0];
--top; --top;
} }
inline void nasal_vm::o_slc() inline void vm::o_slc()
{ {
nas_ref val=(top--)[0]; var val=(top--)[0];
nas_ref res=top[-1].vec().get_val(val.tonum()); var res=top[-1].vec().get_val(val.tonum());
if(res.type==vm_none) if(res.type==vm_none)
vm_error("index out of range:"+std::to_string(val.tonum())); vm_error("index out of range:"+std::to_string(val.tonum()));
top[0].vec().elems.push_back(res); top[0].vec().elems.push_back(res);
} }
inline void nasal_vm::o_slc2() inline void vm::o_slc2()
{ {
nas_ref val2=(top--)[0]; var val2=(top--)[0];
nas_ref val1=(top--)[0]; var val1=(top--)[0];
std::vector<nas_ref>& ref=top[-1].vec().elems; std::vector<var>& ref=top[-1].vec().elems;
std::vector<nas_ref>& aim=top[0].vec().elems; std::vector<var>& aim=top[0].vec().elems;
u8 type1=val1.type,type2=val2.type; u8 type1=val1.type,type2=val2.type;
i32 num1=val1.tonum(); i32 num1=val1.tonum();
@ -823,31 +823,31 @@ inline void nasal_vm::o_slc2()
aim.push_back(i>=0?ref[i]:ref[i+size]); aim.push_back(i>=0?ref[i]:ref[i+size]);
} }
} }
inline void nasal_vm::o_mcallg() inline void vm::o_mcallg()
{ {
memr=stack+imm[pc]; memr=stack+imm[pc];
(++top)[0]=memr[0]; (++top)[0]=memr[0];
// push value in this memory space on stack // push value in this memory space on stack
// to avoid being garbage collected // to avoid being garbage collected
} }
inline void nasal_vm::o_mcalll() inline void vm::o_mcalll()
{ {
memr=localr+imm[pc]; memr=localr+imm[pc];
(++top)[0]=memr[0]; (++top)[0]=memr[0];
// push value in this memory space on stack // push value in this memory space on stack
// to avoid being garbage collected // to avoid being garbage collected
} }
inline void nasal_vm::o_mupval() inline void vm::o_mupval()
{ {
memr=&(funcr.func().upval[(imm[pc]>>16)&0xffff].upval()[imm[pc]&0xffff]); memr=&(funcr.func().upval[(imm[pc]>>16)&0xffff].upval()[imm[pc]&0xffff]);
(++top)[0]=memr[0]; (++top)[0]=memr[0];
// push value in this memory space on stack // push value in this memory space on stack
// to avoid being garbage collected // to avoid being garbage collected
} }
inline void nasal_vm::o_mcallv() inline void vm::o_mcallv()
{ {
nas_ref val=top[0]; // index var val=top[0]; // index
nas_ref vec=(--top)[0]; // mcall vector, reserved on stack to avoid gc var vec=(--top)[0]; // mcall vector, reserved on stack to avoid gc
if(vec.type==vm_vec) if(vec.type==vm_vec)
{ {
memr=vec.vec().get_mem(val.tonum()); memr=vec.vec().get_mem(val.tonum());
@ -868,9 +868,9 @@ inline void nasal_vm::o_mcallv()
}else }else
vm_error("cannot get memory space in this type"); vm_error("cannot get memory space in this type");
} }
inline void nasal_vm::o_mcallh() inline void vm::o_mcallh()
{ {
nas_ref hash=top[0]; // mcall hash, reserved on stack to avoid gc var hash=top[0]; // mcall hash, reserved on stack to avoid gc
if(hash.type!=vm_hash) if(hash.type!=vm_hash)
vm_error("must call a hash"); vm_error("must call a hash");
nas_hash& ref=hash.hash(); nas_hash& ref=hash.hash();
@ -882,7 +882,7 @@ inline void nasal_vm::o_mcallh()
memr=ref.get_mem(str); memr=ref.get_mem(str);
} }
} }
inline void nasal_vm::o_ret() inline void vm::o_ret()
{ {
/* +-------------+ /* +-------------+
* | return value| <- top[0] * | return value| <- top[0]
@ -899,10 +899,10 @@ inline void nasal_vm::o_ret()
* | old funcr | <- old function stored in funcr * | old funcr | <- old function stored in funcr
* +-------------+ * +-------------+
*/ */
nas_ref ret =top[0]; var ret =top[0];
nas_ref* local=localr; var* local=localr;
nas_ref func =funcr; var func =funcr;
nas_ref up =upvalr; var up =upvalr;
pc =top[-1].ret(); pc =top[-1].ret();
localr=top[-2].addr(); localr=top[-2].addr();
@ -923,11 +923,11 @@ inline void nasal_vm::o_ret()
// cannot use gc.cort to judge, // cannot use gc.cort to judge,
// because there maybe another function call inside // because there maybe another function call inside
if(!pc) if(!pc)
gc.ctxreserve(); ngc.ctxreserve();
} }
void nasal_vm::run( void vm::run(
const nasal_codegen& gen, const codegen& gen,
const nasal_import& linker, const linker& linker,
const std::vector<string>& argv, const std::vector<string>& argv,
const bool detail) const bool detail)
{ {
@ -965,47 +965,47 @@ void nasal_vm::run(
// goto the first operand // goto the first operand
goto *code[pc]; goto *code[pc];
#else #else
typedef void (nasal_vm::*nafunc)(); typedef void (vm::*nafunc)();
const nafunc oprs[]= const nafunc oprs[]=
{ {
nullptr, &nasal_vm::o_intg, nullptr, &vm::o_intg,
&nasal_vm::o_intl, &nasal_vm::o_loadg, &vm::o_intl, &vm::o_loadg,
&nasal_vm::o_loadl, &nasal_vm::o_loadu, &vm::o_loadl, &vm::o_loadu,
&nasal_vm::o_pnum, &nasal_vm::o_pnil, &vm::o_pnum, &vm::o_pnil,
&nasal_vm::o_pstr, &nasal_vm::o_newv, &vm::o_pstr, &vm::o_newv,
&nasal_vm::o_newh, &nasal_vm::o_newf, &vm::o_newh, &vm::o_newf,
&nasal_vm::o_happ, &nasal_vm::o_para, &vm::o_happ, &vm::o_para,
&nasal_vm::o_deft, &nasal_vm::o_dyn, &vm::o_deft, &vm::o_dyn,
&nasal_vm::o_unot, &nasal_vm::o_usub, &vm::o_unot, &vm::o_usub,
&nasal_vm::o_add, &nasal_vm::o_sub, &vm::o_add, &vm::o_sub,
&nasal_vm::o_mul, &nasal_vm::o_div, &vm::o_mul, &vm::o_div,
&nasal_vm::o_lnk, &nasal_vm::o_addc, &vm::o_lnk, &vm::o_addc,
&nasal_vm::o_subc, &nasal_vm::o_mulc, &vm::o_subc, &vm::o_mulc,
&nasal_vm::o_divc, &nasal_vm::o_lnkc, &vm::o_divc, &vm::o_lnkc,
&nasal_vm::o_addeq, &nasal_vm::o_subeq, &vm::o_addeq, &vm::o_subeq,
&nasal_vm::o_muleq, &nasal_vm::o_diveq, &vm::o_muleq, &vm::o_diveq,
&nasal_vm::o_lnkeq, &nasal_vm::o_addeqc, &vm::o_lnkeq, &vm::o_addeqc,
&nasal_vm::o_subeqc, &nasal_vm::o_muleqc, &vm::o_subeqc, &vm::o_muleqc,
&nasal_vm::o_diveqc, &nasal_vm::o_lnkeqc, &vm::o_diveqc, &vm::o_lnkeqc,
&nasal_vm::o_meq, &nasal_vm::o_eq, &vm::o_meq, &vm::o_eq,
&nasal_vm::o_neq, &nasal_vm::o_less, &vm::o_neq, &vm::o_less,
&nasal_vm::o_leq, &nasal_vm::o_grt, &vm::o_leq, &vm::o_grt,
&nasal_vm::o_geq, &nasal_vm::o_lessc, &vm::o_geq, &vm::o_lessc,
&nasal_vm::o_leqc, &nasal_vm::o_grtc, &vm::o_leqc, &vm::o_grtc,
&nasal_vm::o_geqc, &nasal_vm::o_pop, &vm::o_geqc, &vm::o_pop,
&nasal_vm::o_jmp, &nasal_vm::o_jt, &vm::o_jmp, &vm::o_jt,
&nasal_vm::o_jf, &nasal_vm::o_cnt, &vm::o_jf, &vm::o_cnt,
&nasal_vm::o_findex, &nasal_vm::o_feach, &vm::o_findex, &vm::o_feach,
&nasal_vm::o_callg, &nasal_vm::o_calll, &vm::o_callg, &vm::o_calll,
&nasal_vm::o_upval, &nasal_vm::o_callv, &vm::o_upval, &vm::o_callv,
&nasal_vm::o_callvi, &nasal_vm::o_callh, &vm::o_callvi, &vm::o_callh,
&nasal_vm::o_callfv, &nasal_vm::o_callfh, &vm::o_callfv, &vm::o_callfh,
&nasal_vm::o_callb, &nasal_vm::o_slcbeg, &vm::o_callb, &vm::o_slcbeg,
&nasal_vm::o_slcend, &nasal_vm::o_slc, &vm::o_slcend, &vm::o_slc,
&nasal_vm::o_slc2, &nasal_vm::o_mcallg, &vm::o_slc2, &vm::o_mcallg,
&nasal_vm::o_mcalll, &nasal_vm::o_mupval, &vm::o_mcalll, &vm::o_mupval,
&nasal_vm::o_mcallv, &nasal_vm::o_mcallh, &vm::o_mcallv, &vm::o_mcallh,
&nasal_vm::o_ret &vm::o_ret
}; };
std::vector<nafunc> code; std::vector<nafunc> code;
for(auto& i:gen.codes()) for(auto& i:gen.codes())
@ -1023,8 +1023,8 @@ void nasal_vm::run(
vmexit: vmexit:
if(detail) if(detail)
gc.info(); ngc.info();
gc.clear(); ngc.clear();
imm.clear(); imm.clear();
return; return;