🔥 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.
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++:
```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
// because local[0] is reserved for value 'me'
nas_ref vec=local[1];
var vec=local[1];
// main process
// also check number of arguments and type here
// 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:
```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)
return nas_err("keys","\"hash\" must be hash");
// 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;
for(auto& iter:hash.hash().elems)
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
{
const char* name;
nas_ref (*func)(nas_ref*,nasal_gc&);
var (*func)(var*,nasal_gc&);
} builtin[]=
{
{"__print",builtin_print},
@ -617,10 +617,10 @@ double fibonaci(double x){
}
// remember to use extern "C",
// 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
// 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
// nas_err will print the error info on screen
// 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添加新的数据结构, 可以看下文如何通过修改本项目来添加内置函数。
@ -469,11 +469,11 @@ nas_native(builtin_print);
然后用C++完成这个函数的函数体:
```C++
nas_ref builtin_print(nas_ref* local,nasal_gc& gc)
var builtin_print(var* local,nasal_gc& gc)
{
// 局部变量的下标其实是从1开始的
// 因为local[0]是保留给'me'的空间
nas_ref vec=local[1];
var vec=local[1];
// 主要部分
// 一些必要的类型检查和输入合法性检测也要在这里写出
// 如果检测到问题用builtin_err函数来返回vm_null
@ -504,13 +504,13 @@ nas_ref builtin_print(nas_ref* local,nasal_gc& gc)
可以使用`gc::temp`来暂时存储一个会被返回的需要gc管理的变量这样可以防止内部所有的申请错误触发垃圾回收。如下所示
```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)
return nas_err("keys","\"hash\" must be hash");
// 使用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;
for(auto& iter:hash.hash().elems)
vec.push_back(gc.newstr(iter.first));
@ -525,7 +525,7 @@ nas_ref builtin_keys(nas_ref* local,nasal_gc& gc)
struct func
{
const char* name;
nas_ref (*func)(nas_ref*,nasal_gc&);
var (*func)(var*,nasal_gc&);
} builtin[]=
{
{"__print",builtin_print},
@ -592,9 +592,9 @@ double fibonaci(double x){
}
// 记得用extern "C"
// 这样找符号会更加快速便捷不要在意编译时的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类型中送过来而不是上文中那种指针直接指向局部作用域
nas_ref num=args[0];
var num=args[0];
// 如果你想让这个函数有更强的稳定性,那么一定要进行合法性检查
// builtin_err会输出错误信息并返回错误类型让虚拟机终止执行
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`,
`addr_stack`, a stack used to store the memory address,
is deleted from `nasal_vm`,
and now `nasal_vm` use `nas_val** mem_addr` to store the memory address.
is deleted from `vm`,
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.
### 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).
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!
And vm runs test/fib in 0.8s on linux.
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:
```C++
+--------------------------+(main stack)
| old pc(vm_ret) | <- top[0]
+--------------------------+
| old localr(vm_addr) | <- top[-1]
+--------------------------+
| old upvalr(vm_upval) | <- top[-2]
+--------------------------+
| local scope(nas_ref) |
| ... |
+--------------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+--------------------------+
+----------------------+(main stack)
| old pc(vm_ret) | <- top[0]
+----------------------+
| old localr(vm_addr) | <- top[-1]
+----------------------+
| old upvalr(vm_upval) | <- top[-2]
+----------------------+
| local scope(var) |
| ... |
+----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+----------------------+
```
In `op_callb`'s progress, next step the stack frame is:
```C++
+--------------------------+(main stack)
| nil(vm_nil) | <- push nil
+--------------------------+
| old pc(vm_ret) |
+--------------------------+
| old localr(vm_addr) |
+--------------------------+
| old upvalr(vm_upval) |
+--------------------------+
| local scope(nas_ref) |
| ... |
+--------------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+--------------------------+
+----------------------+(main stack)
| nil(vm_nil) | <- push nil
+----------------------+
| old pc(vm_ret) |
+----------------------+
| old localr(vm_addr) |
+----------------------+
| old upvalr(vm_upval) |
+----------------------+
| local scope(var) |
| ... |
+----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+----------------------+
```
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.
```C++
+--------------------------+(coroutine stack)
| pc:0(vm_ret) | <- now gc.top[0]
+--------------------------+
+----------------------+(coroutine stack)
| pc:0(vm_ret) | <- now gc.top[0]
+----------------------+
```
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?
```C++
+--------------------------+(coroutine stack)
| nil(vm_nil) | <- push nil
+--------------------------+
| old pc(vm_ret) |
+--------------------------+
| old localr(vm_addr) |
+--------------------------+
| old upvalr(vm_upval) |
+--------------------------+
| local scope(nas_ref) |
| ... |
+--------------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+--------------------------+
+----------------------+(coroutine stack)
| nil(vm_nil) | <- push nil
+----------------------+
| old pc(vm_ret) |
+----------------------+
| old localr(vm_addr) |
+----------------------+
| old upvalr(vm_upval) |
+----------------------+
| local scope(var) |
| ... |
+----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+----------------------+
```
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`:
```C++
+--------------------------+(main stack)
| return_value(nas_ref) |
+--------------------------+
| old pc(vm_ret) |
+--------------------------+
| old localr(vm_addr) |
+--------------------------+
| old upvalr(vm_upval) |
+--------------------------+
| local scope(nas_ref) |
| ... |
+--------------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+--------------------------+
+----------------------+(main stack)
| return_value(var) |
+----------------------+
| old pc(vm_ret) |
+----------------------+
| old localr(vm_addr) |
+----------------------+
| old upvalr(vm_upval) |
+----------------------+
| local scope(var) |
| ... |
+----------------------+ <- local pointer stored in localr
| 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`.

View File

@ -305,7 +305,7 @@ m(0)._=m(1)._=10;
从上面这些字节码可以看出,`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)
@ -491,37 +491,37 @@ __接下来我们解释这个协程的运行原理:__
当`op_callb`被执行时,栈帧如下所示:
```C++
+--------------------------+(主操作数栈)
| old pc(vm_ret) | <- top[0]
+--------------------------+
| old localr(vm_addr) | <- top[-1]
+--------------------------+
| old upvalr(vm_upval) | <- top[-2]
+--------------------------+
| local scope(nas_ref) |
| ... |
+--------------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+--------------------------+
+----------------------+(主操作数栈)
| old pc(vm_ret) | <- top[0]
+----------------------+
| old localr(vm_addr) | <- top[-1]
+----------------------+
| old upvalr(vm_upval) | <- top[-2]
+----------------------+
| local scope(var) |
| ... |
+----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+----------------------+
```
在`op_callb`执行过程中,下一步的栈帧如下:
```C++
+--------------------------+(主操作数栈)
| nil(vm_nil) | <- push nil
+--------------------------+
| old pc(vm_ret) |
+--------------------------+
| old localr(vm_addr) |
+--------------------------+
| old upvalr(vm_upval) |
+--------------------------+
| local scope(nas_ref) |
| ... |
+--------------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+--------------------------+
+----------------------+(主操作数栈)
| nil(vm_nil) | <- push nil
+----------------------+
| old pc(vm_ret) |
+----------------------+
| old localr(vm_addr) |
+----------------------+
| old upvalr(vm_upval) |
+----------------------+
| local scope(var) |
| ... |
+----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+----------------------+
```
接着我们调用`resume`,这个函数会替换操作数栈。我们会看到,协程的操作数栈上已经保存了一些数据,但是我们首次进入协程执行时,这个操作数栈的栈顶将会是`vm_ret`,并且返回的`pc`值是`0`。
@ -529,47 +529,47 @@ __接下来我们解释这个协程的运行原理:__
为了保证栈顶的数据不会被破坏,`resume`会返回`gc.top[0]`。`op_callb`将会执行`top[0]=resume()`,所以栈顶的数据虽然被覆盖了一次,但是实际上还是原来的数据。
```C++
+--------------------------+(协程操作数栈)
| pc:0(vm_ret) | <- now gc.top[0]
+--------------------------+
+----------------------+(协程操作数栈)
| pc:0(vm_ret) | <- now gc.top[0]
+----------------------+
```
当我们调用`yield`的时候,该函数会执行出这个情况,我们发现`op_callb` 已经把`nil`放在的栈顶。但是应该返回的`local[1]`到底发送到哪里去了?
```C++
+--------------------------+(协程操作数栈)
| nil(vm_nil) | <- push nil
+--------------------------+
| old pc(vm_ret) |
+--------------------------+
| old localr(vm_addr) |
+--------------------------+
| old upvalr(vm_upval) |
+--------------------------+
| local scope(nas_ref) |
| ... |
+--------------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+--------------------------+
+----------------------+(协程操作数栈)
| nil(vm_nil) | <- push nil
+----------------------+
| old pc(vm_ret) |
+----------------------+
| old localr(vm_addr) |
+----------------------+
| old upvalr(vm_upval) |
+----------------------+
| local scope(var) |
| ... |
+----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+----------------------+
```
当`builtin_coyield`执行完毕之后,栈又切换到了主操作数栈上,这时可以看到返回的`local[1]`实际上被`op_callb`放在了这里的栈顶:
```C++
+--------------------------+(主操作数栈)
| return_value(nas_ref) |
+--------------------------+
| old pc(vm_ret) |
+--------------------------+
| old localr(vm_addr) |
+--------------------------+
| old upvalr(vm_upval) |
+--------------------------+
| local scope(nas_ref) |
| ... |
+--------------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+--------------------------+
+----------------------+(主操作数栈)
| return_value(var) |
+----------------------+
| old pc(vm_ret) |
+----------------------+
| old localr(vm_addr) |
+----------------------+
| old upvalr(vm_upval) |
+----------------------+
| local scope(var) |
| ... |
+----------------------+ <- local pointer stored in localr
| old funcr(vm_func) | <- old function stored in funcr
+----------------------+
```
所以主程序会认为顶部这个返回值好像是`resume`返回的。而实际上`resume`的返回值在协程的操作数栈顶。综上所述:

View File

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

View File

@ -6,20 +6,20 @@ double fibonaci(double x){
return x;
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";
if(!args.size())
return nas_err("fib","lack arguments");
nas_ref num=args[0];
var num=args[0];
if(num.type!=vm_num)
return nas_err("extern_fib","\"num\" must be number");
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";
if(!args.size())
return nas_err("fib","lack arguments");
nas_ref num=args[0];
var num=args[0];
if(num.type!=vm_num)
return nas_err("extern_quick_fib","\"num\" must be number");
if(num.num()<2)

View File

@ -71,13 +71,13 @@ public:
};
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()};
}
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()};
}
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())
return {vm_num,(double)this_window.noecho_getch()};
return nil;

View File

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

View File

@ -25,14 +25,14 @@ static WSAmanager win;
#include <netinet/in.h>
#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)
return nas_err("socket","\"af\", \"type\", \"protocol\" should be number");
int sd=socket(args[0].num(),args[1].num(),args[2].num());
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)
return nas_err("closesocket","\"\" should be number");
#ifdef _WIN32
@ -42,7 +42,7 @@ extern "C" nas_ref nas_closesocket(std::vector<nas_ref>& args,nasal_gc& gc){
#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)
return nas_err("shutdown","\"sd\" must be a number");
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())};
}
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)
return nas_err("bind","\"sd\" muse be a number");
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))};
}
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)
return nas_err("listen","\"sd\" must be a number");
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())};
}
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)
return nas_err("connect","\"sd\" must be a number");
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))};
}
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)
return nas_err("accept","\"sd\" must be a number");
sockaddr_in client;
@ -99,15 +99,15 @@ extern "C" nas_ref nas_accept(std::vector<nas_ref>& args,nasal_gc& gc){
#else
int client_sd=accept(args[0].num(),(sockaddr*)&client,(socklen_t*)&socklen);
#endif
nas_ref res=gc.temp=gc.alloc(vm_hash);
var res=ngc.temp=ngc.alloc(vm_hash);
auto& hash=res.hash().elems;
hash["sd"]={vm_num,(double)client_sd};
hash["ip"]=gc.newstr(inet_ntoa(client.sin_addr));
gc.temp=nil;
hash["ip"]=ngc.newstr(inet_ntoa(client.sin_addr));
ngc.temp=nil;
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)
return nas_err("send","\"sd\" must be a number");
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())};
}
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)
return nas_err("sendto","\"sd\" must be a number");
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))};
}
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)
return nas_err("recv","\"sd\" must be a number");
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");
if(args[2].type!=vm_num)
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;
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["str"]=gc.newstr(buf);
hash["str"]=ngc.newstr(buf);
delete[] buf;
gc.temp=nil;
ngc.temp=nil;
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)
return nas_err("recvfrom","\"sd\" must be a number");
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");
sockaddr_in addr;
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;
char* buf=new char[(int)args[1].num()+1];
#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)};
#endif
buf[(int)hash["size"].num()]=0;
hash["str"]=gc.newstr(buf);
hash["str"]=ngc.newstr(buf);
delete[] buf;
hash["fromip"]=gc.newstr(inet_ntoa(addr.sin_addr));
gc.temp=nil;
hash["fromip"]=ngc.newstr(inet_ntoa(addr.sin_addr));
ngc.temp=nil;
return res;
}
extern "C" nas_ref nas_errno(std::vector<nas_ref>& args,nasal_gc& gc){
return gc.newstr(strerror(errno));
extern "C" var nas_errno(std::vector<var>& args,gc& ngc){
return ngc.newstr(strerror(errno));
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -198,11 +198,11 @@ public:
}
};
class nasal_codegen
class codegen
{
private:
u16 fileindex;
nasal_err& nerr;
error& err;
const string* file;
std::stack<u32> in_iterloop;
std::unordered_map<f64,u32> num_table;
@ -264,24 +264,24 @@ private:
void singleop(const u32);
public:
nasal_codegen(nasal_err& e):fileindex(0),nerr(e),file(nullptr){}
void compile(const nasal_parse&,const nasal_import&);
codegen(error& e):fileindex(0),err(e),file(nullptr){}
void compile(const parse&,const linker&);
void print();
const std::vector<string>& strs() const {return str_res;}
const std::vector<f64>& nums() const {return num_res;}
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)
nerr.err("code",line,col,info);
err.err("code",line,col,info);
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))
{
@ -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))
{
@ -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
// if find a function, return
@ -326,7 +326,7 @@ void nasal_codegen::find_symbol(const ast& node)
find_symbol(i);
}
void nasal_codegen::add_sym(const string& name)
void codegen::add_sym(const string& name)
{
if(local.empty())
{
@ -342,19 +342,19 @@ void nasal_codegen::add_sym(const string& name)
local.back()[name]=index;
}
i32 nasal_codegen::local_find(const string& name)
i32 codegen::local_find(const string& name)
{
if(local.empty())
return -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;
}
i32 nasal_codegen::upvalue_find(const string& name)
i32 codegen::upvalue_find(const string& name)
{
// 32768 level 65536 upvalues
i32 index=-1;
@ -368,32 +368,32 @@ i32 nasal_codegen::upvalue_find(const string& name)
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});
}
void nasal_codegen::num_gen(const ast& node)
void codegen::num_gen(const ast& node)
{
f64 num=node.num();
regist_num(num);
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());
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())
calc_gen(child);
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());
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();
gen(op_newf,0,node.line());
@ -462,7 +462,7 @@ void nasal_codegen::func_gen(const ast& node)
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]);
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();
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());
}
void nasal_codegen::call_hash(const ast& node)
void codegen::call_hash(const ast& node)
{
regist_str(node.str());
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
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());
}
void nasal_codegen::call_func(const ast& node)
void codegen::call_func(const ast& node)
{
if(!node.size())
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.
* 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.
* 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)
{
@ -597,7 +597,7 @@ void nasal_codegen::mcall(const ast& node)
mcall_vec(tmp);
}
void nasal_codegen::mcall_id(const ast& node)
void codegen::mcall_id(const ast& node)
{
const string& str=node.str();
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());
}
void nasal_codegen::mcall_vec(const ast& node)
void codegen::mcall_vec(const ast& node)
{
calc_gen(node[0]);
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());
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();
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_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();
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);
}
void nasal_codegen::multi_assign_gen(const ast& node)
void codegen::multi_assign_gen(const ast& node)
{
i32 size=node[0].size();
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;
for(auto& tmp:node.child())
@ -754,7 +754,7 @@ void nasal_codegen::conditional_gen(const ast& node)
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>());
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())
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();
}
void nasal_codegen::while_gen(const ast& node)
void codegen::while_gen(const ast& node)
{
usize loop_ptr=code.size();
calc_gen(node[0]);
@ -790,7 +790,7 @@ void nasal_codegen::while_gen(const ast& node)
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())
{
@ -915,7 +915,7 @@ void nasal_codegen::for_gen(const ast& node)
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]);
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.line());// pop iterator
}
void nasal_codegen::foreach_gen(const ast& node)
void codegen::foreach_gen(const ast& node)
{
calc_gen(node[1]);
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
}
void nasal_codegen::or_gen(const ast& node)
void codegen::or_gen(const ast& node)
{
calc_gen(node[0]);
usize l1=code.size();
@ -1001,7 +1001,7 @@ void nasal_codegen::or_gen(const ast& node)
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]);
gen(op_jt,code.size()+2,node[0].line());
@ -1019,7 +1019,7 @@ void nasal_codegen::and_gen(const ast& node)
//jt jumps here
}
void nasal_codegen::trino_gen(const ast& node)
void codegen::trino_gen(const ast& node)
{
calc_gen(node[0]);
usize lfalse=code.size();
@ -1032,7 +1032,7 @@ void nasal_codegen::trino_gen(const ast& node)
code[lexit].num=code.size();
}
void nasal_codegen::calc_gen(const ast& node)
void codegen::calc_gen(const ast& node)
{
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())
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)
{
@ -1236,7 +1236,7 @@ void nasal_codegen::ret_gen(const ast& node)
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;
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);
if(code.size()>0xffffffff)
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
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";
}
void nasal_codegen::print()
void codegen::print()
{
for(auto& num:num_res)
std::cout<<" .number "<<num<<"\n";

View File

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

View File

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

View File

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

View File

@ -13,29 +13,29 @@
#define F_OK 0
#endif
class nasal_import
class linker
{
private:
bool show_path;
bool lib_loaded;
nasal_err& nerr;
error& err;
std::vector<string> files;
std::vector<string> envpath;
bool imptchk(const ast&);
bool exist(const string&);
void linker(ast&,ast&&);
void link(ast&,ast&&);
string path(const ast&);
string findf(const string&);
ast fimpt(ast&);
ast libimpt();
ast load(ast&,u16);
public:
nasal_import(nasal_err&);
void link(nasal_parse&,const string&,bool);
linker(error&);
void link(parse&,const string&,bool);
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
char sep=';';
#else
@ -55,7 +55,7 @@ nasal_import::nasal_import(nasal_err& e):lib_loaded(false),nerr(e){
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)
return node[1][0].str();
@ -69,7 +69,7 @@ string nasal_import::path(const ast& node)
return fpath+".nas";
}
string nasal_import::findf(const string& fname)
string linker::findf(const string& fname)
{
std::vector<string> filepath={fname};
for(auto&p:envpath)
@ -91,17 +91,17 @@ string nasal_import::findf(const string& fname)
#endif
if(!show_path)
{
nerr.err("link","cannot find file <"+fname+">");
err.err("link","cannot find file <"+fname+">");
return "";
}
string paths="";
for(auto& i:filepath)
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 "";
}
bool nasal_import::imptchk(const ast& node)
bool linker::imptchk(const ast& node)
{
// 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
for(auto& fname:files)
@ -143,17 +143,17 @@ bool nasal_import::exist(const string& file)
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
for(auto& i:add_root.child())
root.add(std::move(i));
}
ast nasal_import::fimpt(ast& node)
ast linker::fimpt(ast& node)
{
nasal_lexer lex(nerr);
nasal_parse par(nerr);
lexer lex(err);
parse par(err);
// get filename and set node to ast_null
string filename=path(node);
node.clear();
@ -171,10 +171,10 @@ ast nasal_import::fimpt(ast& node)
return load(tmp,files.size()-1);
}
ast nasal_import::libimpt()
ast linker::libimpt()
{
nasal_lexer lex(nerr);
nasal_parse par(nerr);
lexer lex(err);
parse par(err);
string filename=findf("lib.nas");
if(!filename.length())
return {0,0,ast_root};
@ -191,18 +191,18 @@ ast nasal_import::libimpt()
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);
if(!lib_loaded)
{
linker(new_root,libimpt());
link(new_root,libimpt());
lib_loaded=true;
}
for(auto& i:root.child())
{
if(imptchk(i))
linker(new_root,fimpt(i));
link(new_root,fimpt(i));
else
break;
}
@ -210,11 +210,11 @@ ast nasal_import::load(ast& root,u16 fileindex)
ast file_head(0,0,ast_file);
file_head.set_num(fileindex);
new_root.add(std::move(file_head));
linker(new_root,std::move(root));
link(new_root,std::move(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;
// 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
// the main file's index is 0
parse.tree()=load(parse.tree(),0);
nerr.chkerr();
err.chkerr();
}
#endif

View File

@ -115,54 +115,52 @@ struct token
}
};
class nasal_lexer
class lexer
{
private:
u32 line;
u32 column;
usize ptr;
string res;
nasal_err& nerr;
error& err;
std::vector<token> tokens;
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&);
string utf8_gen();
string id_gen();
string num_gen();
string str_gen();
public:
nasal_lexer(nasal_err& e):
line(1),
column(0),
ptr(0),
res(""),
nerr(e){}
lexer(error& e):
line(1),column(0),
ptr(0),res(""),
err(e){}
void scan(const string&);
void print();
const std::vector<token>& result() const {return tokens;}
};
void nasal_lexer::open(const string& file)
void lexer::open(const string& file)
{
struct stat buffer;
if(stat(file.c_str(),&buffer)==0 && !S_ISREG(buffer.st_mode))
{
nerr.err("lexer","<"+file+"> is not a regular file");
nerr.chkerr();
err.err("lexer","<"+file+"> is not a regular file");
err.chkerr();
}
std::ifstream fin(file,std::ios::binary);
if(fin.fail())
nerr.err("lexer","failed to open <"+file+">");
err.err("lexer","failed to open <"+file+">");
else
nerr.load(file);
err.load(file);
std::stringstream ss;
ss<<fin.rdbuf();
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)
if(str==tok_table[i].str)
@ -170,7 +168,7 @@ u32 nasal_lexer::get_type(const string& str)
return tok_null;
}
string nasal_lexer::utf8_gen()
string lexer::utf8_gen()
{
string str="";
while(ptr<res.size() && res[ptr]<0)
@ -204,7 +202,7 @@ string nasal_lexer::utf8_gen()
return str;
}
string nasal_lexer::id_gen()
string lexer::id_gen()
{
string str="";
while(ptr<res.size() && (ID(res[ptr])||DIGIT(res[ptr])))
@ -220,7 +218,7 @@ string nasal_lexer::id_gen()
return str;
}
string nasal_lexer::num_gen()
string lexer::num_gen()
{
// generate hex number
if(ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='x')
@ -283,7 +281,7 @@ string nasal_lexer::num_gen()
return str;
}
string nasal_lexer::str_gen()
string lexer::str_gen()
{
string str="";
const char begin=res[ptr];
@ -333,7 +331,7 @@ string nasal_lexer::str_gen()
return str;
}
void nasal_lexer::scan(const string& file)
void lexer::scan(const string& file)
{
line=1;
column=0;
@ -409,10 +407,10 @@ void nasal_lexer::scan(const string& file)
}
tokens.push_back({line,column,tok_eof,"eof"});
res="";
nerr.chkerr();
err.chkerr();
}
void nasal_lexer::print()
void lexer::print()
{
for(auto& tok:tokens)
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 is_call(type) ((type)==tok_lcurve || (type)==tok_lbracket || (type)==tok_dot)
@ -46,12 +46,13 @@ private:
u32 ptr;
u32 in_func; // count function block
u32 in_loop; // count loop block
const token* tokens;// ref from nasal_lexer
const token* tokens;// ref from lexer
ast root;
nasal_err& nerr;
error& err;
void die(u32,string,bool);
void match(u32 type,const char* info=nullptr);
bool lookahead(u32 type);
bool check_comma(const u32*);
bool check_multi_scalar();
bool check_func_end(const ast&);
@ -100,46 +101,47 @@ private:
ast break_expr();
ast ret_expr();
public:
nasal_parse(nasal_err& e):
parse(error& e):
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 compile(const nasal_lexer&);
void compile(const lexer&);
ast& tree(){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();
ptr=in_func=in_loop=0;
root={0,0,ast_root};
while(tokens[ptr].type!=tok_eof)
while(!lookahead(tok_eof))
{
root.add(expr());
if(tokens[ptr].type==tok_semi)
if(lookahead(tok_semi))
match(tok_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);
}
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());
if(tokens[ptr].type==tok_str)
i32 col=(i32)tokens[ptr].col-(lookahead(tok_eof)?0:(i32)tokens[ptr].str.length());
if(lookahead(tok_str))
col-=2; // tok_str's str has no \"
if(report_prev && ptr) // used to report lack of ',' ';'
{
line=tokens[ptr-1].line;
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)
{
@ -155,21 +157,25 @@ void nasal_parse::match(u32 type,const char* info)
}
return;
}
if(tokens[ptr].type==tok_eof)
if(lookahead(tok_eof))
return;
++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)
if(tokens[ptr].type==panic_set[i])
if(lookahead(panic_set[i]))
{
die(error_line,"expected ',' between scalars",true);
return true;
}
return false;
}
bool nasal_parse::check_multi_scalar()
bool parse::check_multi_scalar()
{
u32 check_ptr=ptr,curve=1,bracket=0,brace=0;
while(tokens[++check_ptr].type!=tok_eof && curve)
@ -188,7 +194,7 @@ bool nasal_parse::check_multi_scalar()
}
return false;
}
bool nasal_parse::check_func_end(const ast& node)
bool parse::check_func_end(const ast& node)
{
u32 type=node.type();
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 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);
u32 check_ptr=ptr,curve=1,bracket=0,brace=0;
@ -235,14 +241,14 @@ bool nasal_parse::check_special_call()
}
return false;
}
bool nasal_parse::need_semi_check(const ast& node)
bool parse::need_semi_check(const ast& node)
{
u32 type=node.type();
if(type==ast_for || type==ast_foreach || type==ast_forindex || type==ast_while || type==ast_conditional)
return false;
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)
{
@ -255,36 +261,36 @@ void nasal_parse::check_memory_reachable(const ast& node)
else if(node.type()!=ast_id)
die(node.line(),"bad left-value");
}
ast nasal_parse::null()
ast parse::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};
}
ast nasal_parse::num()
ast parse::num()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_num);
node.set_num(str2num(tokens[ptr].str.c_str()));
match(tok_num);
return node;
}
ast nasal_parse::str()
ast parse::str()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_str);
node.set_str(tokens[ptr].str);
match(tok_str);
return node;
}
ast nasal_parse::id()
ast parse::id()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_id);
node.set_str(tokens[ptr].str);
match(tok_id);
return node;
}
ast nasal_parse::vec()
ast parse::vec()
{
// panic set for this token is not ','
// 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);
match(tok_lbracket);
while(tokens[ptr].type!=tok_rbracket)
while(!lookahead(tok_rbracket))
{
node.add(calc());
if(tokens[ptr].type==tok_comma)
if(lookahead(tok_comma))
match(tok_comma);
else if(tokens[ptr].type==tok_eof)
else if(lookahead(tok_eof))
break;
else if(tokens[ptr].type!=tok_rbracket && !check_comma(panic_set))
else if(!lookahead(tok_rbracket) && !check_comma(panic_set))
break;
}
match(tok_rbracket,"expected ']' when generating vector");
return node;
}
ast nasal_parse::hash()
ast parse::hash()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_hash);
match(tok_lbrace);
while(tokens[ptr].type!=tok_rbrace)
while(!lookahead(tok_rbrace))
{
node.add(pair());
if(tokens[ptr].type==tok_comma)
if(lookahead(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);
else
break;
@ -327,12 +333,12 @@ ast nasal_parse::hash()
match(tok_rbrace,"expected '}' when generating hash");
return node;
}
ast nasal_parse::pair()
ast parse::pair()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_pair);
if(tokens[ptr].type==tok_id)
if(lookahead(tok_id))
node.add(id());
else if(tokens[ptr].type==tok_str)
else if(lookahead(tok_str))
node.add(str());
else
match(tok_id,"expected hashmap key");
@ -340,12 +346,12 @@ ast nasal_parse::pair()
node.add(calc());
return node;
}
ast nasal_parse::func()
ast parse::func()
{
++in_func;
ast node(tokens[ptr].line,tokens[ptr].col,ast_func);
match(tok_func);
if(tokens[ptr].type==tok_lcurve)
if(lookahead(tok_lcurve))
node.add(args());
else
node.add(null());
@ -353,17 +359,17 @@ ast nasal_parse::func()
--in_func;
return node;
}
ast nasal_parse::args()
ast parse::args()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_args);
match(tok_lcurve);
while(tokens[ptr].type!=tok_rcurve)
while(!lookahead(tok_rcurve))
{
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);
if(tokens[ptr].type==tok_eq)
if(lookahead(tok_eq))
{
match(tok_eq);
special_arg=std::move(tmp);
@ -380,9 +386,9 @@ ast nasal_parse::args()
}
else
node.add(std::move(tmp));
if(tokens[ptr].type==tok_comma)
if(lookahead(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);
else
break;
@ -430,13 +436,13 @@ ast nasal_parse::args()
}
return node;
}
ast nasal_parse::lcurve_expr()
ast parse::lcurve_expr()
{
if(tokens[ptr+1].type==tok_var)
return definition();
return check_multi_scalar()?multi_assgin():calc();
}
ast nasal_parse::expr()
ast parse::expr()
{
u32 type=tokens[ptr].type;
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};
}
ast nasal_parse::exprs()
ast parse::exprs()
{
if(tokens[ptr].type==tok_eof)
if(lookahead(tok_eof))
{
die(error_line,"expected expression block");
return null();
}
ast node(tokens[ptr].line,tokens[ptr].col,ast_block);
if(tokens[ptr].type==tok_lbrace)
if(lookahead(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());
if(tokens[ptr].type==tok_semi)
if(lookahead(tok_semi))
match(tok_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);
}
match(tok_rbrace,"expected '}' when generating expressions");
@ -497,15 +503,15 @@ ast nasal_parse::exprs()
else
{
node.add(expr());
if(tokens[ptr].type==tok_semi)
if(lookahead(tok_semi))
match(tok_semi);
}
return node;
}
ast nasal_parse::calc()
ast parse::calc()
{
ast node=or_expr();
if(tokens[ptr].type==tok_quesmark)
if(lookahead(tok_quesmark))
{
// trinocular calculation
ast tmp(tokens[ptr].line,tokens[ptr].col,ast_trino);
@ -528,10 +534,10 @@ ast nasal_parse::calc()
}
return node;
}
ast nasal_parse::or_expr()
ast parse::or_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);
tmp.add(std::move(node));
@ -541,10 +547,10 @@ ast nasal_parse::or_expr()
}
return node;
}
ast nasal_parse::and_expr()
ast parse::and_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);
tmp.add(std::move(node));
@ -554,7 +560,7 @@ ast nasal_parse::and_expr()
}
return node;
}
ast nasal_parse::cmp_expr()
ast parse::cmp_expr()
{
ast node=additive_expr();
while(tok_cmpeq<=tokens[ptr].type && tokens[ptr].type<=tok_geq)
@ -568,10 +574,10 @@ ast nasal_parse::cmp_expr()
}
return node;
}
ast nasal_parse::additive_expr()
ast parse::additive_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);
switch(tokens[ptr].type)
@ -587,20 +593,20 @@ ast nasal_parse::additive_expr()
}
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();
while(tokens[ptr].type==tok_mult || tokens[ptr].type==tok_div)
ast node=(lookahead(tok_sub) || lookahead(tok_not))?unary():scalar();
while(lookahead(tok_mult) || lookahead(tok_div))
{
ast tmp(tokens[ptr].line,tokens[ptr].col,tokens[ptr].type-tok_mult+ast_mult);
tmp.add(std::move(node));
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);
}
return node;
}
ast nasal_parse::unary()
ast parse::unary()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_null);
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_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;
}
ast nasal_parse::scalar()
ast parse::scalar()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_null);
if(tokens[ptr].type==tok_nil) {node=nil();match(tok_nil);}
else if(tokens[ptr].type==tok_num) node=num();
else if(tokens[ptr].type==tok_str) node=str();
else if(tokens[ptr].type==tok_id) node=id();
else if(tokens[ptr].type==tok_func) node=func();
else if(tokens[ptr].type==tok_lbracket) node=vec();
else if(tokens[ptr].type==tok_lbrace) node=hash();
else if(tokens[ptr].type==tok_lcurve)
if(lookahead(tok_nil)) {node=nil();match(tok_nil);}
else if(lookahead(tok_num)) node=num();
else if(lookahead(tok_str)) node=str();
else if(lookahead(tok_id)) node=id();
else if(lookahead(tok_func)) node=func();
else if(lookahead(tok_lbracket)) node=vec();
else if(lookahead(tok_lbrace)) node=hash();
else if(lookahead(tok_lcurve))
{
match(tok_lcurve);
node=calc();
match(tok_rcurve);
}
else if(tokens[ptr].type==tok_var)
else if(lookahead(tok_var))
{
match(tok_var);
node.set_type(ast_def);
@ -641,7 +647,7 @@ ast nasal_parse::scalar()
return node;
}
// 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);
node={tokens[ptr].line,tokens[ptr].col,ast_call};
@ -651,7 +657,7 @@ ast nasal_parse::scalar()
}
return node;
}
ast nasal_parse::call_scalar()
ast parse::call_scalar()
{
switch(tokens[ptr].type)
{
@ -662,7 +668,7 @@ ast nasal_parse::call_scalar()
// should never run this expression
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);
match(tok_dot);
@ -670,7 +676,7 @@ ast nasal_parse::callh()
match(tok_id,"expected hashmap key"); // get key
return node;
}
ast nasal_parse::callv()
ast parse::callv()
{
// panic set for this token is not ','
// 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);
match(tok_lbracket);
while(tokens[ptr].type!=tok_rbracket)
while(!lookahead(tok_rbracket))
{
node.add(subvec());
if(tokens[ptr].type==tok_comma)
if(lookahead(tok_comma))
match(tok_comma);
else if(tokens[ptr].type==tok_eof)
else if(lookahead(tok_eof))
break;
else if(tokens[ptr].type!=tok_rbracket && !check_comma(panic_set))
else if(!lookahead(tok_rbracket) && !check_comma(panic_set))
break;
}
if(node.size()==0)
@ -699,7 +705,7 @@ ast nasal_parse::callv()
match(tok_rbracket,"expected ']' when calling vector");
return node;
}
ast nasal_parse::callf()
ast parse::callf()
{
// panic set for this token is not ','
// 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);
bool special_call=check_special_call();
match(tok_lcurve);
while(tokens[ptr].type!=tok_rcurve)
while(!lookahead(tok_rcurve))
{
node.add(special_call?pair():calc());
if(tokens[ptr].type==tok_comma)
if(lookahead(tok_comma))
match(tok_comma);
else if(tokens[ptr].type==tok_eof)
else if(lookahead(tok_eof))
break;
else if(tokens[ptr].type!=tok_rcurve && !check_comma(panic_set))
else if(!lookahead(tok_rcurve) && !check_comma(panic_set))
break;
}
match(tok_rcurve,"expected ')' when calling function");
return node;
}
ast nasal_parse::subvec()
ast parse::subvec()
{
ast node=tokens[ptr].type==tok_colon?nil():calc();
if(tokens[ptr].type==tok_colon)
ast node=lookahead(tok_colon)?nil():calc();
if(lookahead(tok_colon))
{
ast tmp(node.line(),node.col(),ast_subvec);
match(tok_colon);
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);
}
return node;
}
ast nasal_parse::definition()
ast parse::definition()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_def);
if(tokens[ptr].type==tok_var)
if(lookahead(tok_var))
{
match(tok_var);
switch(tokens[ptr].type)
@ -752,10 +758,10 @@ ast nasal_parse::definition()
default: die(error_line,"expected identifier");break;
}
}
else if(tokens[ptr].type==tok_lcurve)
else if(lookahead(tok_lcurve))
node.add(incurve_def());
match(tok_eq);
if(tokens[ptr].type==tok_lcurve)
if(lookahead(tok_lcurve))
node.add(check_multi_scalar()?multi_scalar(false):calc());
else
node.add(calc());
@ -765,7 +771,7 @@ ast nasal_parse::definition()
die(node[0].line(),"too much or lack values in multi-definition");
return node;
}
ast nasal_parse::incurve_def()
ast parse::incurve_def()
{
match(tok_lcurve);
match(tok_var);
@ -773,17 +779,17 @@ ast nasal_parse::incurve_def()
match(tok_rcurve);
return node;
}
ast nasal_parse::outcurve_def()
ast parse::outcurve_def()
{
match(tok_lcurve);
ast node=multi_id();
match(tok_rcurve);
return node;
}
ast nasal_parse::multi_id()
ast parse::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());
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
die(error_line,"cannot call identifier in multi-definition");
}
if(tokens[ptr].type==tok_comma)
if(lookahead(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);
else
break;
}
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
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);
match(tok_lcurve);
while(tokens[ptr].type!=tok_rcurve)
while(!lookahead(tok_rcurve))
{
node.add(calc());
if(check_call_memory)
check_memory_reachable(node.child().back());
if(tokens[ptr].type==tok_comma)
if(lookahead(tok_comma))
match(tok_comma);
else if(tokens[ptr].type==tok_eof)
else if(lookahead(tok_eof))
break;
else if(tokens[ptr].type!=tok_rcurve && !check_comma(panic_set))
else if(!lookahead(tok_rcurve) && !check_comma(panic_set))
break;
}
match(tok_rcurve,"expected ')' after multi-scalar");
return node;
}
ast nasal_parse::multi_assgin()
ast parse::multi_assgin()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_multi_assign);
node.add(multi_scalar(true));
match(tok_eq);
if(tokens[ptr].type==tok_eof)
if(lookahead(tok_eof))
{
die(error_line,"expected value list");
return node;
}
if(tokens[ptr].type==tok_lcurve)
if(lookahead(tok_lcurve))
node.add(check_multi_scalar()?multi_scalar(false):calc());
else
node.add(calc());
@ -845,7 +851,7 @@ ast nasal_parse::multi_assgin()
die(node[0].line(),"too much or lack values in multi-assignment");
return node;
}
ast nasal_parse::loop()
ast parse::loop()
{
++in_loop;
ast node(0,0,ast_null);
@ -859,7 +865,7 @@ ast nasal_parse::loop()
--in_loop;
return node;
}
ast nasal_parse::while_loop()
ast parse::while_loop()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_while);
match(tok_while);
@ -869,35 +875,35 @@ ast nasal_parse::while_loop()
node.add(exprs());
return node;
}
ast nasal_parse::for_loop()
ast parse::for_loop()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_for);
match(tok_for);
match(tok_lcurve);
// first expression
if(tokens[ptr].type==tok_eof)
if(lookahead(tok_eof))
die(error_line,"expected definition");
if(tokens[ptr].type==tok_semi)
if(lookahead(tok_semi))
node.add(null());
else if(tokens[ptr].type==tok_var)
else if(lookahead(tok_var))
node.add(definition());
else if(tokens[ptr].type==tok_lcurve)
else if(lookahead(tok_lcurve))
node.add(lcurve_expr());
else
node.add(calc());
match(tok_semi,"expected ';' in for(;;)");
// conditional expression
if(tokens[ptr].type==tok_eof)
if(lookahead(tok_eof))
die(error_line,"expected conditional expr");
if(tokens[ptr].type==tok_semi)
if(lookahead(tok_semi))
node.add(null());
else
node.add(calc());
match(tok_semi,"expected ';' in for(;;)");
//after loop expression
if(tokens[ptr].type==tok_eof)
if(lookahead(tok_eof))
die(error_line,"expected calculation");
if(tokens[ptr].type==tok_rcurve)
if(lookahead(tok_rcurve))
node.add(null());
else
node.add(calc());
@ -905,7 +911,7 @@ ast nasal_parse::for_loop()
node.add(exprs());
return node;
}
ast nasal_parse::forei_loop()
ast parse::forei_loop()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_null);
switch(tokens[ptr].type)
@ -916,21 +922,21 @@ ast nasal_parse::forei_loop()
match(tok_lcurve);
// first expression
// 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");
node.add(iter_gen());
match(tok_semi,"expected ';' in foreach/forindex(iter;vector)");
if(tokens[ptr].type==tok_eof)
if(lookahead(tok_eof))
die(error_line,"expected vector");
node.add(calc());
match(tok_rcurve);
node.add(exprs());
return node;
}
ast nasal_parse::iter_gen()
ast parse::iter_gen()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_null);
if(tokens[ptr].type==tok_var)
if(lookahead(tok_var))
{
match(tok_var);
node.set_type(ast_iter);
@ -946,7 +952,7 @@ ast nasal_parse::iter_gen()
}
return node;
}
ast nasal_parse::conditional()
ast parse::conditional()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_conditional);
ast ifnode(tokens[ptr].line,tokens[ptr].col,ast_if);
@ -956,7 +962,7 @@ ast nasal_parse::conditional()
match(tok_rcurve);
ifnode.add(exprs());
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);
match(tok_elsif);
@ -966,7 +972,7 @@ ast nasal_parse::conditional()
elsifnode.add(exprs());
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);
match(tok_else);
@ -975,19 +981,19 @@ ast nasal_parse::conditional()
}
return node;
}
ast nasal_parse::continue_expr()
ast parse::continue_expr()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_continue);
match(tok_continue);
return node;
}
ast nasal_parse::break_expr()
ast parse::break_expr()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_break);
match(tok_break);
return node;
}
ast nasal_parse::ret_expr()
ast parse::ret_expr()
{
ast node(tokens[ptr].line,tokens[ptr].col,ast_ret);
match(tok_ret);

View File

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