complete simple tutorial
This commit is contained in:
parent
818685c48d
commit
58ea303202
364
README.md
364
README.md
|
@ -3,45 +3,37 @@
|
|||
## Introduction
|
||||
|
||||
[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)
|
||||
without reusing the code in Andy Ross's nasal interpreter(<https://github.com/andyross/nasal>).
|
||||
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>).
|
||||
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!
|
||||
|
||||
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).
|
||||
Now this project uses MIT license (2021/5/4).
|
||||
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>).
|
||||
|
||||
But in last summer holiday,
|
||||
members in FGPRC told me that it is hard to debug with nasal-console in Flightgear,
|
||||
created by [Andy Ross](<https://github.com/andyross>).
|
||||
But in 2019 summer holiday,
|
||||
members in [FGPRC](https://www.fgprc.org/) 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,
|
||||
parser and
|
||||
bytecode 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
|
||||
We 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.
|
||||
|
||||
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
|
||||
|
||||
|
@ -49,7 +41,7 @@ Better choose the latest update of the interpreter.
|
|||
Download the source code and build it!
|
||||
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++.
|
||||
|
||||
|
@ -174,7 +166,7 @@ There's an example of byte code below:
|
|||
for(var i=0;i<4000000;i+=1);
|
||||
```
|
||||
|
||||
```MIPS
|
||||
```x86asm
|
||||
.number 0
|
||||
.number 4e+006
|
||||
.number 1
|
||||
|
@ -225,7 +217,7 @@ So the bytecode generator changed a lot.
|
|||
for(var i=0;i<4000000;i+=1);
|
||||
```
|
||||
|
||||
```MIPS
|
||||
```x86asm
|
||||
.number 4e+006
|
||||
0x00000000: intg 0x00000001
|
||||
0x00000001: pzero 0x00000000
|
||||
|
@ -273,7 +265,7 @@ var f=func(x,y){return x+y;}
|
|||
f(1024,2048);
|
||||
```
|
||||
|
||||
```MIPS
|
||||
```x86asm
|
||||
.number 1024
|
||||
.number 2048
|
||||
.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().
|
||||
So the bytecode is totally different now:
|
||||
|
||||
```MIPS
|
||||
```x86asm
|
||||
.number 10
|
||||
.number 2
|
||||
.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:
|
||||
|
||||
```MIPS
|
||||
```x86asm
|
||||
.number 4e+006
|
||||
.number 1
|
||||
0x00000000: intg 0x00000001
|
||||
|
@ -454,7 +446,7 @@ var (a,b)=(1,2);
|
|||
a=b=0;
|
||||
```
|
||||
|
||||
```MIPS
|
||||
```x86asm
|
||||
.number 2
|
||||
0x00000000: intg 0x00000002
|
||||
0x00000001: pone 0x00000000
|
||||
|
@ -487,7 +479,7 @@ Delete an old operand 'op_offset'.
|
|||
|
||||
The format of output information of bytecodes changes to this:
|
||||
|
||||
```MIPS
|
||||
```x86asm
|
||||
0x0000017c: jmp 0x181
|
||||
0x0000017d: calll 0x1
|
||||
0x0000017e: calll 0x1
|
||||
|
@ -588,48 +580,52 @@ running time:
|
|||
|quick_sort.nas|0s|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;
|
||||
|
||||
__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_none` is error type.
|
||||
This type is used to interrupt the execution of virtual machine and will not be created by user program.
|
||||
|
||||
`vm_nil` is a null type. It means nothing.
|
||||
```javascript
|
||||
var spc=nil;
|
||||
|
||||
var a=1;
|
||||
var a=2.71828;
|
||||
var a=2.147e16;
|
||||
var a=1e-10;
|
||||
var a=0x7fffffff;
|
||||
var a=0xAA55;
|
||||
var a=0o170001;
|
||||
|
||||
var b='str';
|
||||
var b="another string";
|
||||
var b=`c`;
|
||||
|
||||
var c=[];
|
||||
var c=[
|
||||
```
|
||||
`vm_num` has 3 formats. Dec, hex and oct. Using IEEE754 double to store.
|
||||
```javascript
|
||||
var n=1;
|
||||
var n=2.71828;
|
||||
var n=2.147e16;
|
||||
var n=1e-10;
|
||||
var n=0x7fffffff;
|
||||
var n=0xAA55;
|
||||
var n=0o170001;
|
||||
```
|
||||
`vm_str` has 3 formats. But the third one is often used to declare a character.
|
||||
```javascript
|
||||
var s='str';
|
||||
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,
|
||||
nil,
|
||||
{},
|
||||
[],
|
||||
func(){return 0;}
|
||||
];
|
||||
append(c,0,1,2);
|
||||
|
||||
var d={
|
||||
append(vec,0,1,2);
|
||||
```
|
||||
`vm_hash` is a hashmap that stores values with strings/identifiers as the key.
|
||||
```javascript
|
||||
var hash={
|
||||
member1:nil,
|
||||
member2:'str',
|
||||
'member3':'member\'s name can also be a string constant',
|
||||
|
@ -639,35 +635,61 @@ var d={
|
|||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
var f=func(x,y,z){return nil;}
|
||||
var f=func{return 1024;}
|
||||
var f=func(x,y,z,default_para1=1,default_para2=2){
|
||||
return x+y+z+default_para1+default_para2;
|
||||
```
|
||||
`vm_func` is a function type (in fact it is lambda).
|
||||
```javascript
|
||||
var f=func(x,y,z){
|
||||
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;
|
||||
foreach(var i;dynamic_para)
|
||||
foreach(var i;args)
|
||||
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
|
||||
1+2-1*2/1;
|
||||
'str1'~'str2';
|
||||
(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<0 or 1>0;
|
||||
1<=0 and 1>=0;
|
||||
1==0 or 1!=0;
|
||||
|
||||
```
|
||||
Unary operators `-` `!` have the same function as C/C++.
|
||||
```javascript
|
||||
-1;
|
||||
!0;
|
||||
|
||||
```
|
||||
Operators `=` `+=` `-=` `*=` `/=` `~=` are used in assignment expressions.
|
||||
```javascript
|
||||
a=b=c=d=1;
|
||||
a+=1;
|
||||
a-=1;
|
||||
|
@ -676,7 +698,7 @@ a/=1;
|
|||
a~='string';
|
||||
```
|
||||
|
||||
### definition
|
||||
### __Definition__
|
||||
|
||||
```javascript
|
||||
var a=1;
|
||||
|
@ -686,7 +708,7 @@ var (a,b,c)=(0,1,2);
|
|||
(var a,b,c)=(0,1,2);
|
||||
```
|
||||
|
||||
### multi-assignment
|
||||
### __Multi-Assignment__
|
||||
|
||||
```javascript
|
||||
(a,b[0],c.d)=[0,1,2];
|
||||
|
@ -694,7 +716,10 @@ var (a,b,c)=(0,1,2);
|
|||
(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
|
||||
if(1){
|
||||
|
@ -708,23 +733,30 @@ if(1){
|
|||
}
|
||||
```
|
||||
|
||||
### loop
|
||||
### __Loop__
|
||||
|
||||
While loop and for loop is simalar to C/C++.
|
||||
```javascript
|
||||
while(condition)
|
||||
continue;
|
||||
|
||||
for(var i=0;i<10;i+=1)
|
||||
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)
|
||||
print(elem[i]);
|
||||
|
||||
```
|
||||
`foreach` will get the element of a vector.
|
||||
```javascript
|
||||
foreach(var i;elem)
|
||||
print(i);
|
||||
```
|
||||
|
||||
### subvec
|
||||
### __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().
|
||||
|
@ -734,15 +766,16 @@ a[-1,1,0:2,0:,:3,:,nil:8,3:nil,nil:nil];
|
|||
"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
|
||||
a(x:0,y:1,z:2);
|
||||
f(x:0,y:nil,z:[]);
|
||||
```
|
||||
|
||||
### lambda
|
||||
### __Lambda__
|
||||
|
||||
Also functions have this kind of use:
|
||||
|
||||
|
@ -766,60 +799,91 @@ var fib=func(f){
|
|||
);
|
||||
```
|
||||
|
||||
### closure
|
||||
|
||||
Use closure to OOP.
|
||||
|
||||
### __Closure__
|
||||
Closure means you could get the variable that is not in the local scope of a function that you called.
|
||||
Here is an example, result is `1`:
|
||||
```javascript
|
||||
var f=func(){
|
||||
var a=1;
|
||||
return func(){return a;};
|
||||
}
|
||||
print(f()());
|
||||
|
||||
var student=func(name,age){
|
||||
var val={
|
||||
name:name,
|
||||
age:age
|
||||
};
|
||||
```
|
||||
Using closure makes it easier to OOP.
|
||||
```javascript
|
||||
var student=func(n,a){
|
||||
var (name,age)=(n,a);
|
||||
return {
|
||||
print_info:func(){println(val.name,' ',val.age);},
|
||||
set_age: func(age){val.age=age;},
|
||||
get_age: func(){return val.age;},
|
||||
set_name: func(name){val.name=name;},
|
||||
get_name: func(){return val.name;}
|
||||
print_info:func() {println(name,' ',age);},
|
||||
set_age: func(a){age=a;},
|
||||
get_age: func() {return age;},
|
||||
set_name: func(n){name=n;},
|
||||
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!
|
||||
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:
|
||||
|
||||
```C++
|
||||
nasal_ref builtin_chr(std::vector<nasal_ref>&,nasal_gc&);
|
||||
```
|
||||
|
||||
Then complete this function using C++:
|
||||
|
||||
```C++
|
||||
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
|
||||
// because local_scope[0] is reserved for value 'me'
|
||||
nasal_ref vec=local[1];
|
||||
// main process
|
||||
// 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)
|
||||
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;
|
||||
}
|
||||
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/gc.one/gc.zero
|
||||
return gc.nil;
|
||||
}
|
||||
```
|
||||
|
||||
After that, write the built-in function's name(in nasal) and the function's pointer in this table:
|
||||
|
||||
After that, register the built-in function's name(in nasal) and the function's pointer in this table:
|
||||
```C++
|
||||
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
|
||||
var print=func(elems...){
|
||||
return __builtin_print(elems);
|
||||
};
|
||||
```
|
||||
|
||||
In fact the arguments that '__builtin_print' uses is not necessary,So writting it like this is also right:
|
||||
In fact the arguments that `__builtin_print` uses is not necessary.
|
||||
So writting it like this is also right:
|
||||
|
||||
```javascript
|
||||
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,
|
||||
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.
|
||||
|
||||
version 6.5 update:
|
||||
|
@ -893,8 +953,8 @@ So use builtin_alloc in builtin functions like this:
|
|||
```C++
|
||||
nasal_ref builtin_keys(std::vector<nasal_ref>& local,nasal_gc& gc)
|
||||
{
|
||||
nasal_ref hash_addr=local[1];
|
||||
if(hash_addr.type!=vm_hash)
|
||||
nasal_ref hash=local[1];
|
||||
if(hash.type!=vm_hash)
|
||||
{
|
||||
builtin_err("keys","\"hash\" must be hash");
|
||||
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
|
||||
local.push_back(gc.gc_alloc(vm_vec));
|
||||
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);
|
||||
*str_addr.str()=iter.first;
|
||||
vec.push_back(str_addr);
|
||||
nasal_ref str=gc.builtin_alloc(vm_str);
|
||||
*str.str()=iter.first;
|
||||
vec.push_back(str);
|
||||
}
|
||||
return local.back();
|
||||
}
|
||||
|
@ -1001,26 +1061,25 @@ Function 'die' is used to throw error and crash.
|
|||
```javascript
|
||||
hello
|
||||
[vm] error: error occurred this line
|
||||
[vm] error at 0x000000b0: native function error.
|
||||
[vm] error at 0x0000009b: native function error.
|
||||
trace back:
|
||||
0x000000b0: callb 0x00000021:__builtin_die (lib.nas line 85)
|
||||
0x0000017f: callfv 0x00000001 (a.nas line 19)
|
||||
0x00000183: callfv 0x00000000 (a.nas line 21)
|
||||
0x0000009b: callb 0x22 <__builtin_die> (lib.nas line 85)
|
||||
0x00000182: callfv 0x1 (a.nas line 6)
|
||||
0x00000186: callfv 0x0 (a.nas line 8)
|
||||
vm stack(limit 10):
|
||||
0x0 nullptr
|
||||
0x7fa5f8e19c80 func | func(1 para){..}
|
||||
0x7fa5f8e1a780 func | func(0 para){..}
|
||||
0x7fa5f8c0c040 num | 0.017453
|
||||
0x7fa5f8e33370 hash | {9 member}
|
||||
0x7fa5f8e33330 hash | {5 member}
|
||||
0x7fa5f8e332e0 hash | {2 member}
|
||||
0x7fa5f8e1a000 func | func(1 para){..}
|
||||
0x7fa5f8e19f80 func | func(2 para){..}
|
||||
0x7fa5f8e19f00 func | func(2 para){..}
|
||||
null |
|
||||
func | <0x8b0f50> func{entry=0x9b}
|
||||
func | <0x8b1db0> func{entry=0x17c}
|
||||
num | 57.295780
|
||||
num | 1852.000000
|
||||
num | 1.943800
|
||||
num | 0.000540
|
||||
num | 39.370100
|
||||
num | 3.280800
|
||||
num | 0.453600
|
||||
```
|
||||
|
||||
Here is an example of stack overflow:
|
||||
|
||||
```javascript
|
||||
func(f){
|
||||
return f(f);
|
||||
|
@ -1032,15 +1091,30 @@ func(f){
|
|||
```
|
||||
|
||||
And the trace back info:
|
||||
|
||||
```javascript
|
||||
[vm] stack overflow
|
||||
trace back:
|
||||
0x00000011: callfv 0x00000001 (a.nas line 5)
|
||||
0x00000011: 4076 same call(s) ...
|
||||
0x00000008: callfv 0x00000001 (a.nas line 2)
|
||||
0x00000015: callfv 0x00000001 (a.nas line 3)
|
||||
0x0000000f: callfv 0x1 (a.nas line 5)
|
||||
0x0000000f: 4090 same call(s) ...
|
||||
0x00000007: callfv 0x1 (a.nas line 2)
|
||||
0x00000013: callfv 0x1 (a.nas line 3)
|
||||
vm stack(limit 10):
|
||||
0x7fcc3110ad00 func | func(1 para){..}
|
||||
0x7fcc3110ad00 ... | 9 same value(s)
|
||||
func | <0xc511e0> func{entry=0xd}
|
||||
... | 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");
|
||||
|
||||
var student=func(name,age)
|
||||
{
|
||||
var (n,a)=(name,age);
|
||||
var student=func(n,a){
|
||||
return {
|
||||
print_info:func println(n,' ',a),
|
||||
set_age: func(age) a=age,
|
||||
|
|
Loading…
Reference in New Issue