complete simple tutorial
This commit is contained in:
parent
818685c48d
commit
58ea303202
364
README.md
364
README.md
|
@ -3,45 +3,37 @@
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
[Nasal](http://wiki.flightgear.org/Nasal_scripting_language)
|
[Nasal](http://wiki.flightgear.org/Nasal_scripting_language)
|
||||||
is a script language that used in [FlightGear](https://www.flightgear.org/).
|
is an ECMAscript-like programming language that used in [FlightGear](https://www.flightgear.org/).
|
||||||
|
|
||||||
The interpreter is totally rewritten by ValKmjolnir using C++(standard c++11)
|
The interpreter is totally rewritten by [ValKmjolnir](https://github.com/ValKmjolnir) using C++(`-std=c++11`)
|
||||||
without reusing the code in Andy Ross's nasal interpreter(<https://github.com/andyross/nasal>).
|
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.
|
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)
|
Now this project uses MIT license (2021/5/4).
|
||||||
We really need your support!
|
Edit it if you want,
|
||||||
|
use this project to learn or create more interesting things
|
||||||
Also,i am a member of [FGPRC](https://www.fgprc.org/),
|
(But don't forget me XD).
|
||||||
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).
|
|
||||||
|
|
||||||
## Why Writing Nasal Interpreter
|
## Why Writing Nasal Interpreter
|
||||||
|
|
||||||
Nasal is a script language first used in Flightgear,
|
Nasal is a script language first used in Flightgear,
|
||||||
created by Andy Ross(<https://github.com/andyross>).
|
created by [Andy Ross](<https://github.com/andyross>).
|
||||||
|
But in 2019 summer holiday,
|
||||||
But in last summer holiday,
|
members in [FGPRC](https://www.fgprc.org/) told me that it is hard to debug with nasal-console in Flightgear,
|
||||||
members in FGPRC told me that it is hard to debug with nasal-console in Flightgear,
|
|
||||||
especially when checking syntax errors.
|
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,
|
I wrote the lexer,
|
||||||
parser and runtimebytecode virtual machine(there was an ast-interpreter,
|
parser and
|
||||||
|
bytecode virtual machine(there was an ast-interpreter,
|
||||||
but i deleted it after version4.0) to help checking errors.
|
but i deleted it after version4.0) to help checking errors.
|
||||||
|
We found it much easier to check syntax and runtime
|
||||||
They found it much easier to check syntax and runtime
|
|
||||||
errors before copying nasal-codes in nasal-console in Flightgear to test.
|
errors before copying nasal-codes in nasal-console in Flightgear to test.
|
||||||
|
|
||||||
Also, you could use this language to write some
|
Also, you could use this language to write some
|
||||||
interesting programs and run them without the lib of Flightgear.
|
interesting programs and run them without the lib of Flightgear.
|
||||||
|
|
||||||
You could add your own built-in functions to change
|
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).
|
this interpreter to a useful tool in your own projects (such as a script in your own game).
|
||||||
|
|
||||||
## How to Compile
|
## How to Compile
|
||||||
|
|
||||||
|
@ -49,7 +41,7 @@ Better choose the latest update of the interpreter.
|
||||||
Download the source code and build it!
|
Download the source code and build it!
|
||||||
It's quite easy to build this interpreter.
|
It's quite easy to build this interpreter.
|
||||||
|
|
||||||
MUST USE -O2/-O3 if want to optimize the interpreter!
|
MUST USE `-O2/-O3` if want to optimize the interpreter!
|
||||||
|
|
||||||
Also remember to use g++ or clang++.
|
Also remember to use g++ or clang++.
|
||||||
|
|
||||||
|
@ -174,7 +166,7 @@ There's an example of byte code below:
|
||||||
for(var i=0;i<4000000;i+=1);
|
for(var i=0;i<4000000;i+=1);
|
||||||
```
|
```
|
||||||
|
|
||||||
```MIPS
|
```x86asm
|
||||||
.number 0
|
.number 0
|
||||||
.number 4e+006
|
.number 4e+006
|
||||||
.number 1
|
.number 1
|
||||||
|
@ -225,7 +217,7 @@ So the bytecode generator changed a lot.
|
||||||
for(var i=0;i<4000000;i+=1);
|
for(var i=0;i<4000000;i+=1);
|
||||||
```
|
```
|
||||||
|
|
||||||
```MIPS
|
```x86asm
|
||||||
.number 4e+006
|
.number 4e+006
|
||||||
0x00000000: intg 0x00000001
|
0x00000000: intg 0x00000001
|
||||||
0x00000001: pzero 0x00000000
|
0x00000001: pzero 0x00000000
|
||||||
|
@ -273,7 +265,7 @@ var f=func(x,y){return x+y;}
|
||||||
f(1024,2048);
|
f(1024,2048);
|
||||||
```
|
```
|
||||||
|
|
||||||
```MIPS
|
```x86asm
|
||||||
.number 1024
|
.number 1024
|
||||||
.number 2048
|
.number 2048
|
||||||
.symbol x
|
.symbol x
|
||||||
|
@ -327,7 +319,7 @@ codegen will generate byte code by nasal_codegen::call_gen() instead of nasal_co
|
||||||
and the last child of the ast will be generated by 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:
|
So the bytecode is totally different now:
|
||||||
|
|
||||||
```MIPS
|
```x86asm
|
||||||
.number 10
|
.number 10
|
||||||
.number 2
|
.number 2
|
||||||
.symbol _
|
.symbol _
|
||||||
|
@ -425,7 +417,7 @@ op_addc,op_subc,op_mulc,op_divc,op_lnkc,op_addeqc,op_subeqc,op_muleqc,op_diveqc,
|
||||||
|
|
||||||
Now the bytecode of test/bigloop.nas seems like this:
|
Now the bytecode of test/bigloop.nas seems like this:
|
||||||
|
|
||||||
```MIPS
|
```x86asm
|
||||||
.number 4e+006
|
.number 4e+006
|
||||||
.number 1
|
.number 1
|
||||||
0x00000000: intg 0x00000001
|
0x00000000: intg 0x00000001
|
||||||
|
@ -454,7 +446,7 @@ var (a,b)=(1,2);
|
||||||
a=b=0;
|
a=b=0;
|
||||||
```
|
```
|
||||||
|
|
||||||
```MIPS
|
```x86asm
|
||||||
.number 2
|
.number 2
|
||||||
0x00000000: intg 0x00000002
|
0x00000000: intg 0x00000002
|
||||||
0x00000001: pone 0x00000000
|
0x00000001: pone 0x00000000
|
||||||
|
@ -487,7 +479,7 @@ Delete an old operand 'op_offset'.
|
||||||
|
|
||||||
The format of output information of bytecodes changes to this:
|
The format of output information of bytecodes changes to this:
|
||||||
|
|
||||||
```MIPS
|
```x86asm
|
||||||
0x0000017c: jmp 0x181
|
0x0000017c: jmp 0x181
|
||||||
0x0000017d: calll 0x1
|
0x0000017d: calll 0x1
|
||||||
0x0000017e: calll 0x1
|
0x0000017e: calll 0x1
|
||||||
|
@ -588,48 +580,52 @@ running time:
|
||||||
|quick_sort.nas|0s|great improvement|
|
|quick_sort.nas|0s|great improvement|
|
||||||
|bfs.nas|0.0156s|great improvement|
|
|bfs.nas|0.0156s|great improvement|
|
||||||
|
|
||||||
## Use Nasal to Program
|
## Simple Tutorial
|
||||||
|
|
||||||
### basic value type
|
Nasal is really easy to learn.
|
||||||
|
Reading this tutorial will not takes you over 15 minutes.
|
||||||
|
You could totally use it after reading this simple tutorial:
|
||||||
|
|
||||||
Nasal has 6 value types.Number,string,vector,hash,function,nil.
|
### __Basic Value Type__
|
||||||
|
|
||||||
__Number__ has 3 formats.Dec,hex and oct;
|
`vm_none` is error type.
|
||||||
|
This type is used to interrupt the execution of virtual machine and will not be created by user program.
|
||||||
__String__ has 3 formats.But the third one is often used to declare a character.
|
|
||||||
|
|
||||||
__Vector__ has unlimited length and can store all types of values.
|
|
||||||
|
|
||||||
__Hash__ is a hashmap that stores values with strings/identifiers as the key.
|
|
||||||
|
|
||||||
__Function__ is also a value type in nasal.
|
|
||||||
|
|
||||||
|
`vm_nil` is a null type. It means nothing.
|
||||||
```javascript
|
```javascript
|
||||||
var spc=nil;
|
var spc=nil;
|
||||||
|
```
|
||||||
var a=1;
|
`vm_num` has 3 formats. Dec, hex and oct. Using IEEE754 double to store.
|
||||||
var a=2.71828;
|
```javascript
|
||||||
var a=2.147e16;
|
var n=1;
|
||||||
var a=1e-10;
|
var n=2.71828;
|
||||||
var a=0x7fffffff;
|
var n=2.147e16;
|
||||||
var a=0xAA55;
|
var n=1e-10;
|
||||||
var a=0o170001;
|
var n=0x7fffffff;
|
||||||
|
var n=0xAA55;
|
||||||
var b='str';
|
var n=0o170001;
|
||||||
var b="another string";
|
```
|
||||||
var b=`c`;
|
`vm_str` has 3 formats. But the third one is often used to declare a character.
|
||||||
|
```javascript
|
||||||
var c=[];
|
var s='str';
|
||||||
var c=[
|
var s="another string";
|
||||||
|
var s=`c`;
|
||||||
|
```
|
||||||
|
`vm_vec` has unlimited length and can store all types of values.
|
||||||
|
```javascript
|
||||||
|
var vec=[];
|
||||||
|
var vec=[
|
||||||
0,
|
0,
|
||||||
nil,
|
nil,
|
||||||
{},
|
{},
|
||||||
[],
|
[],
|
||||||
func(){return 0;}
|
func(){return 0;}
|
||||||
];
|
];
|
||||||
append(c,0,1,2);
|
append(vec,0,1,2);
|
||||||
|
```
|
||||||
var d={
|
`vm_hash` is a hashmap that stores values with strings/identifiers as the key.
|
||||||
|
```javascript
|
||||||
|
var hash={
|
||||||
member1:nil,
|
member1:nil,
|
||||||
member2:'str',
|
member2:'str',
|
||||||
'member3':'member\'s name can also be a string constant',
|
'member3':'member\'s name can also be a string constant',
|
||||||
|
@ -639,35 +635,61 @@ var d={
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
```
|
||||||
var f=func(x,y,z){return nil;}
|
`vm_func` is a function type (in fact it is lambda).
|
||||||
var f=func{return 1024;}
|
```javascript
|
||||||
var f=func(x,y,z,default_para1=1,default_para2=2){
|
var f=func(x,y,z){
|
||||||
return x+y+z+default_para1+default_para2;
|
return nil;
|
||||||
}
|
}
|
||||||
var f=func(x,y,z,dynamic_para...){
|
var f=func{
|
||||||
|
return 1024;
|
||||||
|
}
|
||||||
|
var f=func(x,y,z,default1=1,default2=2){
|
||||||
|
return x+y+z+default1+default2;
|
||||||
|
}
|
||||||
|
var f=func(args...){
|
||||||
var sum=0;
|
var sum=0;
|
||||||
foreach(var i;dynamic_para)
|
foreach(var i;args)
|
||||||
sum+=i;
|
sum+=i;
|
||||||
return sum+x+y+z;
|
return sum;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
`vm_obj` is a special type that stores user data.
|
||||||
|
This means you could use other complex C/C++ data types in nasal.
|
||||||
|
This type is used when you are trying to add a new data structure into nasal,
|
||||||
|
so this type is often created by native-function that programmed in C/C++ by library developers.
|
||||||
|
You could see how to write your own native-functions below.
|
||||||
|
```javascript
|
||||||
|
var my_new_obj=func(){
|
||||||
|
return __builtin_my_obj();
|
||||||
|
}
|
||||||
|
var obj=my_new_obj();
|
||||||
|
```
|
||||||
|
|
||||||
### operators
|
### __Operators__
|
||||||
|
|
||||||
|
Nasal has basic math operators `+` `-` `*` `/` and a special operator `~` that links two strings together.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
1+2-1*2/1;
|
1+2-1*2/1;
|
||||||
'str1'~'str2';
|
'str1'~'str2';
|
||||||
(1+2)*(3+4)
|
(1+2)*(3+4)
|
||||||
|
```
|
||||||
|
For conditional expressions, operators `==` `!=` `<` `>` `<=` `>=` are used to compare two values.
|
||||||
|
`and` `or` have the same function as C/C++ `&&` `||`, link comparations together.
|
||||||
|
```javascript
|
||||||
1+1 and 0;
|
1+1 and 0;
|
||||||
1<0 or 1>0;
|
1<0 or 1>0;
|
||||||
1<=0 and 1>=0;
|
1<=0 and 1>=0;
|
||||||
1==0 or 1!=0;
|
1==0 or 1!=0;
|
||||||
|
```
|
||||||
|
Unary operators `-` `!` have the same function as C/C++.
|
||||||
|
```javascript
|
||||||
-1;
|
-1;
|
||||||
!0;
|
!0;
|
||||||
|
```
|
||||||
|
Operators `=` `+=` `-=` `*=` `/=` `~=` are used in assignment expressions.
|
||||||
|
```javascript
|
||||||
a=b=c=d=1;
|
a=b=c=d=1;
|
||||||
a+=1;
|
a+=1;
|
||||||
a-=1;
|
a-=1;
|
||||||
|
@ -676,7 +698,7 @@ a/=1;
|
||||||
a~='string';
|
a~='string';
|
||||||
```
|
```
|
||||||
|
|
||||||
### definition
|
### __Definition__
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var a=1;
|
var a=1;
|
||||||
|
@ -686,7 +708,7 @@ var (a,b,c)=(0,1,2);
|
||||||
(var a,b,c)=(0,1,2);
|
(var a,b,c)=(0,1,2);
|
||||||
```
|
```
|
||||||
|
|
||||||
### multi-assignment
|
### __Multi-Assignment__
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
(a,b[0],c.d)=[0,1,2];
|
(a,b[0],c.d)=[0,1,2];
|
||||||
|
@ -694,7 +716,10 @@ var (a,b,c)=(0,1,2);
|
||||||
(a,b)=(b,a);
|
(a,b)=(b,a);
|
||||||
```
|
```
|
||||||
|
|
||||||
### conditional expression
|
### __Conditional Expression__
|
||||||
|
|
||||||
|
In nasal there's a new key word `elsif`.
|
||||||
|
It has the same functions as `else if`.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
if(1){
|
if(1){
|
||||||
|
@ -708,23 +733,30 @@ if(1){
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### loop
|
### __Loop__
|
||||||
|
|
||||||
|
While loop and for loop is simalar to C/C++.
|
||||||
```javascript
|
```javascript
|
||||||
while(condition)
|
while(condition)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for(var i=0;i<10;i+=1)
|
for(var i=0;i<10;i+=1)
|
||||||
break;
|
break;
|
||||||
|
```
|
||||||
|
Nasal has another two kinds of loops that iterates through a vector:
|
||||||
|
|
||||||
|
`forindex` will get the index of a vector.
|
||||||
|
```javascript
|
||||||
forindex(var i;elem)
|
forindex(var i;elem)
|
||||||
print(elem[i]);
|
print(elem[i]);
|
||||||
|
```
|
||||||
|
`foreach` will get the element of a vector.
|
||||||
|
```javascript
|
||||||
foreach(var i;elem)
|
foreach(var i;elem)
|
||||||
print(i);
|
print(i);
|
||||||
```
|
```
|
||||||
|
|
||||||
### subvec
|
### __Subvec__
|
||||||
|
|
||||||
Use index to search one element in the string will get the ascii number of this character.
|
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().
|
If you want to get the character,use built-in function chr().
|
||||||
|
@ -734,15 +766,16 @@ a[-1,1,0:2,0:,:3,:,nil:8,3:nil,nil:nil];
|
||||||
"hello world"[0];
|
"hello world"[0];
|
||||||
```
|
```
|
||||||
|
|
||||||
### special function call
|
### __Special Function Call__
|
||||||
|
|
||||||
This is of great use but is not very efficient(because hashmap use string as the key to compare).
|
This is of great use but is not very efficient
|
||||||
|
(because hashmap use string as the key to compare).
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
a(x:0,y:1,z:2);
|
f(x:0,y:nil,z:[]);
|
||||||
```
|
```
|
||||||
|
|
||||||
### lambda
|
### __Lambda__
|
||||||
|
|
||||||
Also functions have this kind of use:
|
Also functions have this kind of use:
|
||||||
|
|
||||||
|
@ -766,60 +799,91 @@ var fib=func(f){
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
### closure
|
### __Closure__
|
||||||
|
Closure means you could get the variable that is not in the local scope of a function that you called.
|
||||||
Use closure to OOP.
|
Here is an example, result is `1`:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var f=func(){
|
var f=func(){
|
||||||
var a=1;
|
var a=1;
|
||||||
return func(){return a;};
|
return func(){return a;};
|
||||||
}
|
}
|
||||||
print(f()());
|
print(f()());
|
||||||
|
```
|
||||||
var student=func(name,age){
|
Using closure makes it easier to OOP.
|
||||||
var val={
|
```javascript
|
||||||
name:name,
|
var student=func(n,a){
|
||||||
age:age
|
var (name,age)=(n,a);
|
||||||
};
|
|
||||||
return {
|
return {
|
||||||
print_info:func(){println(val.name,' ',val.age);},
|
print_info:func() {println(name,' ',age);},
|
||||||
set_age: func(age){val.age=age;},
|
set_age: func(a){age=a;},
|
||||||
get_age: func(){return val.age;},
|
get_age: func() {return age;},
|
||||||
set_name: func(name){val.name=name;},
|
set_name: func(n){name=n;},
|
||||||
get_name: func(){return val.name;}
|
get_name: func() {return name;}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### native functions
|
### __Trait__
|
||||||
|
|
||||||
Must import lib.nas or has these functions' definitions inside your code.
|
Also there's another way to OOP,that is `trait`.
|
||||||
|
|
||||||
Also you could add builtin functions of your own(written in C/C++) to help you calculate things more quickly.(Advanced usage)
|
When a hash has a member named `parents` and the value type is vector,
|
||||||
|
then when you are trying to find a member that is not in this hash,
|
||||||
|
virtual machine will search the member is parents.
|
||||||
|
If there is a hash that has the member, you will get the member's value.
|
||||||
|
|
||||||
|
Using this mechanism, we could OOP like this, the result is `114514`:
|
||||||
|
```javascript
|
||||||
|
var trait={
|
||||||
|
get:func{return me.val;},
|
||||||
|
set:func(x){me.val=x;}
|
||||||
|
};
|
||||||
|
|
||||||
|
var class={
|
||||||
|
new:func(){
|
||||||
|
return {
|
||||||
|
val:nil,
|
||||||
|
parents:[trait]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
First virtual machine cannot find member `set` in hash `a`, but in `a.parents` there's a hash `trait` has the member `set`, so we get the `set`.
|
||||||
|
variable `me` points to hash `a`, so we change the `a.val`.
|
||||||
|
And `get` has the same process.
|
||||||
|
```javascript
|
||||||
|
var a=class.new();
|
||||||
|
a.set(114514);
|
||||||
|
println(a.get());
|
||||||
|
```
|
||||||
|
|
||||||
|
### __Native Functions(This is for library developers)__
|
||||||
|
|
||||||
|
You could add builtin functions of your own
|
||||||
|
(written in C/C++) to help you calculate things more quickly.
|
||||||
|
(Advanced usage)
|
||||||
|
|
||||||
Check built-in functions in lib.nas!
|
Check built-in functions in lib.nas!
|
||||||
|
You could use this file as the example to learn.
|
||||||
|
|
||||||
If you want to add your own built-in functions,define the function in nasal_builtin.h.
|
If you want to add your own built-in functions,
|
||||||
|
define the function in nasal_builtin.h. (or any other place, but remember to compile it)
|
||||||
|
|
||||||
Definition:
|
Definition:
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
nasal_ref builtin_chr(std::vector<nasal_ref>&,nasal_gc&);
|
nasal_ref builtin_chr(std::vector<nasal_ref>&,nasal_gc&);
|
||||||
```
|
```
|
||||||
|
|
||||||
Then complete this function using C++:
|
Then complete this function using C++:
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
nasal_ref builtin_print(std::vector<nasal_ref>& local,nasal_gc& gc)
|
nasal_ref builtin_print(std::vector<nasal_ref>& local,nasal_gc& gc)
|
||||||
{
|
{
|
||||||
// get arguments by using builtin_find
|
|
||||||
// find value with index begin from 1
|
// find value with index begin from 1
|
||||||
// because local_scope[0] is reserved for value 'me'
|
// because local_scope[0] is reserved for value 'me'
|
||||||
nasal_ref vec=local[1];
|
nasal_ref vec=local[1];
|
||||||
// main process
|
// main process
|
||||||
// also check number of arguments and type here
|
// also check number of arguments and type here
|
||||||
// if get a type error,use builtin_err and return nullptr
|
// if get an error,use builtin_err
|
||||||
for(auto i:vec.vec()->elems)
|
for(auto i:vec.vec()->elems)
|
||||||
switch(i.type)
|
switch(i.type)
|
||||||
{
|
{
|
||||||
|
@ -833,15 +897,12 @@ nasal_ref builtin_print(std::vector<nasal_ref>& local,nasal_gc& gc)
|
||||||
case vm_obj: std::cout<<"<object>"; break;
|
case vm_obj: std::cout<<"<object>"; break;
|
||||||
}
|
}
|
||||||
std::cout<<std::flush;
|
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
|
// generate return value,use gc::gc_alloc(type) to make a new value
|
||||||
// or use reserved reference gc.nil/gc.one/gc.zero
|
// or use reserved reference gc.nil/gc.one/gc.zero
|
||||||
return gc.nil;
|
return gc.nil;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
After that, register the built-in function's name(in nasal) and the function's pointer in this table:
|
||||||
After that, write the built-in function's name(in nasal) and the function's pointer in this table:
|
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
struct FUNC_TABLE
|
struct FUNC_TABLE
|
||||||
{
|
{
|
||||||
|
@ -854,15 +915,15 @@ struct FUNC_TABLE
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
At last,warp the '__builtin_print' in a nasal file:
|
At last,warp the `__builtin_print` in a nasal file:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var print=func(elems...){
|
var print=func(elems...){
|
||||||
return __builtin_print(elems);
|
return __builtin_print(elems);
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
In fact the arguments that `__builtin_print` uses is not necessary.
|
||||||
In fact the arguments that '__builtin_print' uses is not necessary,So writting it like this is also right:
|
So writting it like this is also right:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var print=func(elems...){
|
var print=func(elems...){
|
||||||
|
@ -870,12 +931,11 @@ var print=func(elems...){
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
In version 5.0,
|
If you don't warp built-in function in a normal nasal function,
|
||||||
if you don't warp built-in function in a normal nasal function,
|
|
||||||
this built-in function may cause a fault when searching arguments,
|
this built-in function may cause a fault when searching arguments,
|
||||||
which will cause SIGSEGV segmentation error(maybe).
|
which will segmentation error.
|
||||||
|
|
||||||
Use import("") to get the nasal file including your built-in functions,
|
Use `import(".nas")` to get the nasal file including your built-in functions,
|
||||||
then you could use it.
|
then you could use it.
|
||||||
|
|
||||||
version 6.5 update:
|
version 6.5 update:
|
||||||
|
@ -893,8 +953,8 @@ So use builtin_alloc in builtin functions like this:
|
||||||
```C++
|
```C++
|
||||||
nasal_ref builtin_keys(std::vector<nasal_ref>& local,nasal_gc& gc)
|
nasal_ref builtin_keys(std::vector<nasal_ref>& local,nasal_gc& gc)
|
||||||
{
|
{
|
||||||
nasal_ref hash_addr=local[1];
|
nasal_ref hash=local[1];
|
||||||
if(hash_addr.type!=vm_hash)
|
if(hash.type!=vm_hash)
|
||||||
{
|
{
|
||||||
builtin_err("keys","\"hash\" must be hash");
|
builtin_err("keys","\"hash\" must be hash");
|
||||||
return nasal_ref(vm_none);
|
return nasal_ref(vm_none);
|
||||||
|
@ -903,11 +963,11 @@ nasal_ref builtin_keys(std::vector<nasal_ref>& local,nasal_gc& gc)
|
||||||
// push vector into local scope to avoid being sweeped
|
// push vector into local scope to avoid being sweeped
|
||||||
local.push_back(gc.gc_alloc(vm_vec));
|
local.push_back(gc.gc_alloc(vm_vec));
|
||||||
std::vector<nasal_ref>& vec=local.back().vec()->elems;
|
std::vector<nasal_ref>& vec=local.back().vec()->elems;
|
||||||
for(auto iter:hash_addr.hash()->elems)
|
for(auto& iter:hash.hash()->elems)
|
||||||
{
|
{
|
||||||
nasal_ref str_addr=gc.builtin_alloc(vm_str);
|
nasal_ref str=gc.builtin_alloc(vm_str);
|
||||||
*str_addr.str()=iter.first;
|
*str.str()=iter.first;
|
||||||
vec.push_back(str_addr);
|
vec.push_back(str);
|
||||||
}
|
}
|
||||||
return local.back();
|
return local.back();
|
||||||
}
|
}
|
||||||
|
@ -1001,26 +1061,25 @@ Function 'die' is used to throw error and crash.
|
||||||
```javascript
|
```javascript
|
||||||
hello
|
hello
|
||||||
[vm] error: error occurred this line
|
[vm] error: error occurred this line
|
||||||
[vm] error at 0x000000b0: native function error.
|
[vm] error at 0x0000009b: native function error.
|
||||||
trace back:
|
trace back:
|
||||||
0x000000b0: callb 0x00000021:__builtin_die (lib.nas line 85)
|
0x0000009b: callb 0x22 <__builtin_die> (lib.nas line 85)
|
||||||
0x0000017f: callfv 0x00000001 (a.nas line 19)
|
0x00000182: callfv 0x1 (a.nas line 6)
|
||||||
0x00000183: callfv 0x00000000 (a.nas line 21)
|
0x00000186: callfv 0x0 (a.nas line 8)
|
||||||
vm stack(limit 10):
|
vm stack(limit 10):
|
||||||
0x0 nullptr
|
null |
|
||||||
0x7fa5f8e19c80 func | func(1 para){..}
|
func | <0x8b0f50> func{entry=0x9b}
|
||||||
0x7fa5f8e1a780 func | func(0 para){..}
|
func | <0x8b1db0> func{entry=0x17c}
|
||||||
0x7fa5f8c0c040 num | 0.017453
|
num | 57.295780
|
||||||
0x7fa5f8e33370 hash | {9 member}
|
num | 1852.000000
|
||||||
0x7fa5f8e33330 hash | {5 member}
|
num | 1.943800
|
||||||
0x7fa5f8e332e0 hash | {2 member}
|
num | 0.000540
|
||||||
0x7fa5f8e1a000 func | func(1 para){..}
|
num | 39.370100
|
||||||
0x7fa5f8e19f80 func | func(2 para){..}
|
num | 3.280800
|
||||||
0x7fa5f8e19f00 func | func(2 para){..}
|
num | 0.453600
|
||||||
```
|
```
|
||||||
|
|
||||||
Here is an example of stack overflow:
|
Here is an example of stack overflow:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
func(f){
|
func(f){
|
||||||
return f(f);
|
return f(f);
|
||||||
|
@ -1032,15 +1091,30 @@ func(f){
|
||||||
```
|
```
|
||||||
|
|
||||||
And the trace back info:
|
And the trace back info:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
[vm] stack overflow
|
[vm] stack overflow
|
||||||
trace back:
|
trace back:
|
||||||
0x00000011: callfv 0x00000001 (a.nas line 5)
|
0x0000000f: callfv 0x1 (a.nas line 5)
|
||||||
0x00000011: 4076 same call(s) ...
|
0x0000000f: 4090 same call(s) ...
|
||||||
0x00000008: callfv 0x00000001 (a.nas line 2)
|
0x00000007: callfv 0x1 (a.nas line 2)
|
||||||
0x00000015: callfv 0x00000001 (a.nas line 3)
|
0x00000013: callfv 0x1 (a.nas line 3)
|
||||||
vm stack(limit 10):
|
vm stack(limit 10):
|
||||||
0x7fcc3110ad00 func | func(1 para){..}
|
func | <0xc511e0> func{entry=0xd}
|
||||||
0x7fcc3110ad00 ... | 9 same value(s)
|
... | 9 same value(s)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Error will be thrown if there's a fatal error when executing:
|
||||||
|
```javascript
|
||||||
|
func(){
|
||||||
|
return 0;
|
||||||
|
}()[1];
|
||||||
|
```
|
||||||
|
|
||||||
|
And the trace back info:
|
||||||
|
```javascript
|
||||||
|
[vm] error at 0x00000008: callv: must call a vector/hash/string
|
||||||
|
trace back:
|
||||||
|
0x00000008: callv 0x0 (a.nas line 3)
|
||||||
|
vm stack(limit 10):
|
||||||
|
num | 0.000000
|
||||||
|
```
|
|
@ -1,8 +1,6 @@
|
||||||
import("lib.nas");
|
import("lib.nas");
|
||||||
|
|
||||||
var student=func(name,age)
|
var student=func(n,a){
|
||||||
{
|
|
||||||
var (n,a)=(name,age);
|
|
||||||
return {
|
return {
|
||||||
print_info:func println(n,' ',a),
|
print_info:func println(n,' ',a),
|
||||||
set_age: func(age) a=age,
|
set_age: func(age) a=age,
|
||||||
|
|
Loading…
Reference in New Issue