vm_nil,vm_num changed to no-gcobject
This commit is contained in:
parent
d71b4f09e2
commit
1733ac0573
224
README.md
224
README.md
|
@ -2,31 +2,46 @@
|
|||
|
||||
## Introduction
|
||||
|
||||
[Nasal](http://wiki.flightgear.org/Nasal_scripting_language) is a script language that used in [FlightGear](https://www.flightgear.org/).
|
||||
[Nasal](http://wiki.flightgear.org/Nasal_scripting_language)
|
||||
is a script language that used in [FlightGear](https://www.flightgear.org/).
|
||||
|
||||
The interpreter is totally rewritten by ValKmjolnir using C++(standard c++11) without reusing the code in Andy Ross's nasal interpreter(<https://github.com/andyross/nasal>). But we really appreciate that Andy created this amazing programming language and his interpreter project.
|
||||
The interpreter is totally rewritten by ValKmjolnir using C++(standard c++11)
|
||||
without reusing the code in Andy Ross's nasal interpreter(<https://github.com/andyross/nasal>).
|
||||
But we really appreciate that Andy created this amazing programming language and his interpreter project.
|
||||
|
||||
The interpreter is still in development(now it works well --2021/2/15). We really need your support!
|
||||
The interpreter is still in development(now it works well --2021/2/15)
|
||||
We really need your support!
|
||||
|
||||
Also,i am a member of [FGPRC](https://www.fgprc.org/), welcome to join us!
|
||||
Also,i am a member of [FGPRC](https://www.fgprc.org/),
|
||||
welcome to join us!
|
||||
|
||||
(2021/5/4) Now this project uses MIT license.Edit it if you want, use this project to learn or create more interesting things(But don't forget me XD).
|
||||
(2021/5/4) Now this project uses MIT license.Edit it if you want,
|
||||
use this project to learn or create more interesting things(But don't forget me XD).
|
||||
|
||||
## Why Writing Nasal Interpreter
|
||||
|
||||
Nasal is a script language first used in Flightgear, created by Andy Ross(<https://github.com/andyross>).
|
||||
Nasal is a script language first used in Flightgear,
|
||||
created by Andy Ross(<https://github.com/andyross>).
|
||||
|
||||
But in last summer holiday, members in FGPRC told me that it is hard to debug with nasal-console in Flightgear, especially when checking syntax errors.
|
||||
But in last summer holiday,
|
||||
members in FGPRC told me that it is hard to debug with nasal-console in Flightgear,
|
||||
especially when checking syntax errors.
|
||||
|
||||
So i tried to write a new interpreter to help them checking syntax error and even, runtime error.
|
||||
So i tried to write a new interpreter to help them checking syntax error and even,
|
||||
runtime error.
|
||||
|
||||
I wrote the lexer, parser and runtimebytecode virtual machine(there was an ast-interpreter,but i deleted it after version4.0) to help checking errors.
|
||||
I wrote the lexer,
|
||||
parser and runtimebytecode virtual machine(there was an ast-interpreter,
|
||||
but i deleted it after version4.0) to help checking errors.
|
||||
|
||||
They found it much easier to check syntax and runtime errors before copying nasal-codes in nasal-console in Flightgear to test.
|
||||
They found it much easier to check syntax and runtime
|
||||
errors before copying nasal-codes in nasal-console in Flightgear to test.
|
||||
|
||||
Also, you could use this language to write some interesting programs and run them without the lib of Flightgear.
|
||||
Also, you could use this language to write some
|
||||
interesting programs and run them without the lib of Flightgear.
|
||||
|
||||
You could add your own built-in functions to change this interpreter to a useful tool in your own projects(such as a script in your own game).
|
||||
You could add your own built-in functions to change
|
||||
this interpreter to a useful tool in your own projects(such as a script in your own game).
|
||||
|
||||
## How to Compile
|
||||
|
||||
|
@ -139,7 +154,7 @@ I change my mind.AST interpreter leaves me too much things to do.
|
|||
|
||||
If i continue saving this interpreter,it will be harder for me to make the bytecode vm become more efficient.
|
||||
|
||||
## Byte Code Interpreter
|
||||
## Byte Code VM
|
||||
|
||||
### Version 4.0 (last update 2020/12/17)
|
||||
|
||||
|
@ -225,17 +240,29 @@ for(var i=0;i<4000000;i+=1);
|
|||
|
||||
### Version 6.5 (last update 2021/6/24)
|
||||
|
||||
2021/5/31 update: Now gc can collect garbage correctly without re-collecting,which will cause fatal error.
|
||||
2021/5/31 update:
|
||||
|
||||
Add builtin_alloc to avoid mark-sweep when running a built-in function,which will mark useful items as useless garbage to collect.
|
||||
Now gc can collect garbage correctly without re-collecting,
|
||||
which will cause fatal error.
|
||||
|
||||
Better use setsize and assignment to get a big array,append is very slow in this situation.
|
||||
Add builtin_alloc to avoid mark-sweep when running a built-in function,
|
||||
which will mark useful items as useless garbage to collect.
|
||||
|
||||
2021/6/3 update: Fixed a bug that gc still re-collects garbage,this time i use three mark states to make sure garbage is ready to be collected.
|
||||
Better use setsize and assignment to get a big array,
|
||||
append is very slow in this situation.
|
||||
|
||||
Change callf to callfv and callfh.And callfv fetches arguments from val_stack directly instead of using vm_vec,a not very efficient way.
|
||||
2021/6/3 update:
|
||||
|
||||
Better use callfv instead of callfh,callfh will fetch a vm_hash from stack and parse it,making this process slow.
|
||||
Fixed a bug that gc still re-collects garbage,
|
||||
this time i use three mark states to make sure garbage is ready to be collected.
|
||||
|
||||
Change callf to callfv and callfh.
|
||||
And callfv fetches arguments from val_stack directly instead of using vm_vec,
|
||||
a not very efficient way.
|
||||
|
||||
Better use callfv instead of callfh,
|
||||
callfh will fetch a vm_hash from stack and parse it,
|
||||
making this process slow.
|
||||
|
||||
```javascript
|
||||
var f=func(x,y){return x+y;}
|
||||
|
@ -267,7 +294,9 @@ f(1024,2048);
|
|||
0x00000011: nop 0x00000000
|
||||
```
|
||||
|
||||
2021/6/21 update: Now gc will not collect nullptr.And the function of assignment is complete,now these kinds of assignment is allowed:
|
||||
2021/6/21 update: Now gc will not collect nullptr.
|
||||
And the function of assignment is complete,
|
||||
now these kinds of assignment is allowed:
|
||||
|
||||
```javascript
|
||||
var f=func()
|
||||
|
@ -284,9 +313,15 @@ m(0)._=m(1)._=10;
|
|||
[0,1,2][1:2][0]=0;
|
||||
```
|
||||
|
||||
In the old version,parser will check this left-value and tells that these kinds of left-value are not allowed(bad lvalue).
|
||||
In the old version,
|
||||
parser will check this left-value and tells that these kinds of left-value are not allowed(bad lvalue).
|
||||
|
||||
But now it can work.And you could see its use by reading the code above.To make sure this assignment works correctly,codegen will generate byte code by nasal_codegen::call_gen() instead of nasal_codegen::mcall_gen(),and the last child of the ast will be generated by nasal_codegen::mcall_gen().So the bytecode is totally different now:
|
||||
But now it can work.
|
||||
And you could see its use by reading the code above.
|
||||
To make sure this assignment works correctly,
|
||||
codegen will generate byte code by nasal_codegen::call_gen() instead of nasal_codegen::mcall_gen(),
|
||||
and the last child of the ast will be generated by nasal_codegen::mcall_gen().
|
||||
So the bytecode is totally different now:
|
||||
|
||||
```asm
|
||||
.number 10
|
||||
|
@ -349,23 +384,40 @@ But now it can work.And you could see its use by reading the code above.To make
|
|||
0x00000035: nop 0x00000000
|
||||
```
|
||||
|
||||
As you could see from the bytecode above,mcall/mcallv/mcallh operands' using frequency will reduce,call/callv/callh/callfv/callfh at the opposite.
|
||||
As you could see from the bytecode above,
|
||||
mcall/mcallv/mcallh operands' using frequency will reduce,
|
||||
call/callv/callh/callfv/callfh at the opposite.
|
||||
|
||||
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 nasal_val** mem_addr to store the memory address. This will not cause fatal errors because the memory address is used __immediately__ after getting it.
|
||||
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 nasal_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 (latest)
|
||||
### version 7.0 (2021/10/8)
|
||||
|
||||
2021/6/26 update:
|
||||
|
||||
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.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,in Test data section.
|
||||
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.
|
||||
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,
|
||||
in Test data section.
|
||||
|
||||
This version uses g++ extension "labels as values", which is also supported by clang++.(But i don't know if MSVC supports this)
|
||||
This version uses g++ extension "labels as values",
|
||||
which is also supported by clang++.
|
||||
(But i don't know if MSVC supports this)
|
||||
|
||||
There is also a change in nasal_gc: std::vector global is deleted,now the global values are all stored on stack(from val_stack+0 to val_stack+intg-1).
|
||||
There is also a change in nasal_gc:
|
||||
std::vector global is deleted,
|
||||
now the global values are all stored on stack(from val_stack+0 to val_stack+intg-1).
|
||||
|
||||
2021/6/29 update:
|
||||
|
||||
Add some instructions that execute const values:op_addc,op_subc,op_mulc,op_divc,op_lnkc,op_addeqc,op_subeqc,op_muleqc,op_diveqc,op_lnkeqc.
|
||||
Add some instructions that execute const values:
|
||||
op_addc,op_subc,op_mulc,op_divc,op_lnkc,op_addeqc,op_subeqc,op_muleqc,op_diveqc,op_lnkeqc.
|
||||
|
||||
Now the bytecode of test/bigloop.nas seems like this:
|
||||
|
||||
|
@ -386,9 +438,12 @@ Now the bytecode of test/bigloop.nas seems like this:
|
|||
0x0000000b: nop 0x00000000
|
||||
```
|
||||
|
||||
And this test file runs in 0.1s after this update.Most of the calculations are accelerated.
|
||||
And this test file runs in 0.1s after this update.
|
||||
Most of the calculations are accelerated.
|
||||
|
||||
Also, assignment bytecode has changed a lot. Now the first identifier that called in assignment will use op_load to assign, instead of op_meq,op_pop.
|
||||
Also, assignment bytecode has changed a lot.
|
||||
Now the first identifier that called in assignment will use op_load to assign,
|
||||
instead of op_meq,op_pop.
|
||||
|
||||
```javascript
|
||||
var (a,b)=(1,2);
|
||||
|
@ -409,6 +464,17 @@ a=b=0;
|
|||
0x00000009: nop 0x00000000
|
||||
```
|
||||
|
||||
### version 8.0 (latest)
|
||||
|
||||
2021/10/8 update:
|
||||
|
||||
In this version vm_nil and vm_num now is not managed by nasal_gc,
|
||||
this will decrease the usage of gc_alloc and increase the efficiency of execution.
|
||||
|
||||
New value type is added: vm_obj.
|
||||
This type is reserved for user to define their own value types.
|
||||
Related API will be added in the future.
|
||||
|
||||
## Test data
|
||||
|
||||
### version 6.5(i5-8250U windows10 2021/6/19)
|
||||
|
@ -622,7 +688,8 @@ foreach(var i;elem)
|
|||
|
||||
### subvec
|
||||
|
||||
Use index to search one element in the string will get the ascii number of this character.If you want to get the character,use built-in function chr().
|
||||
Use index to search one element in the string will get the ascii number of this character.
|
||||
If you want to get the character,use built-in function chr().
|
||||
|
||||
```javascript
|
||||
a[-1,1,0:2,0:,:3,:,nil:8,3:nil,nil:nil];
|
||||
|
@ -687,36 +754,37 @@ If you want to add your own built-in functions,define the function in nasal_buil
|
|||
Definition:
|
||||
|
||||
```C++
|
||||
nasal_val* builtin_chr(std::vector<nasal_val*>&,nasal_gc&);
|
||||
nasal_ref builtin_chr(std::vector<nasal_ref>&,nasal_gc&);
|
||||
```
|
||||
|
||||
Then complete this function using C++:
|
||||
|
||||
```C++
|
||||
nasal_val* builtin_print(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||
nasal_ref builtin_print(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
// get arguments by using builtin_find
|
||||
// find value with index begin from 1
|
||||
// because local_scope[0] is reserved for value 'me'
|
||||
nasal_val* vector_value=local_scope[1];
|
||||
nasal_ref vec_addr=local_scope[1];
|
||||
// main process
|
||||
// also check number of arguments and type here
|
||||
// if get a type error,use builtin_err and return nullptr
|
||||
for(auto i:vec_addr->ptr.vec->elems)
|
||||
switch(i->type)
|
||||
for(auto i:vec_addr.vec()->elems)
|
||||
switch(i.type)
|
||||
{
|
||||
case vm_nil: std::cout<<"nil"; break;
|
||||
case vm_num: std::cout<<i->ptr.num; break;
|
||||
case vm_str: std::cout<<*i->ptr.str; break;
|
||||
case vm_vec: i->ptr.vec->print(); break;
|
||||
case vm_hash: i->ptr.hash->print(); break;
|
||||
case vm_num: std::cout<<i.num(); break;
|
||||
case vm_str: std::cout<<*i.str(); break;
|
||||
case vm_vec: i.vec()->print(); break;
|
||||
case vm_hash: i.hash()->print(); break;
|
||||
case vm_func: std::cout<<"func(...){...}"; break;
|
||||
case vm_obj: std::cout<<"<obj>"; break;
|
||||
}
|
||||
std::cout<<std::flush;
|
||||
// if a nasal value is not in use,use gc::del_reference to delete it
|
||||
// generate return value,use gc::gc_alloc(type) to make a new value
|
||||
// or use reserved reference gc.nil_addr/gc.one_addr/gc.zero_addr
|
||||
return gc.nil_addr;
|
||||
// or use reserved reference gc.nil/gc.one/gc.zero
|
||||
return gc.nil;
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -726,7 +794,7 @@ After that, write the built-in function's name(in nasal) and the function's poin
|
|||
struct FUNC_TABLE
|
||||
{
|
||||
const char* name;
|
||||
nasal_val* (*func)(std::vector<nasal_val*>&,nasal_gc&);
|
||||
nasal_ref (*func)(std::vector<nasal_ref>&,nasal_gc&);
|
||||
} builtin_func[]=
|
||||
{
|
||||
{"__builtin_print",builtin_print},
|
||||
|
@ -752,38 +820,46 @@ var print=func(elems...)
|
|||
};
|
||||
```
|
||||
|
||||
In version 5.0,if you don't warp built-in function in a normal nasal function,this built-in function may cause a fault when searching arguments,which will cause SIGSEGV segmentation error(maybe).
|
||||
In version 5.0,
|
||||
if you don't warp built-in function in a normal nasal function,
|
||||
this built-in function may cause a fault when searching arguments,
|
||||
which will cause SIGSEGV segmentation error(maybe).
|
||||
|
||||
Use import("") to get the nasal file including your built-in functions,then you could use it.
|
||||
Use import("") to get the nasal file including your built-in functions,
|
||||
then you could use it.
|
||||
|
||||
version 6.5 update:
|
||||
|
||||
Use nasal_gc::builtin_alloc in builtin function if this function uses alloc more than one time.
|
||||
|
||||
When running a builtin function,alloc will run more than one time,this may cause mark-sweep in gc_alloc.
|
||||
When running a builtin function,alloc will run more than one time,
|
||||
this may cause mark-sweep in gc_alloc.
|
||||
|
||||
The value got before will be collected,but stil in use in this builtin function,this is a fatal error.
|
||||
The value got before will be collected,but stil in use in this builtin function,
|
||||
this is a fatal error.
|
||||
|
||||
So use builtin_alloc in builtin functions like this:
|
||||
|
||||
```C++
|
||||
nasal_val* builtin_keys(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
|
||||
nasal_ref builtin_keys(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_val* hash_addr=local_scope[1];
|
||||
if(hash_addr->type!=vm_hash)
|
||||
nasal_ref hash_addr=local_scope[1];
|
||||
if(hash_addr.type!=vm_hash)
|
||||
{
|
||||
builtin_err("keys","\"hash\" must be hash");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
nasal_val* ret_addr=gc.builtin_alloc(vm_vec);
|
||||
std::vector<nasal_val*>& ref_vec=ret_addr->ptr.vec->elems;
|
||||
for(auto iter:hash_addr->ptr.hash->elems)
|
||||
|
||||
// push vector into local scope to avoid being sweeped
|
||||
local_scope.push_back(gc.gc_alloc(vm_vec));
|
||||
std::vector<nasal_ref>& vec=local_scope.back().vec()->elems;
|
||||
for(auto iter:hash_addr.hash()->elems)
|
||||
{
|
||||
nasal_val* str_addr=gc.builtin_alloc(vm_str);
|
||||
*str_addr->ptr.str=iter.first;
|
||||
ref_vec.push_back(str_addr);
|
||||
nasal_ref str_addr=gc.builtin_alloc(vm_str);
|
||||
*str_addr.str()=iter.first;
|
||||
vec.push_back(str_addr);
|
||||
}
|
||||
return ret_addr;
|
||||
return local_scope.back();
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -799,13 +875,16 @@ foreach(i;[0,1,2,3])
|
|||
```
|
||||
|
||||
This program can run normally with output 0 1 2 3.
|
||||
But take a look at the iterator 'i',this symbol is defined in foreach without using keyword 'var'.
|
||||
But take a look at the iterator 'i',
|
||||
this symbol is defined in foreach without using keyword 'var'.
|
||||
I think this design will make programmers filling confused.
|
||||
This is ambiguous that programmers maybe difficult to find the 'i' is defined here.
|
||||
Without 'var',programmers may think this 'i' is defined anywhere else.
|
||||
|
||||
So in this new interpreter i use a more strict syntax to force users to use 'var' to define iterator of forindex and foreach.
|
||||
If you forget to add the keyword 'var', and you haven't defined this symbol before, you will get this:
|
||||
If you forget to add the keyword 'var',
|
||||
and you haven't defined this symbol before,
|
||||
you will get this:
|
||||
|
||||
```javascript
|
||||
[code] <test.nas> line 1: undefined symbol "i".
|
||||
|
@ -830,26 +909,33 @@ But in this new interpreter, it will get:
|
|||
```
|
||||
|
||||
(outdated)This difference is caused by different kinds of ways of lexical analysis.
|
||||
In most script language interpreters, they use dynamic analysis to check if this symbol is defined yet.
|
||||
In most script language interpreters,
|
||||
they use dynamic analysis to check if this symbol is defined yet.
|
||||
However, this kind of analysis is at the cost of lower efficiency.
|
||||
To make sure the interpreter runs at higher efficiency, i choose static analysis to manage the memory space of each symbol.
|
||||
To make sure the interpreter runs at higher efficiency,
|
||||
i choose static analysis to manage the memory space of each symbol.
|
||||
By this way, runtime will never need to check if a symbol exists or not.
|
||||
But this causes a difference.
|
||||
You will get an error of 'undefined symbol', instead of nothing happening in most script language interpreters.
|
||||
You will get an error of 'undefined symbol',
|
||||
instead of nothing happening in most script language interpreters.
|
||||
|
||||
This change is __controversial__ among FGPRC's members.
|
||||
So maybe in the future i will use dynamic analysis again to cater to the habits of senior programmers.
|
||||
|
||||
(2021/8/3 update) __Now i use scanning ast twice to reload symbols.
|
||||
So this difference does not exist from this update.__
|
||||
But a new difference is that if you call a variable before defining it, you'll get nil instead of 'undefined error'.
|
||||
But a new difference is that if you call a variable before defining it,
|
||||
you'll get nil instead of 'undefined error'.
|
||||
|
||||
In this new interpreter, function doesn't put dynamic arguments into vector 'arg' automatically.
|
||||
So if you use 'arg' without definition, you'll get an error of 'undefined symbol'.
|
||||
In this new interpreter,
|
||||
function doesn't put dynamic arguments into vector 'arg' automatically.
|
||||
So if you use 'arg' without definition,
|
||||
you'll get an error of 'undefined symbol'.
|
||||
|
||||
## Trace Back Info
|
||||
|
||||
Now when the interpreter crashes,it will print trace back information:
|
||||
Now when the interpreter crashes,
|
||||
it will print trace back information:
|
||||
|
||||
```javascript
|
||||
func()
|
||||
|
@ -907,4 +993,4 @@ trace back:
|
|||
vm stack(limit 10):
|
||||
0x7fcc3110ad00 func | func(1 para){..}
|
||||
0x7fcc3110ad00 ... | 9 same value(s)
|
||||
```
|
||||
```
|
||||
|
|
2
main.cpp
2
main.cpp
|
@ -34,7 +34,7 @@ void logo()
|
|||
<<" / \\/ / _` / __|/ _` | | \n"
|
||||
<<" / /\\ / (_| \\__ \\ (_| | | \n"
|
||||
<<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
|
||||
<<"nasal interpreter ver 7.0\n"
|
||||
<<"nasal interpreter ver 8.0\n"
|
||||
<<"thanks to : https://github.com/andyross/nasal\n"
|
||||
<<"code repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
|
||||
<<"code repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
|
||||
|
|
468
nasal_builtin.h
468
nasal_builtin.h
|
@ -116,110 +116,111 @@ nasal_ref builtin_print(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
|||
// local_scope[0] is reserved for 'me'
|
||||
nasal_ref vec_addr=local_scope[1];
|
||||
// main process
|
||||
for(auto i:vec_addr->ptr.vec->elems)
|
||||
switch(i->type)
|
||||
for(auto i:vec_addr.vec()->elems)
|
||||
switch(i.type)
|
||||
{
|
||||
case vm_nil: std::cout<<"nil"; break;
|
||||
case vm_num: std::cout<<i->ptr.num; break;
|
||||
case vm_str: std::cout<<*i->ptr.str; break;
|
||||
case vm_vec: i->ptr.vec->print(); break;
|
||||
case vm_hash: i->ptr.hash->print(); break;
|
||||
case vm_num: std::cout<<i.num(); break;
|
||||
case vm_str: std::cout<<*i.str(); break;
|
||||
case vm_vec: i.vec()->print(); break;
|
||||
case vm_hash: i.hash()->print(); break;
|
||||
case vm_func: std::cout<<"func(...){...}"; break;
|
||||
case vm_obj: std::cout<<"<obj>"; break;
|
||||
}
|
||||
std::cout<<std::flush;
|
||||
// generate return value
|
||||
return gc.nil_addr;
|
||||
return gc.nil;
|
||||
}
|
||||
nasal_ref builtin_append(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref vec_addr=local_scope[1];
|
||||
nasal_ref elem_addr=local_scope[2];
|
||||
if(vec_addr->type!=vm_vec)
|
||||
if(vec_addr.type!=vm_vec)
|
||||
{
|
||||
builtin_err("append","\"vector\" must be vector");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
std::vector<nasal_ref>& ref_vec=vec_addr->ptr.vec->elems;
|
||||
for(auto i:elem_addr->ptr.vec->elems)
|
||||
std::vector<nasal_ref>& ref_vec=vec_addr.vec()->elems;
|
||||
for(auto i:elem_addr.vec()->elems)
|
||||
ref_vec.push_back(i);
|
||||
return gc.nil_addr;
|
||||
return gc.nil;
|
||||
}
|
||||
nasal_ref builtin_setsize(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref vec_addr=local_scope[1];
|
||||
nasal_ref size_addr=local_scope[2];
|
||||
if(vec_addr->type!=vm_vec)
|
||||
if(vec_addr.type!=vm_vec)
|
||||
{
|
||||
builtin_err("setsize","\"vector\" must be vector");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(size_addr->type!=vm_num)
|
||||
if(size_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("setsize","\"size\" is not a number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
int num=size_addr->ptr.num;
|
||||
int num=size_addr.num();
|
||||
if(num<0)
|
||||
{
|
||||
builtin_err("setsize","\"size\" must be greater than -1");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
vec_addr->ptr.vec->elems.resize(num,gc.nil_addr);
|
||||
return gc.nil_addr;
|
||||
vec_addr.vec()->elems.resize(num,gc.nil);
|
||||
return gc.nil;
|
||||
}
|
||||
|
||||
nasal_ref builtin_system(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
nasal_ref ret_addr(vm_num);
|
||||
nasal_ref str_addr=local_scope[1];
|
||||
if(str_addr->type!=vm_str)
|
||||
if(str_addr.type!=vm_str)
|
||||
{
|
||||
builtin_err("system","\"str\" must be string");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
ret_addr->ptr.num=(double)system(str_addr->ptr.str->c_str());
|
||||
ret_addr.num()=(double)system(str_addr.str()->c_str());
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
nasal_ref builtin_input(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_str);
|
||||
std::cin>>*ret_addr->ptr.str;
|
||||
std::cin>>*ret_addr.str();
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
nasal_ref builtin_sleep(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
if(val_addr->type!=vm_num)
|
||||
if(val_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("sleep","\"duration\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
// sleep in unistd.h will make this progress sleep sleep_time seconds.
|
||||
sleep((unsigned int)val_addr->ptr.num);
|
||||
return gc.nil_addr;
|
||||
sleep((unsigned int)val_addr.num());
|
||||
return gc.nil;
|
||||
}
|
||||
|
||||
nasal_ref builtin_fin(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
if(val_addr->type!=vm_str)
|
||||
if(val_addr.type!=vm_str)
|
||||
{
|
||||
builtin_err("io.fin","\"filename\" must be string");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
std::string& filename=*val_addr->ptr.str;
|
||||
std::string& filename=*val_addr.str();
|
||||
std::ifstream fin(filename);
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_str);
|
||||
*ret_addr->ptr.str="";
|
||||
*ret_addr.str()="";
|
||||
if(!fin.fail())
|
||||
while(!fin.eof())
|
||||
{
|
||||
char c=fin.get();
|
||||
if(fin.eof())
|
||||
break;
|
||||
ret_addr->ptr.str->push_back(c);
|
||||
ret_addr.str()->push_back(c);
|
||||
}
|
||||
else
|
||||
builtin_err("io.fin","cannot open \""+filename+"\"");
|
||||
|
@ -231,56 +232,56 @@ nasal_ref builtin_fout(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
|||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
nasal_ref str_addr=local_scope[2];
|
||||
if(val_addr->type!=vm_str)
|
||||
if(val_addr.type!=vm_str)
|
||||
{
|
||||
builtin_err("io.fout","\"filename\" must be string");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(str_addr->type!=vm_str)
|
||||
if(str_addr.type!=vm_str)
|
||||
{
|
||||
builtin_err("io.fout","\"str\" must be string");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
std::ofstream fout(*val_addr->ptr.str);
|
||||
std::ofstream fout(*val_addr.str());
|
||||
if(fout.fail())
|
||||
{
|
||||
builtin_err("io.fout","cannot open \""+*val_addr->ptr.str+"\"");
|
||||
return nullptr;
|
||||
builtin_err("io.fout","cannot open \""+*val_addr.str()+"\"");
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
fout<<*str_addr->ptr.str;
|
||||
fout<<*str_addr.str();
|
||||
fout.close();
|
||||
return gc.nil_addr;
|
||||
return gc.nil;
|
||||
}
|
||||
|
||||
nasal_ref builtin_split(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref deli_val_addr=local_scope[1];
|
||||
nasal_ref str_val_addr=local_scope[2];
|
||||
if(deli_val_addr->type!=vm_str)
|
||||
if(deli_val_addr.type!=vm_str)
|
||||
{
|
||||
builtin_err("split","\"delimeter\" must be string");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(str_val_addr->type!=vm_str)
|
||||
if(str_val_addr.type!=vm_str)
|
||||
{
|
||||
builtin_err("split","\"string\" must be string");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
std::string& delimeter=*deli_val_addr->ptr.str;
|
||||
std::string& source=*str_val_addr->ptr.str;
|
||||
std::string& delimeter=*deli_val_addr.str();
|
||||
std::string& source=*str_val_addr.str();
|
||||
size_t delimeter_len=delimeter.length();
|
||||
size_t source_len=source.length();
|
||||
|
||||
// push it to local scope to avoid being sweeped
|
||||
local_scope.push_back(gc.gc_alloc(vm_vec));
|
||||
|
||||
std::vector<nasal_ref>& vec=local_scope.back()->ptr.vec->elems;
|
||||
std::vector<nasal_ref>& vec=local_scope.back().vec()->elems;
|
||||
if(!delimeter_len)
|
||||
{
|
||||
for(int i=0;i<source_len;++i)
|
||||
{
|
||||
vec.push_back(gc.gc_alloc(vm_str));
|
||||
*vec.back()->ptr.str=source[i];
|
||||
*vec.back().str()=source[i];
|
||||
}
|
||||
return local_scope.back();
|
||||
}
|
||||
|
@ -302,7 +303,7 @@ nasal_ref builtin_split(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
|||
if(tmp.length())
|
||||
{
|
||||
vec.push_back(gc.gc_alloc(vm_str));
|
||||
*vec.back()->ptr.str=tmp;
|
||||
*vec.back().str()=tmp;
|
||||
tmp="";
|
||||
}
|
||||
i+=delimeter_len-1;
|
||||
|
@ -313,7 +314,7 @@ nasal_ref builtin_split(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
|||
if(tmp.length())
|
||||
{
|
||||
vec.push_back(gc.gc_alloc(vm_str));
|
||||
*vec.back()->ptr.str=tmp;
|
||||
*vec.back().str()=tmp;
|
||||
tmp="";
|
||||
}
|
||||
return local_scope.back();
|
||||
|
@ -321,21 +322,21 @@ nasal_ref builtin_split(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
|||
nasal_ref builtin_rand(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
if(val_addr->type!=vm_num && val_addr->type!=vm_nil)
|
||||
if(val_addr.type!=vm_num && val_addr.type!=vm_nil)
|
||||
{
|
||||
builtin_err("rand","\"seed\" must be nil or number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(val_addr->type==vm_num)
|
||||
if(val_addr.type==vm_num)
|
||||
{
|
||||
srand((unsigned int)val_addr->ptr.num);
|
||||
return gc.nil_addr;
|
||||
srand((unsigned int)val_addr.num());
|
||||
return gc.nil;
|
||||
}
|
||||
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=0;
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=0;
|
||||
for(int i=0;i<5;++i)
|
||||
ret_addr->ptr.num=(ret_addr->ptr.num+rand())*(1.0/(RAND_MAX+1.0));
|
||||
ret_addr.num()=(ret_addr.num()+rand())*(1.0/(RAND_MAX+1.0));
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_id(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
|
@ -343,69 +344,72 @@ nasal_ref builtin_id(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
|||
nasal_ref val_addr=local_scope[1];
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_str);
|
||||
char buf[32];
|
||||
sprintf(buf,"%p",val_addr);
|
||||
*ret_addr->ptr.str=buf;
|
||||
if(val_addr.type>vm_num)
|
||||
sprintf(buf,"%p",val_addr.value.gcobj);
|
||||
else
|
||||
sprintf(buf,"0");
|
||||
*ret_addr.str()=buf;
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_int(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
if(val_addr->type!=vm_num)
|
||||
return gc.nil_addr;
|
||||
int number=(int)val_addr->ptr.num;
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=(double)number;
|
||||
if(val_addr.type!=vm_num)
|
||||
return gc.nil;
|
||||
int number=(int)val_addr.num();
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=(double)number;
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_num(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
if(val_addr->type!=vm_str)
|
||||
return gc.nil_addr;
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=val_addr->to_number();
|
||||
if(val_addr.type!=vm_str)
|
||||
return gc.nil;
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=val_addr.to_number();
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_pop(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
if(val_addr->type!=vm_vec)
|
||||
if(val_addr.type!=vm_vec)
|
||||
{
|
||||
builtin_err("pop","\"vector\" must be vector");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(val_addr->ptr.vec->elems.size())
|
||||
if(val_addr.vec()->elems.size())
|
||||
{
|
||||
nasal_ref tmp=val_addr->ptr.vec->elems.back();
|
||||
val_addr->ptr.vec->elems.pop_back();
|
||||
nasal_ref tmp=val_addr.vec()->elems.back();
|
||||
val_addr.vec()->elems.pop_back();
|
||||
return tmp;
|
||||
}
|
||||
return gc.nil_addr;
|
||||
return gc.nil;
|
||||
}
|
||||
nasal_ref builtin_str(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
if(val_addr->type!=vm_num)
|
||||
if(val_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("str","\"number\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_str);
|
||||
*ret_addr->ptr.str=std::to_string(val_addr->ptr.num);
|
||||
*ret_addr.str()=std::to_string(val_addr.num());
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_size(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
switch(val_addr->type)
|
||||
nasal_ref ret_addr(vm_num);
|
||||
switch(val_addr.type)
|
||||
{
|
||||
case vm_nil: ret_addr->ptr.num=0; break;
|
||||
case vm_num: ret_addr->ptr.num=val_addr->ptr.num; break;
|
||||
case vm_func: ret_addr->ptr.num=0; break;
|
||||
case vm_str: ret_addr->ptr.num=val_addr->ptr.str->length(); break;
|
||||
case vm_vec: ret_addr->ptr.num=val_addr->ptr.vec->elems.size(); break;
|
||||
case vm_hash: ret_addr->ptr.num=val_addr->ptr.hash->elems.size();break;
|
||||
case vm_nil: ret_addr.num()=0; break;
|
||||
case vm_num: ret_addr.num()=val_addr.num(); break;
|
||||
case vm_func: ret_addr.num()=0; break;
|
||||
case vm_str: ret_addr.num()=val_addr.str()->length(); break;
|
||||
case vm_vec: ret_addr.num()=val_addr.vec()->elems.size(); break;
|
||||
case vm_hash: ret_addr.num()=val_addr.hash()->elems.size();break;
|
||||
}
|
||||
return ret_addr;
|
||||
}
|
||||
|
@ -413,255 +417,255 @@ nasal_ref builtin_xor(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
|||
{
|
||||
nasal_ref a_addr=local_scope[1];
|
||||
nasal_ref b_addr=local_scope[2];
|
||||
if(a_addr->type!=vm_num)
|
||||
if(a_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("xor","\"a\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(b_addr->type!=vm_num)
|
||||
if(b_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("xor","\"b\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
int number_a=(int)a_addr->ptr.num;
|
||||
int number_b=(int)b_addr->ptr.num;
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=(number_a^number_b);
|
||||
int number_a=(int)a_addr.num();
|
||||
int number_b=(int)b_addr.num();
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=(number_a^number_b);
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_and(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref a_addr=local_scope[1];
|
||||
nasal_ref b_addr=local_scope[2];
|
||||
if(a_addr->type!=vm_num)
|
||||
if(a_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("and","\"a\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(b_addr->type!=vm_num)
|
||||
if(b_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("and","\"b\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
int number_a=(int)a_addr->ptr.num;
|
||||
int number_b=(int)b_addr->ptr.num;
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=(number_a&number_b);
|
||||
int number_a=(int)a_addr.num();
|
||||
int number_b=(int)b_addr.num();
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=(number_a&number_b);
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_or(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref a_addr=local_scope[1];
|
||||
nasal_ref b_addr=local_scope[2];
|
||||
if(a_addr->type!=vm_num)
|
||||
if(a_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("or","\"a\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(b_addr->type!=vm_num)
|
||||
if(b_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("or","\"b\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
int number_a=(int)a_addr->ptr.num;
|
||||
int number_b=(int)b_addr->ptr.num;
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=(number_a|number_b);
|
||||
int number_a=(int)a_addr.num();
|
||||
int number_b=(int)b_addr.num();
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=(number_a|number_b);
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_nand(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref a_addr=local_scope[1];
|
||||
nasal_ref b_addr=local_scope[2];
|
||||
if(a_addr->type!=vm_num)
|
||||
if(a_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("nand","\"a\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(b_addr->type!=vm_num)
|
||||
if(b_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("nand","\"b\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
int number_a=(int)a_addr->ptr.num;
|
||||
int number_b=(int)b_addr->ptr.num;
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=(~(number_a&number_b));
|
||||
int number_a=(int)a_addr.num();
|
||||
int number_b=(int)b_addr.num();
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=(~(number_a&number_b));
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_not(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref a_addr=local_scope[1];
|
||||
if(a_addr->type!=vm_num)
|
||||
if(a_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("not","\"a\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
int number=(int)a_addr->ptr.num;
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=(~number);
|
||||
int number=(int)a_addr.num();
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=(~number);
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_sin(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
if(val_addr->type!=vm_num)
|
||||
if(val_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("sin","\"x\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=sin(val_addr->ptr.num);
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=sin(val_addr.num());
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_cos(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
if(val_addr->type!=vm_num)
|
||||
if(val_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("cos","\"x\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=cos(val_addr->ptr.num);
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=cos(val_addr.num());
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_tan(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
if(val_addr->type!=vm_num)
|
||||
if(val_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("tan","\"x\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=tan(val_addr->ptr.num);
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=tan(val_addr.num());
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_exp(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
if(val_addr->type!=vm_num)
|
||||
if(val_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("exp","\"x\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=exp(val_addr->ptr.num);
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=exp(val_addr.num());
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_ln(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
if(val_addr->type!=vm_num)
|
||||
if(val_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("ln","\"x\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=(log(val_addr->ptr.num)/log(2.7182818284590452354));
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=(log(val_addr.num())/log(2.7182818284590452354));
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_sqrt(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
if(val_addr->type!=vm_num)
|
||||
if(val_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("sqrt","\"x\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=sqrt(val_addr->ptr.num);
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=sqrt(val_addr.num());
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_atan2(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref x_val_addr=local_scope[1];
|
||||
nasal_ref y_val_addr=local_scope[2];
|
||||
if(x_val_addr->type!=vm_num)
|
||||
if(x_val_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("atan2","\"x\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(y_val_addr->type!=vm_num)
|
||||
if(y_val_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("atan2","\"y\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=atan2(y_val_addr->ptr.num,x_val_addr->ptr.num);
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=atan2(y_val_addr.num(),x_val_addr.num());
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_isnan(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref x=local_scope[1];
|
||||
if(x->type==vm_num && std::isnan(x->ptr.num))
|
||||
return gc.one_addr;
|
||||
return gc.zero_addr;
|
||||
if(x.type==vm_num && std::isnan(x.num()))
|
||||
return gc.one;
|
||||
return gc.zero;
|
||||
}
|
||||
nasal_ref builtin_time(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
if(val_addr->type!=vm_num)
|
||||
if(val_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("time","\"begin_time\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
time_t begin_time=(time_t)val_addr->ptr.num;
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=time(&begin_time);
|
||||
time_t begin_time=(time_t)val_addr.num();
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=time(&begin_time);
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_contains(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref hash_addr=local_scope[1];
|
||||
nasal_ref key_addr=local_scope[2];
|
||||
if(hash_addr->type!=vm_hash)
|
||||
if(hash_addr.type!=vm_hash)
|
||||
{
|
||||
builtin_err("contains","\"hash\" must be hash");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(key_addr->type!=vm_str)
|
||||
if(key_addr.type!=vm_str)
|
||||
{
|
||||
builtin_err("contains","\"key\" must be string");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
return hash_addr->ptr.hash->elems.count(*key_addr->ptr.str)?gc.one_addr:gc.zero_addr;
|
||||
return hash_addr.hash()->elems.count(*key_addr.str())?gc.one:gc.zero;
|
||||
}
|
||||
nasal_ref builtin_delete(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref hash_addr=local_scope[1];
|
||||
nasal_ref key_addr=local_scope[2];
|
||||
if(hash_addr->type!=vm_hash)
|
||||
if(hash_addr.type!=vm_hash)
|
||||
{
|
||||
builtin_err("delete","\"hash\" must be hash");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(key_addr->type!=vm_str)
|
||||
if(key_addr.type!=vm_str)
|
||||
{
|
||||
builtin_err("delete","\"key\" must be string");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(hash_addr->ptr.hash->elems.count(*key_addr->ptr.str))
|
||||
hash_addr->ptr.hash->elems.erase(*key_addr->ptr.str);
|
||||
return gc.nil_addr;
|
||||
if(hash_addr.hash()->elems.count(*key_addr.str()))
|
||||
hash_addr.hash()->elems.erase(*key_addr.str());
|
||||
return gc.nil;
|
||||
}
|
||||
nasal_ref builtin_keys(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref hash_addr=local_scope[1];
|
||||
if(hash_addr->type!=vm_hash)
|
||||
if(hash_addr.type!=vm_hash)
|
||||
{
|
||||
builtin_err("keys","\"hash\" must be hash");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
|
||||
// push vector into local scope to avoid being sweeped
|
||||
local_scope.push_back(gc.gc_alloc(vm_vec));
|
||||
std::vector<nasal_ref>& vec=local_scope.back()->ptr.vec->elems;
|
||||
for(auto iter:hash_addr->ptr.hash->elems)
|
||||
std::vector<nasal_ref>& vec=local_scope.back().vec()->elems;
|
||||
for(auto iter:hash_addr.hash()->elems)
|
||||
{
|
||||
nasal_ref str_addr=gc.gc_alloc(vm_str);
|
||||
*str_addr->ptr.str=iter.first;
|
||||
*str_addr.str()=iter.first;
|
||||
vec.push_back(str_addr);
|
||||
}
|
||||
return local_scope.back();
|
||||
|
@ -671,31 +675,31 @@ nasal_ref builtin_import(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
|||
// this function is used in preprocessing.
|
||||
// this function will return nothing when running.
|
||||
builtin_err("import","must use this function in global scope");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
nasal_ref builtin_die(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref str_addr=local_scope[1];
|
||||
if(str_addr->type!=vm_str)
|
||||
if(str_addr.type!=vm_str)
|
||||
{
|
||||
builtin_err("die","\"str\" must be string");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
std::cout<<"[vm] error: "<<*str_addr->ptr.str<<'\n';
|
||||
return nullptr;
|
||||
std::cout<<"[vm] error: "<<*str_addr.str()<<'\n';
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
nasal_ref builtin_type(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref val_addr=local_scope[1];
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_str);
|
||||
switch(val_addr->type)
|
||||
switch(val_addr.type)
|
||||
{
|
||||
case vm_nil: *ret_addr->ptr.str="nil"; break;
|
||||
case vm_num: *ret_addr->ptr.str="num"; break;
|
||||
case vm_str: *ret_addr->ptr.str="str"; break;
|
||||
case vm_vec: *ret_addr->ptr.str="vec"; break;
|
||||
case vm_hash: *ret_addr->ptr.str="hash"; break;
|
||||
case vm_func: *ret_addr->ptr.str="func"; break;
|
||||
case vm_nil: *ret_addr.str()="nil"; break;
|
||||
case vm_num: *ret_addr.str()="num"; break;
|
||||
case vm_str: *ret_addr.str()="str"; break;
|
||||
case vm_vec: *ret_addr.str()="vec"; break;
|
||||
case vm_hash: *ret_addr.str()="hash"; break;
|
||||
case vm_func: *ret_addr.str()="func"; break;
|
||||
}
|
||||
return ret_addr;
|
||||
}
|
||||
|
@ -704,106 +708,106 @@ nasal_ref builtin_substr(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
|||
nasal_ref str_addr=local_scope[1];
|
||||
nasal_ref beg_addr=local_scope[2];
|
||||
nasal_ref len_addr=local_scope[3];
|
||||
if(str_addr->type!=vm_str)
|
||||
if(str_addr.type!=vm_str)
|
||||
{
|
||||
builtin_err("substr","\"str\" must be string");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(beg_addr->type!=vm_num)
|
||||
if(beg_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("substr","\"begin\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(len_addr->type!=vm_num)
|
||||
if(len_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("substr","\"length\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
std::string& str=*str_addr->ptr.str;
|
||||
int beg=(int)beg_addr->ptr.num;
|
||||
int len=(int)len_addr->ptr.num;
|
||||
std::string& str=*str_addr.str();
|
||||
int beg=(int)beg_addr.num();
|
||||
int len=(int)len_addr.num();
|
||||
if(beg>=str.length() || beg+len-1>=str.length())
|
||||
{
|
||||
builtin_err("susbtr","index out of range");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(len<0)
|
||||
len=0;
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_str);
|
||||
*ret_addr->ptr.str=str.substr(beg,len);
|
||||
*ret_addr.str()=str.substr(beg,len);
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_streq(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref a_addr=local_scope[1];
|
||||
nasal_ref b_addr=local_scope[2];
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=(a_addr->type!=vm_str || b_addr->type!=vm_str)?0:(*a_addr->ptr.str==*b_addr->ptr.str);
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=(a_addr.type!=vm_str || b_addr.type!=vm_str)?0:(*a_addr.str()==*b_addr.str());
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_left(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref str_addr=local_scope[1];
|
||||
nasal_ref len_addr=local_scope[2];
|
||||
if(str_addr->type!=vm_str)
|
||||
if(str_addr.type!=vm_str)
|
||||
{
|
||||
builtin_err("left","\"string\" must be string");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(len_addr->type!=vm_num)
|
||||
if(len_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("left","\"length\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
std::string& str=*str_addr->ptr.str;
|
||||
int len=(int)len_addr->ptr.num;
|
||||
std::string& str=*str_addr.str();
|
||||
int len=(int)len_addr.num();
|
||||
if(len<0)
|
||||
len=0;
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_str);
|
||||
*ret_addr->ptr.str=str.substr(0, len);
|
||||
*ret_addr.str()=str.substr(0, len);
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_right(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref str_addr=local_scope[1];
|
||||
nasal_ref len_addr=local_scope[2];
|
||||
if(str_addr->type!=vm_str)
|
||||
if(str_addr.type!=vm_str)
|
||||
{
|
||||
builtin_err("right","\"string\" must be string");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(len_addr->type!=vm_num)
|
||||
if(len_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("right","\"length\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
std::string& str=*str_addr->ptr.str;
|
||||
int len=(int)len_addr->ptr.num;
|
||||
std::string& str=*str_addr.str();
|
||||
int len=(int)len_addr.num();
|
||||
int srclen=str.length();
|
||||
if(len>srclen)
|
||||
len=srclen;
|
||||
if(len<0)
|
||||
len=0;
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_str);
|
||||
*ret_addr->ptr.str=str.substr(srclen-len, srclen);
|
||||
*ret_addr.str()=str.substr(srclen-len, srclen);
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_cmp(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref a_addr=local_scope[1];
|
||||
nasal_ref b_addr=local_scope[2];
|
||||
if(a_addr->type!=vm_str)
|
||||
if(a_addr.type!=vm_str)
|
||||
{
|
||||
builtin_err("cmp","\"a\" must be string");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
if(b_addr->type!=vm_str)
|
||||
if(b_addr.type!=vm_str)
|
||||
{
|
||||
builtin_err("cmp","\"b\" must be string");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_num);
|
||||
ret_addr->ptr.num=strcmp(a_addr->ptr.str->c_str(),b_addr->ptr.str->c_str());
|
||||
nasal_ref ret_addr(vm_num);
|
||||
ret_addr.num()=strcmp(a_addr.str()->c_str(),b_addr.str()->c_str());
|
||||
return ret_addr;
|
||||
}
|
||||
nasal_ref builtin_chr(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
||||
|
@ -827,19 +831,19 @@ nasal_ref builtin_chr(std::vector<nasal_ref>& local_scope,nasal_gc& gc)
|
|||
"ø","ù","ú","û","ü","ý","þ","ÿ"
|
||||
};
|
||||
nasal_ref code_addr=local_scope[1];
|
||||
if(code_addr->type!=vm_num)
|
||||
if(code_addr.type!=vm_num)
|
||||
{
|
||||
builtin_err("chr","\"code\" must be number");
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
nasal_ref ret_addr=gc.gc_alloc(vm_str);
|
||||
int num=code_addr->ptr.num;
|
||||
int num=code_addr.num();
|
||||
if(0<=num && num<128)
|
||||
*ret_addr->ptr.str=(char)num;
|
||||
*ret_addr.str()=(char)num;
|
||||
else if(128<=num && num<256)
|
||||
*ret_addr->ptr.str=extend[num-128];
|
||||
*ret_addr.str()=extend[num-128];
|
||||
else
|
||||
*ret_addr->ptr.str=" ";
|
||||
*ret_addr.str()=" ";
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
|
|
272
nasal_gc.h
272
nasal_gc.h
|
@ -3,8 +3,11 @@
|
|||
|
||||
enum nasal_type
|
||||
{
|
||||
vm_nil=0,
|
||||
// none-gc object
|
||||
vm_none=0,
|
||||
vm_nil,
|
||||
vm_num,
|
||||
// gc object
|
||||
vm_str,
|
||||
vm_func,
|
||||
vm_vec,
|
||||
|
@ -15,10 +18,13 @@ enum nasal_type
|
|||
|
||||
// change parameters here to make your own efficient gc
|
||||
// better set bigger number on vm_num and vm_vec
|
||||
const int increment[vm_type_size]=
|
||||
const uint32_t increment[vm_type_size]=
|
||||
{
|
||||
0, // vm_nil,in fact it is not in use
|
||||
65536,// vm_num
|
||||
// none-gc object
|
||||
0, // vm_none, error type
|
||||
0, // vm_nil
|
||||
0, // vm_num
|
||||
// gc object
|
||||
2048, // vm_str
|
||||
512, // vm_func
|
||||
8192, // vm_vec
|
||||
|
@ -26,12 +32,12 @@ const int increment[vm_type_size]=
|
|||
0 // vm_obj
|
||||
};
|
||||
|
||||
// declaration of nasal_val
|
||||
// declaration of nasal value type
|
||||
struct nasal_vec;
|
||||
struct nasal_hash;
|
||||
struct nasal_func;
|
||||
struct nasal_val;
|
||||
// define nasal_ref => nasal_val*
|
||||
typedef nasal_val* nasal_ref;
|
||||
|
||||
#ifdef __NASAL_REF__
|
||||
// declaration of nasal_ref
|
||||
struct nasal_ref
|
||||
{
|
||||
uint8_t type;
|
||||
|
@ -40,8 +46,44 @@ struct nasal_ref
|
|||
double num;
|
||||
nasal_val* gcobj;
|
||||
}value;
|
||||
nasal_ref(const uint8_t t=vm_none):type(t){}
|
||||
nasal_ref(const uint8_t t,const double n):type(t){value.num=n;}
|
||||
nasal_ref(const uint8_t t,nasal_val* n):type(t){value.gcobj=n;}
|
||||
nasal_ref(const nasal_ref& nr)
|
||||
{
|
||||
type=nr.type;
|
||||
value=nr.value;
|
||||
}
|
||||
nasal_ref(const nasal_ref&& nr)
|
||||
{
|
||||
type=nr.type;
|
||||
value=nr.value;
|
||||
}
|
||||
nasal_ref& operator=(const nasal_ref& nr)
|
||||
{
|
||||
type=nr.type;
|
||||
value=nr.value;
|
||||
return *this;
|
||||
}
|
||||
nasal_ref& operator=(const nasal_ref&& nr)
|
||||
{
|
||||
type=nr.type;
|
||||
value=nr.value;
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const nasal_ref& nr){return type==nr.type && value.gcobj==nr.value.gcobj;}
|
||||
bool operator!=(const nasal_ref& nr){return type!=nr.type || value.gcobj!=nr.value.gcobj;}
|
||||
// nasal is a weak-type programming language because number and string can be translated to each other
|
||||
double to_number();
|
||||
std::string to_string();
|
||||
// inline function to get number and pointers, make it easier to read the code
|
||||
inline double& num ();
|
||||
inline std::string* str ();
|
||||
inline nasal_vec* vec ();
|
||||
inline nasal_hash* hash();
|
||||
inline nasal_func* func();
|
||||
inline void* obj ();
|
||||
};
|
||||
#endif
|
||||
|
||||
struct nasal_vec// 24 bytes
|
||||
{
|
||||
|
@ -83,7 +125,6 @@ struct nasal_val// 16 bytes
|
|||
uint8_t type;
|
||||
union
|
||||
{
|
||||
double num;
|
||||
std::string* str;
|
||||
nasal_vec* vec;
|
||||
nasal_hash* hash;
|
||||
|
@ -91,10 +132,8 @@ struct nasal_val// 16 bytes
|
|||
void* obj;
|
||||
}ptr;
|
||||
|
||||
nasal_val(int);
|
||||
nasal_val(uint8_t);
|
||||
~nasal_val();
|
||||
double to_number();
|
||||
std::string to_string();
|
||||
};
|
||||
|
||||
/*functions of nasal_vec*/
|
||||
|
@ -102,7 +141,7 @@ nasal_ref nasal_vec::get_val(int index)
|
|||
{
|
||||
int vec_size=elems.size();
|
||||
if(index<-vec_size || index>=vec_size)
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
return elems[index>=0?index:index+vec_size];
|
||||
}
|
||||
nasal_ref* nasal_vec::get_mem(int index)
|
||||
|
@ -128,16 +167,17 @@ void nasal_vec::print()
|
|||
}
|
||||
ssize_t iter=0;
|
||||
std::cout<<'[';
|
||||
for(auto i:elems)
|
||||
for(auto& i:elems)
|
||||
{
|
||||
switch(i->type)
|
||||
switch(i.type)
|
||||
{
|
||||
case vm_nil: std::cout<<"nil"; break;
|
||||
case vm_num: std::cout<<i->ptr.num; break;
|
||||
case vm_str: std::cout<<*i->ptr.str; break;
|
||||
case vm_vec: i->ptr.vec->print(); break;
|
||||
case vm_hash: i->ptr.hash->print(); break;
|
||||
case vm_func: std::cout<<"func(..){..}"; break;
|
||||
case vm_none: std::cout<<"undefined"; break;
|
||||
case vm_nil: std::cout<<"nil"; break;
|
||||
case vm_num: std::cout<<i.num(); break;
|
||||
case vm_str: std::cout<<*i.str(); break;
|
||||
case vm_vec: i.vec()->print(); break;
|
||||
case vm_hash: i.hash()->print(); break;
|
||||
case vm_func: std::cout<<"func(..){..}";break;
|
||||
}
|
||||
std::cout<<",]"[(++iter)==elems.size()];
|
||||
}
|
||||
|
@ -152,18 +192,18 @@ nasal_ref nasal_hash::get_val(std::string& key)
|
|||
return elems[key];
|
||||
else if(elems.count("parents"))
|
||||
{
|
||||
nasal_ref ret_addr=nullptr;
|
||||
nasal_ref val_addr=elems["parents"];
|
||||
if(val_addr->type==vm_vec)
|
||||
for(auto i:val_addr->ptr.vec->elems)
|
||||
nasal_ref ret(vm_none);
|
||||
nasal_ref val=elems["parents"];
|
||||
if(val.type==vm_vec)
|
||||
for(auto& i:val.vec()->elems)
|
||||
{
|
||||
if(i->type==vm_hash)
|
||||
ret_addr=i->ptr.hash->get_val(key);
|
||||
if(ret_addr)
|
||||
return ret_addr;
|
||||
if(i.type==vm_hash)
|
||||
ret=i.hash()->get_val(key);
|
||||
if(ret.type!=vm_none)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return nasal_ref(vm_none);
|
||||
}
|
||||
nasal_ref* nasal_hash::get_mem(std::string& key)
|
||||
{
|
||||
|
@ -172,12 +212,12 @@ nasal_ref* nasal_hash::get_mem(std::string& key)
|
|||
else if(elems.count("parents"))
|
||||
{
|
||||
nasal_ref* mem_addr=nullptr;
|
||||
nasal_ref val_addr=elems["parents"];
|
||||
if(val_addr->type==vm_vec)
|
||||
for(auto i:val_addr->ptr.vec->elems)
|
||||
nasal_ref val=elems["parents"];
|
||||
if(val.type==vm_vec)
|
||||
for(auto& i:val.vec()->elems)
|
||||
{
|
||||
if(i->type==vm_hash)
|
||||
mem_addr=i->ptr.hash->get_mem(key);
|
||||
if(i.type==vm_hash)
|
||||
mem_addr=i.hash()->get_mem(key);
|
||||
if(mem_addr)
|
||||
return mem_addr;
|
||||
}
|
||||
|
@ -204,14 +244,15 @@ void nasal_hash::print()
|
|||
{
|
||||
std::cout<<i.first<<':';
|
||||
nasal_ref tmp=i.second;
|
||||
switch(tmp->type)
|
||||
switch(tmp.type)
|
||||
{
|
||||
case vm_nil: std::cout<<"nil"; break;
|
||||
case vm_num: std::cout<<tmp->ptr.num; break;
|
||||
case vm_str: std::cout<<*tmp->ptr.str; break;
|
||||
case vm_vec: tmp->ptr.vec->print(); break;
|
||||
case vm_hash: tmp->ptr.hash->print(); break;
|
||||
case vm_func: std::cout<<"func(..){..}"; break;
|
||||
case vm_none: std::cout<<"undefined"; break;
|
||||
case vm_nil: std::cout<<"nil"; break;
|
||||
case vm_num: std::cout<<tmp.num(); break;
|
||||
case vm_str: std::cout<<*tmp.str(); break;
|
||||
case vm_vec: tmp.vec()->print(); break;
|
||||
case vm_hash: tmp.hash()->print(); break;
|
||||
case vm_func: std::cout<<"func(..){..}";break;
|
||||
}
|
||||
std::cout<<",}"[(++iter)==elems.size()];
|
||||
}
|
||||
|
@ -234,13 +275,12 @@ void nasal_func::clear()
|
|||
}
|
||||
|
||||
/*functions of nasal_val*/
|
||||
nasal_val::nasal_val(int val_type)
|
||||
nasal_val::nasal_val(uint8_t val_type)
|
||||
{
|
||||
mark=GC_COLLECTED;
|
||||
type=val_type;
|
||||
switch(type)
|
||||
{
|
||||
case vm_num: ptr.num=0; break;
|
||||
case vm_str: ptr.str=new std::string; break;
|
||||
case vm_vec: ptr.vec=new nasal_vec; break;
|
||||
case vm_hash: ptr.hash=new nasal_hash; break;
|
||||
|
@ -260,40 +300,47 @@ nasal_val::~nasal_val()
|
|||
type=vm_nil;
|
||||
return;
|
||||
}
|
||||
double nasal_val::to_number()
|
||||
|
||||
/* functions of nasal_ref */
|
||||
double nasal_ref::to_number()
|
||||
{
|
||||
if(type==vm_str)
|
||||
return str2num(ptr.str->c_str());
|
||||
return ptr.num;
|
||||
return str2num(str()->c_str());
|
||||
return num();
|
||||
}
|
||||
std::string nasal_val::to_string()
|
||||
std::string nasal_ref::to_string()
|
||||
{
|
||||
if(type==vm_str)
|
||||
return *ptr.str;
|
||||
return *str();
|
||||
else if(type==vm_num)
|
||||
return std::to_string(ptr.num);
|
||||
return std::to_string(num());
|
||||
return "";
|
||||
}
|
||||
inline double& nasal_ref::num (){return value.num;}
|
||||
inline std::string* nasal_ref::str (){return value.gcobj->ptr.str;}
|
||||
inline nasal_vec* nasal_ref::vec (){return value.gcobj->ptr.vec;}
|
||||
inline nasal_hash* nasal_ref::hash(){return value.gcobj->ptr.hash;}
|
||||
inline nasal_func* nasal_ref::func(){return value.gcobj->ptr.func;}
|
||||
inline void* nasal_ref::obj (){return value.gcobj->ptr.obj;}
|
||||
|
||||
struct nasal_gc
|
||||
{
|
||||
#define STACK_MAX_DEPTH (4095)
|
||||
nasal_ref zero_addr; // reserved address of nasal_val,type vm_num, 0
|
||||
nasal_ref one_addr; // reserved address of nasal_val,type vm_num, 1
|
||||
nasal_ref nil_addr; // reserved address of nasal_val,type vm_nil
|
||||
nasal_ref val_stack[STACK_MAX_DEPTH+1];// 1 reserved to avoid stack overflow, stack grows 1 each time
|
||||
nasal_ref* stack_top; // stack top
|
||||
std::vector<nasal_ref> num_addrs; // reserved address for const vm_num
|
||||
std::vector<nasal_ref> str_addrs; // reserved address for const vm_str
|
||||
std::vector<nasal_ref> memory; // gc memory
|
||||
std::queue <nasal_ref> free_list[vm_type_size]; // gc free list
|
||||
std::vector<nasal_ref> local;
|
||||
void mark();
|
||||
void sweep();
|
||||
void gc_init(const std::vector<double>&,const std::vector<std::string>&);
|
||||
void gc_clear();
|
||||
nasal_ref gc_alloc(int);
|
||||
nasal_ref builtin_alloc(int);
|
||||
nasal_ref zero; // reserved address of nasal_val,type vm_num, 0
|
||||
nasal_ref one; // reserved address of nasal_val,type vm_num, 1
|
||||
nasal_ref nil; // reserved address of nasal_val,type vm_nil
|
||||
nasal_ref val_stack[STACK_MAX_DEPTH+1];// 1 reserved to avoid stack overflow, stack grows 1 each time
|
||||
nasal_ref* stack_top; // stack top
|
||||
std::vector<nasal_ref> str_addrs; // reserved address for const vm_str
|
||||
std::vector<nasal_val*> memory; // gc memory
|
||||
std::queue<nasal_val*> free_list[vm_type_size]; // gc free list
|
||||
std::vector<nasal_ref> local;
|
||||
void mark();
|
||||
void sweep();
|
||||
void gc_init(const std::vector<std::string>&);
|
||||
void gc_clear();
|
||||
nasal_ref gc_alloc(const uint8_t);
|
||||
nasal_ref builtin_alloc(const uint8_t);
|
||||
};
|
||||
|
||||
/* gc functions */
|
||||
|
@ -308,22 +355,22 @@ void nasal_gc::mark()
|
|||
{
|
||||
nasal_ref tmp=bfs.front();
|
||||
bfs.pop();
|
||||
if(tmp->mark) continue;
|
||||
tmp->mark=GC_FOUND;
|
||||
switch(tmp->type)
|
||||
if(tmp.type<=vm_num || tmp.value.gcobj->mark) continue;
|
||||
tmp.value.gcobj->mark=GC_FOUND;
|
||||
switch(tmp.type)
|
||||
{
|
||||
case vm_vec:
|
||||
for(auto i:tmp->ptr.vec->elems)
|
||||
for(auto& i:tmp.vec()->elems)
|
||||
bfs.push(i);
|
||||
break;
|
||||
case vm_hash:
|
||||
for(auto& i:tmp->ptr.hash->elems)
|
||||
for(auto& i:tmp.hash()->elems)
|
||||
bfs.push(i.second);
|
||||
break;
|
||||
case vm_func:
|
||||
bfs.push(tmp->ptr.func->closure);
|
||||
for(auto i:tmp->ptr.func->default_para)
|
||||
if(i)
|
||||
bfs.push(tmp.func()->closure);
|
||||
for(auto& i:tmp.func()->default_para)
|
||||
if(i.type>vm_num)
|
||||
bfs.push(i);
|
||||
break;
|
||||
}
|
||||
|
@ -351,39 +398,28 @@ void nasal_gc::sweep()
|
|||
}
|
||||
return;
|
||||
}
|
||||
void nasal_gc::gc_init(const std::vector<double>& nums,const std::vector<std::string>& strs)
|
||||
void nasal_gc::gc_init(const std::vector<std::string>& strs)
|
||||
{
|
||||
for(int i=vm_num;i<vm_type_size;++i)
|
||||
for(int j=0;j<increment[i];++j)
|
||||
for(uint8_t i=vm_str;i<vm_type_size;++i)
|
||||
for(uint32_t j=0;j<increment[i];++j)
|
||||
{
|
||||
nasal_ref tmp=new nasal_val(i);
|
||||
memory.push_back(tmp);
|
||||
free_list[i].push(tmp);
|
||||
nasal_ref tmp={i,new nasal_val(i)};
|
||||
memory.push_back(tmp.value.gcobj);
|
||||
free_list[i].push(tmp.value.gcobj);
|
||||
}
|
||||
|
||||
stack_top=val_stack; // set stack_top to val_stack
|
||||
|
||||
zero_addr=new nasal_val(vm_num); // init constant 0
|
||||
zero_addr->ptr.num=0;
|
||||
zero={vm_num,(double)0}; // init constant 0
|
||||
one ={vm_num,(double)1}; // init constant 1
|
||||
nil.type=vm_nil; // init constant nil
|
||||
|
||||
one_addr=new nasal_val(vm_num); // init constant 1
|
||||
one_addr->ptr.num=1;
|
||||
|
||||
nil_addr=new nasal_val(vm_nil); // init nil
|
||||
|
||||
// init constant numbers
|
||||
num_addrs.resize(nums.size());
|
||||
for(int i=0;i<nums.size();++i)
|
||||
{
|
||||
num_addrs[i]=new nasal_val(vm_num);
|
||||
num_addrs[i]->ptr.num=nums[i];
|
||||
}
|
||||
// init constant strings
|
||||
str_addrs.resize(strs.size());
|
||||
for(int i=0;i<strs.size();++i)
|
||||
{
|
||||
str_addrs[i]=new nasal_val(vm_str);
|
||||
*str_addrs[i]->ptr.str=strs[i];
|
||||
str_addrs[i]={vm_str,new nasal_val(vm_str)};
|
||||
*str_addrs[i].str()=strs[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -392,23 +428,17 @@ void nasal_gc::gc_clear()
|
|||
for(auto i:memory)
|
||||
delete i;
|
||||
memory.clear();
|
||||
for(int i=0;i<vm_type_size;++i)
|
||||
for(uint8_t i=0;i<vm_type_size;++i)
|
||||
while(!free_list[i].empty())
|
||||
free_list[i].pop();
|
||||
local.clear();
|
||||
|
||||
delete nil_addr;
|
||||
delete one_addr;
|
||||
delete zero_addr;
|
||||
for(auto i:num_addrs)
|
||||
delete i;
|
||||
num_addrs.clear();
|
||||
for(auto i:str_addrs)
|
||||
delete i;
|
||||
for(auto& i:str_addrs)
|
||||
delete i.value.gcobj;
|
||||
str_addrs.clear();
|
||||
return;
|
||||
}
|
||||
nasal_ref nasal_gc::gc_alloc(int type)
|
||||
nasal_ref nasal_gc::gc_alloc(uint8_t type)
|
||||
{
|
||||
if(free_list[type].empty())
|
||||
{
|
||||
|
@ -416,32 +446,32 @@ nasal_ref nasal_gc::gc_alloc(int type)
|
|||
sweep();
|
||||
}
|
||||
if(free_list[type].empty())
|
||||
for(int i=0;i<increment[type];++i)
|
||||
for(uint32_t i=0;i<increment[type];++i)
|
||||
{
|
||||
nasal_ref tmp=new nasal_val(type);
|
||||
memory.push_back(tmp);
|
||||
free_list[type].push(tmp);
|
||||
nasal_ref tmp={type,new nasal_val(type)};
|
||||
memory.push_back(tmp.value.gcobj);
|
||||
free_list[type].push(tmp.value.gcobj);
|
||||
}
|
||||
nasal_ref ret=free_list[type].front();
|
||||
ret->mark=GC_UNCOLLECTED;
|
||||
nasal_ref ret={type,free_list[type].front()};
|
||||
ret.value.gcobj->mark=GC_UNCOLLECTED;
|
||||
free_list[type].pop();
|
||||
return ret;
|
||||
}
|
||||
nasal_ref nasal_gc::builtin_alloc(int type)
|
||||
nasal_ref nasal_gc::builtin_alloc(uint8_t type)
|
||||
{
|
||||
// when running a builtin function,alloc will run more than one time
|
||||
// this may cause mark-sweep in gc_alloc
|
||||
// and the value got before will be collected,this is a fatal error
|
||||
// so use builtin_alloc in builtin functions if this function uses alloc more then one time
|
||||
if(free_list[type].empty())
|
||||
for(int i=0;i<increment[type];++i)
|
||||
for(uint32_t i=0;i<increment[type];++i)
|
||||
{
|
||||
nasal_ref tmp=new nasal_val(type);
|
||||
memory.push_back(tmp);
|
||||
free_list[type].push(tmp);
|
||||
nasal_ref tmp={type,new nasal_val(type)};
|
||||
memory.push_back(tmp.value.gcobj);
|
||||
free_list[type].push(tmp.value.gcobj);
|
||||
}
|
||||
nasal_ref ret=free_list[type].front();
|
||||
ret->mark=GC_UNCOLLECTED;
|
||||
nasal_ref ret={type,free_list[type].front()};
|
||||
ret.value.gcobj->mark=GC_UNCOLLECTED;
|
||||
free_list[type].pop();
|
||||
return ret;
|
||||
}
|
||||
|
|
314
nasal_vm.h
314
nasal_vm.h
|
@ -117,8 +117,8 @@ void nasal_vm::init(
|
|||
const std::vector<double>& nums,
|
||||
const std::vector<std::string>& filenames)
|
||||
{
|
||||
gc.gc_init(nums,strs);
|
||||
gc.val_stack[STACK_MAX_DEPTH-1]=nullptr;
|
||||
gc.gc_init(strs);
|
||||
gc.val_stack[STACK_MAX_DEPTH-1].value.gcobj=nullptr;
|
||||
num_table=nums; // get constant numbers
|
||||
str_table=strs; // get constant strings & symbols
|
||||
files=filenames;// get filenames for debugger
|
||||
|
@ -173,7 +173,7 @@ void nasal_vm::stackinfo(int limit)
|
|||
{
|
||||
printf("vm stack(limit %d):\n",limit);
|
||||
uint32_t same_cnt=0;
|
||||
nasal_ref last_ptr=(nasal_ref)0xffff;
|
||||
nasal_ref last_ptr={vm_none,0xffffffff};
|
||||
for(int i=0;i<limit && stack_top-i>=gc.val_stack;++i)
|
||||
{
|
||||
if(stack_top[-i]==last_ptr)
|
||||
|
@ -183,28 +183,27 @@ void nasal_vm::stackinfo(int limit)
|
|||
}
|
||||
if(same_cnt)
|
||||
{
|
||||
printf("\t%p ... | %d same value(s)\n",last_ptr,same_cnt);
|
||||
printf("\t%p ... | %d same value(s)\n",last_ptr.value.gcobj,same_cnt);
|
||||
same_cnt=0;
|
||||
}
|
||||
last_ptr=stack_top[-i];
|
||||
printf("\t%p ",stack_top[-i]);
|
||||
if(!stack_top[-i])
|
||||
printf("nullptr");
|
||||
else
|
||||
switch(stack_top[-i]->type)
|
||||
{
|
||||
case vm_nil: printf("nil | gc.nil_addr");break;
|
||||
case vm_num: printf("num | %lf",stack_top[-i]->ptr.num);break;
|
||||
case vm_str: printf("str | ");raw_string(*stack_top[-i]->ptr.str);break;
|
||||
case vm_func: printf("func | func(%lu para){..}",stack_top[-i]->ptr.func->key_table.size());break;
|
||||
case vm_vec: printf("vec | [%lu val]",stack_top[-i]->ptr.vec->elems.size());break;
|
||||
case vm_hash: printf("hash | {%lu member}",stack_top[-i]->ptr.hash->elems.size());break;
|
||||
default: printf("unknown");break;
|
||||
}
|
||||
printf("\t%p ",stack_top[-i].value.gcobj);
|
||||
switch(stack_top[-i].type)
|
||||
{
|
||||
case vm_none: printf("undefined");break;
|
||||
case vm_nil: printf("nil | gc.nil");break;
|
||||
case vm_num: printf("num | %lf",stack_top[-i].value.num);break;
|
||||
case vm_str: printf("str | ");raw_string(*stack_top[-i].value.gcobj->ptr.str);break;
|
||||
case vm_func: printf("func | func(%lu para){..}",stack_top[-i].value.gcobj->ptr.func->key_table.size());break;
|
||||
case vm_vec: printf("vec | [%lu val]",stack_top[-i].value.gcobj->ptr.vec->elems.size());break;
|
||||
case vm_hash: printf("hash | {%lu member}",stack_top[-i].value.gcobj->ptr.hash->elems.size());break;
|
||||
case vm_obj: printf("user data");break;
|
||||
default: printf("unknown");break;
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
if(same_cnt)
|
||||
printf("\t%p ... | %d same value(s)\n",last_ptr,same_cnt);
|
||||
printf("\t%p ... | %d same value(s)\n",last_ptr.value.gcobj,same_cnt);
|
||||
return;
|
||||
}
|
||||
void nasal_vm::die(std::string str)
|
||||
|
@ -225,13 +224,13 @@ void nasal_vm::stackoverflow()
|
|||
exit(1);
|
||||
return;
|
||||
}
|
||||
inline bool nasal_vm::condition(nasal_ref val_addr)
|
||||
inline bool nasal_vm::condition(nasal_ref val)
|
||||
{
|
||||
if(val_addr->type==vm_num)
|
||||
return val_addr->ptr.num;
|
||||
else if(val_addr->type==vm_str)
|
||||
if(val.type==vm_num)
|
||||
return val.value.num;
|
||||
else if(val.type==vm_str)
|
||||
{
|
||||
std::string& str=*val_addr->ptr.str;
|
||||
std::string& str=*val.str();
|
||||
double num=str2num(str.c_str());
|
||||
if(std::isnan(num))
|
||||
return str.empty();
|
||||
|
@ -243,23 +242,23 @@ inline void nasal_vm::opr_intg()
|
|||
{
|
||||
// global values store on stack
|
||||
for(uint32_t i=0;i<imm[pc];++i)
|
||||
(stack_top++)[0]=gc.nil_addr;
|
||||
(stack_top++)[0].type=vm_nil;
|
||||
--stack_top;// point to the top
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_intl()
|
||||
{
|
||||
auto& vec=stack_top[0]->ptr.func->closure->ptr.vec->elems;
|
||||
auto& vec=stack_top[0].func()->closure.vec()->elems;
|
||||
// if many functions share the same closure
|
||||
// resize will break the size of vector and cause exe_bad_access
|
||||
// so choose the maximum size as the size of this closure
|
||||
if(vec.size()<imm[pc])
|
||||
vec.resize(imm[pc],gc.nil_addr);
|
||||
vec.resize(imm[pc],gc.nil);
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_offset()
|
||||
{
|
||||
stack_top[0]->ptr.func->offset=imm[pc];
|
||||
stack_top[0].func()->offset=imm[pc];
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_loadg()
|
||||
|
@ -269,27 +268,27 @@ inline void nasal_vm::opr_loadg()
|
|||
}
|
||||
inline void nasal_vm::opr_loadl()
|
||||
{
|
||||
gc.local.back()->ptr.vec->elems[imm[pc]]=(stack_top--)[0];
|
||||
gc.local.back().vec()->elems[imm[pc]]=(stack_top--)[0];
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_pnum()
|
||||
{
|
||||
(++stack_top)[0]=gc.num_addrs[imm[pc]];
|
||||
(++stack_top)[0]={vm_num,num_table[imm[pc]]};
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_pone()
|
||||
{
|
||||
(++stack_top)[0]=gc.one_addr;
|
||||
(++stack_top)[0]={vm_num,(double)1};
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_pzero()
|
||||
{
|
||||
(++stack_top)[0]=gc.zero_addr;
|
||||
(++stack_top)[0]={vm_num,(double)0};
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_pnil()
|
||||
{
|
||||
(++stack_top)[0]=gc.nil_addr;
|
||||
(++stack_top)[0].type=vm_nil;
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_pstr()
|
||||
|
@ -301,7 +300,7 @@ inline void nasal_vm::opr_newv()
|
|||
{
|
||||
nasal_ref vec_addr=gc.gc_alloc(vm_vec);
|
||||
nasal_ref* begin=stack_top-imm[pc]+1;
|
||||
auto& vec=vec_addr->ptr.vec->elems;// stack_top-imm[pc] stores the vector
|
||||
auto& vec=vec_addr.vec()->elems;// stack_top-imm[pc] stores the vector
|
||||
vec.resize(imm[pc]);
|
||||
for(uint32_t i=0;i<imm[pc];++i)
|
||||
vec[i]=begin[i];
|
||||
|
@ -317,56 +316,56 @@ inline void nasal_vm::opr_newh()
|
|||
inline void nasal_vm::opr_newf()
|
||||
{
|
||||
(++stack_top)[0]=gc.gc_alloc(vm_func);
|
||||
stack_top[0]->ptr.func->entry=imm[pc];
|
||||
stack_top[0]->ptr.func->closure=gc.nil_addr;
|
||||
stack_top[0].func()->entry=imm[pc];
|
||||
stack_top[0].func()->closure.type=vm_nil;
|
||||
if(gc.local.empty())
|
||||
stack_top[0]->ptr.func->closure=gc.gc_alloc(vm_vec);
|
||||
stack_top[0].func()->closure=gc.gc_alloc(vm_vec);
|
||||
else
|
||||
stack_top[0]->ptr.func->closure=gc.local.back();// local contains 'me'
|
||||
stack_top[0].func()->closure=gc.local.back();// local contains 'me'
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_happ()
|
||||
{
|
||||
nasal_ref val=stack_top[0];
|
||||
(--stack_top)[0]->ptr.hash->elems[str_table[imm[pc]]]=val;
|
||||
stack_top[-1].hash()->elems[str_table[imm[pc]]]=stack_top[0];
|
||||
--stack_top;
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_para()
|
||||
{
|
||||
nasal_func* func=stack_top[0]->ptr.func;
|
||||
int size=func->key_table.size();
|
||||
nasal_func* func=stack_top[0].func();
|
||||
size_t size=func->key_table.size();
|
||||
func->key_table[str_table[imm[pc]]]=size;
|
||||
func->default_para.push_back(nullptr);
|
||||
func->default_para.push_back({vm_none});
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_defpara()
|
||||
{
|
||||
nasal_ref def_val=stack_top[0];
|
||||
nasal_func* func=(--stack_top)[0]->ptr.func;
|
||||
int size=func->key_table.size();
|
||||
nasal_func* func=(--stack_top)[0].func();
|
||||
size_t size=func->key_table.size();
|
||||
func->key_table[str_table[imm[pc]]]=size;
|
||||
func->default_para.push_back(def_val);
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_dynpara()
|
||||
{
|
||||
stack_top[0]->ptr.func->dynpara=imm[pc];
|
||||
stack_top[0].func()->dynpara=imm[pc];
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_unot()
|
||||
{
|
||||
nasal_ref val=stack_top[0];
|
||||
switch(val->type)
|
||||
switch(val.type)
|
||||
{
|
||||
case vm_nil:stack_top[0]=gc.one_addr;break;
|
||||
case vm_num:stack_top[0]=val->ptr.num?gc.zero_addr:gc.one_addr;break;
|
||||
case vm_nil:stack_top[0]=gc.zero;break;
|
||||
case vm_num:stack_top[0]=val.num()?gc.zero:gc.one;break;
|
||||
case vm_str:
|
||||
{
|
||||
double num=str2num(val->ptr.str->c_str());
|
||||
double num=str2num(val.str()->c_str());
|
||||
if(std::isnan(num))
|
||||
stack_top[0]=val->ptr.str->empty()?gc.one_addr:gc.zero_addr;
|
||||
stack_top[0]=val.str()->empty()?gc.one:gc.zero;
|
||||
else
|
||||
stack_top[0]=num?gc.zero_addr:gc.one_addr;
|
||||
stack_top[0]=num?gc.zero:gc.one;
|
||||
}
|
||||
break;
|
||||
default:die("unot: incorrect value type");break;
|
||||
|
@ -375,15 +374,12 @@ inline void nasal_vm::opr_unot()
|
|||
}
|
||||
inline void nasal_vm::opr_usub()
|
||||
{
|
||||
nasal_ref new_val=gc.gc_alloc(vm_num);
|
||||
new_val->ptr.num=-stack_top[0]->to_number();
|
||||
stack_top[0]=new_val;
|
||||
stack_top[0]={vm_num,-stack_top[0].to_number()};
|
||||
return;
|
||||
}
|
||||
|
||||
#define op_calc(type)\
|
||||
nasal_ref new_val=gc.gc_alloc(vm_num);\
|
||||
new_val->ptr.num=stack_top[-1]->to_number() type stack_top[0]->to_number();\
|
||||
nasal_ref new_val(vm_num,stack_top[-1].to_number() type stack_top[0].to_number());\
|
||||
(--stack_top)[0]=new_val;
|
||||
|
||||
inline void nasal_vm::opr_add(){op_calc(+);}
|
||||
|
@ -393,14 +389,13 @@ inline void nasal_vm::opr_div(){op_calc(/);}
|
|||
inline void nasal_vm::opr_lnk()
|
||||
{
|
||||
nasal_ref new_val=gc.gc_alloc(vm_str);
|
||||
*new_val->ptr.str=stack_top[-1]->to_string()+stack_top[0]->to_string();
|
||||
*new_val.str()=stack_top[-1].to_string()+stack_top[0].to_string();
|
||||
(--stack_top)[0]=new_val;
|
||||
return;
|
||||
}
|
||||
|
||||
#define op_calc_const(type)\
|
||||
nasal_ref new_val=gc.gc_alloc(vm_num);\
|
||||
new_val->ptr.num=stack_top[0]->to_number() type num_table[imm[pc]];\
|
||||
nasal_ref new_val(vm_num,stack_top[0].to_number() type num_table[imm[pc]]);\
|
||||
stack_top[0]=new_val;
|
||||
|
||||
inline void nasal_vm::opr_addc(){op_calc_const(+);}
|
||||
|
@ -410,14 +405,13 @@ inline void nasal_vm::opr_divc(){op_calc_const(/);}
|
|||
inline void nasal_vm::opr_lnkc()
|
||||
{
|
||||
nasal_ref new_val=gc.gc_alloc(vm_str);
|
||||
*new_val->ptr.str=stack_top[0]->to_string()+str_table[imm[pc]];
|
||||
*new_val.str()=stack_top[0].to_string()+str_table[imm[pc]];
|
||||
stack_top[0]=new_val;
|
||||
return;
|
||||
}
|
||||
|
||||
#define op_calc_eq(type)\
|
||||
nasal_ref new_val=gc.gc_alloc(vm_num);\
|
||||
new_val->ptr.num=mem_addr[0]->to_number() type stack_top[-1]->to_number();\
|
||||
nasal_ref new_val(vm_num,mem_addr[0].to_number() type stack_top[-1].to_number());\
|
||||
(--stack_top)[0]=mem_addr[0]=new_val;
|
||||
|
||||
inline void nasal_vm::opr_addeq(){op_calc_eq(+);}
|
||||
|
@ -427,14 +421,13 @@ inline void nasal_vm::opr_diveq(){op_calc_eq(/);}
|
|||
inline void nasal_vm::opr_lnkeq()
|
||||
{
|
||||
nasal_ref new_val=gc.gc_alloc(vm_str);
|
||||
*new_val->ptr.str=mem_addr[0]->to_string()+stack_top[-1]->to_string();
|
||||
*new_val.str()=mem_addr[0].to_string()+stack_top[-1].to_string();
|
||||
(--stack_top)[0]=mem_addr[0]=new_val;
|
||||
return;
|
||||
}
|
||||
|
||||
#define op_calc_eq_const(type)\
|
||||
nasal_ref new_val=gc.gc_alloc(vm_num);\
|
||||
new_val->ptr.num=mem_addr[0]->to_number() type num_table[imm[pc]];\
|
||||
nasal_ref new_val(vm_num,mem_addr[0].to_number() type num_table[imm[pc]]);\
|
||||
stack_top[0]=mem_addr[0]=new_val;
|
||||
|
||||
inline void nasal_vm::opr_addeqc(){op_calc_eq_const(+);}
|
||||
|
@ -444,7 +437,7 @@ inline void nasal_vm::opr_diveqc(){op_calc_eq_const(/);}
|
|||
inline void nasal_vm::opr_lnkeqc()
|
||||
{
|
||||
nasal_ref new_val=gc.gc_alloc(vm_str);
|
||||
*new_val->ptr.str=mem_addr[0]->to_string()+str_table[imm[pc]];
|
||||
*new_val.str()=mem_addr[0].to_string()+str_table[imm[pc]];
|
||||
stack_top[0]=mem_addr[0]=new_val;
|
||||
return;
|
||||
}
|
||||
|
@ -458,45 +451,45 @@ inline void nasal_vm::opr_eq()
|
|||
{
|
||||
nasal_ref val2=stack_top[0];
|
||||
nasal_ref val1=(--stack_top)[0];
|
||||
int a_type=val1->type;
|
||||
int b_type=val2->type;
|
||||
uint8_t a_type=val1.type;
|
||||
uint8_t b_type=val2.type;
|
||||
if(a_type==vm_nil && b_type==vm_nil)
|
||||
stack_top[0]=gc.one_addr;
|
||||
stack_top[0]=gc.one;
|
||||
else if(a_type==vm_str && b_type==vm_str)
|
||||
stack_top[0]=(*val1->ptr.str==*val2->ptr.str)?gc.one_addr:gc.zero_addr;
|
||||
stack_top[0]=(*val1.str()==*val2.str())?gc.one:gc.zero;
|
||||
else if(a_type==vm_num || b_type==vm_num)
|
||||
stack_top[0]=(val1->to_number()==val2->to_number())?gc.one_addr:gc.zero_addr;
|
||||
stack_top[0]=(val1.to_number()==val2.to_number())?gc.one:gc.zero;
|
||||
else
|
||||
stack_top[0]=(val1==val2)?gc.one_addr:gc.zero_addr;
|
||||
stack_top[0]=(val1==val2)?gc.one:gc.zero;
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_neq()
|
||||
{
|
||||
nasal_ref val2=stack_top[0];
|
||||
nasal_ref val1=(--stack_top)[0];
|
||||
int a_type=val1->type;
|
||||
int b_type=val2->type;
|
||||
uint8_t a_type=val1.type;
|
||||
uint8_t b_type=val2.type;
|
||||
if(a_type==vm_nil && b_type==vm_nil)
|
||||
stack_top[0]=gc.zero_addr;
|
||||
stack_top[0]=gc.zero;
|
||||
else if(a_type==vm_str && b_type==vm_str)
|
||||
stack_top[0]=(*val1->ptr.str!=*val2->ptr.str)?gc.one_addr:gc.zero_addr;
|
||||
stack_top[0]=(*val1.str()!=*val2.str())?gc.one:gc.zero;
|
||||
else if(a_type==vm_num || b_type==vm_num)
|
||||
stack_top[0]=(val1->to_number()!=val2->to_number())?gc.one_addr:gc.zero_addr;
|
||||
stack_top[0]=(val1.to_number()!=val2.to_number())?gc.one:gc.zero;
|
||||
else
|
||||
stack_top[0]=(val1!=val2)?gc.one_addr:gc.zero_addr;
|
||||
stack_top[0]=(val1!=val2)?gc.one:gc.zero;
|
||||
return;
|
||||
}
|
||||
|
||||
#define op_cmp(type)\
|
||||
--stack_top;\
|
||||
stack_top[0]=(stack_top[0]->to_number() type stack_top[1]->to_number())?gc.one_addr:gc.zero_addr;
|
||||
stack_top[0]=(stack_top[0].to_number() type stack_top[1].to_number())?gc.one:gc.zero;
|
||||
|
||||
inline void nasal_vm::opr_less(){op_cmp(<);}
|
||||
inline void nasal_vm::opr_leq(){op_cmp(<=);}
|
||||
inline void nasal_vm::opr_grt(){op_cmp(>);}
|
||||
inline void nasal_vm::opr_geq(){op_cmp(>=);}
|
||||
|
||||
#define op_cmp_const(type) stack_top[0]=(stack_top[0]->to_number() type num_table[imm[pc]])?gc.one_addr:gc.zero_addr;
|
||||
#define op_cmp_const(type) stack_top[0]=(stack_top[0].to_number() type num_table[imm[pc]])?gc.one:gc.zero;
|
||||
|
||||
inline void nasal_vm::opr_lessc(){op_cmp_const(<);}
|
||||
inline void nasal_vm::opr_leqc(){op_cmp_const(<=);}
|
||||
|
@ -529,7 +522,7 @@ inline void nasal_vm::opr_jf()
|
|||
inline void nasal_vm::opr_counter()
|
||||
{
|
||||
counter.push(-1);
|
||||
if(stack_top[0]->type!=vm_vec)
|
||||
if(stack_top[0].type!=vm_vec)
|
||||
die("cnt: must use vector in forindex/foreach");
|
||||
return;
|
||||
}
|
||||
|
@ -540,18 +533,17 @@ inline void nasal_vm::opr_cntpop()
|
|||
}
|
||||
inline void nasal_vm::opr_findex()
|
||||
{
|
||||
if(++counter.top()>=stack_top[0]->ptr.vec->elems.size())
|
||||
if(++counter.top()>=stack_top[0].vec()->elems.size())
|
||||
{
|
||||
pc=imm[pc]-1;
|
||||
return;
|
||||
}
|
||||
(++stack_top)[0]=gc.gc_alloc(vm_num);
|
||||
stack_top[0]->ptr.num=counter.top();
|
||||
(++stack_top)[0]={vm_num,static_cast<double>(counter.top())};
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_feach()
|
||||
{
|
||||
std::vector<nasal_ref>& ref=stack_top[0]->ptr.vec->elems;
|
||||
std::vector<nasal_ref>& ref=stack_top[0].vec()->elems;
|
||||
if(++counter.top()>=ref.size())
|
||||
{
|
||||
pc=imm[pc]-1;
|
||||
|
@ -567,47 +559,46 @@ inline void nasal_vm::opr_callg()
|
|||
}
|
||||
inline void nasal_vm::opr_calll()
|
||||
{
|
||||
(++stack_top)[0]=gc.local.back()->ptr.vec->elems[imm[pc]];
|
||||
(++stack_top)[0]=gc.local.back().vec()->elems[imm[pc]];
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_callv()
|
||||
{
|
||||
nasal_ref val=stack_top[0];
|
||||
nasal_ref vec_addr=(--stack_top)[0];
|
||||
if(vec_addr->type==vm_vec)
|
||||
nasal_ref vec=(--stack_top)[0];
|
||||
if(vec.type==vm_vec)
|
||||
{
|
||||
stack_top[0]=vec_addr->ptr.vec->get_val(val->to_number());
|
||||
if(!stack_top[0])
|
||||
die("callv: index out of range:"+std::to_string(val->to_number()));
|
||||
stack_top[0]=vec.vec()->get_val(val.to_number());
|
||||
if(stack_top[0].type==vm_none)
|
||||
die("callv: index out of range:"+std::to_string(val.to_number()));
|
||||
}
|
||||
else if(vec_addr->type==vm_hash)
|
||||
else if(vec.type==vm_hash)
|
||||
{
|
||||
if(val->type!=vm_str)
|
||||
if(val.type!=vm_str)
|
||||
{
|
||||
die("callv: must use string as the key");
|
||||
return;
|
||||
}
|
||||
stack_top[0]=vec_addr->ptr.hash->get_val(*val->ptr.str);
|
||||
if(!stack_top[0])
|
||||
stack_top[0]=vec.hash()->get_val(*val.value.gcobj->ptr.str);
|
||||
if(stack_top[0].type==vm_none)
|
||||
{
|
||||
die("callv: cannot find member \""+*val->ptr.str+"\" of this hash");
|
||||
die("callv: cannot find member \""+*val.str()+"\" of this hash");
|
||||
return;
|
||||
}
|
||||
if(stack_top[0]->type==vm_func)
|
||||
stack_top[0]->ptr.func->closure->ptr.vec->elems[0]=val;// me
|
||||
if(stack_top[0].type==vm_func)
|
||||
stack_top[0].func()->closure.vec()->elems[0]=val;// me
|
||||
}
|
||||
else if(vec_addr->type==vm_str)
|
||||
else if(vec.type==vm_str)
|
||||
{
|
||||
std::string& str=*vec_addr->ptr.str;
|
||||
int num=val->to_number();
|
||||
std::string& str=*vec.str();
|
||||
int num=val.to_number();
|
||||
int str_size=str.length();
|
||||
if(num<-str_size || num>=str_size)
|
||||
{
|
||||
die("callv: index out of range:"+std::to_string(val->to_number()));
|
||||
die("callv: index out of range:"+std::to_string(val.to_number()));
|
||||
return;
|
||||
}
|
||||
stack_top[0]=gc.gc_alloc(vm_num);
|
||||
stack_top[0]->ptr.num=(str[num>=0? num:num+str_size]);
|
||||
stack_top[0]={vm_num,static_cast<double>(str[num>=0? num:num+str_size])};
|
||||
}
|
||||
else
|
||||
die("callv: must call a vector/hash/string");
|
||||
|
@ -616,33 +607,33 @@ inline void nasal_vm::opr_callv()
|
|||
inline void nasal_vm::opr_callvi()
|
||||
{
|
||||
nasal_ref val=stack_top[0];
|
||||
if(val->type!=vm_vec)
|
||||
if(val.type!=vm_vec)
|
||||
{
|
||||
die("callvi: must use a vector");
|
||||
return;
|
||||
}
|
||||
// cannot use operator[],because this may cause overflow
|
||||
(++stack_top)[0]=val->ptr.vec->get_val(imm[pc]);
|
||||
if(!stack_top[0])
|
||||
(++stack_top)[0]=val.vec()->get_val(imm[pc]);
|
||||
if(stack_top[0].type==vm_none)
|
||||
die("callvi: index out of range:"+std::to_string(imm[pc]));
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_callh()
|
||||
{
|
||||
nasal_ref val=stack_top[0];
|
||||
if(val->type!=vm_hash)
|
||||
if(val.type!=vm_hash)
|
||||
{
|
||||
die("callh: must call a hash");
|
||||
return;
|
||||
}
|
||||
stack_top[0]=val->ptr.hash->get_val(str_table[imm[pc]]);
|
||||
if(!stack_top[0])
|
||||
stack_top[0]=val.hash()->get_val(str_table[imm[pc]]);
|
||||
if(stack_top[0].type==vm_none)
|
||||
{
|
||||
die("callh: member \""+str_table[imm[pc]]+"\" does not exist");
|
||||
return;
|
||||
}
|
||||
if(stack_top[0]->type==vm_func)
|
||||
stack_top[0]->ptr.func->closure->ptr.vec->elems[0]=val;// me
|
||||
if(stack_top[0].type==vm_func)
|
||||
stack_top[0].func()->closure.vec()->elems[0]=val;// me
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_callfv()
|
||||
|
@ -651,26 +642,26 @@ inline void nasal_vm::opr_callfv()
|
|||
uint32_t args_size=imm[pc];
|
||||
nasal_ref* vec=stack_top-args_size+1;
|
||||
nasal_ref func_addr=vec[-1];
|
||||
if(func_addr->type!=vm_func)
|
||||
if(func_addr.type!=vm_func)
|
||||
{
|
||||
die("callfv: must call a function");
|
||||
return;
|
||||
}
|
||||
// push new local scope
|
||||
auto& ref_func=*func_addr->ptr.func;
|
||||
cls_stk.push(func_addr->ptr.func->closure);
|
||||
auto& ref_func=*func_addr.func();
|
||||
cls_stk.push(func_addr.func()->closure);
|
||||
gc.local.push_back(gc.gc_alloc(vm_vec));
|
||||
gc.local.back()->ptr.vec->elems=ref_func.closure->ptr.vec->elems;
|
||||
gc.local.back().vec()->elems=ref_func.closure.vec()->elems;
|
||||
// load parameters
|
||||
auto& ref_default=ref_func.default_para;
|
||||
auto& ref_closure=gc.local.back()->ptr.vec->elems;
|
||||
auto& ref_closure=gc.local.back().vec()->elems;
|
||||
|
||||
uint32_t offset=ref_func.offset;
|
||||
uint32_t para_size=ref_func.key_table.size();
|
||||
// load arguments
|
||||
if(args_size<para_size && !ref_default[args_size])
|
||||
if(args_size<para_size && ref_default[args_size].type==vm_none)
|
||||
{
|
||||
// if the first default value is not nullptr,then values after it are not nullptr
|
||||
// if the first default value is not vm_none,then values after it are not nullptr
|
||||
die("callfv: lack argument(s)");
|
||||
return;
|
||||
}
|
||||
|
@ -685,7 +676,7 @@ inline void nasal_vm::opr_callfv()
|
|||
{
|
||||
nasal_ref vec_addr=gc.gc_alloc(vm_vec);
|
||||
for(uint32_t i=para_size;i<args_size;++i)
|
||||
vec_addr->ptr.vec->elems.push_back(vec[i]);
|
||||
vec_addr.vec()->elems.push_back(vec[i]);
|
||||
ref_closure[para_size+offset]=vec_addr;
|
||||
}
|
||||
|
||||
|
@ -697,21 +688,21 @@ inline void nasal_vm::opr_callfv()
|
|||
inline void nasal_vm::opr_callfh()
|
||||
{
|
||||
// get parameter list and function value
|
||||
auto& ref_hash=stack_top[0]->ptr.hash->elems;
|
||||
auto& ref_hash=stack_top[0].hash()->elems;
|
||||
nasal_ref func_addr=stack_top[-1];
|
||||
if(func_addr->type!=vm_func)
|
||||
if(func_addr.type!=vm_func)
|
||||
{
|
||||
die("callfh: must call a function");
|
||||
return;
|
||||
}
|
||||
// push new local scope
|
||||
auto& ref_func=*func_addr->ptr.func;
|
||||
cls_stk.push(func_addr->ptr.func->closure);
|
||||
auto& ref_func=*func_addr.func();
|
||||
cls_stk.push(func_addr.func()->closure);
|
||||
gc.local.push_back(gc.gc_alloc(vm_vec));
|
||||
gc.local.back()->ptr.vec->elems=ref_func.closure->ptr.vec->elems;
|
||||
gc.local.back().vec()->elems=ref_func.closure.vec()->elems;
|
||||
// load parameters
|
||||
auto& ref_default=ref_func.default_para;
|
||||
auto& ref_closure=gc.local.back()->ptr.vec->elems;
|
||||
auto& ref_closure=gc.local.back().vec()->elems;
|
||||
|
||||
if(ref_func.dynpara>=0)
|
||||
{
|
||||
|
@ -723,7 +714,7 @@ inline void nasal_vm::opr_callfh()
|
|||
{
|
||||
if(ref_hash.count(i.first))
|
||||
ref_closure[i.second+offset]=ref_hash[i.first];
|
||||
else if(ref_default[i.second])
|
||||
else if(ref_default[i.second].type!=vm_none)
|
||||
ref_closure[i.second+offset]=ref_default[i.second];
|
||||
else
|
||||
{
|
||||
|
@ -739,8 +730,8 @@ inline void nasal_vm::opr_callfh()
|
|||
}
|
||||
inline void nasal_vm::opr_callb()
|
||||
{
|
||||
(++stack_top)[0]=(*builtin_func[imm[pc]].func)(gc.local.back()->ptr.vec->elems,gc);
|
||||
if(!stack_top[0])
|
||||
(++stack_top)[0]=(*builtin_func[imm[pc]].func)(gc.local.back().vec()->elems,gc);
|
||||
if(stack_top[0].type==vm_none)
|
||||
die("native function error.");
|
||||
return;
|
||||
}
|
||||
|
@ -751,7 +742,7 @@ inline void nasal_vm::opr_slcbegin()
|
|||
// | resource_vec | <-- stack_top[-1]
|
||||
// ----------------
|
||||
(++stack_top)[0]=gc.gc_alloc(vm_vec);
|
||||
if(stack_top[-1]->type!=vm_vec)
|
||||
if(stack_top[-1].type!=vm_vec)
|
||||
die("slcbegin: must slice a vector");
|
||||
return;
|
||||
}
|
||||
|
@ -764,22 +755,22 @@ inline void nasal_vm::opr_slcend()
|
|||
inline void nasal_vm::opr_slc()
|
||||
{
|
||||
nasal_ref val=(stack_top--)[0];
|
||||
nasal_ref res=stack_top[-1]->ptr.vec->get_val(val->to_number());
|
||||
if(!res)
|
||||
die("slc: index out of range:"+std::to_string(val->to_number()));
|
||||
stack_top[0]->ptr.vec->elems.push_back(res);
|
||||
nasal_ref res=stack_top[-1].vec()->get_val(val.to_number());
|
||||
if(res.type==vm_none)
|
||||
die("slc: index out of range:"+std::to_string(val.to_number()));
|
||||
stack_top[0].vec()->elems.push_back(res);
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_slc2()
|
||||
{
|
||||
nasal_ref val2=(stack_top--)[0];
|
||||
nasal_ref val1=(stack_top--)[0];
|
||||
std::vector<nasal_ref>& ref=stack_top[-1]->ptr.vec->elems;
|
||||
std::vector<nasal_ref>& aim=stack_top[0]->ptr.vec->elems;
|
||||
std::vector<nasal_ref>& ref=stack_top[-1].vec()->elems;
|
||||
std::vector<nasal_ref>& aim=stack_top[0].vec()->elems;
|
||||
|
||||
int type1=val1->type,type2=val2->type;
|
||||
int num1=val1->to_number();
|
||||
int num2=val2->to_number();
|
||||
uint8_t type1=val1.type,type2=val2.type;
|
||||
int num1=val1.to_number();
|
||||
int num2=val2.to_number();
|
||||
int ref_size=ref.size();
|
||||
if(type1==vm_nil && type2==vm_nil)
|
||||
{
|
||||
|
@ -810,7 +801,7 @@ inline void nasal_vm::opr_mcallg()
|
|||
}
|
||||
inline void nasal_vm::opr_mcalll()
|
||||
{
|
||||
mem_addr=&(gc.local.back()->ptr.vec->elems[imm[pc]]);
|
||||
mem_addr=&(gc.local.back().vec()->elems[imm[pc]]);
|
||||
(++stack_top)[0]=mem_addr[0];
|
||||
return;
|
||||
}
|
||||
|
@ -818,26 +809,25 @@ inline void nasal_vm::opr_mcallv()
|
|||
{
|
||||
nasal_ref val=stack_top[0];
|
||||
nasal_ref vec_addr=(--stack_top)[0];
|
||||
int type=vec_addr->type;
|
||||
if(type==vm_vec)
|
||||
if(vec_addr.type==vm_vec)
|
||||
{
|
||||
mem_addr=vec_addr->ptr.vec->get_mem(val->to_number());
|
||||
mem_addr=vec_addr.vec()->get_mem(val.to_number());
|
||||
if(!mem_addr)
|
||||
die("mcallv: index out of range:"+std::to_string(val->to_number()));
|
||||
die("mcallv: index out of range:"+std::to_string(val.to_number()));
|
||||
}
|
||||
else if(type==vm_hash)
|
||||
else if(vec_addr.type==vm_hash)
|
||||
{
|
||||
if(val->type!=vm_str)
|
||||
if(val.type!=vm_str)
|
||||
{
|
||||
die("mcallv: must use string as the key");
|
||||
return;
|
||||
}
|
||||
nasal_hash& ref=*vec_addr->ptr.hash;
|
||||
std::string& str=*val->ptr.str;
|
||||
nasal_hash& ref=*vec_addr.hash();
|
||||
std::string& str=*val.str();
|
||||
mem_addr=ref.get_mem(str);
|
||||
if(!mem_addr)
|
||||
{
|
||||
ref.elems[str]=gc.nil_addr;
|
||||
ref.elems[str]=gc.nil;
|
||||
mem_addr=ref.get_mem(str);
|
||||
}
|
||||
}
|
||||
|
@ -848,24 +838,24 @@ inline void nasal_vm::opr_mcallv()
|
|||
inline void nasal_vm::opr_mcallh()
|
||||
{
|
||||
nasal_ref hash_addr=stack_top[0];
|
||||
if(hash_addr->type!=vm_hash)
|
||||
if(hash_addr.type!=vm_hash)
|
||||
{
|
||||
die("mcallh: must call a hash");
|
||||
return;
|
||||
}
|
||||
nasal_hash& ref=*hash_addr->ptr.hash;
|
||||
nasal_hash& ref=*hash_addr.hash();
|
||||
std::string& str=str_table[imm[pc]];
|
||||
mem_addr=ref.get_mem(str);
|
||||
if(!mem_addr) // create a new key
|
||||
{
|
||||
ref.elems[str]=gc.nil_addr;
|
||||
ref.elems[str]=gc.nil;
|
||||
mem_addr=ref.get_mem(str);
|
||||
}
|
||||
return;
|
||||
}
|
||||
inline void nasal_vm::opr_ret()
|
||||
{
|
||||
nasal_func* func=stack_top[-1]->ptr.func;
|
||||
nasal_func* func=stack_top[-1].func();
|
||||
uint32_t offset=func->offset;
|
||||
nasal_ref cls=cls_stk.top();cls_stk.pop();
|
||||
// same closure detected,update the last local scope instead of the closure
|
||||
|
@ -875,20 +865,20 @@ inline void nasal_vm::opr_ret()
|
|||
// this condition in fact is that two called function are using the same closure
|
||||
// if this copy of closure is changed, the closure will be updated at the same time
|
||||
// also the copy of closure that still in using will alse be updated
|
||||
auto& vec=gc.local.back()->ptr.vec->elems;
|
||||
auto& func_vec=func->closure->ptr.vec->elems;
|
||||
auto& vec=gc.local.back().vec()->elems;
|
||||
auto& func_vec=func->closure.vec()->elems;
|
||||
gc.local.pop_back();
|
||||
for(uint32_t i=0;i<offset;++i)
|
||||
gc.local.back()->ptr.vec->elems[i]=func_vec[i]=vec[i];
|
||||
gc.local.back().vec()->elems[i]=func_vec[i]=vec[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
// two closures are not the same, update the func's closure and drop gc.local.back()
|
||||
auto& vec=func->closure->ptr.vec->elems;
|
||||
auto& vec=func->closure.vec()->elems;
|
||||
for(uint32_t i=0;i<offset;++i)
|
||||
vec[i]=gc.local.back()->ptr.vec->elems[i];
|
||||
vec[i]=gc.local.back().vec()->elems[i];
|
||||
gc.local.pop_back();
|
||||
vec[0]=gc.nil_addr;// set 'me' to nil
|
||||
vec[0].type=vm_nil;// set 'me' to nil
|
||||
}
|
||||
|
||||
pc=ret.top();ret.pop();// fetch pc
|
||||
|
@ -937,7 +927,7 @@ void nasal_vm::run(std::vector<opcode>& exec,bool op_cnt)
|
|||
goto *code[pc];
|
||||
|
||||
nop:
|
||||
if(canary)
|
||||
if(canary.value.gcobj)
|
||||
stackoverflow();
|
||||
if(op_cnt)
|
||||
{
|
||||
|
@ -957,7 +947,7 @@ nop:
|
|||
}
|
||||
return;
|
||||
// may cause stackoverflow
|
||||
#define exec_operand(op,num) {op();++count[num];if(!canary)goto *code[++pc];goto nop;}
|
||||
#define exec_operand(op,num) {op();++count[num];if(!canary.value.gcobj)goto *code[++pc];goto nop;}
|
||||
// do not cause stackoverflow
|
||||
#define exec_opnodie(op,num) {op();++count[num];goto *code[++pc];}
|
||||
|
||||
|
|
Loading…
Reference in New Issue