🔥 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:
parent
025ff49ffc
commit
3fd1b25f79
18
README.md
18
README.md
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
120
doc/dev.md
120
doc/dev.md
|
@ -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`.
|
||||
|
|
116
doc/dev_zh.md
116
doc/dev_zh.md
|
@ -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`的返回值在协程的操作数栈顶。综上所述:
|
||||
|
|
19
main.cpp
19
main.cpp
|
@ -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[])
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
2
nasal.h
2
nasal.h
|
@ -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
|
||||
|
|
514
nasal_builtin.h
514
nasal_builtin.h
File diff suppressed because it is too large
Load Diff
104
nasal_codegen.h
104
nasal_codegen.h
|
@ -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";
|
||||
|
|
112
nasal_dbg.h
112
nasal_dbg.h
|
@ -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;
|
||||
|
|
14
nasal_err.h
14
nasal_err.h
|
@ -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
|
248
nasal_gc.h
248
nasal_gc.h
|
@ -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};
|
||||
|
|
|
@ -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
|
|
@ -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";
|
||||
|
|
288
nasal_parse.h
288
nasal_parse.h
|
@ -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);
|
||||
|
|
410
nasal_vm.h
410
nasal_vm.h
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue