Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d121dcd630 | ||
|
|
c705b75513 | ||
|
|
3ef8effe9a | ||
|
|
3fd1b25f79 | ||
|
|
025ff49ffc | ||
|
|
7a93527948 | ||
|
|
405175061a | ||
|
|
ae85791f01 | ||
|
|
3cb5d0f2d9 | ||
|
|
a3f5dc01d3 | ||
|
|
35d7772dd3 | ||
|
|
e25eb76e94 | ||
|
|
946aa020a5 | ||
|
|
6ef22d3228 | ||
|
|
c4cac512a6 | ||
|
|
dc3770094a | ||
|
|
791de656c3 | ||
|
|
cff9f91bee | ||
|
|
06f02ec0cb | ||
|
|
24ae1c246f | ||
|
|
0576459fbe | ||
|
|
518ce7fcb9 | ||
|
|
0e682b7c07 | ||
|
|
26f4e1359f | ||
|
|
aa5b1d3d66 | ||
|
|
6a6eab8db5 | ||
|
|
91b3074ce9 | ||
|
|
10e579dabc | ||
|
|
add5e0c2cd | ||
|
|
1e0f0f8e7b | ||
|
|
972ad49a4f | ||
|
|
a13e419518 | ||
|
|
6c04487319 | ||
|
|
5715c1df5f | ||
|
|
aa0023a23b | ||
|
|
f86ea2445f | ||
|
|
52a38709bb | ||
|
|
b022b25cea | ||
|
|
27ceeb517d | ||
|
|
8293f85c5b | ||
|
|
0e578b3e21 | ||
|
|
24ba300f3c | ||
|
|
5be6351b60 | ||
|
|
a91826607c | ||
|
|
987d3ce9e2 | ||
|
|
da8aa4744e | ||
|
|
978957aca7 | ||
|
|
caf048aae4 | ||
|
|
692f8ccefe | ||
|
|
007b83bed5 |
9
.github/workflows/c-cpp.yml
vendored
@@ -17,7 +17,12 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: make
|
||||
run: make
|
||||
run: |
|
||||
make
|
||||
cd module
|
||||
make all
|
||||
cd ..
|
||||
tar -czf nasal-mac-nightly.tgz .
|
||||
- name: Release file
|
||||
# You may pin to the exact commit or the version.
|
||||
# uses: djnicholson/release-action@e9a535b3eced09c460e07a84118fb74ae9b53236
|
||||
@@ -30,5 +35,5 @@ jobs:
|
||||
# Name of the tag for the release (will be associated with current branch)
|
||||
automatic_release_tag: next
|
||||
# File to release
|
||||
files: nasal
|
||||
files: nasal-mac-nightly.tgz
|
||||
|
||||
|
||||
8
.gitignore
vendored
@@ -45,4 +45,10 @@ nasal.exe
|
||||
|
||||
# misc
|
||||
.vscode
|
||||
dump
|
||||
dump
|
||||
|
||||
# macOS special cache directory
|
||||
.DS_Store
|
||||
|
||||
# ppm picture generated by ppmgen.nas
|
||||
*.ppm
|
||||
457
README.md
@@ -1,16 +1,8 @@
|
||||
# __Nasal Scripting Language__
|
||||
|
||||
```C++
|
||||
__ _
|
||||
/\ \ \__ _ ___ __ _| |
|
||||
/ \/ / _` / __|/ _` | |
|
||||
/ /\ / (_| \__ \ (_| | |
|
||||
\_\ \/ \__,_|___/\__,_|_|
|
||||
```
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
[](./LICENSE)
|
||||
|
||||
> This document is also available in: [__中文__](./doc/README_zh.md) | [__English__](./README.md)
|
||||
@@ -34,33 +26,31 @@ __Contact us if having great ideas to share!__
|
||||
|
||||
## __Introduction__
|
||||
|
||||
__[Nasal](http://wiki.flightgear.org/Nasal_scripting_language)__
|
||||
[Nasal](http://wiki.flightgear.org/Nasal_scripting_language)
|
||||
is an ECMAscript-like language that used in [FlightGear](https://www.flightgear.org/).
|
||||
The designer is [Andy Ross](https://github.com/andyross).
|
||||
|
||||
This 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.
|
||||
This interpreter is totally rewritten by [ValKmjolnir](https://github.com/ValKmjolnir) using `C++`(`-std=c++14`)
|
||||
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.
|
||||
|
||||
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).
|
||||
This project uses __MIT license__ (2021/5/4).
|
||||
|
||||
__Why writing this nasal interpreter?__
|
||||
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 wrote a new interpreter to help them checking syntax error and even, runtime error.
|
||||
|
||||
I wrote the lexer, parser and
|
||||
bytecode virtual machine(there was an ast-interpreter,
|
||||
but deleted after v4.0) to help checking errors.
|
||||
bytecode virtual machine to help checking errors.
|
||||
We found it much easier to check syntax and runtime
|
||||
errors before copying nasal-codes in nasal-console in Flightgear to test.
|
||||
errors.
|
||||
|
||||
Also, you could use this language to write some
|
||||
You could also use this language to write some
|
||||
interesting programs and run them without the lib of Flightgear.
|
||||
You could add your own modules to make
|
||||
this interpreter a useful tool in your own projects (such as a script in a game just as Flightgear does).
|
||||
the interpreter a useful tool in your own projects.
|
||||
|
||||
## __How to Compile__
|
||||
|
||||
@@ -72,63 +62,36 @@ this interpreter a useful tool in your own projects (such as a script in a game
|
||||

|
||||

|
||||
|
||||
Better choose the latest update of the interpreter.
|
||||
Download the source and build it! It's quite easy to build this interpreter.
|
||||
Better download the latest update source of the interpreter and build it! It's quite easy to build this interpreter.
|
||||
__CAUTION__: If want to use the release zip/tar.gz file to build the interpreter, please read the [__Release Notes__](./doc/dev.md#release-notes) to make sure this release file has no fatal bugs.
|
||||
|
||||
__CAUTION__: If want to use the release zip/tar.gz file to build the interpreter, please read the [__Release Notes__](./doc/dev.md#release-notes) to make sure this release file has no fatal bugs. There are some tips to fix the release manually.
|
||||
Use g++(`MinGW-w64`) or MSVC(`Visual Studio`) on `Windows` .
|
||||
|
||||
Use g++(`MinGW-w64`) or MSVC(`Visual Studio`) on __`Windows`__ platform. Download MinGW-w64 [__HERE__](https://www.mingw-w64.org/downloads/)(Visual Studio also has this), and use g++/clang++ on __`linux/macOS/Unix`__ platform (we suggest `clang`).
|
||||
Use g++/clang++ on `Linux/macOS/Unix` platform (we suggest `clang`).
|
||||
|
||||
We could build the interpreter using `makefile`.
|
||||
|
||||
`mingw32-make` is __`Windows(MinGW-w64)`__ platform's `make`:
|
||||
On `Windows (MinGW-w64)`:
|
||||
|
||||
> mingw32-make nasal.exe
|
||||
>
|
||||
> mingw32-make.exe nasal.exe
|
||||
|
||||
on __`linux/macOS/Unix`__:
|
||||
You could create project in `Visual Studio` by this way: [__Click__](./doc/vs.md).
|
||||
|
||||
On `Linux/macOS/Unix`:
|
||||
|
||||
> make nasal
|
||||
|
||||
You could choose which compiler you want to use:
|
||||
|
||||
> make nasal CXX=clang++
|
||||
>
|
||||
> make nasal CXX=g++
|
||||
>
|
||||
> make nasal CXX=...
|
||||
|
||||
If you think `-O3` isn't that safe and stable, you could choose:
|
||||
|
||||
> make stable-release
|
||||
>
|
||||
> mingw32-make stable-release-mingw
|
||||
|
||||
You could create project in `Visual Studio` by this way: [__CLICK__](./doc/vs.md).
|
||||
|
||||
## __How to Use__
|
||||
|
||||
First we should learn how to write and run a program using this language,
|
||||
click to see the [__tutorial__](#tutorial).
|
||||

|
||||
|
||||
Use this get version of interpreter:
|
||||
|
||||
> ./nasal
|
||||
|
||||
Input this command to run scripts __directly__:
|
||||
|
||||
> ./nasal filename
|
||||
|
||||
Use these commands to get help(see more debug commands in help):
|
||||
|
||||
> ./nasal -h | --help
|
||||
|
||||
If your system is __`Windows`__ and you want to output unicode,please use this command before running nasal interpreter:
|
||||
|
||||
> chcp 65001
|
||||
|
||||
or you could write this in your nasal code:
|
||||
If your system is `Windows` and you want to output unicode, you could write this in nasal code:
|
||||
|
||||
```javascript
|
||||
if(os.platform()=="windows")
|
||||
@@ -142,18 +105,18 @@ Reading this tutorial will not takes you over 15 minutes.
|
||||
__If you have learnt C/C++/Javascript before, this will take less time.__
|
||||
You could totally use it after reading this simple tutorial:
|
||||
|
||||
<details><summary> basic value type </summary>
|
||||
<details><summary> Basic type </summary>
|
||||
|
||||
__`vm_none`__ is error type.
|
||||
This type is used to interrupt the execution of virtual machine and will not be created by user program.
|
||||
__`none`__ is error type used to interrupt the execution.
|
||||
This type is not created by user program.
|
||||
|
||||
__`vm_nil`__ is a null type. It means nothing.
|
||||
__`nil`__ is a null type. Just like `null`.
|
||||
|
||||
```javascript
|
||||
var spc=nil;
|
||||
```
|
||||
|
||||
__`vm_num`__ has 3 formats: `dec`, `hex` and `oct`. Using IEEE754 `double` to store.
|
||||
__`num`__ has 3 formats: `dec`, `hex` and `oct`. Using IEEE754 `double` to store.
|
||||
|
||||
```javascript
|
||||
# this language use '#' to write notes
|
||||
@@ -164,7 +127,7 @@ var n=0xAA55; # hex
|
||||
var n=0o170001; # oct
|
||||
```
|
||||
|
||||
__`vm_str`__ has 3 formats. The third one is used to declare a character.
|
||||
__`str`__ has 3 formats. The third one is used to declare a character.
|
||||
|
||||
```javascript
|
||||
var s='str';
|
||||
@@ -177,7 +140,7 @@ var s=`c`;
|
||||
'\"';
|
||||
```
|
||||
|
||||
__`vm_vec`__ has unlimited length and can store all types of values.
|
||||
__`vec`__ has unlimited length and can store all types of values.
|
||||
|
||||
```javascript
|
||||
var vec=[];
|
||||
@@ -185,7 +148,7 @@ var vec=[0,nil,{},[],func(){return 0}];
|
||||
append(vec,0,1,2);
|
||||
```
|
||||
|
||||
__`vm_hash`__ is a hashmap(or like a dict in `python`) that stores values with strings/identifiers as the key.
|
||||
__`hash`__ is a hashmap (or like a `dict` in `python`) that stores values with strings/identifiers as the key.
|
||||
|
||||
```javascript
|
||||
var hash={
|
||||
@@ -198,11 +161,16 @@ var hash={
|
||||
};
|
||||
```
|
||||
|
||||
__`vm_func`__ is a function type (in fact it is lambda).
|
||||
__`func`__ is a function type (in fact it is `lambda`).
|
||||
|
||||
```javascript
|
||||
var f=func(x,y,z){return nil;}
|
||||
var f=func{return 114514;}
|
||||
var f=func(x,y,z){
|
||||
return nil;
|
||||
}
|
||||
# function could be declared without parameters and `(`, `)`
|
||||
var f=func{
|
||||
return 114514;
|
||||
}
|
||||
var f=func(x,y,z,deft=1){
|
||||
return x+y+z+deft;
|
||||
}
|
||||
@@ -214,28 +182,27 @@ var f=func(args...){
|
||||
}
|
||||
```
|
||||
|
||||
__`vm_upval`__ is used to store upvalues, used in __`nasal_vm`__ to make sure closure runs correctly.
|
||||
__`upval`__ is used to store upvalues, used in __`vm`__ to make sure closure runs correctly.
|
||||
|
||||
__`vm_obj`__ is used to store other complex C/C++ data types.
|
||||
This type is often created by native-function of nasal. If want to define your own data type, see how to add native-functions by editing this project.
|
||||
__`obj`__ is used to store other complex `C/C++` data types.
|
||||
This type is created by native-function of nasal. If want to define a new data type, see how to add native-functions by editing code.
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary> operators </summary>
|
||||
<details><summary> Operators </summary>
|
||||
|
||||
Nasal has basic math operators `+` `-` `*` `/` and a special operator `~` that links two strings together.
|
||||
Nasal has basic math operators `+` `-` `*` `/` and a special operator `~` that joints strings.
|
||||
|
||||
```javascript
|
||||
1+2-(1+3)*(2+4)/(16-9);
|
||||
'str1'~'str2';
|
||||
"str1"~"str2";
|
||||
```
|
||||
|
||||
For conditional expressions, operators `==` `!=` `<` `>` `<=` `>=` are used to compare two values.
|
||||
`and` `or` have the same function as C/C++ `&&` `||`, link comparations together.
|
||||
`and` `or` have the same function as C/C++ `&&` `||`.
|
||||
|
||||
```javascript
|
||||
1+1 and 0;
|
||||
1<0 or 1>0;
|
||||
1+1 and (1<0 or 1>0);
|
||||
1<=0 and 1>=0;
|
||||
1==0 or 1!=0;
|
||||
```
|
||||
@@ -251,25 +218,28 @@ Operators `=` `+=` `-=` `*=` `/=` `~=` are used in assignment expressions.
|
||||
|
||||
```javascript
|
||||
a=b=c=d=1;
|
||||
a+=1; a-=1; a*=1; a/=1;
|
||||
a~='string';
|
||||
a+=1;
|
||||
a-=1;
|
||||
a*=1;
|
||||
a/=1;
|
||||
a~="string";
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary> definition </summary>
|
||||
<details><summary> Definition </summary>
|
||||
|
||||
As follows.
|
||||
|
||||
```javascript
|
||||
var a=1;
|
||||
var (a,b,c)=[0,1,2];
|
||||
var (a,b,c)=(0,1,2);
|
||||
(var a,b,c)=[0,1,2];
|
||||
(var a,b,c)=(0,1,2);
|
||||
var a=1; # define single variable
|
||||
var (a,b,c)=[0,1,2]; # define multiple variables from a vector
|
||||
var (a,b,c)=(0,1,2); # define multiple variables from a tuple
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary> multi-assignment </summary>
|
||||
<details><summary> Multi-assignment </summary>
|
||||
|
||||
The last one is often used to swap two variables.
|
||||
|
||||
@@ -281,7 +251,7 @@ The last one is often used to swap two variables.
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary> conditional expression </summary>
|
||||
<details><summary> Conditional expression </summary>
|
||||
|
||||
In nasal there's a new key word `elsif`.
|
||||
It has the same functions as `else if`.
|
||||
@@ -300,7 +270,7 @@ if(1){
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary> loop </summary>
|
||||
<details><summary> Loop </summary>
|
||||
|
||||
While loop and for loop is simalar to C/C++.
|
||||
|
||||
@@ -329,7 +299,7 @@ foreach(var i;elem)
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary> subvec </summary>
|
||||
<details><summary> Subvec </summary>
|
||||
|
||||
Nasal provides this special syntax to help user generate a new vector by getting values by one index or getting values by indexes in a range from an old vector.
|
||||
If there's only one index in the bracket, then we will get the value directly.
|
||||
@@ -344,10 +314,12 @@ a[-1,1,0:2,0:,:3,:,nil:8,3:nil,nil:nil];
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary> special function call </summary>
|
||||
<details><summary> Special function call </summary>
|
||||
|
||||
This is of great use but is not very efficient
|
||||
(because hashmap use string as the key to compare).
|
||||
This is not very efficient,
|
||||
because hashmap use string as the key to compare.
|
||||
|
||||
But if it really useful, the efficientcy may not be so important...
|
||||
|
||||
```javascript
|
||||
f(x:0,y:nil,z:[]);
|
||||
@@ -355,13 +327,17 @@ f(x:0,y:nil,z:[]);
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary> lambda </summary>
|
||||
<details><summary> Lambda </summary>
|
||||
|
||||
Also functions have this kind of use:
|
||||
|
||||
```javascript
|
||||
func(x,y){return x+y}(0,1);
|
||||
func(x){return 1/(1+math.exp(-x));}(0.5);
|
||||
func(x,y){
|
||||
return x+y
|
||||
}(0,1);
|
||||
func(x){
|
||||
return 1/(1+math.exp(-x));
|
||||
}(0.5);
|
||||
```
|
||||
|
||||
There's an interesting test file `y-combinator.nas`,
|
||||
@@ -382,7 +358,7 @@ var fib=func(f){
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary> closure </summary>
|
||||
<details><summary> Closure </summary>
|
||||
|
||||
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`:
|
||||
@@ -412,7 +388,7 @@ var student=func(n,a){
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary> trait </summary>
|
||||
<details><summary> Trait </summary>
|
||||
|
||||
Also there's another way to OOP, that is `trait`.
|
||||
|
||||
@@ -494,20 +470,19 @@ If you want to use this trick to make the program running more efficiently, you
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary> native functions and module import </summary>
|
||||
<details><summary> Native functions and module import </summary>
|
||||
|
||||
This part shows how we add native functions in this nasal interpreter.
|
||||
This part shows how we add native functions in this interpreter.
|
||||
If you are interested in this part, this may help you.
|
||||
And...
|
||||
|
||||
__CAUTION:__ If you want to add your own functions __without__ changing the source code of the interpreter, see the __`module`__ after this part.
|
||||
__CAUTION:__ If you want to add your own functions __without__ changing the source code, see the __`module`__ after this part.
|
||||
|
||||
If you really want to change source code, check built-in functions in `lib.nas` and see the example below.
|
||||
|
||||
Definition:
|
||||
|
||||
```C++
|
||||
nas_ref builtin_print(nas_ref*,nasal_gc&);
|
||||
// you could also use a macro to define one.
|
||||
nas_native(builtin_print);
|
||||
```
|
||||
@@ -515,11 +490,11 @@ nas_native(builtin_print);
|
||||
Then complete this function using C++:
|
||||
|
||||
```C++
|
||||
nas_ref builtin_print(nas_ref* local,nasal_gc& gc)
|
||||
var builtin_print(var* local,gc& ngc)
|
||||
{
|
||||
// find value with index begin from 1
|
||||
// because local[0] is reserved for value 'me'
|
||||
nas_ref vec=local[1];
|
||||
var vec=local[1];
|
||||
// main process
|
||||
// also check number of arguments and type here
|
||||
// if get an error,use nas_err
|
||||
@@ -530,26 +505,47 @@ nas_ref builtin_print(nas_ref* local,nasal_gc& gc)
|
||||
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_vec: std::cout<<i.vec(); break;
|
||||
case vm_hash: std::cout<<i.hash(); break;
|
||||
case vm_func: std::cout<<"func(..){..}";break;
|
||||
case vm_obj: std::cout<<"<object>"; break;
|
||||
}
|
||||
std::cout<<std::flush;
|
||||
// generate return value,
|
||||
// use gc::alloc(type) to make a new value
|
||||
// use ngc::alloc(type) to make a new value
|
||||
// or use reserved reference nil/one/zero
|
||||
return nil;
|
||||
}
|
||||
```
|
||||
|
||||
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 will cause a fatal error.
|
||||
|
||||
So use `gc::temp` in builtin functions to temprorarily store the gc-managed value that you want to return later. Like this:
|
||||
|
||||
```C++
|
||||
var builtin_keys(var* local,gc& ngc)
|
||||
{
|
||||
var hash=local[1];
|
||||
if(hash.type!=vm_hash)
|
||||
return nas_err("keys","\"hash\" must be hash");
|
||||
// use gc.temp to store the gc-managed-value, to avoid being sweeped
|
||||
var res=ngc.temp=ngc.alloc(vm_vec);
|
||||
auto& vec=res.vec().elems;
|
||||
for(auto& iter:hash.hash().elems)
|
||||
vec.push_back(ngc.newstr(iter.first));
|
||||
ngc.temp=nil;
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
After that, register the built-in function's name(in nasal) and the function's pointer in this table:
|
||||
|
||||
```C++
|
||||
struct func
|
||||
{
|
||||
const char* name;
|
||||
nas_ref (*func)(nas_ref*,nasal_gc&);
|
||||
var (*func)(var*,gc&);
|
||||
} builtin[]=
|
||||
{
|
||||
{"__print",builtin_print},
|
||||
@@ -575,8 +571,7 @@ var print=func(elems...){
|
||||
```
|
||||
|
||||
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 __segmentation error__.
|
||||
this native function may cause __segmentation fault__ when searching arguments.
|
||||
|
||||
Use `import("filename.nas")` to get the nasal file including your built-in functions, then you could use it.
|
||||
Also there's another way of importing nasal files, the two way of importing have the same function:
|
||||
@@ -586,30 +581,9 @@ import.dirname.dirname.filename;
|
||||
import("./dirname/dirname/filename.nas");
|
||||
```
|
||||
|
||||
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 will cause a fatal error.
|
||||
|
||||
So use `gc::temp` in builtin functions to temprorarily store the gc-managed value that you want to return later. Like this:
|
||||
|
||||
```C++
|
||||
nas_ref builtin_keys(nas_ref* local,nasal_gc& gc)
|
||||
{
|
||||
nas_ref hash=local[1];
|
||||
if(hash.type!=vm_hash)
|
||||
return nas_err("keys","\"hash\" must be hash");
|
||||
// avoid being sweeped
|
||||
nas_ref res=gc.temp=gc.alloc(vm_vec);
|
||||
auto& vec=res.vec().elems;
|
||||
for(auto& iter:hash.hash().elems)
|
||||
vec.push_back(gc.newstr(iter.first));
|
||||
gc.temp=nil;
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary> modules(for lib developers) </summary>
|
||||
<details><summary> Modules(for lib developers) </summary>
|
||||
|
||||
If there is only one way to add your own functions into nasal,
|
||||
that is really inconvenient.
|
||||
@@ -624,7 +598,7 @@ var dylib=
|
||||
dlopen: func(libname){return __dlopen;},
|
||||
dlsym: func(lib,sym){return __dlsym; },
|
||||
dlclose: func(lib){return __dlclose; },
|
||||
dlcall: func(funcptr,args...){return __dlcall}
|
||||
dlcall: func(funcptr,args...){return __dlcall;}
|
||||
};
|
||||
```
|
||||
|
||||
@@ -641,22 +615,33 @@ double fibonaci(double x){
|
||||
return x;
|
||||
return fibonaci(x-1)+fibonaci(x-2);
|
||||
}
|
||||
// remember to use extern "C",
|
||||
// so you could search the symbol quickly
|
||||
extern "C" nas_ref fib(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
// module functions' parameter list example
|
||||
var fib(var* args,usize size,gc* ngc){
|
||||
// the arguments are generated into a vm_vec: args
|
||||
// get values from the vector that must be used here
|
||||
nas_ref num=args[0];
|
||||
var num=args[0];
|
||||
// if you want your function safer, try this
|
||||
// nas_err will print the error info on screen
|
||||
// and return vm_null for runtime to interrupt
|
||||
if(num.type!=vm_num)
|
||||
return nas_err("extern_fib","\"num\" must be number");
|
||||
// ok, you must know that vm_num now is not managed by gc
|
||||
// if want to return a gc object, use gc.alloc(type)
|
||||
// if want to return a gc object, use ngc->alloc(type)
|
||||
// usage of gc is the same as adding a native function
|
||||
return {vm_num,fibonaci(num.tonum())};
|
||||
}
|
||||
|
||||
// must write this function, this will help nasal to
|
||||
// get the function pointer by name
|
||||
// the reason why using this way to get function pointer
|
||||
// is because `var` has constructors, which is not compatiable in C
|
||||
// so "extern "C" var fib" may get compilation warnings
|
||||
extern "C" mod get(const char* n){
|
||||
string name=n;
|
||||
if(name=="fib")
|
||||
return fib;
|
||||
return nullptr;
|
||||
}
|
||||
```
|
||||
|
||||
Next, compile this `fib.cpp` into dynamic lib.
|
||||
@@ -675,10 +660,9 @@ Windows(`.dll`):
|
||||
|
||||
`g++ -shared -o libfib.dll fib.o`
|
||||
|
||||
Then we write a test nasal file to run this fib function, using `os.platform()` we could write a program that runs on three different OS:
|
||||
Then we write a test nasal file to run this fib function, using `os.platform()` we could write a cross-platform program:
|
||||
|
||||
```javascript
|
||||
import("lib.nas");
|
||||
var dlhandle=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
||||
var fib=dylib.dlsym(dlhandle,"fib");
|
||||
for(var i=1;i<30;i+=1)
|
||||
@@ -733,14 +717,15 @@ If get this, Congratulations!
|
||||
|
||||
## __Difference Between Andy's and This Interpreter__
|
||||
|
||||
### 1. must use `var` to define variables
|
||||

|
||||
|
||||
<details><summary>Must use `var` to define variables</summary>
|
||||
|
||||
This interpreter uses more strict syntax to make sure it is easier for you to program and debug.
|
||||
|
||||
In Andy's interpreter:
|
||||
|
||||
```javascript
|
||||
import("lib.nas");
|
||||
foreach(i;[0,1,2,3])
|
||||
print(i)
|
||||
```
|
||||
@@ -755,25 +740,55 @@ So in this interpreter i use a more strict syntax to force users to use `var` to
|
||||
If you forget to add the keyword `var`, you will get this:
|
||||
|
||||
```javascript
|
||||
[code] test.nas:2 undefined symbol "i".
|
||||
foreach(i;[0,1,2,3])
|
||||
[code] test.nas:3 undefined symbol "i".
|
||||
print(i)
|
||||
code: undefined symbol "i"
|
||||
--> test.nas:1:9
|
||||
|
|
||||
1 | foreach(i;[0,1,2,3])
|
||||
| ^ undefined symbol "i"
|
||||
|
||||
code: undefined symbol "i"
|
||||
--> test.nas:2:11
|
||||
|
|
||||
2 | print(i)
|
||||
| ^ undefined symbol "i"
|
||||
```
|
||||
|
||||
### 2. default dynamic arguments not supported
|
||||
</details>
|
||||
|
||||
<details><summary>Default dynamic arguments not supported</summary>
|
||||
|
||||
In this interpreter,
|
||||
function doesn't put dynamic args into vector `arg` by default.
|
||||
So if you use `arg` without definition,
|
||||
you'll get an error of `undefined symbol`.
|
||||
|
||||
```javascript
|
||||
var f=func(){
|
||||
println(arg)
|
||||
}
|
||||
f(1,2,3);
|
||||
```
|
||||
|
||||
Compilation result:
|
||||
|
||||
```javascript
|
||||
code: undefined symbol "arg"
|
||||
--> test.nas:2:15
|
||||
|
|
||||
2 | println(arg)
|
||||
| ^ undefined symbol "arg"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## __Trace Back Info__
|
||||
|
||||

|
||||
|
||||
When interpreter crashes,
|
||||
it will print trace back information:
|
||||
|
||||
<details><summary>1. native function [die]</summary>
|
||||
<details><summary>Native function `die`</summary>
|
||||
|
||||
Function `die` is used to throw error and crash immediately.
|
||||
|
||||
@@ -791,10 +806,10 @@ hello
|
||||
[vm] error: error occurred this line
|
||||
[vm] native function error.
|
||||
trace back:
|
||||
0x000000ac: 40 00 00 00 25 callb 0x25 <__die@0x41afc0> (lib.nas:131)
|
||||
0x000004f6: 3e 00 00 00 01 callfv 0x1 (a.nas:4)
|
||||
0x000004fa: 3e 00 00 00 00 callfv 0x0 (a.nas:6)
|
||||
vm stack(0x7fffcd21bc68<sp+80>, limit 10, total 12):
|
||||
0x000000ac 40 00 00 00 25 callb 0x25 <__die@0x41afc0> (lib.nas:131)
|
||||
0x000004f6 3e 00 00 00 01 callfv 0x1 (a.nas:4)
|
||||
0x000004fa 3e 00 00 00 00 callfv 0x0 (a.nas:6)
|
||||
vm stack (0x7fffcd21bc68 <sp+80>, limit 10, total 12):
|
||||
0x0000005b | null |
|
||||
...
|
||||
0x00000057 | str | <0x138ff60> error occurred t...
|
||||
@@ -804,7 +819,7 @@ vm stack(0x7fffcd21bc68<sp+80>, limit 10, total 12):
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>2. stack overflow crash info</summary>
|
||||
<details><summary>Stack overflow</summary>
|
||||
|
||||
Here is an example of stack overflow:
|
||||
|
||||
@@ -821,11 +836,11 @@ func(f){
|
||||
```javascript
|
||||
[vm] stack overflow
|
||||
trace back:
|
||||
0x000004fb: 3e 00 00 00 01 callfv 0x1 (a.nas:5)
|
||||
0x000004fb: 1349 same call(s)
|
||||
0x000004f3: 3e 00 00 00 01 callfv 0x1 (a.nas:2)
|
||||
0x000004ff: 3e 00 00 00 01 callfv 0x1 (a.nas:3)
|
||||
vm stack(0x7fffd3781d58<sp+80>, limit 10, total 8108):
|
||||
0x000004fb 3e 00 00 00 01 callfv 0x1 (a.nas:5)
|
||||
0x000004fb 1349 same call(s)
|
||||
0x000004f3 3e 00 00 00 01 callfv 0x1 (a.nas:2)
|
||||
0x000004ff 3e 00 00 00 01 callfv 0x1 (a.nas:3)
|
||||
vm stack (0x7fffd3781d58 <sp+80>, limit 10, total 8108):
|
||||
0x00001ffb | func | <0x15f8d90> entry:0x4f9
|
||||
0x00001ffa | func | <0x15f8d90> entry:0x4f9
|
||||
0x00001ff9 | pc | 0x4fb
|
||||
@@ -835,7 +850,7 @@ vm stack(0x7fffd3781d58<sp+80>, limit 10, total 8108):
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>3. normal vm error crash info</summary>
|
||||
<details><summary>Normal vm error crash info</summary>
|
||||
|
||||
Error will be thrown if there's a fatal error when executing:
|
||||
|
||||
@@ -848,102 +863,126 @@ func(){
|
||||
```javascript
|
||||
[vm] callv: must call a vector/hash/string
|
||||
trace back:
|
||||
0x000004f4: 3b 00 00 00 00 callv 0x0 (a.nas:3)
|
||||
vm stack(0x7fffff539c28<sp+80>, limit 10, total 1):
|
||||
0x000004f4 3b 00 00 00 00 callv 0x0 (a.nas:3)
|
||||
vm stack (0x7fffff539c28 <sp+80>, limit 10, total 1):
|
||||
0x00000050 | num | 0
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>4. detailed crash info</summary>
|
||||
<details><summary>Detailed crash info</summary>
|
||||
|
||||
Use command __`-d`__ or __`--detail`__ the trace back info will show more details:
|
||||
|
||||
```javascript
|
||||
hello
|
||||
[vm] error: error occurred this line
|
||||
[vm] native function error.
|
||||
trace back:
|
||||
0x000000ac: 40 00 00 00 25 callb 0x25 <__die@0x41afc0> (lib.nas:131)
|
||||
0x000004f6: 3e 00 00 00 01 callfv 0x1 (a.nas:4)
|
||||
0x000004fa: 3e 00 00 00 00 callfv 0x0 (a.nas:6)
|
||||
vm stack(0x7ffff42f3d08<sp+80>, limit 10, total 12):
|
||||
0x0000005b | null |
|
||||
0x0000005a | pc | 0x4f6
|
||||
0x00000059 | addr | 0x7ffff42f3d18
|
||||
[vm] error: native function error
|
||||
trace back (main)
|
||||
0x000000b0 40 00 00 00 2b callb 0x2b <__die@0x41c380> (lib.nas:131)
|
||||
0x00000553 3e 00 00 00 01 callfv 0x1 (test.nas:4)
|
||||
0x00000557 3e 00 00 00 00 callfv 0x0 (test.nas:6)
|
||||
vm stack (0x7fffe0ffed90 <sp+63>, limit 10, total 12)
|
||||
0x0000004a | null |
|
||||
0x00000049 | pc | 0x553
|
||||
0x00000048 | addr | 0x7fffe0ffeda0
|
||||
...
|
||||
0x00000052 | nil |
|
||||
registers(main):
|
||||
[ pc ] | pc | 0xac
|
||||
[ global ] | addr | 0x7ffff42f3808
|
||||
[ localr ] | addr | 0x7ffff42f3d68
|
||||
0x00000041 | nil |
|
||||
registers (main)
|
||||
[ pc ] | pc | 0xb0
|
||||
[ global ] | addr | 0x7fffe0ffe9a0
|
||||
[ localr ] | addr | 0x7fffe0ffedf0
|
||||
[ memr ] | addr | 0x0
|
||||
[ funcr ] | func | <0x18fbe50> entry:0xac
|
||||
[ canary ] | addr | 0x7fffe1002990
|
||||
[ top ] | addr | 0x7fffe0ffee40
|
||||
[ funcr ] | func | <0x677cd0> entry:0xb0
|
||||
[ upvalr ] | nil |
|
||||
[ canary ] | addr | 0x7ffff43137f8
|
||||
[ top ] | addr | 0x7ffff42f3db8
|
||||
global(0x7ffff42f3808<sp+0>):
|
||||
0x00000000 | func | <0x18d62d0> entry:0x5
|
||||
0x00000001 | func | <0x18d7e40> entry:0xc
|
||||
global (0x7fffe0ffe9a0 <sp+0>)
|
||||
0x00000000 | func | <0x65fb00> entry:0x5
|
||||
0x00000001 | func | <0x65fb20> entry:0xd
|
||||
...
|
||||
0x0000004e | func | <0x18e6710> entry:0x4c2
|
||||
0x0000004f | hash | <0x191f8b0> {5 val}
|
||||
local(0x7ffff42f3d68<sp+86>):
|
||||
0x0000003d | func | <0x66bf00> entry:0x51f
|
||||
0x0000003e | hash | <0x65ffa0> {5 val}
|
||||
local (0x7fffe0ffedf0 <sp+45>)
|
||||
0x00000000 | nil |
|
||||
0x00000001 | str | <0x1932480> error occurred t...
|
||||
0x00000001 | str | <0x6cb630> error occurred t...
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## __Debugger__
|
||||
|
||||

|
||||
|
||||
We added a debugger in `v8.0`.
|
||||
Use command `./nasal -dbg xxx.nas` to use the debugger,
|
||||
and the debugger will print this:
|
||||
|
||||
<details><summary>Click to unfold</summary>
|
||||
|
||||
```javascript
|
||||
[debug] nasal debug mode
|
||||
input 'h' to get help
|
||||
|
||||
source code:
|
||||
--> var fib=func(x)
|
||||
{
|
||||
--> var fib=func(x)
|
||||
{
|
||||
if(x<2) return x;
|
||||
return fib(x-1)+fib(x-2);
|
||||
}
|
||||
for(var i=0;i<31;i+=1)
|
||||
}
|
||||
for(var i=0;i<31;i+=1)
|
||||
print(fib(i),'\n');
|
||||
|
||||
next bytecode:
|
||||
--> 0x00000000: 01 00 00 00 50 intg 0x50 (test/fib.nas:0)
|
||||
0x00000001: 0b 00 00 00 05 newf 0x5 (./lib.nas:5)
|
||||
0x00000002: 02 00 00 00 02 intl 0x2 (./lib.nas:5)
|
||||
0x00000003: 0f 00 00 00 00 dyn 0x0 ("elems") (./lib.nas:5)
|
||||
0x00000004: 32 00 00 00 07 jmp 0x7 (./lib.nas:5)
|
||||
0x00000005: 40 00 00 00 00 callb 0x0 <__print@0x419400> (./lib.nas:6)
|
||||
0x00000006: 4a 00 00 00 00 ret 0x0 (./lib.nas:6)
|
||||
0x00000007: 03 00 00 00 00 loadg 0x0 (./lib.nas:5)
|
||||
vm stack(0x7fffce09e6e8<sp+80>, limit 10, total 0)
|
||||
--> 0x00000000 01 00 00 00 41 intg 0x41 (test/fib.nas:0)
|
||||
0x00000001 0b 00 00 00 05 newf 0x5 (lib.nas:6)
|
||||
0x00000002 02 00 00 00 02 intl 0x2 (lib.nas:6)
|
||||
0x00000003 0f 00 00 00 00 dyn 0x0 ("elems") (lib.nas:6)
|
||||
0x00000004 32 00 00 00 07 jmp 0x7 (lib.nas:6)
|
||||
0x00000005 40 00 00 00 00 callb 0x0 <__print@0x419c80> (lib.nas:7)
|
||||
0x00000006 4a 00 00 00 00 ret 0x0 (lib.nas:7)
|
||||
0x00000007 03 00 00 00 00 loadg 0x0 (lib.nas:6)
|
||||
vm stack (0x7fffd0259138 <sp+65>, limit 10, total 0)
|
||||
>>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
If want help, input `h` to get help.
|
||||
|
||||
When running the debugger, you could see what is on stack.
|
||||
This will help you debugging or learning how the vm works:
|
||||
|
||||
<details><summary>Click to unfold</summary>
|
||||
|
||||
```javascript
|
||||
source code:
|
||||
...
|
||||
var fib=func(x)
|
||||
{
|
||||
--> if(x<2) return x;
|
||||
return fib(x-1)+fib(x-2);
|
||||
}
|
||||
for(var i=0;i<31;i+=1)
|
||||
print(fib(i),'\n');
|
||||
|
||||
next bytecode:
|
||||
...
|
||||
vm stack(0x7fffce09e6e8<sp+80>, limit 10, total 7)
|
||||
0x00000056 | pc | 0x533
|
||||
0x00000055 | addr | 0x0
|
||||
0x00000054 | nil |
|
||||
0x00000053 | num | 0
|
||||
0x00000052 | nil |
|
||||
0x00000051 | nil |
|
||||
0x00000050 | func | <0x166e000> entry:0x5
|
||||
0x00000548 0c 00 00 00 aa happ 0xaa ("running") (lib.nas:503)
|
||||
0x00000549 03 00 00 00 3e loadg 0x3e (lib.nas:498)
|
||||
0x0000054a 0b 00 00 05 4e newf 0x54e (test/fib.nas:1)
|
||||
0x0000054b 02 00 00 00 02 intl 0x2 (test/fib.nas:1)
|
||||
0x0000054c 0d 00 00 00 1b para 0x1b ("x") (test/fib.nas:1)
|
||||
0x0000054d 32 00 00 05 5d jmp 0x55d (test/fib.nas:1)
|
||||
--> 0x0000054e 39 00 00 00 01 calll 0x1 (test/fib.nas:3)
|
||||
0x0000054f 2d 00 00 00 03 lessc 0x3 (2) (test/fib.nas:3)
|
||||
vm stack (0x7fffd0259138 <sp+65>, limit 10, total 7)
|
||||
0x00000047 | pc | 0x566
|
||||
0x00000046 | addr | 0x0
|
||||
0x00000045 | nil |
|
||||
0x00000044 | num | 0
|
||||
0x00000043 | nil |
|
||||
0x00000042 | nil |
|
||||
0x00000041 | func | <0x88d2f0> entry:0x5
|
||||
>>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
447
doc/README_zh.md
@@ -1,19 +1,11 @@
|
||||
# __Nasal 脚本语言__
|
||||
|
||||
```C++
|
||||
__ _
|
||||
/\ \ \__ _ ___ __ _| |
|
||||
/ \/ / _` / __|/ _` | |
|
||||
/ /\ / (_| \__ \ (_| | |
|
||||
\_\ \/ \__,_|___/\__,_|_|
|
||||
```
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
[](../LICENSE)
|
||||
|
||||
> 这篇文档包含多种语言版本: [__中文__](../doc/README_zh.md) | [__English__](../README.md)
|
||||
> 这篇文档包含多语言版本: [__中文__](../doc/README_zh.md) | [__English__](../README.md)
|
||||
|
||||
## __目录__
|
||||
|
||||
@@ -34,20 +26,20 @@ __如果有好的意见或建议,欢迎联系我们!__
|
||||
|
||||
## __简介__
|
||||
|
||||
__[Nasal](http://wiki.flightgear.org/Nasal_scripting_language)__
|
||||
[Nasal](http://wiki.flightgear.org/Nasal_scripting_language)
|
||||
是一个与ECMAscript标准语法设计相似的编程语言,并且作为运行脚本被著名的开源飞行模拟器 [FlightGear](https://www.flightgear.org/) 所依赖。
|
||||
该语言的设计者和初版解释器实现者为 [Andy Ross](https://github.com/andyross)。
|
||||
该语言的设计者为 [Andy Ross](https://github.com/andyross)。
|
||||
|
||||
这个解释器项目则由 [ValKmjolnir](https://github.com/ValKmjolnir) 完全使用 `C++`(`-std=c++11`)重新实现,没有复用 [Andy Ross的nasal解释器](<https://github.com/andyross/nasal>) 中的任何一行代码。尽管没有任何的参考代码,我们依然非常感谢Andy为我们带来了这样一个神奇且容易上手的编程语言。
|
||||
该解释器项目由 [ValKmjolnir](https://github.com/ValKmjolnir) 完全使用 `C++`(`-std=c++14`)重新实现,没有复用 [Andy Ross的nasal解释器](https://github.com/andyross/nasal) 中的任何一行代码。尽管没有参考任何代码,我们依然非常感谢Andy为我们带来了这样一个神奇且容易上手的编程语言。
|
||||
|
||||
现在这个项目已经使用 __MIT 协议__ 开源 (2021/5/4)。根据该协议的内容,你们可以根据自己的需求进行修改,使用它来学习或者创造更多有趣的东西(不过可别忘了,如果要开源必须要附带本项目拥有者的相关信息)。
|
||||
该项目已使用 __MIT__ 协议开源 (2021/5/4)。
|
||||
|
||||
__我们为什么想要重新写一个nasal解释器?__
|
||||
这是个很偶然的想法。2019年暑假,[FGPRC](https://www.fgprc.org.cn/) 的成员告诉我,在Flightgear中提供的nasal控制台窗口中进行调试实在是太费劲了,有时候只是想检查语法错误,也得花费时间打开这个软件等待加载进去之后进行调试。所以我就想,也许可以写一个全新的解释器来帮助他们检查语法错误,甚至是检查运行时的错误。
|
||||
2019年暑假,[FGPRC](https://www.fgprc.org.cn/) 的成员告诉我,在Flightgear中提供的nasal控制台窗口中进行调试很不方便,仅仅是想检查语法错误,也得花时间打开软件等待加载进去后进行调试。所以我就写了一个全新的解释器来帮助他们检查语法错误,甚至是检查运行时的错误。
|
||||
|
||||
我编写了nasal的词法分析器和语法分析器,以及一个全新的字节码虚拟机(曾经我们使用ast解释器来直接在抽象语法树中执行,然而在v4.0之后这个解释器已经淘汰),并用这个运行时来进行nasal程序的调试。我们发现使用这个解释器来检测语法和运行时错误非常快捷,远比每次都需要复制nasal代码到Flightgear的nasal控制台中去查看要方便,且错误信息清晰直观。
|
||||
我编写了nasal的词法分析器和语法分析器,以及一个全新的字节码虚拟机,并用这个运行时来进行nasal程序的调试。我们发现使用这个解释器来检测语法和运行时错误提高了我们的工作效率。
|
||||
|
||||
当然,你也可以使用这个语言来写一些与Flightgear运行环境无关的其他有趣的程序,并用这个解释器来执行,让这个语言脱离Flightgear的环境,去别的地方大展身手。你也可以编写你自己的模块,让nasal来调用,使得这个语言成为你的项目中一个非常有用的工具。
|
||||
你也可以使用这个语言来写一些与Flightgear运行环境无关的有趣的程序,并用这个解释器来执行。你也可以让解释器来调用你自己编写的模块,使它成为项目中一个非常有用的工具。
|
||||
|
||||
## __编译__
|
||||
|
||||
@@ -60,61 +52,35 @@ __我们为什么想要重新写一个nasal解释器?__
|
||||

|
||||
|
||||
我们推荐你下载最新更新的代码包来直接编译,这个项目非常小巧因此你可以非常快速地将它编译出来。
|
||||
__注意__: 如果你想直接下载发行版提供的zip/tar.gz压缩包来构建这个解释器,在下载之前请阅读[__发行日志__](../doc/dev_zh.md#发行日志)以保证这个发行版的文件中不包含非常严重的bug。
|
||||
|
||||
__注意__: 如果你想直接下载发行版提供的zip/tar.gz压缩包来构建这个解释器,在下载之前请阅读[__发行日志__](../doc/dev_zh.md#发行日志)以保证这个发行版的文件中不包含非常严重的bug(有的严重bug都是在发行之后才发现,非常搞心态)。在发行版日志中我们会告知如何在代码中手动修复这个严重的bug。
|
||||
`Windows` 用户通过 g++(`MinGW-w64`) 或者使用 MSVC(`Visual Studio`) 来进行编译。
|
||||
|
||||
__`Windows`__ 用户通过g++(`MinGW-w64`)使用以下命令或者使用MSVC(`Visual Studio`)来进行编译. 没有编译环境的请在[__这里__](https://www.mingw-w64.org/downloads/)下载MinGW-w64。(VS同样也有MinGW-w64)
|
||||
__`linux/macOS/Unix`__ 用户可以使用g++或者clang++替代下面命令中中括号的部分来进行编译(我们建议您使用`clang`)。
|
||||
`Linux/macOS/Unix` 用户可以使用 g++ 或者 clang++ 来进行编译 (建议您使用 `clang`)。
|
||||
|
||||
使用makefile我们就可以编译这个解释器。
|
||||
|
||||
`mingw32-make`是 __`Windows(MinGW-w64)`__ 平台的`make`:
|
||||
`Windows` 平台(`MinGW-w64`):
|
||||
|
||||
> mingw32-make nasal.exe
|
||||
>
|
||||
> mingw32-make.exe nasal.exe
|
||||
|
||||
__`linux/macOS/Unix`__ 平台直接使用make即可:
|
||||
你也可以在`Visual Studio`中用这种方式来创建项目:[__点击跳转__](../doc/vs.md)。
|
||||
|
||||
`Linux/macOS/Unix` 平台:
|
||||
|
||||
> make nasal
|
||||
|
||||
你也可以通过如下的其中一行命令来指定你想要使用的编译器:
|
||||
|
||||
> make nasal CXX=clang++
|
||||
>
|
||||
> make nasal CXX=g++
|
||||
>
|
||||
> make nasal CXX=...
|
||||
|
||||
如果你觉得`-O3`编译的版本不是那么安全和稳定,你也可以选择生成稳定的版本:
|
||||
|
||||
> make stable-release
|
||||
>
|
||||
> mingw32-make stable-release-mingw
|
||||
|
||||
你可以在`Visual Studio`中用这种方式来创建项目:[__点击跳转__](../doc/vs.md)。
|
||||
|
||||
## __使用方法__
|
||||
|
||||
首先我们要通过[__教程__](#教程)知道这个语言的语法以及如何使用这个解释器来运行nasal程序。
|
||||

|
||||
|
||||
使用这个命令查看解释器的版本:
|
||||
|
||||
> ./nasal
|
||||
|
||||
输入下面的命令来 __直接__ 执行:
|
||||
|
||||
> ./nasal filename
|
||||
|
||||
下面两个命令可以用于查看帮助(调试器的使用方法可以进入调试模式之后根据提示来查询):
|
||||
|
||||
> ./nasal -h | --help
|
||||
|
||||
如果你的操作系统是 __`Windows`__ 并且你想输出unicode,请保证你的控制台程序的代码页支持utf-8,若不支持,使用下面这个命令启用代码页:
|
||||
|
||||
> chcp 65001
|
||||
|
||||
或者你可以直接在nasal代码里写这个来开启:
|
||||
如果你是 `Windows` 用户且想正常输出unicode,在nasal代码里写这个来开启unicode代码页:
|
||||
|
||||
```javascript
|
||||
if(os.platform()=="windows")
|
||||
@@ -124,19 +90,19 @@ if(os.platform()=="windows")
|
||||
## __教程__
|
||||
|
||||
Nasal是非常容易上手的,你甚至可以在15分钟之内看完这里的基本教程并且直接开始编写你想要的程序。
|
||||
__如果你先前已经是C/C++,javascript选手,那么这个教程几乎可以不用看了……__ 在看完该教程之后,基本上你就完全掌握了这个语言:
|
||||
__如果你先前已经是C/C++, javascript选手,那么几乎可以不用看这个教程……__ 在看完该教程之后,基本上你就完全掌握了这个语言:
|
||||
|
||||
<details><summary>基本类型</summary>
|
||||
|
||||
__`vm_none`__ 是特殊的错误类型。这个类型用于终止虚拟机的执行,用户是无法申请到这个类型的,该类型只能由字节码虚拟机自己在抛出错误时产生。
|
||||
__`none`__ 是特殊的错误类型。这个类型用于终止虚拟机的执行,该类型只能由虚拟机在抛出错误时产生。
|
||||
|
||||
__`vm_nil`__ 是空类型。类似于null。
|
||||
__`nil`__ 是空类型。类似于null。
|
||||
|
||||
```javascript
|
||||
var spc=nil;
|
||||
```
|
||||
|
||||
__`vm_num`__ 有三种形式:十进制,十六进制以及八进制。并且该类型使用IEEE754标准的浮点数`double`格式来存储。
|
||||
__`num`__ 有三种形式:十进制,十六进制以及八进制。并且该类型使用IEEE754标准的浮点数`double`格式来存储。
|
||||
|
||||
```javascript
|
||||
# this language use '#' to write notes
|
||||
@@ -147,7 +113,7 @@ var n=0xAA55; # hex
|
||||
var n=0o170001; # oct
|
||||
```
|
||||
|
||||
__`vm_str`__ 也有三种不同的格式。第三种只允许包含一个的字符。
|
||||
__`str`__ 也有三种不同的格式。第三种只允许包含一个的字符。
|
||||
|
||||
```javascript
|
||||
var s='str';
|
||||
@@ -160,7 +126,7 @@ var s=`c`;
|
||||
'\"';
|
||||
```
|
||||
|
||||
__`vm_vec`__ 有不受限制的长度并且可以存储所有类型的数据。(当然不能超过可分配内存空间的长度)
|
||||
__`vec`__ 有不受限制的长度并且可以存储所有类型的数据。(当然不能超过可分配内存空间的长度)
|
||||
|
||||
```javascript
|
||||
var vec=[];
|
||||
@@ -168,7 +134,7 @@ var vec=[0,nil,{},[],func(){return 0}];
|
||||
append(vec,0,1,2);
|
||||
```
|
||||
|
||||
__`vm_hash`__ 使用哈希表(类似于`python`中的字典),通过键值对来存储数据。key可以是一个字符串,也可以是一个标识符。
|
||||
__`hash`__ 使用哈希表 (类似于`python`中的`dict`),通过键值对来存储数据。key可以是一个字符串,也可以是一个标识符。
|
||||
|
||||
```javascript
|
||||
var hash={
|
||||
@@ -181,11 +147,16 @@ var hash={
|
||||
};
|
||||
```
|
||||
|
||||
__`vm_func`__ 函数类型。(实际上在这个语言里函数也是一种lambda表达式)
|
||||
__`func`__ 函数类型。(实际上在这个语言里函数是一种`lambda`表达式)
|
||||
|
||||
```javascript
|
||||
var f=func(x,y,z){return nil;}
|
||||
var f=func{return 114514;}
|
||||
var f=func(x,y,z){
|
||||
return nil;
|
||||
}
|
||||
# 函数声明可以没有参数列表以及 `(`, `)`
|
||||
var f=func{
|
||||
return 114514;
|
||||
}
|
||||
var f=func(x,y,z,deft=1){
|
||||
return x+y+z+deft;
|
||||
}
|
||||
@@ -197,26 +168,25 @@ var f=func(args...){
|
||||
}
|
||||
```
|
||||
|
||||
__`vm_upval`__ 是存储闭包数据的特殊类型, 在 __`nasal_vm`__ 中使用,用于确保闭包功能正常。
|
||||
__`upval`__ 是存储闭包数据的特殊类型, 在 __`vm`__ 中使用,以确保闭包功能正常。
|
||||
|
||||
__`vm_obj`__ 是用来存储C/C++的一些复杂数据结构。这种类型的数据一般由内置函数或者库开发者提供的模块函数生成。如果你想为nasal添加一种新的数据结构, 可以看下文如何通过修改本项目来添加自己的内置函数。
|
||||
__`obj`__ 是用来存储`C/C++`的一些复杂数据结构。这种类型的数据由内置函数生成。如果想为nasal添加新的数据结构, 可以看下文如何通过修改本项目来添加内置函数。
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>运算符</summary>
|
||||
|
||||
Nasal拥有基本的四种数学运算符 `+` `-` `*` `/`以及一个特别的运算符 `~`,这个运算符用于拼接两个字符串。
|
||||
Nasal拥有基本的四种数学运算符 `+` `-` `*` `/`以及一个特别的运算符 `~`,用于拼接字符串。
|
||||
|
||||
```javascript
|
||||
1+2-(1+3)*(2+4)/(16-9);
|
||||
'str1'~'str2';
|
||||
"str1"~"str2";
|
||||
```
|
||||
|
||||
对于条件语句,可以使用`==` `!=` `<` `>` `<=` `>=`来比较两个数据。`and` `or` 有着与C/C++中 `&&` `||`运算符相同的功能,用于连接两个不同的条件语句。
|
||||
对于条件语句,可以使用`==` `!=` `<` `>` `<=` `>=`来比较数据。`and` `or` 与C/C++中 `&&` `||`运算符一致。
|
||||
|
||||
```javascript
|
||||
1+1 and 0;
|
||||
1<0 or 1>0;
|
||||
1+1 and (1<0 or 1>0);
|
||||
1<=0 and 1>=0;
|
||||
1==0 or 1!=0;
|
||||
```
|
||||
@@ -232,20 +202,23 @@ Nasal拥有基本的四种数学运算符 `+` `-` `*` `/`以及一个特别的
|
||||
|
||||
```javascript
|
||||
a=b=c=d=1;
|
||||
a+=1; a-=1; a*=1; a/=1;
|
||||
a~='string';
|
||||
a+=1;
|
||||
a-=1;
|
||||
a*=1;
|
||||
a/=1;
|
||||
a~="string";
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>定义变量</summary>
|
||||
|
||||
如下所示。
|
||||
|
||||
```javascript
|
||||
var a=1;
|
||||
var (a,b,c)=[0,1,2];
|
||||
var (a,b,c)=(0,1,2);
|
||||
(var a,b,c)=[0,1,2];
|
||||
(var a,b,c)=(0,1,2);
|
||||
var a=1; # 定义单个变量
|
||||
var (a,b,c)=[0,1,2]; # 从数组中初始化多个变量
|
||||
var (a,b,c)=(0,1,2); # 从元组中初始化多个变量
|
||||
```
|
||||
|
||||
</details>
|
||||
@@ -323,7 +296,9 @@ a[-1,1,0:2,0:,:3,:,nil:8,3:nil,nil:nil];
|
||||
|
||||
<details><summary>特殊函数调用语法</summary>
|
||||
|
||||
这种特别的调用方式有时非常有用,但是切记这种调用方式不是很高效,因为哈希表会使用字符串比对来找到数据存放的位置。
|
||||
这种调用方式不是很高效,因为哈希表会使用字符串比对来找到数据存放的位置。
|
||||
|
||||
然而如果它用起来非常舒适,那效率也显得不是非常重要了……
|
||||
|
||||
```javascript
|
||||
f(x:0,y:nil,z:[]);
|
||||
@@ -333,14 +308,18 @@ f(x:0,y:nil,z:[]);
|
||||
|
||||
<details><summary>lambda表达式</summary>
|
||||
|
||||
正如上文所述,函数有这样一种直接编写函数体并且直接调用的方式:
|
||||
函数有这样一种直接编写函数体并且立即调用的方式:
|
||||
|
||||
```javascript
|
||||
func(x,y){return x+y}(0,1);
|
||||
func(x){return 1/(1+math.exp(-x));}(0.5);
|
||||
func(x,y){
|
||||
return x+y;
|
||||
}(0,1);
|
||||
func(x){
|
||||
return 1/(1+math.exp(-x));
|
||||
}(0.5);
|
||||
```
|
||||
|
||||
测试文件中有一个非常有趣的文件`y-combinator.nas`,也就是y组合子,可以试一试,非常有趣:
|
||||
测试文件中有一个非常有趣的文件`y-combinator.nas`,可以试一试:
|
||||
|
||||
```javascript
|
||||
var fib=func(f){
|
||||
@@ -359,7 +338,9 @@ var fib=func(f){
|
||||
|
||||
<details><summary>闭包</summary>
|
||||
|
||||
闭包是一种特别的作用域,你可以从这个作用域中获取其保存的所有变量,而这些变量原本不是你当前运行的函数的局部作用域中的。下面这个例子里,结果是`1`:
|
||||
闭包是一种特别的作用域,你可以从这个作用域中获取其保存的所有变量,
|
||||
而这些变量原本不是你当前运行的函数的局部作用域中的。
|
||||
下面这个例子里,结果是`1`:
|
||||
|
||||
```javascript
|
||||
var f=func(){
|
||||
@@ -390,8 +371,10 @@ var student=func(n,a){
|
||||
|
||||
当然,也有另外一种办法来面向对象编程,那就是利用`trait`。
|
||||
|
||||
当一个hash类型中,有一个成员的key是`parents`,并且该成员是一个数组的话,那么当你试图从这个hash中寻找一个它自己没有的成员名时,虚拟机会进一步搜索`parents`数组。
|
||||
如果该数组中有一个hash类型,有一个成员的key与当前你搜索的成员名一致,那么你会得到这个成员对应的值。
|
||||
当一个hash类型中,有一个成员的key是`parents`,并且该成员是一个数组的话,
|
||||
那么当你试图从这个hash中寻找一个它自己没有的成员名时,虚拟机会进一步搜索`parents`数组。
|
||||
如果该数组中有一个hash类型,有一个成员的key与当前你搜索的成员名一致,
|
||||
那么你会得到这个成员对应的值。
|
||||
|
||||
使用这个机制,我们可以进行面向对象编程,下面样例的结果是`114514`:
|
||||
|
||||
@@ -467,16 +450,18 @@ println(d());
|
||||
|
||||
<details><summary>原生内置函数以及模块导入(import)语法</summary>
|
||||
|
||||
这个部分对于纯粹的使用者来说是不需要了解的,它将告诉你我们是如何为这个解释器添加新的内置函数的。如果你对于添加自己私人订制的内置函数很感兴趣,那么这个部分可能会帮到你,并且……
|
||||
这个部分对于纯粹的使用者来说是不需要了解的,
|
||||
它将告诉你我们是如何为解释器添加新的内置函数的。
|
||||
如果你对此很感兴趣,那么这个部分可能会帮到你,并且……
|
||||
|
||||
__警告:__ 如果你 __不想__ 通过直接修改解释器源码来添加你自定义的函数,那么你应该看下一个部分 __`模块`__ 的内容,而不是这个部分的内容。
|
||||
__警告:__ 如果你 __不想__ 通过直接修改解释器源码来添加你自定义的函数,那么你应该看下一个节 __`模块`__ 的内容。
|
||||
|
||||
如果你确实是想修改源码来搞一个自己私人订制的解释器,那么你可以说:“我他妈就是想自己私人订制,你们他妈的管得着吗”,然后看看源码中关于内置函数的部分,以及`lib.nas`中是如何包装这些函数的,还有下面的样例:
|
||||
如果你确实是想修改源码来搞一个自己私人订制的解释器,那么你可以说:“我他妈就是想自己私人订制,你们他妈的管得着吗”,
|
||||
然后看看源码中关于内置函数的部分,以及`lib.nas`中是如何包装这些函数的,还有下面的样例:
|
||||
|
||||
定义新的内置函数:
|
||||
|
||||
```C++
|
||||
nas_ref builtin_print(nas_ref*,nasal_gc&);
|
||||
// 你可以使用这个宏来直接定义一个新的内置函数
|
||||
nas_native(builtin_print);
|
||||
```
|
||||
@@ -484,11 +469,11 @@ nas_native(builtin_print);
|
||||
然后用C++完成这个函数的函数体:
|
||||
|
||||
```C++
|
||||
nas_ref builtin_print(nas_ref* local,nasal_gc& gc)
|
||||
var builtin_print(var* local,gc& ngc)
|
||||
{
|
||||
// 局部变量的下标其实是从1开始的
|
||||
// 因为local[0]是保留给'me'的空间
|
||||
nas_ref vec=local[1];
|
||||
var vec=local[1];
|
||||
// 主要部分
|
||||
// 一些必要的类型检查和输入合法性检测也要在这里写出
|
||||
// 如果检测到问题,用builtin_err函数来返回vm_null
|
||||
@@ -500,26 +485,47 @@ nas_ref builtin_print(nas_ref* local,nasal_gc& gc)
|
||||
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_vec: std::cout<<i.vec(); break;
|
||||
case vm_hash: std::cout<<i.hash(); break;
|
||||
case vm_func: std::cout<<"func(..){..}";break;
|
||||
case vm_obj: std::cout<<"<object>"; break;
|
||||
}
|
||||
std::cout<<std::flush;
|
||||
// 最后一定要记得生成返回值,返回值必须是一个内置的类型,
|
||||
// 可以使用gc::alloc(type)来申请一个需要内存管理的复杂数据结构
|
||||
// 可以使用ngc::alloc(type)来申请一个需要内存管理的复杂数据结构
|
||||
// 或者用我们已经定义好的nil/one/zero,这些可以直接使用
|
||||
return nil;
|
||||
}
|
||||
```
|
||||
|
||||
当运行内置函数的时候,内存分配器如果运行超过一次,那么会有更大可能性多次触发垃圾收集器的mark-sweep。这个操作会在`gc::alloc`中触发。
|
||||
如果先前获取的数值没有被正确存到可以被垃圾收集器索引到的地方,那么它会被错误地回收,这会导致严重的错误。
|
||||
|
||||
可以使用`gc::temp`来暂时存储一个会被返回的需要gc管理的变量,这样可以防止内部所有的申请错误触发垃圾回收。如下所示:
|
||||
|
||||
```C++
|
||||
var builtin_keys(var* local,gc& ngc)
|
||||
{
|
||||
var hash=local[1];
|
||||
if(hash.type!=vm_hash)
|
||||
return nas_err("keys","\"hash\" must be hash");
|
||||
// 使用gc.temp来存储gc管理的变量,防止错误的回收
|
||||
var res=ngc.temp=ngc.alloc(vm_vec);
|
||||
auto& vec=res.vec().elems;
|
||||
for(auto& iter:hash.hash().elems)
|
||||
vec.push_back(ngc.newstr(iter.first));
|
||||
ngc.temp=nil;
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
这些工作都完成之后,在内置函数注册表中填写它在nasal中的别名,并且在表中填对这个函数的函数指针:
|
||||
|
||||
```C++
|
||||
struct func
|
||||
{
|
||||
const char* name;
|
||||
nas_ref (*func)(nas_ref*,nasal_gc&);
|
||||
var (*func)(var*,gc&);
|
||||
} builtin[]=
|
||||
{
|
||||
{"__print",builtin_print},
|
||||
@@ -527,7 +533,7 @@ struct func
|
||||
};
|
||||
```
|
||||
|
||||
最后,将其包装起来扔到nasal文件中:
|
||||
最后,将其包装到nasal文件中:
|
||||
|
||||
```javascript
|
||||
var print=func(elems...){
|
||||
@@ -543,7 +549,7 @@ var print=func(elems...){
|
||||
};
|
||||
```
|
||||
|
||||
一定要注意,如果你不把内置函数包装到一个普通的nasal函数中,那么直接调用这个内置函数会在参数传入阶段出现严重的错误,这个错误会导致 __segmentation error__。也就是大家的老朋友段错误。
|
||||
如果你不把内置函数包装到一个普通的nasal函数中,那么直接调用这个内置函数会在参数传入阶段出现 __segmentation fault(段错误)__。
|
||||
|
||||
在nasal文件中使用`import("文件名.nas")`可以导入该文件中你包装的所有内置函数,接下来你就可以使用他们了。
|
||||
当然也有另外一种办法来导入这些nasal文件,下面两种导入方式的效果是一样的:
|
||||
@@ -553,32 +559,12 @@ import.dirname.dirname.filename;
|
||||
import("./dirname/dirname/filename.nas");
|
||||
```
|
||||
|
||||
当运行内置函数的时候,内存分配器如果运行超过一次,那么会有更大可能性多次触发垃圾收集器的mark-sweep。这个操作会在`gc::alloc`中触发。
|
||||
如果先前获取的数值没有被正确存到可以被垃圾收集器索引到的地方,那么它会被错误地回收,这会导致严重的错误。
|
||||
|
||||
所以请使用`gc::temp`来暂时存储一个会被返回的需要gc管理的变量,这样可以防止内部所有的申请错误触发垃圾回收。如下所示:
|
||||
|
||||
```C++
|
||||
nas_ref builtin_keys(nas_ref* local,nasal_gc& gc)
|
||||
{
|
||||
nas_ref hash=local[1];
|
||||
if(hash.type!=vm_hash)
|
||||
return nas_err("keys","\"hash\" must be hash");
|
||||
// 使用gc.temp来存储gc管理的变量,防止错误的回收
|
||||
nas_ref res=gc.temp=gc.alloc(vm_vec);
|
||||
auto& vec=res.vec().elems;
|
||||
for(auto& iter:hash.hash().elems)
|
||||
vec.push_back(gc.newstr(iter.first));
|
||||
gc.temp=nil;
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>模块(开发者教程)</summary>
|
||||
|
||||
如果只有上文中那种方式来添加你自定义的函数到nasal中,这肯定是非常麻烦的。因此,我们实现了一组实用的内置函数来帮助你添加你自己创建的模块。
|
||||
如果只有上文中那种方式来添加你自定义的函数到nasal中,这肯定是非常麻烦的。
|
||||
因此,我们实现了一组实用的内置函数来帮助你添加你自己创建的模块。
|
||||
|
||||
在2021/12/3更新后,我们给`lib.nas`添加了下面的这一批函数:
|
||||
|
||||
@@ -588,7 +574,7 @@ var dylib=
|
||||
dlopen: func(libname){return __dlopen;},
|
||||
dlsym: func(lib,sym){return __dlsym; },
|
||||
dlclose: func(lib){return __dlclose; },
|
||||
dlcall: func(funcptr,args...){return __dlcall}
|
||||
dlcall: func(funcptr,args...){return __dlcall;}
|
||||
};
|
||||
```
|
||||
|
||||
@@ -604,19 +590,30 @@ double fibonaci(double x){
|
||||
return x;
|
||||
return fibonaci(x-1)+fibonaci(x-2);
|
||||
}
|
||||
// 记得用extern "C"
|
||||
// 这样找符号会更加快速便捷,不要在意编译时的warning
|
||||
extern "C" nas_ref fib(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
// 传参会被送到一个vm_vec类型中送过来,而不是上文中那种指针直接指向局部作用域
|
||||
nas_ref num=args[0];
|
||||
|
||||
// 模块函数的参数列表一律以这个为准
|
||||
var fib(var* args,usize size,gc* ngc){
|
||||
// 传参会给予一个var指针,指向一个vm_vec的data()
|
||||
var num=args[0];
|
||||
// 如果你想让这个函数有更强的稳定性,那么一定要进行合法性检查
|
||||
// builtin_err会输出错误信息并返回错误类型让虚拟机终止执行
|
||||
// nas_err会输出错误信息并返回错误类型让虚拟机终止执行
|
||||
if(num.type!=vm_num)
|
||||
return nas_err("extern_fib","\"num\" must be number");
|
||||
// vm_num作为普通的数字类型,不是内存管理的对象,所以无需申请
|
||||
// 如果需要返回内存管理的对象,请使用gc.alloc(type)
|
||||
// 如果需要返回内存管理的对象,请使用ngc->alloc(type)
|
||||
return {vm_num,fibonaci(num.tonum())};
|
||||
}
|
||||
|
||||
// 必须实现这个函数, 这样nasal可以通过字符串名字获得函数指针
|
||||
// 之所以用这种方式来获取函数指针, 是因为`var`是有构造函数的
|
||||
// 有构造函数的类型作为返回值, 和C是不兼容的, 这导致
|
||||
// 类似 "extern "C" var fib" 的写法会得到编译错误
|
||||
extern "C" mod get(const char* n){
|
||||
string name=n;
|
||||
if(name=="fib")
|
||||
return fib;
|
||||
return nullptr;
|
||||
}
|
||||
```
|
||||
|
||||
接着我们把`fib.cpp`编译成动态库。
|
||||
@@ -635,10 +632,10 @@ Windows(`.dll`):
|
||||
|
||||
`g++ -shared -o libfib.dll fib.o`
|
||||
|
||||
好了,那么我们可以写一个测试用的nasal代码来运行这个斐波那契函数了。下面例子中`os.platform()`是用来检测当前运行的系统环境的,这样我们可以对不同系统进行适配:
|
||||
好了,那么我们可以写一个测试用的nasal代码来运行这个斐波那契函数了。
|
||||
下面例子中`os.platform()`是用来检测当前运行的系统环境的,这样可以实现跨平台:
|
||||
|
||||
```javascript
|
||||
import("lib.nas");
|
||||
var dlhandle=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
||||
var fib=dylib.dlsym(dlhandle,"fib");
|
||||
for(var i=1;i<30;i+=1)
|
||||
@@ -693,14 +690,15 @@ dylib.dlclose(dlhandle);
|
||||
|
||||
## __与andy解释器的不同之处__
|
||||
|
||||
### 1. 必须用`var`定义变量
|
||||

|
||||
|
||||
<details><summary>必须用 var 定义变量</summary>
|
||||
|
||||
这个解释器使用了更加严格的语法检查来保证你可以更轻松地debug。这是非常有必要的严格,否则debug会非常痛苦。
|
||||
|
||||
在Andy的解释器中:
|
||||
|
||||
```javascript
|
||||
import("lib.nas");
|
||||
foreach(i;[0,1,2,3])
|
||||
print(i)
|
||||
```
|
||||
@@ -710,21 +708,50 @@ foreach(i;[0,1,2,3])
|
||||
所以在这个解释器中,我直接使用严格的语法检查方法来强行要求用户必须要使用`var`来定义新的变量或者迭代器。如果你忘了加这个关键字,那么你就会得到这个:
|
||||
|
||||
```javascript
|
||||
[code] test.nas:2 undefined symbol "i".
|
||||
foreach(i;[0,1,2,3])
|
||||
[code] test.nas:3 undefined symbol "i".
|
||||
print(i)
|
||||
```
|
||||
code: undefined symbol "i"
|
||||
--> test.nas:1:9
|
||||
|
|
||||
1 | foreach(i;[0,1,2,3])
|
||||
| ^ undefined symbol "i"
|
||||
|
||||
### 2. 默认不定长参数
|
||||
code: undefined symbol "i"
|
||||
--> test.nas:2:11
|
||||
|
|
||||
2 | print(i)
|
||||
| ^ undefined symbol "i"
|
||||
```
|
||||
</details>
|
||||
|
||||
<details><summary>默认不定长参数</summary>
|
||||
|
||||
这个解释器在运行时,函数不会将超出参数表的那部分不定长参数放到默认的`arg`中。所以你如果不定义`arg`就使用它,那你只会得到`undefined symbol`。
|
||||
|
||||
```javascript
|
||||
var f=func(){
|
||||
println(arg)
|
||||
}
|
||||
f(1,2,3);
|
||||
```
|
||||
|
||||
编译结果:
|
||||
|
||||
```javascript
|
||||
code: undefined symbol "arg"
|
||||
--> test.nas:2:15
|
||||
|
|
||||
2 | println(arg)
|
||||
| ^ undefined symbol "arg"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## __堆栈追踪信息__
|
||||
|
||||

|
||||
|
||||
当解释器崩溃时,它会反馈错误产生过程的堆栈追踪信息:
|
||||
|
||||
<details><summary>1. 内置函数die</summary>
|
||||
<details><summary>内置函数 die</summary>
|
||||
|
||||
`die`函数用于直接抛出错误并终止执行。
|
||||
|
||||
@@ -742,10 +769,10 @@ hello
|
||||
[vm] error: error occurred this line
|
||||
[vm] native function error.
|
||||
trace back:
|
||||
0x000000ac: 40 00 00 00 25 callb 0x25 <__die@0x41afc0> (lib.nas:131)
|
||||
0x000004f6: 3e 00 00 00 01 callfv 0x1 (a.nas:4)
|
||||
0x000004fa: 3e 00 00 00 00 callfv 0x0 (a.nas:6)
|
||||
vm stack(0x7fffcd21bc68<sp+80>, limit 10, total 12):
|
||||
0x000000ac 40 00 00 00 25 callb 0x25 <__die@0x41afc0> (lib.nas:131)
|
||||
0x000004f6 3e 00 00 00 01 callfv 0x1 (a.nas:4)
|
||||
0x000004fa 3e 00 00 00 00 callfv 0x0 (a.nas:6)
|
||||
vm stack (0x7fffcd21bc68 <sp+80>, limit 10, total 12):
|
||||
0x0000005b | null |
|
||||
...
|
||||
0x00000057 | str | <0x138ff60> error occurred t...
|
||||
@@ -755,7 +782,7 @@ vm stack(0x7fffcd21bc68<sp+80>, limit 10, total 12):
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>2. 栈溢出</summary>
|
||||
<details><summary>栈溢出</summary>
|
||||
|
||||
这是一个会导致栈溢出的例子:
|
||||
|
||||
@@ -772,11 +799,11 @@ func(f){
|
||||
```javascript
|
||||
[vm] stack overflow
|
||||
trace back:
|
||||
0x000004fb: 3e 00 00 00 01 callfv 0x1 (a.nas:5)
|
||||
0x000004fb: 1349 same call(s)
|
||||
0x000004f3: 3e 00 00 00 01 callfv 0x1 (a.nas:2)
|
||||
0x000004ff: 3e 00 00 00 01 callfv 0x1 (a.nas:3)
|
||||
vm stack(0x7fffd3781d58<sp+80>, limit 10, total 8108):
|
||||
0x000004fb 3e 00 00 00 01 callfv 0x1 (a.nas:5)
|
||||
0x000004fb 1349 same call(s)
|
||||
0x000004f3 3e 00 00 00 01 callfv 0x1 (a.nas:2)
|
||||
0x000004ff 3e 00 00 00 01 callfv 0x1 (a.nas:3)
|
||||
vm stack (0x7fffd3781d58 <sp+80>, limit 10, total 8108):
|
||||
0x00001ffb | func | <0x15f8d90> entry:0x4f9
|
||||
0x00001ffa | func | <0x15f8d90> entry:0x4f9
|
||||
0x00001ff9 | pc | 0x4fb
|
||||
@@ -786,7 +813,7 @@ vm stack(0x7fffd3781d58<sp+80>, limit 10, total 8108):
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>3. 运行时错误</summary>
|
||||
<details><summary>运行时错误</summary>
|
||||
|
||||
如果在执行的时候出现错误,程序会直接终止执行:
|
||||
|
||||
@@ -799,101 +826,125 @@ func(){
|
||||
```javascript
|
||||
[vm] callv: must call a vector/hash/string
|
||||
trace back:
|
||||
0x000004f4: 3b 00 00 00 00 callv 0x0 (a.nas:3)
|
||||
vm stack(0x7fffff539c28<sp+80>, limit 10, total 1):
|
||||
0x000004f4 3b 00 00 00 00 callv 0x0 (a.nas:3)
|
||||
vm stack (0x7fffff539c28 <sp+80>, limit 10, total 1):
|
||||
0x00000050 | num | 0
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>4. 详细的崩溃信息</summary>
|
||||
<details><summary>详细的崩溃信息</summary>
|
||||
|
||||
使用命令 __`-d`__ 或 __`--detail`__ 后,trace back信息会包含更多的细节内容:
|
||||
|
||||
```javascript
|
||||
hello
|
||||
[vm] error: error occurred this line
|
||||
[vm] native function error.
|
||||
trace back:
|
||||
0x000000ac: 40 00 00 00 25 callb 0x25 <__die@0x41afc0> (lib.nas:131)
|
||||
0x000004f6: 3e 00 00 00 01 callfv 0x1 (a.nas:4)
|
||||
0x000004fa: 3e 00 00 00 00 callfv 0x0 (a.nas:6)
|
||||
vm stack(0x7ffff42f3d08<sp+80>, limit 10, total 12):
|
||||
0x0000005b | null |
|
||||
0x0000005a | pc | 0x4f6
|
||||
0x00000059 | addr | 0x7ffff42f3d18
|
||||
[vm] error: native function error
|
||||
trace back (main)
|
||||
0x000000b0 40 00 00 00 2b callb 0x2b <__die@0x41c380> (lib.nas:131)
|
||||
0x00000553 3e 00 00 00 01 callfv 0x1 (test.nas:4)
|
||||
0x00000557 3e 00 00 00 00 callfv 0x0 (test.nas:6)
|
||||
vm stack (0x7fffe0ffed90 <sp+63>, limit 10, total 12)
|
||||
0x0000004a | null |
|
||||
0x00000049 | pc | 0x553
|
||||
0x00000048 | addr | 0x7fffe0ffeda0
|
||||
...
|
||||
0x00000052 | nil |
|
||||
registers(main):
|
||||
[ pc ] | pc | 0xac
|
||||
[ global ] | addr | 0x7ffff42f3808
|
||||
[ localr ] | addr | 0x7ffff42f3d68
|
||||
0x00000041 | nil |
|
||||
registers (main)
|
||||
[ pc ] | pc | 0xb0
|
||||
[ global ] | addr | 0x7fffe0ffe9a0
|
||||
[ localr ] | addr | 0x7fffe0ffedf0
|
||||
[ memr ] | addr | 0x0
|
||||
[ funcr ] | func | <0x18fbe50> entry:0xac
|
||||
[ canary ] | addr | 0x7fffe1002990
|
||||
[ top ] | addr | 0x7fffe0ffee40
|
||||
[ funcr ] | func | <0x677cd0> entry:0xb0
|
||||
[ upvalr ] | nil |
|
||||
[ canary ] | addr | 0x7ffff43137f8
|
||||
[ top ] | addr | 0x7ffff42f3db8
|
||||
global(0x7ffff42f3808<sp+0>):
|
||||
0x00000000 | func | <0x18d62d0> entry:0x5
|
||||
0x00000001 | func | <0x18d7e40> entry:0xc
|
||||
global (0x7fffe0ffe9a0 <sp+0>)
|
||||
0x00000000 | func | <0x65fb00> entry:0x5
|
||||
0x00000001 | func | <0x65fb20> entry:0xd
|
||||
...
|
||||
0x0000004e | func | <0x18e6710> entry:0x4c2
|
||||
0x0000004f | hash | <0x191f8b0> {5 val}
|
||||
local(0x7ffff42f3d68<sp+86>):
|
||||
0x0000003d | func | <0x66bf00> entry:0x51f
|
||||
0x0000003e | hash | <0x65ffa0> {5 val}
|
||||
local (0x7fffe0ffedf0 <sp+45>)
|
||||
0x00000000 | nil |
|
||||
0x00000001 | str | <0x1932480> error occurred t...
|
||||
0x00000001 | str | <0x6cb630> error occurred t...
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## __调试器__
|
||||
|
||||

|
||||
|
||||
在`v8.0`版本中我们添加了调试器。
|
||||
使用这个命令`./nasal -dbg xxx.nas`来启用调试器,接下来调试器会打开文件并输出以下内容:
|
||||
|
||||
<details><summary>展开</summary>
|
||||
|
||||
```javascript
|
||||
[debug] nasal debug mode
|
||||
input 'h' to get help
|
||||
|
||||
source code:
|
||||
--> var fib=func(x)
|
||||
{
|
||||
--> var fib=func(x)
|
||||
{
|
||||
if(x<2) return x;
|
||||
return fib(x-1)+fib(x-2);
|
||||
}
|
||||
for(var i=0;i<31;i+=1)
|
||||
}
|
||||
for(var i=0;i<31;i+=1)
|
||||
print(fib(i),'\n');
|
||||
|
||||
next bytecode:
|
||||
--> 0x00000000: 01 00 00 00 50 intg 0x50 (test/fib.nas:0)
|
||||
0x00000001: 0b 00 00 00 05 newf 0x5 (./lib.nas:5)
|
||||
0x00000002: 02 00 00 00 02 intl 0x2 (./lib.nas:5)
|
||||
0x00000003: 0f 00 00 00 00 dyn 0x0 ("elems") (./lib.nas:5)
|
||||
0x00000004: 32 00 00 00 07 jmp 0x7 (./lib.nas:5)
|
||||
0x00000005: 40 00 00 00 00 callb 0x0 <__print@0x419400> (./lib.nas:6)
|
||||
0x00000006: 4a 00 00 00 00 ret 0x0 (./lib.nas:6)
|
||||
0x00000007: 03 00 00 00 00 loadg 0x0 (./lib.nas:5)
|
||||
vm stack(0x7fffce09e6e8<sp+80>, limit 10, total 0)
|
||||
--> 0x00000000 01 00 00 00 41 intg 0x41 (test/fib.nas:0)
|
||||
0x00000001 0b 00 00 00 05 newf 0x5 (lib.nas:6)
|
||||
0x00000002 02 00 00 00 02 intl 0x2 (lib.nas:6)
|
||||
0x00000003 0f 00 00 00 00 dyn 0x0 ("elems") (lib.nas:6)
|
||||
0x00000004 32 00 00 00 07 jmp 0x7 (lib.nas:6)
|
||||
0x00000005 40 00 00 00 00 callb 0x0 <__print@0x419c80> (lib.nas:7)
|
||||
0x00000006 4a 00 00 00 00 ret 0x0 (lib.nas:7)
|
||||
0x00000007 03 00 00 00 00 loadg 0x0 (lib.nas:6)
|
||||
vm stack (0x7fffd0259138 <sp+65>, limit 10, total 0)
|
||||
>>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
如果需要查看命令的使用方法,可以输入`h`获取帮助信息。
|
||||
|
||||
当运行调试器的时候,你可以看到现在的操作数栈上到底有些什么数据。
|
||||
这些信息可以帮助你调试,同时也可以帮助你理解这个虚拟机是如何工作的:
|
||||
|
||||
<details><summary>展开</summary>
|
||||
|
||||
```javascript
|
||||
source code:
|
||||
...
|
||||
var fib=func(x)
|
||||
{
|
||||
--> if(x<2) return x;
|
||||
return fib(x-1)+fib(x-2);
|
||||
}
|
||||
for(var i=0;i<31;i+=1)
|
||||
print(fib(i),'\n');
|
||||
|
||||
next bytecode:
|
||||
...
|
||||
vm stack(0x7fffce09e6e8<sp+80>, limit 10, total 7)
|
||||
0x00000056 | pc | 0x533
|
||||
0x00000055 | addr | 0x0
|
||||
0x00000054 | nil |
|
||||
0x00000053 | num | 0
|
||||
0x00000052 | nil |
|
||||
0x00000051 | nil |
|
||||
0x00000050 | func | <0x166e000> entry:0x5
|
||||
0x00000548 0c 00 00 00 aa happ 0xaa ("running") (lib.nas:503)
|
||||
0x00000549 03 00 00 00 3e loadg 0x3e (lib.nas:498)
|
||||
0x0000054a 0b 00 00 05 4e newf 0x54e (test/fib.nas:1)
|
||||
0x0000054b 02 00 00 00 02 intl 0x2 (test/fib.nas:1)
|
||||
0x0000054c 0d 00 00 00 1b para 0x1b ("x") (test/fib.nas:1)
|
||||
0x0000054d 32 00 00 05 5d jmp 0x55d (test/fib.nas:1)
|
||||
--> 0x0000054e 39 00 00 00 01 calll 0x1 (test/fib.nas:3)
|
||||
0x0000054f 2d 00 00 00 03 lessc 0x3 (2) (test/fib.nas:3)
|
||||
vm stack (0x7fffd0259138 <sp+65>, limit 10, total 7)
|
||||
0x00000047 | pc | 0x566
|
||||
0x00000046 | addr | 0x0
|
||||
0x00000045 | nil |
|
||||
0x00000044 | num | 0
|
||||
0x00000043 | nil |
|
||||
0x00000042 | nil |
|
||||
0x00000041 | func | <0x88d2f0> entry:0x5
|
||||
>>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# __Benchmark__
|
||||
|
||||

|
||||

|
||||
|
||||
## version 6.5 (i5-8250U windows10 2021/6/19)
|
||||
|
||||
@@ -109,4 +109,4 @@ And we use this bf interpreter to draw a mandelbrot set.
|
||||
|
||||
In 2022/2/17 update we added `\e` into the lexer. And the `bfcolored.nas` uses this special ASCII code. Here is the result:
|
||||
|
||||

|
||||

|
||||
|
||||
134
doc/dev.md
@@ -59,7 +59,7 @@ var f=func(x,y,z){return x+y+z};
|
||||
|
||||
### version 1.0 parser (last update 2019/10/14)
|
||||
|
||||
First fully functional version of nasal_parser.
|
||||
First fully functional version of parser.
|
||||
|
||||
Before version 1.0,i tried many times to create a correct parser.
|
||||
|
||||
@@ -99,6 +99,8 @@ it will be harder for me to make the bytecode vm become more efficient.
|
||||
|
||||
## __Bytecode Virtual Machine__
|
||||
|
||||

|
||||
|
||||
### version 4.0 vm (last update 2020/12/17)
|
||||
|
||||
I have just finished the first version of bytecode-interpreter.
|
||||
@@ -264,8 +266,8 @@ parser will check this left-value and tells that these kinds of left-value are n
|
||||
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()`.
|
||||
codegen will generate byte code by `codegen::call_gen()` instead of `codegen::mcall_gen()`,
|
||||
and the last child of the ast will be generated by `codegen::mcall_gen()`.
|
||||
So the bytecode is totally different now:
|
||||
|
||||
```x86asm
|
||||
@@ -335,8 +337,8 @@ As you could see from the bytecode above,
|
||||
|
||||
And because of the new structure of `mcall`,
|
||||
`addr_stack`, a stack used to store the memory address,
|
||||
is deleted from `nasal_vm`,
|
||||
and now `nasal_vm` use `nasal_val** mem_addr` to store the memory address.
|
||||
is deleted from `vm`,
|
||||
and now `vm` use `nas_val** mem_addr` to store the memory address.
|
||||
This will not cause fatal errors because the memory address is used __immediately__ after getting it.
|
||||
|
||||
### version 7.0 vm (last update 2021/10/8)
|
||||
@@ -345,7 +347,7 @@ This will not cause fatal errors because the memory address is used __immediatel
|
||||
|
||||
Instruction dispatch is changed from call-threading to computed-goto(with inline function).
|
||||
After changing the way of instruction dispatch,
|
||||
there is a great improvement in nasal_vm.
|
||||
there is a great improvement in `vm`.
|
||||
Now vm can run test/bigloop and test/pi in 0.2s!
|
||||
And vm runs test/fib in 0.8s on linux.
|
||||
You could see the time use data below,
|
||||
@@ -355,7 +357,7 @@ 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:
|
||||
There is also a change in `gc`:
|
||||
`std::vector` global is deleted,
|
||||
now the global values are all stored on stack(from `val_stack+0` to `val_stack+intg-1`).
|
||||
|
||||
@@ -413,7 +415,7 @@ a=b=0;
|
||||
|
||||
2021/10/8 update:
|
||||
|
||||
In this version vm_nil and vm_num now is not managed by `nasal_gc`,
|
||||
In this version vm_nil and vm_num now is not managed by `gc`,
|
||||
this will decrease the usage of `gc::alloc` and increase the efficiency of execution.
|
||||
|
||||
New value type is added: `vm_obj`.
|
||||
@@ -469,7 +471,7 @@ Both of them are meaningless and will be replaced by `op_pnum`.
|
||||
Local values now are __stored on stack__.
|
||||
So function calling will be faster than before.
|
||||
Because in v8.0 when calling a function,
|
||||
new `vm_vec` will be allocated by `nasal_gc`, this makes gc doing mark-sweep too many times and spends a quite lot of time.
|
||||
new `vm_vec` will be allocated by `gc`, this makes gc doing mark-sweep too many times and spends a quite lot of time.
|
||||
In test file `test/bf.nas`, it takes too much time to test the file because this file has too many function calls(see test data below in table `version 8.0 (R9-5900HX ubuntu-WSL 2022/1/23)`).
|
||||
|
||||
Upvalue now is generated when creating first new function in the local scope, using `vm_vec`.
|
||||
@@ -548,37 +550,37 @@ __We will explain how resume and yield work here:__
|
||||
When `op_callb` is called, the stack frame is like this:
|
||||
|
||||
```C++
|
||||
+--------------------------+(main stack)
|
||||
| old pc(vm_ret) | <- top[0]
|
||||
+--------------------------+
|
||||
| old localr(vm_addr) | <- top[-1]
|
||||
+--------------------------+
|
||||
| old upvalr(vm_upval) | <- top[-2]
|
||||
+--------------------------+
|
||||
| local scope(nas_ref) |
|
||||
| ... |
|
||||
+--------------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+--------------------------+
|
||||
+----------------------+(main stack)
|
||||
| old pc(vm_ret) | <- top[0]
|
||||
+----------------------+
|
||||
| old localr(vm_addr) | <- top[-1]
|
||||
+----------------------+
|
||||
| old upvalr(vm_upval) | <- top[-2]
|
||||
+----------------------+
|
||||
| local scope(var) |
|
||||
| ... |
|
||||
+----------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+----------------------+
|
||||
```
|
||||
|
||||
In `op_callb`'s progress, next step the stack frame is:
|
||||
|
||||
```C++
|
||||
+--------------------------+(main stack)
|
||||
| nil(vm_nil) | <- push nil
|
||||
+--------------------------+
|
||||
| old pc(vm_ret) |
|
||||
+--------------------------+
|
||||
| old localr(vm_addr) |
|
||||
+--------------------------+
|
||||
| old upvalr(vm_upval) |
|
||||
+--------------------------+
|
||||
| local scope(nas_ref) |
|
||||
| ... |
|
||||
+--------------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+--------------------------+
|
||||
+----------------------+(main stack)
|
||||
| nil(vm_nil) | <- push nil
|
||||
+----------------------+
|
||||
| old pc(vm_ret) |
|
||||
+----------------------+
|
||||
| old localr(vm_addr) |
|
||||
+----------------------+
|
||||
| old upvalr(vm_upval) |
|
||||
+----------------------+
|
||||
| local scope(var) |
|
||||
| ... |
|
||||
+----------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+----------------------+
|
||||
```
|
||||
|
||||
Then we call `resume`, this function will change stack.
|
||||
@@ -589,9 +591,9 @@ So for safe running, `resume` will return `gc.top[0]`.
|
||||
`op_callb` will do `top[0]=resume()`, so the value does not change.
|
||||
|
||||
```C++
|
||||
+--------------------------+(coroutine stack)
|
||||
| pc:0(vm_ret) | <- now gc.top[0]
|
||||
+--------------------------+
|
||||
+----------------------+(coroutine stack)
|
||||
| pc:0(vm_ret) | <- now gc.top[0]
|
||||
+----------------------+
|
||||
```
|
||||
|
||||
When we call `yield`, the function will do like this.
|
||||
@@ -599,40 +601,40 @@ And we find that `op_callb` has put the `nil` at the top.
|
||||
but where is the returned `local[1]` sent?
|
||||
|
||||
```C++
|
||||
+--------------------------+(coroutine stack)
|
||||
| nil(vm_nil) | <- push nil
|
||||
+--------------------------+
|
||||
| old pc(vm_ret) |
|
||||
+--------------------------+
|
||||
| old localr(vm_addr) |
|
||||
+--------------------------+
|
||||
| old upvalr(vm_upval) |
|
||||
+--------------------------+
|
||||
| local scope(nas_ref) |
|
||||
| ... |
|
||||
+--------------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+--------------------------+
|
||||
+----------------------+(coroutine stack)
|
||||
| nil(vm_nil) | <- push nil
|
||||
+----------------------+
|
||||
| old pc(vm_ret) |
|
||||
+----------------------+
|
||||
| old localr(vm_addr) |
|
||||
+----------------------+
|
||||
| old upvalr(vm_upval) |
|
||||
+----------------------+
|
||||
| local scope(var) |
|
||||
| ... |
|
||||
+----------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+----------------------+
|
||||
```
|
||||
|
||||
When `builtin_coyield` is finished, the stack is set to main stack,
|
||||
and the returned `local[1]` in fact is set to the top of the main stack by `op_callb`:
|
||||
|
||||
```C++
|
||||
+--------------------------+(main stack)
|
||||
| return_value(nas_ref) |
|
||||
+--------------------------+
|
||||
| old pc(vm_ret) |
|
||||
+--------------------------+
|
||||
| old localr(vm_addr) |
|
||||
+--------------------------+
|
||||
| old upvalr(vm_upval) |
|
||||
+--------------------------+
|
||||
| local scope(nas_ref) |
|
||||
| ... |
|
||||
+--------------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+--------------------------+
|
||||
+----------------------+(main stack)
|
||||
| return_value(var) |
|
||||
+----------------------+
|
||||
| old pc(vm_ret) |
|
||||
+----------------------+
|
||||
| old localr(vm_addr) |
|
||||
+----------------------+
|
||||
| old upvalr(vm_upval) |
|
||||
+----------------------+
|
||||
| local scope(var) |
|
||||
| ... |
|
||||
+----------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+----------------------+
|
||||
```
|
||||
|
||||
so the main progress feels the value on the top is the returned value of `resume`.
|
||||
|
||||
126
doc/dev_zh.md
@@ -91,6 +91,8 @@ __该项目于2019/7/25正式开始__。
|
||||
|
||||
## __字节码虚拟机__
|
||||
|
||||

|
||||
|
||||
### version 4.0 vm (last update 2020/12/17)
|
||||
|
||||
我在这个版本实现了第一版字节码虚拟机。不过这个虚拟机仍然在测试中,在这次测试结束之后,我会发布v4.0发行版。
|
||||
@@ -236,7 +238,7 @@ m(0)._=m(1)._=10;
|
||||
[0,1,2][1:2][0]=0;
|
||||
```
|
||||
|
||||
在老版本中,语法分析器会检查左值,并且在检测到有特别调用的情况下直接告知用户这种左值是不被接受的(bad lvalue)。但是现在它可以正常运作了。为了保证这种赋值语句能正常执行,codegen模块会优先使用`nasal_codegen::call_gen()`生成前面调用链的字节码而不是全部使用 `nasal_codegen::mcall_gen()`,在最后一个调用处才会使用`nasal_codegen::mcall_gen()`。
|
||||
在老版本中,语法分析器会检查左值,并且在检测到有特别调用的情况下直接告知用户这种左值是不被接受的(bad lvalue)。但是现在它可以正常运作了。为了保证这种赋值语句能正常执行,codegen模块会优先使用`codegen::call_gen()`生成前面调用链的字节码而不是全部使用 `codegen::mcall_gen()`,在最后一个调用处才会使用`codegen::mcall_gen()`。
|
||||
|
||||
所以现在生成的相关字节码也完全不同了:
|
||||
|
||||
@@ -303,17 +305,17 @@ m(0)._=m(1)._=10;
|
||||
|
||||
从上面这些字节码可以看出,`mcall`/`mcallv`/`mcallh`指令的使用频率比以前减小了一些,而`call`/`callv`/`callh`/`callfv`/`callfh`则相反。
|
||||
|
||||
并且因为新的数据结构,`mcall`指令以及`addr_stack`,一个曾用来存储指针的栈,从`nasal_vm`中被移除。现在`nasal_vm`使用`nasal_val** mem_addr`来暂存获取的内存地址。这不会导致严重的问题,因为内存空间是 __获取即使用__ 的。
|
||||
并且因为新的数据结构,`mcall`指令以及`addr_stack`,一个曾用来存储指针的栈,从`vm`中被移除。现在`vm`使用`nas_val** mem_addr`来暂存获取的内存地址。这不会导致严重的问题,因为内存空间是 __获取即使用__ 的。
|
||||
|
||||
### version 7.0 vm (last update 2021/10/8)
|
||||
|
||||
2021/6/26 update:
|
||||
|
||||
指令分派方式从call-threading改为了computed-goto。在更改了指令分派方式之后,nasal_vm的执行效率有了非常巨大的提升。现在虚拟机可以在0.2秒内执行完test/bigloop和test/pi!并且在linux平台虚拟机可以在0.8秒内执行完test/fib。你可以在下面的测试数据部分看到测试的结果。
|
||||
指令分派方式从call-threading改为了computed-goto。在更改了指令分派方式之后,`vm`的执行效率有了非常巨大的提升。现在虚拟机可以在0.2秒内执行完`test/bigloop`和`test/pi`!并且在linux平台虚拟机可以在0.8秒内执行完`test/fib`。你可以在下面的测试数据部分看到测试的结果。
|
||||
|
||||
这个分派方式使用了g++扩展"labels as values",clang++目前也支持这种指令分派的实现方式。(不过MSVC支不支持就不得而知了,哈哈)
|
||||
|
||||
nasal_gc中也有部分改动:
|
||||
`gc`中也有部分改动:
|
||||
全局变量不再用`std::vector`存储,而是全部存在操作数栈上(从`val_stack+0`到`val_stack+intg-1`)。
|
||||
|
||||
2021/6/29 update:
|
||||
@@ -367,7 +369,7 @@ a=b=0;
|
||||
|
||||
2021/10/8 update:
|
||||
|
||||
从这个版本开始`vm_nil`和`vm_num`不再由`nasal_gc`管理,这会大幅度降低`gc::alloc`的调用并且会大幅度提升执行效率。
|
||||
从这个版本开始`vm_nil`和`vm_num`不再由`gc`管理,这会大幅度降低`gc::alloc`的调用并且会大幅度提升执行效率。
|
||||
|
||||
添加了新的数据类型: `vm_obj`。这个类型是留给用户定义他们想要的数据类型的。相关的API会在未来加入。
|
||||
|
||||
@@ -489,37 +491,37 @@ __接下来我们解释这个协程的运行原理:__
|
||||
当`op_callb`被执行时,栈帧如下所示:
|
||||
|
||||
```C++
|
||||
+--------------------------+(主操作数栈)
|
||||
| old pc(vm_ret) | <- top[0]
|
||||
+--------------------------+
|
||||
| old localr(vm_addr) | <- top[-1]
|
||||
+--------------------------+
|
||||
| old upvalr(vm_upval) | <- top[-2]
|
||||
+--------------------------+
|
||||
| local scope(nas_ref) |
|
||||
| ... |
|
||||
+--------------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+--------------------------+
|
||||
+----------------------+(主操作数栈)
|
||||
| old pc(vm_ret) | <- top[0]
|
||||
+----------------------+
|
||||
| old localr(vm_addr) | <- top[-1]
|
||||
+----------------------+
|
||||
| old upvalr(vm_upval) | <- top[-2]
|
||||
+----------------------+
|
||||
| local scope(var) |
|
||||
| ... |
|
||||
+----------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+----------------------+
|
||||
```
|
||||
|
||||
在`op_callb`执行过程中,下一步的栈帧如下:
|
||||
|
||||
```C++
|
||||
+--------------------------+(主操作数栈)
|
||||
| nil(vm_nil) | <- push nil
|
||||
+--------------------------+
|
||||
| old pc(vm_ret) |
|
||||
+--------------------------+
|
||||
| old localr(vm_addr) |
|
||||
+--------------------------+
|
||||
| old upvalr(vm_upval) |
|
||||
+--------------------------+
|
||||
| local scope(nas_ref) |
|
||||
| ... |
|
||||
+--------------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+--------------------------+
|
||||
+----------------------+(主操作数栈)
|
||||
| nil(vm_nil) | <- push nil
|
||||
+----------------------+
|
||||
| old pc(vm_ret) |
|
||||
+----------------------+
|
||||
| old localr(vm_addr) |
|
||||
+----------------------+
|
||||
| old upvalr(vm_upval) |
|
||||
+----------------------+
|
||||
| local scope(var) |
|
||||
| ... |
|
||||
+----------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+----------------------+
|
||||
```
|
||||
|
||||
接着我们调用`resume`,这个函数会替换操作数栈。我们会看到,协程的操作数栈上已经保存了一些数据,但是我们首次进入协程执行时,这个操作数栈的栈顶将会是`vm_ret`,并且返回的`pc`值是`0`。
|
||||
@@ -527,47 +529,47 @@ __接下来我们解释这个协程的运行原理:__
|
||||
为了保证栈顶的数据不会被破坏,`resume`会返回`gc.top[0]`。`op_callb`将会执行`top[0]=resume()`,所以栈顶的数据虽然被覆盖了一次,但是实际上还是原来的数据。
|
||||
|
||||
```C++
|
||||
+--------------------------+(协程操作数栈)
|
||||
| pc:0(vm_ret) | <- now gc.top[0]
|
||||
+--------------------------+
|
||||
+----------------------+(协程操作数栈)
|
||||
| pc:0(vm_ret) | <- now gc.top[0]
|
||||
+----------------------+
|
||||
```
|
||||
|
||||
当我们调用`yield`的时候,该函数会执行出这个情况,我们发现`op_callb` 已经把`nil`放在的栈顶。但是应该返回的`local[1]`到底发送到哪里去了?
|
||||
|
||||
```C++
|
||||
+--------------------------+(协程操作数栈)
|
||||
| nil(vm_nil) | <- push nil
|
||||
+--------------------------+
|
||||
| old pc(vm_ret) |
|
||||
+--------------------------+
|
||||
| old localr(vm_addr) |
|
||||
+--------------------------+
|
||||
| old upvalr(vm_upval) |
|
||||
+--------------------------+
|
||||
| local scope(nas_ref) |
|
||||
| ... |
|
||||
+--------------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+--------------------------+
|
||||
+----------------------+(协程操作数栈)
|
||||
| nil(vm_nil) | <- push nil
|
||||
+----------------------+
|
||||
| old pc(vm_ret) |
|
||||
+----------------------+
|
||||
| old localr(vm_addr) |
|
||||
+----------------------+
|
||||
| old upvalr(vm_upval) |
|
||||
+----------------------+
|
||||
| local scope(var) |
|
||||
| ... |
|
||||
+----------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+----------------------+
|
||||
```
|
||||
|
||||
当`builtin_coyield`执行完毕之后,栈又切换到了主操作数栈上,这时可以看到返回的`local[1]`实际上被`op_callb`放在了这里的栈顶:
|
||||
|
||||
```C++
|
||||
+--------------------------+(主操作数栈)
|
||||
| return_value(nas_ref) |
|
||||
+--------------------------+
|
||||
| old pc(vm_ret) |
|
||||
+--------------------------+
|
||||
| old localr(vm_addr) |
|
||||
+--------------------------+
|
||||
| old upvalr(vm_upval) |
|
||||
+--------------------------+
|
||||
| local scope(nas_ref) |
|
||||
| ... |
|
||||
+--------------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+--------------------------+
|
||||
+----------------------+(主操作数栈)
|
||||
| return_value(var) |
|
||||
+----------------------+
|
||||
| old pc(vm_ret) |
|
||||
+----------------------+
|
||||
| old localr(vm_addr) |
|
||||
+----------------------+
|
||||
| old upvalr(vm_upval) |
|
||||
+----------------------+
|
||||
| local scope(var) |
|
||||
| ... |
|
||||
+----------------------+ <- local pointer stored in localr
|
||||
| old funcr(vm_func) | <- old function stored in funcr
|
||||
+----------------------+
|
||||
```
|
||||
|
||||
所以主程序会认为顶部这个返回值好像是`resume`返回的。而实际上`resume`的返回值在协程的操作数栈顶。综上所述:
|
||||
|
||||
BIN
doc/gif/dbg.gif
Normal file
|
After Width: | Height: | Size: 867 KiB |
BIN
doc/gif/error.gif
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
doc/gif/help.gif
Normal file
|
After Width: | Height: | Size: 207 KiB |
BIN
doc/gif/opcode.gif
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
doc/gif/stackoverflow.gif
Normal file
|
After Width: | Height: | Size: 64 KiB |
@@ -60,8 +60,8 @@
|
||||
</p>
|
||||
</text>
|
||||
<h2> Benchmark | 执行效率</h2>
|
||||
<img src="/pic/benchmark.png" width="450" height="350"></img>
|
||||
<img src="/pic/mandelbrot.png" width="450" height="350"><br /></img>
|
||||
<img src="/doc/pic/benchmark.png" width="450" height="350"></img>
|
||||
<img src="/doc/pic/mandelbrot.png" width="450" height="350"><br /></img>
|
||||
<text>
|
||||
<p>
|
||||
Benchmark of different versions of nasal interpreter(left).
|
||||
@@ -93,17 +93,16 @@
|
||||
<li><a href="/ascii-art.nas">ascii-art.nas</a></li>
|
||||
<li><a href="/auto_crash.nas">auto_crash.nas</a></li>
|
||||
<li><a href="/bf.nas">bf.nas</a></li>
|
||||
<li><a href="/bfcolored.nas">bfcolored.nas</a></li>
|
||||
<li><a href="/bfconvertor.nas">bfconvertor.nas</a></li>
|
||||
<li><a href="/bfs.nas">bfs.nas</a></li>
|
||||
<li><a href="/bigloop.nas">bigloop.nas</a></li>
|
||||
<li><a href="/bp.nas">bp.nas</a></li>
|
||||
<li><a href="/calc.nas">calc.nas</a></li>
|
||||
<li><a href="/choice.nas">choice.nas</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li><a href="/choice.nas">choice.nas</a></li>
|
||||
<li><a href="/class.nas">class.nas</a></li>
|
||||
<li><a href="/coroutine.nas">coroutine.nas</a></li>
|
||||
<li><a href="/diff.nas">diff.nas</a></li>
|
||||
@@ -112,20 +111,20 @@
|
||||
<li><a href="/filesystem.nas">filesystem.nas</a></li>
|
||||
<li><a href="/hexdump.nas">hexdump.nas</a></li>
|
||||
<li><a href="/httptest.nas">httptest.nas</a></li>
|
||||
<li><a href="/json.nas">json.nas</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li><a href="/json.nas">json.nas</a></li>
|
||||
<li><a href="/leetcode1319.nas">leetcode1319.nas</a></li>
|
||||
<li><a href="/lexer.nas">lexer.nas</a></li>
|
||||
<li><a href="/life.nas">life.nas</a></li>
|
||||
<li><a href="/loop.nas">loop.nas</a></li>
|
||||
<li><a href="/mandel.nas">mandel.nas</a></li>
|
||||
<li><a href="/mandelbrot.nas">mandelbrot.nas</a></li>
|
||||
<li><a href="/mcpu.nas">mcpu.nas</a></li>
|
||||
<li><a href="/md5.nas">md5.nas</a></li>
|
||||
<li><a href="/md5compare.nas">md5compare.nas</a></li>
|
||||
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
@@ -134,20 +133,23 @@
|
||||
<li><a href="/nasal_test.nas">nasal_test.nas</a></li>
|
||||
<li><a href="/occupation.nas">occupation.nas</a></li>
|
||||
<li><a href="/pi.nas">pi.nas</a></li>
|
||||
<li><a href="/ppmgen.nas">ppmgen.nas</a></li>
|
||||
<li><a href="/prime.nas">prime.nas</a></li>
|
||||
<li><a href="/qrcode.nas">qrcode.nas</a></li>
|
||||
<li><a href="/quick_sort.nas">quick_sort.nas</a></li>
|
||||
<li><a href="/scalar.nas">scalar.nas</a></li>
|
||||
<li><a href="/snake.nas">snake.nas</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li><a href="/snake.nas">snake.nas</a></li>
|
||||
<li><a href="/tetris.nas">tetris.nas</a></li>
|
||||
<li><a href="/trait.nas">trait.nas</a></li>
|
||||
<li><a href="/turingmachine.nas">turingmachine.nas</a></li>
|
||||
<li><a href="/utf8chk.nas">utf8chk.nas</a></li>
|
||||
<li><a href="/watchdog.nas">watchdog.nas</a></li>
|
||||
<li><a href="/wavecollapse.nas">wavecollapse.nas</a></li>
|
||||
<li><a href="/word_collector.nas">word_collector.nas</a></li>
|
||||
<li><a href="/ycombinator.nas">ycombinator.nas</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
32
doc/vs.md
@@ -1,9 +1,31 @@
|
||||
# How to Create VS project | 如何创建VS工程
|
||||
# Create VS project | 创建 VS 工程
|
||||
|
||||
1. Get code from this repo using `git`. | 用`git`从这个仓库获取代码。
|
||||
## First | 首先
|
||||
|
||||
2. In Visual Studio, click `File`->`New`->`Project From Existing Code...`. | 在VS的界面,点击文件(F)->新建(N)->从现有代码创建项目(E)。
|
||||
Make sure you are using VS 2022.
|
||||
|
||||
3. Select `Visual C++`->`Next`->choose `project file location`->write the `project name` at ease->`Finish`. | 选择创建`Visual C++`项目->下一步->项目文件位置选择你下载的代码存放的文件夹->填项目名称,随便写->完成。
|
||||
确保你使用的是 VS 2022。
|
||||
|
||||
4. Click `Source Files` in `Search Solution Explorer` at left, right click `main.cpp`, compile. | 点开左侧解决方案资源管理器中的`Source Files`,右键点击`main.cpp`,编译。
|
||||
## How to Create VS project
|
||||
|
||||
1. Get code from this repo using `git`.
|
||||
|
||||
2. In Visual Studio, click `File`->`New`->`Project From Existing Code...`.
|
||||
|
||||
3. Select `Visual C++`->`Next`->choose `project file location`->write the `project name` at ease->`Finish`.
|
||||
|
||||
4. Remove cpp files in `module` to avoid compilation problems.(they should be compiled to dynamic libraries)
|
||||
|
||||
5. Click `Source Files` in `Search Solution Explorer` at left, right click `main.cpp`, compile.
|
||||
|
||||
## 如何创建VS工程
|
||||
|
||||
1. 用`git`从这个仓库获取代码。
|
||||
|
||||
2. 在VS的界面,点击文件(F)->新建(N)->从现有代码创建项目(E)。
|
||||
|
||||
3. 选择创建`Visual C++`项目->下一步->项目文件位置选择你下载的代码存放的文件夹->填项目名称,随便写->完成。
|
||||
|
||||
4. 从项目中去掉 `module` 里的cpp文件,以防止编译错误。(那些本应该编译到动态库)
|
||||
|
||||
5. 点开左侧解决方案资源管理器中的`Source Files`,右键点击`main.cpp`,编译。
|
||||
|
||||
7
lib.nas
@@ -49,7 +49,7 @@ var id=func(object){
|
||||
return __id(object);
|
||||
}
|
||||
|
||||
# int will get the integer of input number.
|
||||
# int will get the integer of input number/string.
|
||||
# but carefully use it, because int has range between -2147483648~2147483647
|
||||
var int=func(val){
|
||||
return __int(val);
|
||||
@@ -61,6 +61,11 @@ var floor=func(val){
|
||||
return __floor(val);
|
||||
}
|
||||
|
||||
# exit using std::exit
|
||||
var exit=func(val=-1){
|
||||
return __exit(val);
|
||||
}
|
||||
|
||||
# abort using std::abort
|
||||
var abort=func(){
|
||||
__abort();
|
||||
|
||||
127
main.cpp
@@ -1,15 +1,28 @@
|
||||
#include "nasal.h"
|
||||
#include "nasal_err.h"
|
||||
#include "nasal_lexer.h"
|
||||
#include "nasal_ast.h"
|
||||
#include "nasal_parse.h"
|
||||
#include "nasal_import.h"
|
||||
#include "nasal_opt.h"
|
||||
#include "nasal_gc.h"
|
||||
#include "nasal_builtin.h"
|
||||
#include "nasal_codegen.h"
|
||||
#include "nasal_vm.h"
|
||||
#include "nasal_dbg.h"
|
||||
|
||||
const u32 VM_LEXINFO =0x01;
|
||||
const u32 VM_ASTINFO =0x02;
|
||||
const u32 VM_CODEINFO =0x04;
|
||||
const u32 VM_EXECTIME =0x08;
|
||||
const u32 VM_OPCALLNUM=0x10;
|
||||
const u32 VM_EXEC =0x20;
|
||||
const u32 VM_DBGINFO =0x40;
|
||||
const u32 VM_DEBUG =0x80;
|
||||
const u32 VM_OPTIMIZE =0x100;
|
||||
const u32 VM_SHOWPATH =0x200;
|
||||
#include <unordered_map>
|
||||
|
||||
using ch_clk=std::chrono::high_resolution_clock;
|
||||
|
||||
const u32 VM_TOKEN =0x01;
|
||||
const u32 VM_AST =0x02;
|
||||
const u32 VM_CODE =0x04;
|
||||
const u32 VM_TIME =0x08;
|
||||
const u32 VM_EXEC =0x10;
|
||||
const u32 VM_DETAIL=0x20;
|
||||
const u32 VM_DEBUG =0x40;
|
||||
const u32 VM_OPT =0x80;
|
||||
|
||||
void help()
|
||||
{
|
||||
@@ -22,23 +35,21 @@ void help()
|
||||
#endif
|
||||
<<"nasal <option>\n"
|
||||
<<"option:\n"
|
||||
<<" -h, --help | get this help and exit.\n"
|
||||
<<" -v, --version | get version of nasal interpreter.\n\n"
|
||||
<<" -h, --help | get this help and exit.\n"
|
||||
<<" -v, --version | get version of nasal interpreter.\n\n"
|
||||
<<"nasal [option...] <file> [argv...]\n"
|
||||
<<"option:\n"
|
||||
<<" -l, --lex | view token info.\n"
|
||||
<<" -a, --ast | view abstract syntax tree.\n"
|
||||
<<" -c, --code | view bytecode.\n"
|
||||
<<" -e, --exec | execute.\n"
|
||||
<<" -t, --time | get the running time.\n"
|
||||
<<" -o, --opcnt | count used operands.\n"
|
||||
<<" | available in debug mode.\n"
|
||||
<<" -d, --detail | get detail crash info.\n"
|
||||
<<" -l, --lex | view token info.\n"
|
||||
<<" -a, --ast | view abstract syntax tree.\n"
|
||||
<<" -c, --code | view bytecode.\n"
|
||||
<<" -e, --exec | execute.\n"
|
||||
<<" -t, --time | get the running time.\n"
|
||||
<<" -d, --detail | get detail runtime crash info.\n"
|
||||
<<" | get detail linker path-not-found info.\n"
|
||||
<<" | get garbage collector info if didn't crash.\n"
|
||||
<<" -op, --optimize| use optimizer(beta).\n"
|
||||
<<" -o, --optimize | use optimizer(beta).\n"
|
||||
<<" | if want to use -op and run, please use -op -e/-t/-d.\n"
|
||||
<<" -dbg, --debug | debug mode (this will ignore -t -d).\n"
|
||||
<<" -cp, --chkpath | show path if linker cannot find files.\n"
|
||||
<<" -dbg, --debug | debug mode (this will ignore -t -d).\n"
|
||||
<<"file:\n"
|
||||
<<" input file name to execute.\n"
|
||||
<<"argv:\n"
|
||||
@@ -53,7 +64,7 @@ void logo()
|
||||
<<" / \\/ / _` / __|/ _` | |\n"
|
||||
<<" / /\\ / (_| \\__ \\ (_| | |\n"
|
||||
<<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
|
||||
<<"nasal ver : "<<__nasver<<" ("<<__DATE__<<")\n"
|
||||
<<"version : "<<__nasver<<" ("<<__DATE__<<" "<<__TIME__<<")\n"
|
||||
<<"c++ std : "<<__cplusplus<<"\n"
|
||||
<<"thanks to : https://github.com/andyross/nasal\n"
|
||||
<<"code repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
|
||||
@@ -73,47 +84,45 @@ void err()
|
||||
|
||||
void execute(const string& file,const std::vector<string>& argv,const u32 cmd)
|
||||
{
|
||||
// front end use the same error module
|
||||
nasal_err nerr;
|
||||
nasal_lexer lexer(nerr);
|
||||
nasal_parse parse(nerr);
|
||||
nasal_import linker(nerr);
|
||||
nasal_codegen gen(nerr);
|
||||
// back end
|
||||
nasal_vm vm;
|
||||
error err;
|
||||
lexer lex(err);
|
||||
parse parse(err);
|
||||
linker ld(err);
|
||||
codegen gen(err);
|
||||
vm ctx;
|
||||
|
||||
// lexer scans file to get tokens
|
||||
lexer.scan(file);
|
||||
if(cmd&VM_LEXINFO)
|
||||
lexer.print();
|
||||
lex.scan(file);
|
||||
if(cmd&VM_TOKEN)
|
||||
lex.print();
|
||||
|
||||
// parser gets lexer's token list to compile
|
||||
parse.compile(lexer);
|
||||
parse.compile(lex);
|
||||
// linker gets parser's ast and load import files to this ast
|
||||
linker.link(parse,file,cmd&VM_SHOWPATH);
|
||||
ld.link(parse,file,cmd&VM_DETAIL);
|
||||
// optimizer does simple optimization on ast
|
||||
if(cmd&VM_OPTIMIZE)
|
||||
optimize(parse.ast());
|
||||
if(cmd&VM_ASTINFO)
|
||||
if(cmd&VM_OPT)
|
||||
optimize(parse.tree());
|
||||
if(cmd&VM_AST)
|
||||
parse.print();
|
||||
|
||||
// code generator gets parser's ast and linker's import file list to generate code
|
||||
gen.compile(parse,linker);
|
||||
if(cmd&VM_CODEINFO)
|
||||
gen.compile(parse,ld);
|
||||
if(cmd&VM_CODE)
|
||||
gen.print();
|
||||
|
||||
// run
|
||||
if(cmd&VM_DEBUG)
|
||||
nasal_dbg(nerr).run(gen,linker,argv,cmd&VM_OPCALLNUM);
|
||||
else if(cmd&VM_EXECTIME)
|
||||
debugger(err).run(gen,ld,argv);
|
||||
else if(cmd&VM_TIME)
|
||||
{
|
||||
auto start=std::chrono::high_resolution_clock::now();
|
||||
vm.run(gen,linker,argv,cmd&VM_DBGINFO);
|
||||
auto end=std::chrono::high_resolution_clock::now();
|
||||
std::clog<<"process exited after "<<(end-start).count()*1.0/std::chrono::high_resolution_clock::duration::period::den<<"s.\n";
|
||||
auto start=ch_clk::now();
|
||||
ctx.run(gen,ld,argv,cmd&VM_DETAIL);
|
||||
auto end=ch_clk::now();
|
||||
std::clog<<"process exited after "<<(end-start).count()*1.0/ch_clk::duration::period::den<<"s.\n";
|
||||
}
|
||||
else if(cmd&VM_EXEC)
|
||||
vm.run(gen,linker,argv,cmd&VM_DBGINFO);
|
||||
ctx.run(gen,ld,argv,cmd&VM_DETAIL);
|
||||
}
|
||||
|
||||
i32 main(i32 argc,const char* argv[])
|
||||
@@ -127,7 +136,7 @@ i32 main(i32 argc,const char* argv[])
|
||||
{
|
||||
string s(argv[1]);
|
||||
if(s=="-v" || s=="--version")
|
||||
logo();
|
||||
std::clog<<"nasal "<<__nasver<<" ("<<__DATE__<<" "<<__TIME__<<")\n";
|
||||
else if(s=="-h" || s=="--help")
|
||||
help();
|
||||
else if(s[0]!='-')
|
||||
@@ -137,16 +146,14 @@ i32 main(i32 argc,const char* argv[])
|
||||
return 0;
|
||||
}
|
||||
std::unordered_map<string,u32> cmdlst={
|
||||
{"--lex",VM_LEXINFO},{"-l",VM_LEXINFO},
|
||||
{"--ast",VM_ASTINFO},{"-a",VM_ASTINFO},
|
||||
{"--code",VM_CODEINFO},{"-c",VM_CODEINFO},
|
||||
{"--lex",VM_TOKEN},{"-l",VM_TOKEN},
|
||||
{"--ast",VM_AST},{"-a",VM_AST},
|
||||
{"--code",VM_CODE},{"-c",VM_CODE},
|
||||
{"--exec",VM_EXEC},{"-e",VM_EXEC},
|
||||
{"--opcnt",VM_OPCALLNUM|VM_EXEC},{"-o",VM_OPCALLNUM|VM_EXEC},
|
||||
{"--time",VM_EXECTIME|VM_EXEC},{"-t",VM_EXECTIME|VM_EXEC},
|
||||
{"--detail",VM_DBGINFO|VM_EXEC},{"-d",VM_DBGINFO|VM_EXEC},
|
||||
{"--optimize",VM_OPTIMIZE},{"-op",VM_OPTIMIZE},
|
||||
{"--debug",VM_DEBUG},{"-dbg",VM_DEBUG},
|
||||
{"--chkpath",VM_SHOWPATH|VM_EXEC},{"-cp",VM_SHOWPATH|VM_EXEC}
|
||||
{"--time",VM_TIME|VM_EXEC},{"-t",VM_TIME|VM_EXEC},
|
||||
{"--detail",VM_DETAIL|VM_EXEC},{"-d",VM_DETAIL|VM_EXEC},
|
||||
{"--optimize",VM_OPT},{"-o",VM_OPT},
|
||||
{"--debug",VM_DEBUG},{"-dbg",VM_DEBUG}
|
||||
};
|
||||
u32 cmd=0;
|
||||
string filename;
|
||||
@@ -162,6 +169,6 @@ i32 main(i32 argc,const char* argv[])
|
||||
}
|
||||
if(!filename.length())
|
||||
err();
|
||||
execute(filename,vm_argv,cmd?cmd:cmd|VM_EXEC);
|
||||
execute(filename,vm_argv,cmd?cmd:VM_EXEC);
|
||||
return 0;
|
||||
}
|
||||
92
makefile
@@ -15,57 +15,57 @@ SRC=\
|
||||
nasal_dbg.h\
|
||||
nasal.h
|
||||
|
||||
CPPSTANDARD=-std=c++11
|
||||
STD=14
|
||||
|
||||
nasal:$(SRC)
|
||||
$(CXX) $(CPPSTANDARD) -O3 main.cpp -o nasal -fno-exceptions -ldl -Wshadow -Wall
|
||||
$(CXX) -std=c++$(STD) -O3 main.cpp -o nasal -fno-exceptions -ldl -Wshadow -Wall
|
||||
nasal.exe:$(SRC)
|
||||
$(CXX) $(CPPSTANDARD) -O3 main.cpp -o nasal.exe -fno-exceptions -Wshadow -Wall -static
|
||||
$(CXX) -std=c++$(STD) -O3 main.cpp -o nasal.exe -fno-exceptions -Wshadow -Wall -static
|
||||
|
||||
stable-release:$(SRC)
|
||||
$(CXX) $(CPPSTANDARD) -O2 main.cpp -o nasal -fno-exceptions -ldl -Wshadow -Wall
|
||||
$(CXX) -std=c++$(STD) -O2 main.cpp -o nasal -fno-exceptions -ldl -Wshadow -Wall
|
||||
stable-release-mingw:$(SRC)
|
||||
$(CXX) $(CPPSTANDARD) -O2 main.cpp -o nasal.exe -fno-exceptions -Wshadow -Wall -static
|
||||
$(CXX) -std=c++$(STD) -O2 main.cpp -o nasal.exe -fno-exceptions -Wshadow -Wall -static
|
||||
|
||||
test:nasal
|
||||
@ ./nasal -op -e test/ascii-art.nas
|
||||
@ ./nasal -op -c test/auto_crash.nas
|
||||
@ ./nasal -op -a -c test/bf.nas
|
||||
@ ./nasal -op -a -c test/bfcolored.nas
|
||||
@ ./nasal -op -a -c test/bfconvertor.nas
|
||||
@ ./nasal -op -e -d test/bfs.nas
|
||||
@ ./nasal -op -t test/bigloop.nas
|
||||
@ ./nasal -op -e test/bp.nas
|
||||
@ ./nasal -op -e -d test/calc.nas
|
||||
@ ./nasal -op -e test/choice.nas
|
||||
@ ./nasal -op -e test/class.nas
|
||||
@ ./nasal -op -d test/coroutine.nas
|
||||
@ ./nasal -op -e test/diff.nas
|
||||
-@ ./nasal -op -d test/exception.nas
|
||||
@ ./nasal -op -t -d test/fib.nas
|
||||
@ ./nasal -op -e test/filesystem.nas
|
||||
@ ./nasal -op -e -d test/hexdump.nas
|
||||
@ ./nasal -op -c test/httptest.nas
|
||||
@ ./nasal -op -e test/json.nas
|
||||
@ ./nasal -op -e test/leetcode1319.nas
|
||||
@ ./nasal -op -e -d test/lexer.nas
|
||||
@ ./nasal -op -e -d test/life.nas
|
||||
@ ./nasal -op -t test/loop.nas
|
||||
@ ./nasal -op -t -d test/mandel.nas
|
||||
@ ./nasal -op -t -d test/mandelbrot.nas
|
||||
@ ./nasal -op -t -d test/md5.nas
|
||||
@ ./nasal -op -t -d test/md5compare.nas
|
||||
-@ ./nasal -op -d test/module_test.nas
|
||||
@ ./nasal -op -e test/nasal_test.nas
|
||||
@ ./nasal -op -c test/occupation.nas
|
||||
@ ./nasal -op -t -d test/pi.nas
|
||||
@ ./nasal -op -t -d test/prime.nas
|
||||
@ ./nasal -op -e test/qrcode.nas
|
||||
@ ./nasal -op -t -d test/quick_sort.nas
|
||||
@ ./nasal -op -e test/scalar.nas hello world
|
||||
-@ ./nasal -op -c -t test/snake.nas
|
||||
@ ./nasal -op -c -e test/trait.nas
|
||||
-@ ./nasal -op -c -t test/tetris.nas
|
||||
@ ./nasal -op -c -t -d test/turingmachine.nas
|
||||
@ ./nasal -op -c -t -d test/ycombinator.nas
|
||||
@ ./nasal -op -d test/wavecollapse.nas
|
||||
@ ./nasal -o -e test/ascii-art.nas
|
||||
@ ./nasal -o -c test/auto_crash.nas
|
||||
@ ./nasal -o -a -c test/bf.nas
|
||||
@ ./nasal -o -a -c test/bfconvertor.nas
|
||||
@ ./nasal -o -e -d test/bfs.nas
|
||||
@ ./nasal -o -t test/bigloop.nas
|
||||
@ ./nasal -o -e test/bp.nas
|
||||
@ ./nasal -o -e -d test/calc.nas
|
||||
@ ./nasal -o -e test/choice.nas
|
||||
@ ./nasal -o -e test/class.nas
|
||||
@ ./nasal -o -d test/coroutine.nas
|
||||
@ ./nasal -o -e test/diff.nas
|
||||
-@ ./nasal -o -d test/exception.nas
|
||||
@ ./nasal -o -t -d test/fib.nas
|
||||
@ ./nasal -o -e test/filesystem.nas
|
||||
@ ./nasal -o -e -d test/hexdump.nas
|
||||
@ ./nasal -o -c test/httptest.nas
|
||||
@ ./nasal -o -e test/json.nas
|
||||
@ ./nasal -o -e test/leetcode1319.nas
|
||||
@ ./nasal -o -e -d test/lexer.nas
|
||||
@ ./nasal -o -e -d test/life.nas
|
||||
@ ./nasal -o -t test/loop.nas
|
||||
@ ./nasal -o -t -d test/mandel.nas
|
||||
@ ./nasal -o -t -d test/mandelbrot.nas
|
||||
@ ./nasal -o -t -d test/md5.nas
|
||||
@ ./nasal -o -t -d test/md5compare.nas
|
||||
-@ ./nasal -o -d test/module_test.nas
|
||||
@ ./nasal -o -e test/nasal_test.nas
|
||||
@ ./nasal -o -c test/occupation.nas
|
||||
@ ./nasal -o -t -d test/pi.nas
|
||||
@ ./nasal -o -c test/ppmgen.nas
|
||||
@ ./nasal -o -t -d test/prime.nas
|
||||
@ ./nasal -o -e test/qrcode.nas
|
||||
@ ./nasal -o -t -d test/quick_sort.nas
|
||||
@ ./nasal -o -e test/scalar.nas hello world
|
||||
-@ ./nasal -o -c -t test/snake.nas
|
||||
@ ./nasal -o -c -e test/trait.nas
|
||||
-@ ./nasal -o -c -t test/tetris.nas
|
||||
@ ./nasal -o -c -t -d test/turingmachine.nas
|
||||
@ ./nasal -o -c -t -d test/ycombinator.nas
|
||||
@ ./nasal -o -d test/wavecollapse.nas
|
||||
@@ -6,20 +6,22 @@ double fibonaci(double x){
|
||||
return x;
|
||||
return fibonaci(x-1)+fibonaci(x-2);
|
||||
}
|
||||
extern "C" nas_ref fib(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
|
||||
var fib(var* args,usize size,gc* ngc){
|
||||
std::cout<<"[mod] this is the first test module of nasal\n";
|
||||
if(!args.size())
|
||||
if(!size)
|
||||
return nas_err("fib","lack arguments");
|
||||
nas_ref num=args[0];
|
||||
var num=args[0];
|
||||
if(num.type!=vm_num)
|
||||
return nas_err("extern_fib","\"num\" must be number");
|
||||
return {vm_num,fibonaci(num.tonum())};
|
||||
}
|
||||
extern "C" nas_ref quick_fib(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
|
||||
var quick_fib(var* args,usize size,gc* ngc){
|
||||
std::cout<<"[mod] this is the first test module of nasal\n";
|
||||
if(!args.size())
|
||||
if(!size)
|
||||
return nas_err("fib","lack arguments");
|
||||
nas_ref num=args[0];
|
||||
var num=args[0];
|
||||
if(num.type!=vm_num)
|
||||
return nas_err("extern_quick_fib","\"num\" must be number");
|
||||
if(num.num()<2)
|
||||
@@ -31,4 +33,13 @@ extern "C" nas_ref quick_fib(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
b=res;
|
||||
}
|
||||
return {vm_num,res};
|
||||
}
|
||||
|
||||
extern "C" mod get(const char* n){
|
||||
string name=n;
|
||||
if(name=="fib")
|
||||
return fib;
|
||||
else if(name=="quick_fib")
|
||||
return quick_fib;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "../nasal.h"
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#ifdef _WIN32
|
||||
#include <conio.h>
|
||||
@@ -61,7 +62,7 @@ public:
|
||||
peek_char=-1;
|
||||
return ch;
|
||||
}
|
||||
read(0,&ch,1);
|
||||
ssize_t tmp=read(0,&ch,1);
|
||||
return ch;
|
||||
#else
|
||||
return getch();
|
||||
@@ -70,14 +71,25 @@ public:
|
||||
};
|
||||
|
||||
noecho_input this_window;
|
||||
extern "C" nas_ref nas_getch(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
var nas_getch(var* args,usize size,gc* ngc){
|
||||
return {vm_num,(double)this_window.noecho_getch()};
|
||||
}
|
||||
extern "C" nas_ref nas_kbhit(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
var nas_kbhit(var* args,usize size,gc* ngc){
|
||||
return {vm_num,(double)this_window.noecho_kbhit()};
|
||||
}
|
||||
extern "C" nas_ref nas_noblock(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
var nas_noblock(var* args,usize size,gc* ngc){
|
||||
if(this_window.noecho_kbhit())
|
||||
return {vm_num,(double)this_window.noecho_getch()};
|
||||
return nil;
|
||||
}
|
||||
|
||||
extern "C" mod get(const char* n){
|
||||
string name=n;
|
||||
if(name=="nas_getch")
|
||||
return nas_getch;
|
||||
else if(name=="nas_kbhit")
|
||||
return nas_kbhit;
|
||||
else if(name=="nas_noblock")
|
||||
return nas_noblock;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1,37 +1,43 @@
|
||||
.PHONY=clean all mingw-all
|
||||
|
||||
CPPSTANDARD=-std=c++11
|
||||
STD=14
|
||||
|
||||
libfib.so: fib.cpp
|
||||
$(CXX) $(CPPSTANDARD) -c -O3 fib.cpp -fPIC -o fib.o
|
||||
$(CXX) -shared -o libfib.so fib.o
|
||||
rm fib.o
|
||||
@ echo "[build] libfib.so"
|
||||
@ $(CXX) -std=c++$(STD) -c -O3 fib.cpp -fPIC -o fib.o
|
||||
@ $(CXX) -shared -o libfib.so fib.o
|
||||
@ rm fib.o
|
||||
libfib.dll: fib.cpp
|
||||
$(CXX) $(CPPSTANDARD) -c -O3 fib.cpp -fPIC -o fib.o
|
||||
$(CXX) -shared -o libfib.dll fib.o
|
||||
del fib.o
|
||||
@ echo [build] libfib.dll
|
||||
@ $(CXX) -std=c++$(STD) -c -O3 fib.cpp -fPIC -o fib.o
|
||||
@ $(CXX) -shared -o libfib.dll fib.o
|
||||
@ del fib.o
|
||||
|
||||
libkey.so: keyboard.cpp
|
||||
$(CXX) $(CPPSTANDARD) -c -O3 keyboard.cpp -fPIC -o keyboard.o
|
||||
$(CXX) -shared -o libkey.so keyboard.o
|
||||
rm keyboard.o
|
||||
@ echo "[build] libkey.so"
|
||||
@ $(CXX) -std=c++$(STD) -c -O3 keyboard.cpp -fPIC -o keyboard.o
|
||||
@ $(CXX) -shared -o libkey.so keyboard.o
|
||||
@ rm keyboard.o
|
||||
libkey.dll: keyboard.cpp
|
||||
$(CXX) $(CPPSTANDARD) -c -O3 keyboard.cpp -fPIC -o keyboard.o -static
|
||||
$(CXX) -shared -o libkey.dll keyboard.o -static
|
||||
del keyboard.o
|
||||
@ echo [build] libkey.dll
|
||||
@ $(CXX) -std=c++$(STD) -c -O3 keyboard.cpp -fPIC -o keyboard.o -static
|
||||
@ $(CXX) -shared -o libkey.dll keyboard.o -static
|
||||
@ del keyboard.o
|
||||
|
||||
libnasock.so: nasocket.cpp
|
||||
$(CXX) $(CPPSTANDARD) -c -O3 nasocket.cpp -fPIC -o nasocket.o
|
||||
$(CXX) -shared -o libnasock.so nasocket.o
|
||||
rm nasocket.o
|
||||
@ echo "[build] libnasock.so"
|
||||
@ $(CXX) -std=c++$(STD) -c -O3 nasocket.cpp -fPIC -o nasocket.o
|
||||
@ $(CXX) -shared -o libnasock.so nasocket.o
|
||||
@ rm nasocket.o
|
||||
libnasock.dll: nasocket.cpp
|
||||
$(CXX) $(CPPSTANDARD) -c -O3 nasocket.cpp -fPIC -o nasocket.o -lwsock32 -static
|
||||
$(CXX) -shared -o libnasock.dll nasocket.o -lwsock32 -static
|
||||
del nasocket.o
|
||||
@ echo [build] libnasock.dll
|
||||
@ $(CXX) -std=c++$(STD) -c -O3 nasocket.cpp -fPIC -o nasocket.o -lwsock32 -static
|
||||
@ $(CXX) -shared -o libnasock.dll nasocket.o -lwsock32 -static
|
||||
@ del nasocket.o
|
||||
|
||||
clean:
|
||||
rm *.so *.dll *.dylib
|
||||
-@ rm *.so *.dll *.dylib
|
||||
all: libfib.so libkey.so libnasock.so
|
||||
@ echo "build done"
|
||||
@ echo "[build] done"
|
||||
mingw-all: libfib.dll libkey.dll libnasock.dll
|
||||
@ echo build done
|
||||
@ echo [build] done
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "../nasal.h"
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
@@ -24,14 +25,14 @@ static WSAmanager win;
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
extern "C" nas_ref nas_socket(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
var nas_socket(var* args,usize size,gc* ngc){
|
||||
if(args[0].type!=vm_num || args[1].type!=vm_num || args[2].type!=vm_num)
|
||||
return nas_err("socket","\"af\", \"type\", \"protocol\" should be number");
|
||||
int sd=socket(args[0].num(),args[1].num(),args[2].num());
|
||||
return {vm_num,(double)sd};
|
||||
}
|
||||
|
||||
extern "C" nas_ref nas_closesocket(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
var nas_closesocket(var* args,usize size,gc* ngc){
|
||||
if(args[0].type!=vm_num)
|
||||
return nas_err("closesocket","\"\" should be number");
|
||||
#ifdef _WIN32
|
||||
@@ -41,7 +42,7 @@ extern "C" nas_ref nas_closesocket(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" nas_ref nas_shutdown(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
var nas_shutdown(var* args,usize size,gc* ngc){
|
||||
if(args[0].type!=vm_num)
|
||||
return nas_err("shutdown","\"sd\" must be a number");
|
||||
if(args[1].type!=vm_num)
|
||||
@@ -49,7 +50,7 @@ extern "C" nas_ref nas_shutdown(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
return {vm_num,(double)shutdown(args[0].num(),args[1].num())};
|
||||
}
|
||||
|
||||
extern "C" nas_ref nas_bind(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
var nas_bind(var* args,usize size,gc* ngc){
|
||||
if(args[0].type!=vm_num)
|
||||
return nas_err("bind","\"sd\" muse be a number");
|
||||
if(args[1].type!=vm_str)
|
||||
@@ -64,7 +65,7 @@ extern "C" nas_ref nas_bind(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
return {vm_num,(double)bind(args[0].num(),(sockaddr*)&server,sizeof(server))};
|
||||
}
|
||||
|
||||
extern "C" nas_ref nas_listen(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
var nas_listen(var* args,usize size,gc* ngc){
|
||||
if(args[0].type!=vm_num)
|
||||
return nas_err("listen","\"sd\" must be a number");
|
||||
if(args[1].type!=vm_num)
|
||||
@@ -72,7 +73,7 @@ extern "C" nas_ref nas_listen(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
return{vm_num,(double)listen(args[0].num(),args[1].num())};
|
||||
}
|
||||
|
||||
extern "C" nas_ref nas_connect(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
var nas_connect(var* args,usize size,gc* ngc){
|
||||
if(args[0].type!=vm_num)
|
||||
return nas_err("connect","\"sd\" must be a number");
|
||||
if(args[1].type!=vm_str)
|
||||
@@ -88,7 +89,7 @@ extern "C" nas_ref nas_connect(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
return {vm_num,(double)connect(args[0].num(),(sockaddr*)&addr,sizeof(sockaddr_in))};
|
||||
}
|
||||
|
||||
extern "C" nas_ref nas_accept(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
var nas_accept(var* args,usize size,gc* ngc){
|
||||
if(args[0].type!=vm_num)
|
||||
return nas_err("accept","\"sd\" must be a number");
|
||||
sockaddr_in client;
|
||||
@@ -98,15 +99,15 @@ extern "C" nas_ref nas_accept(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
#else
|
||||
int client_sd=accept(args[0].num(),(sockaddr*)&client,(socklen_t*)&socklen);
|
||||
#endif
|
||||
nas_ref res=gc.temp=gc.alloc(vm_hash);
|
||||
var res=ngc->temp=ngc->alloc(vm_hash);
|
||||
auto& hash=res.hash().elems;
|
||||
hash["sd"]={vm_num,(double)client_sd};
|
||||
hash["ip"]=gc.newstr(inet_ntoa(client.sin_addr));
|
||||
gc.temp=nil;
|
||||
hash["ip"]=ngc->newstr(inet_ntoa(client.sin_addr));
|
||||
ngc->temp=nil;
|
||||
return res;
|
||||
}
|
||||
|
||||
extern "C" nas_ref nas_send(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
var nas_send(var* args,usize size,gc* ngc){
|
||||
if(args[0].type!=vm_num)
|
||||
return nas_err("send","\"sd\" must be a number");
|
||||
if(args[1].type!=vm_str)
|
||||
@@ -116,7 +117,7 @@ extern "C" nas_ref nas_send(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
return {vm_num,(double)send(args[0].num(),args[1].str().c_str(),args[1].str().length(),args[2].num())};
|
||||
}
|
||||
|
||||
extern "C" nas_ref nas_sendto(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
var nas_sendto(var* args,usize size,gc* ngc){
|
||||
if(args[0].type!=vm_num)
|
||||
return nas_err("sendto","\"sd\" must be a number");
|
||||
if(args[1].type!=vm_str)
|
||||
@@ -136,7 +137,7 @@ extern "C" nas_ref nas_sendto(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
return {vm_num,(double)sendto(args[0].num(),args[3].str().c_str(),args[3].str().length(),args[4].num(),(sockaddr*)&addr,sizeof(sockaddr_in))};
|
||||
}
|
||||
|
||||
extern "C" nas_ref nas_recv(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
var nas_recv(var* args,usize size,gc* ngc){
|
||||
if(args[0].type!=vm_num)
|
||||
return nas_err("recv","\"sd\" must be a number");
|
||||
if(args[1].type!=vm_num)
|
||||
@@ -145,17 +146,17 @@ extern "C" nas_ref nas_recv(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
return nas_err("recv","\"len\" out of range");
|
||||
if(args[2].type!=vm_num)
|
||||
return nas_err("recv","\"flags\" muse be a number");
|
||||
nas_ref res=gc.temp=gc.alloc(vm_hash);
|
||||
var res=ngc->temp=ngc->alloc(vm_hash);
|
||||
auto& hash=res.hash().elems;
|
||||
char* buf=new char[(int)args[1].num()];
|
||||
hash["size"]={vm_num,(double)recv(args[0].num(),buf,args[1].num(),args[2].num())};
|
||||
hash["str"]=gc.newstr(buf);
|
||||
hash["str"]=ngc->newstr(buf);
|
||||
delete[] buf;
|
||||
gc.temp=nil;
|
||||
ngc->temp=nil;
|
||||
return res;
|
||||
}
|
||||
|
||||
extern "C" nas_ref nas_recvfrom(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
var nas_recvfrom(var* args,usize size,gc* ngc){
|
||||
if(args[0].type!=vm_num)
|
||||
return nas_err("recvfrom","\"sd\" must be a number");
|
||||
if(args[1].type!=vm_num)
|
||||
@@ -166,7 +167,7 @@ extern "C" nas_ref nas_recvfrom(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
return nas_err("recvfrom","\"flags\" muse be a number");
|
||||
sockaddr_in addr;
|
||||
int socklen=sizeof(sockaddr_in);
|
||||
nas_ref res=gc.temp=gc.alloc(vm_hash);
|
||||
var res=ngc->temp=ngc->alloc(vm_hash);
|
||||
auto& hash=res.hash().elems;
|
||||
char* buf=new char[(int)args[1].num()+1];
|
||||
#ifdef _WIN32
|
||||
@@ -175,13 +176,42 @@ extern "C" nas_ref nas_recvfrom(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
hash["size"]={vm_num,(double)recvfrom(args[0].num(),buf,args[1].num(),args[2].num(),(sockaddr*)&addr,(socklen_t*)&socklen)};
|
||||
#endif
|
||||
buf[(int)hash["size"].num()]=0;
|
||||
hash["str"]=gc.newstr(buf);
|
||||
hash["str"]=ngc->newstr(buf);
|
||||
delete[] buf;
|
||||
hash["fromip"]=gc.newstr(inet_ntoa(addr.sin_addr));
|
||||
gc.temp=nil;
|
||||
hash["fromip"]=ngc->newstr(inet_ntoa(addr.sin_addr));
|
||||
ngc->temp=nil;
|
||||
return res;
|
||||
}
|
||||
|
||||
extern "C" nas_ref nas_errno(std::vector<nas_ref>& args,nasal_gc& gc){
|
||||
return gc.newstr(strerror(errno));
|
||||
var nas_errno(var* args,usize size,gc* ngc){
|
||||
return ngc->newstr(strerror(errno));
|
||||
}
|
||||
|
||||
extern "C" mod get(const char* n){
|
||||
string name=n;
|
||||
if(name=="nas_socket")
|
||||
return nas_socket;
|
||||
else if(name=="nas_closesocket")
|
||||
return nas_closesocket;
|
||||
else if(name=="nas_shutdown")
|
||||
return nas_shutdown;
|
||||
else if(name=="nas_bind")
|
||||
return nas_bind;
|
||||
else if(name=="nas_listen")
|
||||
return nas_listen;
|
||||
else if(name=="nas_connect")
|
||||
return nas_connect;
|
||||
else if(name=="nas_accept")
|
||||
return nas_accept;
|
||||
else if(name=="nas_send")
|
||||
return nas_send;
|
||||
else if(name=="nas_sendto")
|
||||
return nas_sendto;
|
||||
else if(name=="nas_recv")
|
||||
return nas_recv;
|
||||
else if(name=="nas_recvfrom")
|
||||
return nas_recvfrom;
|
||||
else if(name=="nas_errno")
|
||||
return nas_errno;
|
||||
return nullptr;
|
||||
}
|
||||
122
nasal.h
@@ -1,44 +1,15 @@
|
||||
#ifndef __NASAL_H__
|
||||
#define __NASAL_H__
|
||||
#define __nasver "10.0"
|
||||
#pragma once
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#else
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#ifndef __nasver
|
||||
#define __nasver "10.1"
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <cmath>
|
||||
#include <list>
|
||||
#include <stack>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
using i32=std::int32_t;
|
||||
using i64=std::int64_t;
|
||||
@@ -52,37 +23,35 @@ using std::string;
|
||||
|
||||
const u32 STACK_DEPTH=1024;
|
||||
|
||||
inline f64 hex_to_double(const char* str)
|
||||
inline f64 hex2f(const char* str)
|
||||
{
|
||||
f64 ret=0;
|
||||
for(;*str;++str)
|
||||
{
|
||||
ret*=16;
|
||||
if('0'<=*str && *str<='9')
|
||||
ret+=(*str-'0');
|
||||
ret=ret*16+(*str-'0');
|
||||
else if('a'<=*str && *str<='f')
|
||||
ret+=(*str-'a'+10);
|
||||
ret=ret*16+(*str-'a'+10);
|
||||
else if('A'<=*str && *str<='F')
|
||||
ret+=(*str-'A'+10);
|
||||
ret=ret*16+(*str-'A'+10);
|
||||
else
|
||||
return nan("");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
inline f64 oct_to_double(const char* str)
|
||||
inline f64 oct2f(const char* str)
|
||||
{
|
||||
f64 ret=0;
|
||||
for(;*str;++str)
|
||||
{
|
||||
ret*=8;
|
||||
if('0'<=*str && *str<'8')
|
||||
ret+=(*str-'0');
|
||||
else
|
||||
return nan("");
|
||||
}
|
||||
while('0'<=*str && *str<'8')
|
||||
ret=ret*8+(*str++-'0');
|
||||
if(*str) return nan("");
|
||||
return ret;
|
||||
}
|
||||
inline f64 dec_to_double(const char* str)
|
||||
// we have the same reason not using atof here just as andy's interpreter does.
|
||||
// it is not platform independent, and may have strange output.
|
||||
// so we write a new function here to convert str to number manually.
|
||||
// but this also makes 0.1+0.2==0.3, not another result that you may get in other languages.
|
||||
inline f64 dec2f(const char* str)
|
||||
{
|
||||
f64 ret=0,negative=1,num_pow=0;
|
||||
while('0'<=*str && *str<='9')
|
||||
@@ -106,13 +75,9 @@ inline f64 dec_to_double(const char* str)
|
||||
negative=(*str++=='-'? -1:1);
|
||||
if(!*str) return nan("");
|
||||
num_pow=0;
|
||||
for(;*str;++str)
|
||||
{
|
||||
if('0'<=*str && *str<='9')
|
||||
num_pow=num_pow*10+(*str-'0');
|
||||
else
|
||||
return nan("");
|
||||
}
|
||||
while('0'<=*str && *str<='9')
|
||||
num_pow=num_pow*10+(*str++-'0');
|
||||
if(*str) return nan("");
|
||||
return ret*std::pow(10,negative*num_pow);
|
||||
}
|
||||
f64 str2num(const char* str)
|
||||
@@ -124,11 +89,11 @@ f64 str2num(const char* str)
|
||||
if(!*str)
|
||||
return nan("");
|
||||
if(str[0]=='0' && str[1]=='x')
|
||||
res=hex_to_double(str+2);
|
||||
res=hex2f(str+2);
|
||||
else if(str[0]=='0' && str[1]=='o')
|
||||
res=oct_to_double(str+2);
|
||||
res=oct2f(str+2);
|
||||
else
|
||||
res=dec_to_double(str);
|
||||
res=dec2f(str);
|
||||
return negative?-res:res;
|
||||
}
|
||||
|
||||
@@ -167,39 +132,24 @@ string rawstr(const string& str,const usize maxlen=0)
|
||||
#endif
|
||||
switch(i)
|
||||
{
|
||||
case '\0': ret+="\\0"; break;
|
||||
case '\a': ret+="\\a"; break;
|
||||
case '\b': ret+="\\b"; break;
|
||||
case '\t': ret+="\\t"; break;
|
||||
case '\n': ret+="\\n"; break;
|
||||
case '\v': ret+="\\v"; break;
|
||||
case '\f': ret+="\\f"; break;
|
||||
case '\r': ret+="\\r"; break;
|
||||
#ifdef _MSC_VER
|
||||
case '\033':ret+="\\e";break;
|
||||
#else
|
||||
case '\e': ret+="\\e"; break;
|
||||
#endif
|
||||
case '\"': ret+="\\\"";break;
|
||||
case '\'': ret+="\\\'";break;
|
||||
case '\\': ret+="\\\\";break;
|
||||
default: ret+=i; break;
|
||||
case '\0': ret+="\\0"; break;
|
||||
case '\a': ret+="\\a"; break;
|
||||
case '\b': ret+="\\b"; break;
|
||||
case '\t': ret+="\\t"; break;
|
||||
case '\n': ret+="\\n"; break;
|
||||
case '\v': ret+="\\v"; break;
|
||||
case '\f': ret+="\\f"; break;
|
||||
case '\r': ret+="\\r"; break;
|
||||
case '\033':ret+="\\e"; break;
|
||||
case '\"': ret+="\\\"";break;
|
||||
case '\'': ret+="\\\'";break;
|
||||
case '\\': ret+="\\\\";break;
|
||||
default: ret+=i; break;
|
||||
}
|
||||
}
|
||||
if(maxlen && ret.length()>maxlen)
|
||||
ret=ret.substr(0,maxlen)+"...";
|
||||
return ret;
|
||||
}
|
||||
#include "nasal_err.h"
|
||||
#include "nasal_lexer.h"
|
||||
#include "nasal_ast.h"
|
||||
#include "nasal_parse.h"
|
||||
#include "nasal_import.h"
|
||||
#include "nasal_opt.h"
|
||||
#include "nasal_gc.h"
|
||||
#include "nasal_builtin.h"
|
||||
#include "nasal_codegen.h"
|
||||
#include "nasal_vm.h"
|
||||
#include "nasal_dbg.h"
|
||||
|
||||
#endif
|
||||
#include "nasal_gc.h" // declarations of var and nasal_gc
|
||||
|
||||
183
nasal_ast.h
@@ -1,5 +1,7 @@
|
||||
#ifndef __NASAL_AST_H__
|
||||
#define __NASAL_AST_H__
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
enum ast_node:u32
|
||||
{
|
||||
@@ -50,12 +52,12 @@ enum ast_node:u32
|
||||
ast_foreach, // foreach keyword
|
||||
ast_while, // while
|
||||
ast_iter, // iterator, used in forindex/foreach
|
||||
ast_conditional, // mark a sub-tree of conditional expression
|
||||
ast_cond, // mark a sub-tree of conditional expression
|
||||
ast_if, // if keyword
|
||||
ast_elsif, // elsif keyword
|
||||
ast_else, // else keyword
|
||||
ast_multi_id, // multi identifiers sub-tree
|
||||
ast_multi_scalar,// multi value sub-tree
|
||||
ast_tuple, // tuple, only used in multiple assignment
|
||||
ast_def, // definition
|
||||
ast_multi_assign,// multi assignment sub-tree
|
||||
ast_continue, // continue keyword, only used in loop
|
||||
@@ -104,20 +106,20 @@ const char* ast_name[]=
|
||||
"*",
|
||||
"/",
|
||||
"~",
|
||||
"unary-",
|
||||
"unary!",
|
||||
"neg",
|
||||
"!",
|
||||
"trino",
|
||||
"for",
|
||||
"forindex",
|
||||
"foreach",
|
||||
"while",
|
||||
"iter",
|
||||
"conditional",
|
||||
"cond",
|
||||
"if",
|
||||
"elsif",
|
||||
"else",
|
||||
"multi-id",
|
||||
"multi-scalar",
|
||||
"tuple",
|
||||
"def",
|
||||
"multi-assign",
|
||||
"continue",
|
||||
@@ -125,119 +127,130 @@ const char* ast_name[]=
|
||||
"return"
|
||||
};
|
||||
|
||||
class nasal_ast
|
||||
class ast
|
||||
{
|
||||
private:
|
||||
u32 _line;
|
||||
u32 _type;
|
||||
f64 _num;
|
||||
string _str;
|
||||
std::vector<nasal_ast> _child;
|
||||
u32 nd_line;
|
||||
u32 nd_col;
|
||||
u32 nd_type;
|
||||
f64 nd_num;
|
||||
string nd_str;
|
||||
std::vector<ast> nd_child;
|
||||
public:
|
||||
nasal_ast(const u32 l=0,const u32 t=ast_null):_line(l),_type(t),_num(0){}
|
||||
nasal_ast(const nasal_ast&);
|
||||
nasal_ast(nasal_ast&&);
|
||||
void print(u32,bool);
|
||||
ast(const u32 l,const u32 c,const u32 t):
|
||||
nd_line(l),nd_col(c),nd_type(t),nd_num(0){}
|
||||
ast(const ast&);
|
||||
ast(ast&&);
|
||||
void print_tree();
|
||||
void print(u32,bool,std::vector<string>&);
|
||||
void clear();
|
||||
|
||||
nasal_ast& operator=(const nasal_ast&);
|
||||
nasal_ast& operator=(nasal_ast&&);
|
||||
nasal_ast& operator[](usize n){return _child[n];}
|
||||
const nasal_ast& operator[](usize n) const {return _child[n];}
|
||||
usize size() const {return _child.size();}
|
||||
ast& operator=(const ast&);
|
||||
ast& operator=(ast&&);
|
||||
ast& operator[](usize n){return nd_child[n];}
|
||||
const ast& operator[](usize n) const {return nd_child[n];}
|
||||
usize size() const {return nd_child.size();}
|
||||
|
||||
void add(nasal_ast&& ast){_child.push_back(std::move(ast));}
|
||||
void add(const nasal_ast& ast){_child.push_back(ast);}
|
||||
void set_line(const u32 l){_line=l;}
|
||||
void set_type(const u32 t){_type=t;}
|
||||
void set_str(const string& s){_str=s;}
|
||||
void set_num(const f64 n){_num=n;}
|
||||
void add(ast&& node){nd_child.push_back(std::move(node));}
|
||||
void add(const ast& node){nd_child.push_back(node);}
|
||||
void set_line(const u32 l){nd_line=l;}
|
||||
void set_type(const u32 t){nd_type=t;}
|
||||
void set_str(const string& s){nd_str=s;}
|
||||
void set_num(const f64 n){nd_num=n;}
|
||||
|
||||
inline u32 line() const {return _line;}
|
||||
inline u32 type() const {return _type;}
|
||||
inline f64 num() const {return _num;}
|
||||
inline const string& str() const {return _str;}
|
||||
inline const std::vector<nasal_ast>& child() const {return _child;}
|
||||
inline std::vector<nasal_ast>& child(){return _child;}
|
||||
inline u32 line() const {return nd_line;}
|
||||
inline u32 col() const {return nd_col;}
|
||||
inline u32 type() const {return nd_type;}
|
||||
inline f64 num() const {return nd_num;}
|
||||
inline const string& str() const {return nd_str;}
|
||||
inline const std::vector<ast>& child() const {return nd_child;}
|
||||
inline std::vector<ast>& child(){return nd_child;}
|
||||
};
|
||||
|
||||
nasal_ast::nasal_ast(const nasal_ast& tmp):
|
||||
_str(tmp._str),_child(tmp._child)
|
||||
ast::ast(const ast& tmp):
|
||||
nd_str(tmp.nd_str),nd_child(tmp.nd_child)
|
||||
{
|
||||
_line=tmp._line;
|
||||
_type=tmp._type;
|
||||
_num =tmp._num;
|
||||
nd_line=tmp.nd_line;
|
||||
nd_col=tmp.nd_col;
|
||||
nd_type=tmp.nd_type;
|
||||
nd_num =tmp.nd_num;
|
||||
}
|
||||
|
||||
nasal_ast::nasal_ast(nasal_ast&& tmp)
|
||||
ast::ast(ast&& tmp)
|
||||
{
|
||||
_line=tmp._line;
|
||||
_type=tmp._type;
|
||||
_num =tmp._num;
|
||||
_str.swap(tmp._str);
|
||||
_child.swap(tmp._child);
|
||||
nd_line=tmp.nd_line;
|
||||
nd_col=tmp.nd_col;
|
||||
nd_type=tmp.nd_type;
|
||||
nd_num =tmp.nd_num;
|
||||
nd_str.swap(tmp.nd_str);
|
||||
nd_child.swap(tmp.nd_child);
|
||||
}
|
||||
|
||||
nasal_ast& nasal_ast::operator=(const nasal_ast& tmp)
|
||||
ast& ast::operator=(const ast& tmp)
|
||||
{
|
||||
_line=tmp._line;
|
||||
_type=tmp._type;
|
||||
_num=tmp._num;
|
||||
_str=tmp._str;
|
||||
_child=tmp._child;
|
||||
nd_line=tmp.nd_line;
|
||||
nd_col=tmp.nd_col;
|
||||
nd_type=tmp.nd_type;
|
||||
nd_num=tmp.nd_num;
|
||||
nd_str=tmp.nd_str;
|
||||
nd_child=tmp.nd_child;
|
||||
return *this;
|
||||
}
|
||||
|
||||
nasal_ast& nasal_ast::operator=(nasal_ast&& tmp)
|
||||
ast& ast::operator=(ast&& tmp)
|
||||
{
|
||||
_line=tmp._line;
|
||||
_type=tmp._type;
|
||||
_num=tmp._num;
|
||||
_str.swap(tmp._str);
|
||||
_child.swap(tmp._child);
|
||||
nd_line=tmp.nd_line;
|
||||
nd_col=tmp.nd_col;
|
||||
nd_type=tmp.nd_type;
|
||||
nd_num=tmp.nd_num;
|
||||
nd_str.swap(tmp.nd_str);
|
||||
nd_child.swap(tmp.nd_child);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void nasal_ast::clear()
|
||||
void ast::clear()
|
||||
{
|
||||
_line=0;
|
||||
_num=0;
|
||||
_str="";
|
||||
_type=ast_null;
|
||||
_child.clear();
|
||||
nd_line=nd_col=0;
|
||||
nd_num=0;
|
||||
nd_str.clear();
|
||||
nd_type=ast_null;
|
||||
nd_child.clear();
|
||||
}
|
||||
|
||||
void nasal_ast::print(u32 depth,bool last=false)
|
||||
void ast::print_tree()
|
||||
{
|
||||
static std::vector<string> intentation={};
|
||||
for(auto& i:intentation)
|
||||
std::vector<string> tmp;
|
||||
print(0,false,tmp);
|
||||
}
|
||||
|
||||
void ast::print(u32 depth,bool last,std::vector<string>& indent)
|
||||
{
|
||||
for(auto& i:indent)
|
||||
std::cout<<i;
|
||||
std::cout<<ast_name[_type];
|
||||
if(_type==ast_str || _type==ast_id ||
|
||||
_type==ast_default || _type==ast_dynamic ||
|
||||
_type==ast_callh)
|
||||
std::cout<<":"<<rawstr(_str);
|
||||
else if(_type==ast_num || _type==ast_file)
|
||||
std::cout<<":"<<_num;
|
||||
std::cout<<'\n';
|
||||
std::cout<<ast_name[nd_type];
|
||||
if(nd_type==ast_str || nd_type==ast_id ||
|
||||
nd_type==ast_default || nd_type==ast_dynamic ||
|
||||
nd_type==ast_callh)
|
||||
std::cout<<":"<<rawstr(nd_str);
|
||||
else if(nd_type==ast_num || nd_type==ast_file)
|
||||
std::cout<<":"<<nd_num;
|
||||
std::cout<<"\n";
|
||||
if(last && depth)
|
||||
intentation.back()=" ";
|
||||
indent.back()=" ";
|
||||
else if(!last && depth)
|
||||
#ifdef _WIN32
|
||||
intentation.back()="| ";
|
||||
indent.back()="| ";
|
||||
#else
|
||||
intentation.back()="│ ";
|
||||
indent.back()="│ ";
|
||||
#endif
|
||||
for(u32 i=0;i<_child.size();++i)
|
||||
for(u32 i=0;i<nd_child.size();++i)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
intentation.push_back(i==_child.size()-1?"`-":"|-");
|
||||
indent.push_back(i==nd_child.size()-1?"+-":"|-");
|
||||
#else
|
||||
intentation.push_back(i==_child.size()-1?"└─":"├─");
|
||||
indent.push_back(i==nd_child.size()-1?"└─":"├─");
|
||||
#endif
|
||||
_child[i].print(depth+1,i==_child.size()-1);
|
||||
intentation.pop_back();
|
||||
nd_child[i].print(depth+1,i==nd_child.size()-1,indent);
|
||||
indent.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
665
nasal_builtin.h
789
nasal_codegen.h
163
nasal_dbg.h
@@ -1,38 +1,38 @@
|
||||
#ifndef __NASAL_DBG_H__
|
||||
#define __NASAL_DBG_H__
|
||||
#pragma once
|
||||
|
||||
#include "nasal_err.h"
|
||||
#include "nasal_vm.h"
|
||||
#include <algorithm>
|
||||
|
||||
class nasal_dbg:public nasal_vm
|
||||
class debugger:public vm
|
||||
{
|
||||
private:
|
||||
bool next;
|
||||
usize fsize;
|
||||
u16 bk_fidx;
|
||||
u32 bk_line;
|
||||
nasal_err& src;
|
||||
error& src;
|
||||
|
||||
std::vector<string> parse(const string&);
|
||||
u16 fileindex(const string&);
|
||||
void err();
|
||||
void help();
|
||||
void opcallsort(const u64*);
|
||||
void callsort(const u64*);
|
||||
void stepinfo();
|
||||
void interact();
|
||||
public:
|
||||
nasal_dbg(nasal_err& nerr):
|
||||
debugger(error& err):
|
||||
next(false),fsize(0),
|
||||
bk_fidx(0),bk_line(0),
|
||||
src(nerr){}
|
||||
src(err){}
|
||||
void run(
|
||||
const nasal_codegen&,
|
||||
const nasal_import&,
|
||||
const std::vector<string>&,
|
||||
bool
|
||||
const codegen&,
|
||||
const linker&,
|
||||
const std::vector<string>&
|
||||
);
|
||||
};
|
||||
|
||||
std::vector<string> nasal_dbg::parse(const string& cmd)
|
||||
std::vector<string> debugger::parse(const string& cmd)
|
||||
{
|
||||
std::vector<string> res;
|
||||
usize last=0,pos=cmd.find(" ",0);
|
||||
@@ -48,7 +48,7 @@ std::vector<string> nasal_dbg::parse(const string& cmd)
|
||||
return res;
|
||||
}
|
||||
|
||||
u16 nasal_dbg::fileindex(const string& filename)
|
||||
u16 debugger::fileindex(const string& filename)
|
||||
{
|
||||
for(u16 i=0;i<fsize;++i)
|
||||
if(filename==files[i])
|
||||
@@ -56,14 +56,14 @@ u16 nasal_dbg::fileindex(const string& filename)
|
||||
return 65535;
|
||||
}
|
||||
|
||||
void nasal_dbg::err()
|
||||
void debugger::err()
|
||||
{
|
||||
std::cerr
|
||||
<<"incorrect command\n"
|
||||
<<"input \'h\' to get help\n";
|
||||
}
|
||||
|
||||
void nasal_dbg::help()
|
||||
void debugger::help()
|
||||
{
|
||||
std::cout
|
||||
<<"<option>\n"
|
||||
@@ -82,7 +82,7 @@ void nasal_dbg::help()
|
||||
<<"\tbk, break | set break point\n";
|
||||
}
|
||||
|
||||
void nasal_dbg::opcallsort(const u64* arr)
|
||||
void debugger::callsort(const u64* arr)
|
||||
{
|
||||
typedef std::pair<u32,u64> op;
|
||||
std::vector<op> opcall;
|
||||
@@ -110,31 +110,34 @@ void nasal_dbg::opcallsort(const u64* arr)
|
||||
std::clog<<"\n total : "<<total<<'\n';
|
||||
}
|
||||
|
||||
void nasal_dbg::stepinfo()
|
||||
void debugger::stepinfo()
|
||||
{
|
||||
u32 begin,end;
|
||||
u32 line=bytecode[pc].line==0?0:bytecode[pc].line-1;
|
||||
u32 begin=(line>>3)==0?0:((line>>3)<<3);
|
||||
u32 end=(1+(line>>3))<<3;
|
||||
src.load(files[bytecode[pc].fidx]);
|
||||
std::cout<<"\nsource code:\n";
|
||||
begin=(line>>3)==0?0:((line>>3)<<3);
|
||||
end=(1+(line>>3))<<3;
|
||||
for(u32 i=begin;i<end && i<src.size();++i)
|
||||
std::cout<<(i==line?"--> ":" ")<<src[i]<<"\n";
|
||||
std::cout<<(i==line?back_white:reset)<<(i==line?"--> ":" ")<<src[i]<<reset<<"\n";
|
||||
std::cout<<"next bytecode:\n";
|
||||
begin=(pc>>3)==0?0:((pc>>3)<<3);
|
||||
end=(1+(pc>>3))<<3;
|
||||
for(u32 i=begin;i<end && bytecode[i].op!=op_exit;++i)
|
||||
bytecodeinfo(i==pc?"--> ":" ",i);
|
||||
std::cout
|
||||
<<(i==pc?back_white:reset)<<(i==pc?"--> ":" ")
|
||||
<<codestream(bytecode[i],i,cnum,cstr,files)
|
||||
<<reset<<"\n";
|
||||
stackinfo(10);
|
||||
}
|
||||
|
||||
void nasal_dbg::interact()
|
||||
void debugger::interact()
|
||||
{
|
||||
// special operand
|
||||
if(bytecode[pc].op==op_intg)
|
||||
{
|
||||
std::cout
|
||||
<<"[debug] nasal debug mode\n"
|
||||
<<bold_cyan<<"[debug] "<<reset
|
||||
<<"nasal debug mode\n"
|
||||
<<"input \'h\' to get help\n";
|
||||
}
|
||||
else if(bytecode[pc].op==op_exit)
|
||||
@@ -203,11 +206,10 @@ void nasal_dbg::interact()
|
||||
}
|
||||
}
|
||||
|
||||
void nasal_dbg::run(
|
||||
const nasal_codegen& gen,
|
||||
const nasal_import& linker,
|
||||
const std::vector<string>& argv,
|
||||
bool opcnt)
|
||||
void debugger::run(
|
||||
const codegen& gen,
|
||||
const linker& linker,
|
||||
const std::vector<string>& argv)
|
||||
{
|
||||
detail_info=true;
|
||||
fsize=linker.filelist().size();
|
||||
@@ -245,47 +247,47 @@ void nasal_dbg::run(
|
||||
// goto the first operand
|
||||
goto *code[pc];
|
||||
#else
|
||||
typedef void (nasal_dbg::*nafunc)();
|
||||
typedef void (debugger::*nafunc)();
|
||||
const nafunc oprs[]=
|
||||
{
|
||||
nullptr, &nasal_dbg::o_intg,
|
||||
&nasal_dbg::o_intl, &nasal_dbg::o_loadg,
|
||||
&nasal_dbg::o_loadl, &nasal_dbg::o_loadu,
|
||||
&nasal_dbg::o_pnum, &nasal_dbg::o_pnil,
|
||||
&nasal_dbg::o_pstr, &nasal_dbg::o_newv,
|
||||
&nasal_dbg::o_newh, &nasal_dbg::o_newf,
|
||||
&nasal_dbg::o_happ, &nasal_dbg::o_para,
|
||||
&nasal_dbg::o_deft, &nasal_dbg::o_dyn,
|
||||
&nasal_dbg::o_unot, &nasal_dbg::o_usub,
|
||||
&nasal_dbg::o_add, &nasal_dbg::o_sub,
|
||||
&nasal_dbg::o_mul, &nasal_dbg::o_div,
|
||||
&nasal_dbg::o_lnk, &nasal_dbg::o_addc,
|
||||
&nasal_dbg::o_subc, &nasal_dbg::o_mulc,
|
||||
&nasal_dbg::o_divc, &nasal_dbg::o_lnkc,
|
||||
&nasal_dbg::o_addeq, &nasal_dbg::o_subeq,
|
||||
&nasal_dbg::o_muleq, &nasal_dbg::o_diveq,
|
||||
&nasal_dbg::o_lnkeq, &nasal_dbg::o_addeqc,
|
||||
&nasal_dbg::o_subeqc, &nasal_dbg::o_muleqc,
|
||||
&nasal_dbg::o_diveqc, &nasal_dbg::o_lnkeqc,
|
||||
&nasal_dbg::o_meq, &nasal_dbg::o_eq,
|
||||
&nasal_dbg::o_neq, &nasal_dbg::o_less,
|
||||
&nasal_dbg::o_leq, &nasal_dbg::o_grt,
|
||||
&nasal_dbg::o_geq, &nasal_dbg::o_lessc,
|
||||
&nasal_dbg::o_leqc, &nasal_dbg::o_grtc,
|
||||
&nasal_dbg::o_geqc, &nasal_dbg::o_pop,
|
||||
&nasal_dbg::o_jmp, &nasal_dbg::o_jt,
|
||||
&nasal_dbg::o_jf, &nasal_dbg::o_cnt,
|
||||
&nasal_dbg::o_findex, &nasal_dbg::o_feach,
|
||||
&nasal_dbg::o_callg, &nasal_dbg::o_calll,
|
||||
&nasal_dbg::o_upval, &nasal_dbg::o_callv,
|
||||
&nasal_dbg::o_callvi, &nasal_dbg::o_callh,
|
||||
&nasal_dbg::o_callfv, &nasal_dbg::o_callfh,
|
||||
&nasal_dbg::o_callb, &nasal_dbg::o_slcbeg,
|
||||
&nasal_dbg::o_slcend, &nasal_dbg::o_slc,
|
||||
&nasal_dbg::o_slc2, &nasal_dbg::o_mcallg,
|
||||
&nasal_dbg::o_mcalll, &nasal_dbg::o_mupval,
|
||||
&nasal_dbg::o_mcallv, &nasal_dbg::o_mcallh,
|
||||
&nasal_dbg::o_ret
|
||||
nullptr, &debugger::o_intg,
|
||||
&debugger::o_intl, &debugger::o_loadg,
|
||||
&debugger::o_loadl, &debugger::o_loadu,
|
||||
&debugger::o_pnum, &debugger::o_pnil,
|
||||
&debugger::o_pstr, &debugger::o_newv,
|
||||
&debugger::o_newh, &debugger::o_newf,
|
||||
&debugger::o_happ, &debugger::o_para,
|
||||
&debugger::o_deft, &debugger::o_dyn,
|
||||
&debugger::o_unot, &debugger::o_usub,
|
||||
&debugger::o_add, &debugger::o_sub,
|
||||
&debugger::o_mul, &debugger::o_div,
|
||||
&debugger::o_lnk, &debugger::o_addc,
|
||||
&debugger::o_subc, &debugger::o_mulc,
|
||||
&debugger::o_divc, &debugger::o_lnkc,
|
||||
&debugger::o_addeq, &debugger::o_subeq,
|
||||
&debugger::o_muleq, &debugger::o_diveq,
|
||||
&debugger::o_lnkeq, &debugger::o_addeqc,
|
||||
&debugger::o_subeqc, &debugger::o_muleqc,
|
||||
&debugger::o_diveqc, &debugger::o_lnkeqc,
|
||||
&debugger::o_meq, &debugger::o_eq,
|
||||
&debugger::o_neq, &debugger::o_less,
|
||||
&debugger::o_leq, &debugger::o_grt,
|
||||
&debugger::o_geq, &debugger::o_lessc,
|
||||
&debugger::o_leqc, &debugger::o_grtc,
|
||||
&debugger::o_geqc, &debugger::o_pop,
|
||||
&debugger::o_jmp, &debugger::o_jt,
|
||||
&debugger::o_jf, &debugger::o_cnt,
|
||||
&debugger::o_findex, &debugger::o_feach,
|
||||
&debugger::o_callg, &debugger::o_calll,
|
||||
&debugger::o_upval, &debugger::o_callv,
|
||||
&debugger::o_callvi, &debugger::o_callh,
|
||||
&debugger::o_callfv, &debugger::o_callfh,
|
||||
&debugger::o_callb, &debugger::o_slcbeg,
|
||||
&debugger::o_slcend, &debugger::o_slc,
|
||||
&debugger::o_slc2, &debugger::o_mcallg,
|
||||
&debugger::o_mcalll, &debugger::o_mupval,
|
||||
&debugger::o_mcallv, &debugger::o_mcallh,
|
||||
&debugger::o_ret
|
||||
};
|
||||
std::vector<u32> code;
|
||||
for(auto& i:gen.codes())
|
||||
@@ -298,28 +300,27 @@ void nasal_dbg::run(
|
||||
++count[code[pc]];
|
||||
(this->*oprs[code[pc]])();
|
||||
if(top>=canary)
|
||||
break;
|
||||
die("stack overflow");
|
||||
++pc;
|
||||
}
|
||||
#endif
|
||||
|
||||
vmexit:
|
||||
if(top>=canary)
|
||||
die("stack overflow");
|
||||
if(opcnt)
|
||||
opcallsort(count);
|
||||
gc.clear();
|
||||
callsort(count);
|
||||
ngc.clear();
|
||||
imm.clear();
|
||||
std::cout<<"[debug] debugger exited\n";
|
||||
std::cout<<bold_cyan<<"[debug] "<<reset<<"debugger exited\n";
|
||||
return;
|
||||
#ifndef _MSC_VER
|
||||
#define dbg(op,num) {\
|
||||
interact();\
|
||||
op();\
|
||||
++count[num];\
|
||||
if(top<canary)\
|
||||
interact();\
|
||||
op();\
|
||||
++count[num];\
|
||||
if(top<canary)\
|
||||
goto *code[++pc];\
|
||||
die("stack overflow");\
|
||||
goto *code[++pc];\
|
||||
goto vmexit;}
|
||||
}
|
||||
|
||||
intg: dbg(o_intg ,op_intg );
|
||||
intl: dbg(o_intl ,op_intl );
|
||||
@@ -397,5 +398,3 @@ mcallh: dbg(o_mcallh,op_mcallh);
|
||||
ret: dbg(o_ret ,op_ret );
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
143
nasal_err.h
@@ -1,10 +1,76 @@
|
||||
#ifndef __NASAL_ERR_H__
|
||||
#define __NASAL_ERR_H__
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream> // MSVC need this to use std::getline
|
||||
#include <cstring>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h> // use SetConsoleTextAttribute
|
||||
struct for_reset
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO scr;
|
||||
for_reset(){
|
||||
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&scr);
|
||||
}
|
||||
}reset_ter_color;
|
||||
#endif
|
||||
|
||||
std::ostream& back_white(std::ostream& s)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0xf0);
|
||||
#else
|
||||
s<<"\033[7m";
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
std::ostream& bold_red(std::ostream& s)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0c);
|
||||
#else
|
||||
s<<"\033[91;1m";
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
std::ostream& bold_cyan(std::ostream& s)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x03);
|
||||
#else
|
||||
s<<"\033[36;1m";
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
std::ostream& bold_orange(std::ostream& s)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0e);
|
||||
#else
|
||||
s<<"\033[93;1m";
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
std::ostream& bold_white(std::ostream& s)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0f);
|
||||
#else
|
||||
s<<"\033[0m\033[1m";
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
std::ostream& reset(std::ostream& s)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),reset_ter_color.scr.wAttributes);
|
||||
#else
|
||||
s<<"\033[0m";
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
class fstreamline
|
||||
{
|
||||
protected:
|
||||
@@ -13,59 +79,82 @@ protected:
|
||||
public:
|
||||
void load(const string& f)
|
||||
{
|
||||
if(file==f) // don't need to load a loaded file
|
||||
return;
|
||||
if(file==f) return; // don't need to load a loaded file
|
||||
file=f;
|
||||
res.clear();
|
||||
std::ifstream fin(f,std::ios::binary);
|
||||
if(fin.fail())
|
||||
std::ifstream in(f,std::ios::binary);
|
||||
if(in.fail())
|
||||
{
|
||||
std::cerr<<"[src] cannot open file <"<<f<<">\n";
|
||||
std::cerr<<bold_red<<"src: "<<reset<<"cannot open <"<<f<<">\n";
|
||||
std::exit(1);
|
||||
}
|
||||
string line;
|
||||
while(!fin.eof())
|
||||
while(!in.eof())
|
||||
{
|
||||
std::getline(fin,line);
|
||||
std::getline(in,line);
|
||||
res.push_back(line);
|
||||
}
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
std::vector<string> tmp;
|
||||
res.swap(tmp);
|
||||
}
|
||||
const string& operator[](usize n){return res[n];}
|
||||
const string& name(){return file;}
|
||||
usize size(){return res.size();}
|
||||
};
|
||||
|
||||
class nasal_err:public fstreamline
|
||||
class error:public fstreamline
|
||||
{
|
||||
private:
|
||||
u32 error;
|
||||
u32 cnt;
|
||||
string identation(usize len)
|
||||
{
|
||||
string tmp="";
|
||||
tmp.resize(len,' ');
|
||||
return tmp;
|
||||
}
|
||||
public:
|
||||
nasal_err():error(0){}
|
||||
error():cnt(0){}
|
||||
void err(const char* stage,const string& info)
|
||||
{
|
||||
++error;
|
||||
std::cerr<<"["<<stage<<"] "<<info<<"\n";
|
||||
++cnt;
|
||||
std::cerr<<bold_red<<stage<<": "
|
||||
<<bold_white<<info<<reset<<"\n\n";
|
||||
}
|
||||
void err(const char* stage,u32 line,u32 column,const string& info)
|
||||
{
|
||||
++error;
|
||||
++cnt;
|
||||
const string& code=res[line-1];
|
||||
std::cerr<<"["<<stage<<"] "<<file<<":"<<line<<":"<<column<<" "<<info<<"\n"<<code<<"\n";
|
||||
const string ident=identation(std::to_string(line).length());
|
||||
std::cerr<<bold_red<<stage<<": "
|
||||
<<bold_white<<info<<reset<<"\n"
|
||||
<<bold_cyan<<" --> "<<reset
|
||||
<<bold_orange<<file<<":"<<line<<":"<<column<<"\n";
|
||||
if(!line)
|
||||
{
|
||||
std::cerr<<"\n";
|
||||
return;
|
||||
}
|
||||
std::cerr<<bold_cyan<<ident<<" | "<<reset<<"\n"
|
||||
<<bold_cyan<<line<<" | "<<reset<<code<<"\n"
|
||||
<<bold_cyan<<ident<<" | "<<reset;
|
||||
for(i32 i=0;i<(i32)column-1;++i)
|
||||
std::cerr<<char(" \t"[code[i]=='\t']);
|
||||
std::cerr<<"^\n";
|
||||
std::cerr<<bold_red<<"^ "<<info<<reset<<"\n\n";
|
||||
}
|
||||
void err(const char* stage,u32 line,const string& info)
|
||||
{
|
||||
++error;
|
||||
std::cerr<<"["<<stage<<"] "<<file<<":"<<line<<" "<<info<<"\n"<<res[line-1]<<'\n';
|
||||
++cnt;
|
||||
const string ident=identation(std::to_string(line).length());
|
||||
std::cerr<<bold_red<<stage<<": "
|
||||
<<bold_white<<info<<reset<<"\n"
|
||||
<<bold_cyan<<" --> "<<reset
|
||||
<<bold_orange<<file<<":"<<line<<"\n";
|
||||
if(!line)
|
||||
{
|
||||
std::cerr<<"\n";
|
||||
return;
|
||||
}
|
||||
std::cerr<<bold_cyan<<ident<<" | "<<reset<<"\n"
|
||||
<<bold_cyan<<line<<" | "<<reset<<res[line-1]<<"\n"
|
||||
<<bold_cyan<<ident<<" | "<<reset<<"\n\n";
|
||||
}
|
||||
void chkerr(){if(error)std::exit(1);}
|
||||
void chkerr(){if(cnt)std::exit(1);}
|
||||
};
|
||||
|
||||
#endif
|
||||
401
nasal_gc.h
@@ -1,5 +1,10 @@
|
||||
#ifndef __NASAL_GC_H__
|
||||
#define __NASAL_GC_H__
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "nasal_err.h"
|
||||
|
||||
enum vm_type:u8{
|
||||
/* none-gc object */
|
||||
@@ -16,10 +21,9 @@ enum vm_type:u8{
|
||||
vm_func,
|
||||
vm_upval,
|
||||
vm_obj,
|
||||
vm_co,
|
||||
vm_tsize
|
||||
vm_co
|
||||
};
|
||||
const u32 gc_tsize=vm_tsize-vm_str;
|
||||
const u32 gc_tsize=vm_co-vm_str+1;
|
||||
// change parameters here to make your own efficient gc
|
||||
// better set bigger number on vm_vec
|
||||
const u32 ini[gc_tsize]=
|
||||
@@ -27,20 +31,20 @@ const u32 ini[gc_tsize]=
|
||||
128, // vm_str
|
||||
128, // vm_vec
|
||||
32, // vm_hash
|
||||
512, // vm_func
|
||||
512, // vm_upval
|
||||
128, // vm_func
|
||||
0, // vm_upval
|
||||
0, // vm_obj
|
||||
0 // vm_co
|
||||
};
|
||||
const u32 incr[gc_tsize]=
|
||||
{
|
||||
256, // vm_str
|
||||
1024,// vm_str
|
||||
512, // vm_vec
|
||||
512, // vm_hash
|
||||
512, // vm_func
|
||||
128, // vm_upval
|
||||
512, // vm_upval
|
||||
128, // vm_obj
|
||||
16 // vm_co
|
||||
32 // vm_co
|
||||
};
|
||||
|
||||
struct nas_vec; // vector
|
||||
@@ -49,9 +53,9 @@ struct nas_func; // function(lambda)
|
||||
struct nas_upval;// upvalue
|
||||
struct nas_obj; // special objects
|
||||
struct nas_co; // coroutine
|
||||
struct nas_val; // nasal_val includes gc-managed types
|
||||
struct nas_val; // nas_val includes gc-managed types
|
||||
|
||||
struct nas_ref
|
||||
struct var
|
||||
{
|
||||
u8 type;
|
||||
union
|
||||
@@ -59,31 +63,32 @@ struct nas_ref
|
||||
u32 ret;
|
||||
i64 cnt;
|
||||
f64 num;
|
||||
nas_ref* addr;
|
||||
var* addr;
|
||||
nas_val* gcobj;
|
||||
} val;
|
||||
|
||||
// vm_none/vm_nil
|
||||
nas_ref(const u8 t=vm_none):type(t){}
|
||||
var(const u8 t=vm_none):type(t){}
|
||||
// vm_ret
|
||||
nas_ref(const u8 t,const u32 n):type(t){val.ret=n;}
|
||||
var(const u8 t,const u32 n):type(t){val.ret=n;}
|
||||
// vm_cnt
|
||||
nas_ref(const u8 t,const i64 n):type(t){val.cnt=n;}
|
||||
var(const u8 t,const i64 n):type(t){val.cnt=n;}
|
||||
// vm_num
|
||||
nas_ref(const u8 t,const f64 n):type(t){val.num=n;}
|
||||
// vm_str/vm_func/vm_vec/vm_hash/vm_upval/vm_obj
|
||||
nas_ref(const u8 t,nas_val* n):type(t){val.gcobj=n;}
|
||||
var(const u8 t,const f64 n):type(t){val.num=n;}
|
||||
// nas_val
|
||||
var(const u8 t,nas_val* n):type(t){val.gcobj=n;}
|
||||
// vm_addr
|
||||
nas_ref(const u8 t,nas_ref* n):type(t){val.addr=n;}
|
||||
nas_ref(const nas_ref& nr):type(nr.type),val(nr.val){}
|
||||
bool operator==(const nas_ref& nr){return type==nr.type && val.gcobj==nr.val.gcobj;}
|
||||
bool operator!=(const nas_ref& nr){return type!=nr.type || val.gcobj!=nr.val.gcobj;}
|
||||
var(const u8 t,var* n):type(t){val.addr=n;}
|
||||
// copy
|
||||
var(const var& nr):type(nr.type),val(nr.val){}
|
||||
bool operator==(const var& nr){return type==nr.type && val.gcobj==nr.val.gcobj;}
|
||||
bool operator!=(const var& nr){return type!=nr.type || val.gcobj!=nr.val.gcobj;}
|
||||
// number and string can be translated to each other
|
||||
f64 tonum();
|
||||
string tostr();
|
||||
void print();
|
||||
friend std::ostream& operator<<(std::ostream&,var&);
|
||||
bool objchk(u32);
|
||||
inline nas_ref* addr();
|
||||
inline var* addr();
|
||||
inline u32 ret ();
|
||||
inline i64& cnt ();
|
||||
inline f64 num ();
|
||||
@@ -99,25 +104,25 @@ struct nas_ref
|
||||
struct nas_vec
|
||||
{
|
||||
bool printed;
|
||||
std::vector<nas_ref> elems;
|
||||
std::vector<var> elems;
|
||||
|
||||
nas_vec():printed(false){}
|
||||
void print();
|
||||
usize size(){return elems.size();}
|
||||
nas_ref get_val(const i32);
|
||||
nas_ref* get_mem(const i32);
|
||||
friend std::ostream& operator<<(std::ostream&,nas_vec&);
|
||||
usize size(){return elems.size();}
|
||||
var get_val(const i32);
|
||||
var* get_mem(const i32);
|
||||
};
|
||||
|
||||
struct nas_hash
|
||||
{
|
||||
bool printed;
|
||||
std::unordered_map<string,nas_ref> elems;
|
||||
std::unordered_map<string,var> elems;
|
||||
|
||||
nas_hash():printed(false){}
|
||||
void print();
|
||||
usize size(){return elems.size();}
|
||||
nas_ref get_val(const string&);
|
||||
nas_ref* get_mem(const string&);
|
||||
friend std::ostream& operator<<(std::ostream&,nas_hash&);
|
||||
usize size(){return elems.size();}
|
||||
var get_val(const string&);
|
||||
var* get_mem(const string&);
|
||||
};
|
||||
|
||||
struct nas_func
|
||||
@@ -126,8 +131,8 @@ struct nas_func
|
||||
u32 entry; // pc will set to entry-1 to call this function
|
||||
u32 psize; // used to load default parameters to a new function
|
||||
u32 lsize; // used to expand memory space for local values on stack
|
||||
std::vector<nas_ref> local; // local scope with default value(nas_ref)
|
||||
std::vector<nas_ref> upval; // closure
|
||||
std::vector<var> local; // local scope with default value(var)
|
||||
std::vector<var> upval; // closure
|
||||
std::unordered_map<u32,u32> keys; // parameter table, u32 begins from 1
|
||||
|
||||
nas_func():dpara(-1),entry(0),psize(0),lsize(0){}
|
||||
@@ -137,12 +142,12 @@ struct nas_func
|
||||
struct nas_upval
|
||||
{
|
||||
bool onstk;
|
||||
u32 size;
|
||||
nas_ref* stk;
|
||||
std::vector<nas_ref> elems;
|
||||
u32 size;
|
||||
var* stk;
|
||||
std::vector<var> elems;
|
||||
|
||||
nas_upval(){onstk=true;stk=nullptr;size=0;}
|
||||
nas_ref& operator[](usize n){return onstk?stk[n]:elems[n];}
|
||||
var& operator[](usize n){return onstk?stk[n]:elems[n];}
|
||||
void clear(){onstk=true;elems.clear();size=0;}
|
||||
};
|
||||
|
||||
@@ -190,15 +195,15 @@ struct nas_co
|
||||
running,
|
||||
dead
|
||||
};
|
||||
nas_ref stack[STACK_DEPTH];
|
||||
var stack[STACK_DEPTH];
|
||||
|
||||
u32 pc;
|
||||
nas_ref* top;
|
||||
nas_ref* canary;
|
||||
nas_ref* localr;
|
||||
nas_ref* memr;
|
||||
nas_ref funcr;
|
||||
nas_ref upvalr;
|
||||
u32 pc;
|
||||
var* top;
|
||||
var* canary;
|
||||
var* localr;
|
||||
var* memr;
|
||||
var funcr;
|
||||
var upvalr;
|
||||
|
||||
u32 status;
|
||||
nas_co():
|
||||
@@ -243,53 +248,51 @@ struct nas_val
|
||||
nas_upval* upval;
|
||||
nas_obj* obj;
|
||||
nas_co* co;
|
||||
}ptr;
|
||||
} ptr;
|
||||
|
||||
nas_val(u8);
|
||||
~nas_val();
|
||||
void clear();
|
||||
};
|
||||
|
||||
nas_ref nas_vec::get_val(const i32 n)
|
||||
var nas_vec::get_val(const i32 n)
|
||||
{
|
||||
i32 size=elems.size();
|
||||
if(n<-size || n>=size)
|
||||
return {vm_none};
|
||||
return elems[n>=0?n:n+size];
|
||||
}
|
||||
nas_ref* nas_vec::get_mem(const i32 n)
|
||||
var* nas_vec::get_mem(const i32 n)
|
||||
{
|
||||
i32 size=elems.size();
|
||||
if(n<-size || n>=size)
|
||||
return nullptr;
|
||||
return &elems[n>=0?n:n+size];
|
||||
}
|
||||
void nas_vec::print()
|
||||
std::ostream& operator<<(std::ostream& out,nas_vec& vec)
|
||||
{
|
||||
if(!elems.size() || printed)
|
||||
if(!vec.elems.size() || vec.printed)
|
||||
{
|
||||
std::cout<<(elems.size()?"[..]":"[]");
|
||||
return;
|
||||
out<<(vec.elems.size()?"[..]":"[]");
|
||||
return out;
|
||||
}
|
||||
printed=true;
|
||||
usize iter=0;
|
||||
usize size=elems.size();
|
||||
std::cout<<'[';
|
||||
for(auto& i:elems)
|
||||
{
|
||||
i.print();
|
||||
std::cout<<",]"[(++iter)==size];
|
||||
}
|
||||
printed=false;
|
||||
vec.printed=true;
|
||||
usize iter=0,size=vec.elems.size();
|
||||
out<<'[';
|
||||
for(auto& i:vec.elems)
|
||||
out<<i<<",]"[(++iter)==size];
|
||||
vec.printed=false;
|
||||
return out;
|
||||
}
|
||||
|
||||
nas_ref nas_hash::get_val(const string& key)
|
||||
var nas_hash::get_val(const string& key)
|
||||
{
|
||||
if(elems.count(key))
|
||||
return elems[key];
|
||||
else if(elems.count("parents"))
|
||||
{
|
||||
nas_ref ret(vm_none);
|
||||
nas_ref val=elems["parents"];
|
||||
var ret(vm_none);
|
||||
var val=elems["parents"];
|
||||
if(val.type==vm_vec)
|
||||
for(auto& i:val.vec().elems)
|
||||
{
|
||||
@@ -301,14 +304,14 @@ nas_ref nas_hash::get_val(const string& key)
|
||||
}
|
||||
return {vm_none};
|
||||
}
|
||||
nas_ref* nas_hash::get_mem(const string& key)
|
||||
var* nas_hash::get_mem(const string& key)
|
||||
{
|
||||
if(elems.count(key))
|
||||
return &elems[key];
|
||||
else if(elems.count("parents"))
|
||||
{
|
||||
nas_ref* addr=nullptr;
|
||||
nas_ref val=elems["parents"];
|
||||
var* addr=nullptr;
|
||||
var val=elems["parents"];
|
||||
if(val.type==vm_vec)
|
||||
for(auto& i:val.vec().elems)
|
||||
{
|
||||
@@ -320,24 +323,20 @@ nas_ref* nas_hash::get_mem(const string& key)
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
void nas_hash::print()
|
||||
std::ostream& operator<<(std::ostream& out,nas_hash& hash)
|
||||
{
|
||||
if(!elems.size() || printed)
|
||||
if(!hash.elems.size() || hash.printed)
|
||||
{
|
||||
std::cout<<(elems.size()?"{..}":"{}");
|
||||
return;
|
||||
out<<(hash.elems.size()?"{..}":"{}");
|
||||
return out;
|
||||
}
|
||||
printed=true;
|
||||
usize iter=0;
|
||||
usize size=elems.size();
|
||||
std::cout<<'{';
|
||||
for(auto& i:elems)
|
||||
{
|
||||
std::cout<<i.first<<':';
|
||||
i.second.print();
|
||||
std::cout<<",}"[(++iter)==size];
|
||||
}
|
||||
printed=false;
|
||||
hash.printed=true;
|
||||
usize iter=0,size=hash.elems.size();
|
||||
out<<'{';
|
||||
for(auto& i:hash.elems)
|
||||
out<<i.first<<':'<<i.second<<",}"[(++iter)==size];
|
||||
hash.printed=false;
|
||||
return out;
|
||||
}
|
||||
|
||||
void nas_func::clear()
|
||||
@@ -378,11 +377,24 @@ nas_val::~nas_val()
|
||||
}
|
||||
type=vm_nil;
|
||||
}
|
||||
f64 nas_ref::tonum()
|
||||
void nas_val::clear()
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case vm_str: ptr.str->clear(); break;
|
||||
case vm_vec: ptr.vec->elems.clear(); break;
|
||||
case vm_hash: ptr.hash->elems.clear();break;
|
||||
case vm_func: ptr.func->clear(); break;
|
||||
case vm_upval:ptr.upval->clear(); break;
|
||||
case vm_obj: ptr.obj->clear(); break;
|
||||
case vm_co: ptr.co->clear(); break;
|
||||
}
|
||||
}
|
||||
f64 var::tonum()
|
||||
{
|
||||
return type!=vm_str?val.num:str2num(str().c_str());
|
||||
}
|
||||
string nas_ref::tostr()
|
||||
string var::tostr()
|
||||
{
|
||||
if(type==vm_str)
|
||||
return str();
|
||||
@@ -395,118 +407,114 @@ string nas_ref::tostr()
|
||||
}
|
||||
return "";
|
||||
}
|
||||
void nas_ref::print()
|
||||
std::ostream& operator<<(std::ostream& out,var& ref)
|
||||
{
|
||||
switch(type)
|
||||
switch(ref.type)
|
||||
{
|
||||
case vm_none: std::cout<<"undefined"; break;
|
||||
case vm_nil: std::cout<<"nil"; break;
|
||||
case vm_num: std::cout<<val.num; break;
|
||||
case vm_str: std::cout<<str(); break;
|
||||
case vm_vec: vec().print(); break;
|
||||
case vm_hash: hash().print(); break;
|
||||
case vm_func: std::cout<<"func(..){..}";break;
|
||||
case vm_obj: std::cout<<"<object>"; break;
|
||||
case vm_co: std::cout<<"<coroutine>"; break;
|
||||
case vm_none: out<<"undefined"; break;
|
||||
case vm_nil: out<<"nil"; break;
|
||||
case vm_num: out<<ref.val.num; break;
|
||||
case vm_str: out<<ref.str(); break;
|
||||
case vm_vec: out<<ref.vec(); break;
|
||||
case vm_hash: out<<ref.hash(); break;
|
||||
case vm_func: out<<"func(..){..}";break;
|
||||
case vm_obj: out<<"<object>"; break;
|
||||
case vm_co: out<<"<coroutine>"; break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
bool nas_ref::objchk(u32 objtype)
|
||||
bool var::objchk(u32 objtype)
|
||||
{
|
||||
return type==vm_obj && obj().type==objtype && obj().ptr;
|
||||
}
|
||||
inline nas_ref* nas_ref::addr (){return val.addr; }
|
||||
inline u32 nas_ref::ret (){return val.ret; }
|
||||
inline i64& nas_ref::cnt (){return val.cnt; }
|
||||
inline f64 nas_ref::num (){return val.num; }
|
||||
inline string& nas_ref::str (){return *val.gcobj->ptr.str; }
|
||||
inline nas_vec& nas_ref::vec (){return *val.gcobj->ptr.vec; }
|
||||
inline nas_hash& nas_ref::hash (){return *val.gcobj->ptr.hash; }
|
||||
inline nas_func& nas_ref::func (){return *val.gcobj->ptr.func; }
|
||||
inline nas_upval& nas_ref::upval(){return *val.gcobj->ptr.upval;}
|
||||
inline nas_obj& nas_ref::obj (){return *val.gcobj->ptr.obj; }
|
||||
inline nas_co& nas_ref::co (){return *val.gcobj->ptr.co; }
|
||||
inline var* var::addr (){return val.addr; }
|
||||
inline u32 var::ret (){return val.ret; }
|
||||
inline i64& var::cnt (){return val.cnt; }
|
||||
inline f64 var::num (){return val.num; }
|
||||
inline string& var::str (){return *val.gcobj->ptr.str; }
|
||||
inline nas_vec& var::vec (){return *val.gcobj->ptr.vec; }
|
||||
inline nas_hash& var::hash (){return *val.gcobj->ptr.hash; }
|
||||
inline nas_func& var::func (){return *val.gcobj->ptr.func; }
|
||||
inline nas_upval& var::upval(){return *val.gcobj->ptr.upval;}
|
||||
inline nas_obj& var::obj (){return *val.gcobj->ptr.obj; }
|
||||
inline nas_co& var::co (){return *val.gcobj->ptr.co; }
|
||||
|
||||
const nas_ref zero={vm_num,(f64)0};
|
||||
const nas_ref one ={vm_num,(f64)1};
|
||||
const nas_ref nil ={vm_nil,(f64)0};
|
||||
const var zero={vm_num,(f64)0};
|
||||
const var one ={vm_num,(f64)1};
|
||||
const var nil ={vm_nil,(f64)0};
|
||||
|
||||
struct nasal_gc
|
||||
struct gc
|
||||
{
|
||||
/* main context */
|
||||
struct
|
||||
{
|
||||
u32 pc;
|
||||
nas_ref* top;
|
||||
nas_ref* localr;
|
||||
nas_ref* memr;
|
||||
nas_ref funcr;
|
||||
nas_ref upvalr;
|
||||
nas_ref* canary;
|
||||
nas_ref* stack;
|
||||
u32 pc;
|
||||
var* top;
|
||||
var* localr;
|
||||
var* memr;
|
||||
var funcr;
|
||||
var upvalr;
|
||||
var* canary;
|
||||
var* stack;
|
||||
} mctx;
|
||||
|
||||
/* runtime context */
|
||||
u32& pc; // program counter
|
||||
nas_ref*& localr;// local scope register
|
||||
nas_ref*& memr; // used for mem_call
|
||||
nas_ref& funcr; // function register
|
||||
nas_ref& upvalr;// upvalue register
|
||||
nas_ref*& canary;// avoid stackoverflow
|
||||
nas_ref*& top; // stack top
|
||||
nas_ref* stack; // stack pointer
|
||||
nas_co* cort; // running coroutine
|
||||
nas_ref temp; // temporary place used in builtin/module functions
|
||||
u32& pc; // program counter
|
||||
var*& localr; // local scope register
|
||||
var*& memr; // used for mem_call
|
||||
var& funcr; // function register
|
||||
var& upvalr; // upvalue register
|
||||
var*& canary; // avoid stackoverflow
|
||||
var*& top; // stack top
|
||||
var* stack; // stack pointer
|
||||
nas_co* cort; // running coroutine
|
||||
|
||||
/* native function used */
|
||||
var temp; // temporary place used in builtin/module functions
|
||||
|
||||
/* constants and memory pool */
|
||||
std::vector<nas_ref> strs; // reserved address for const vm_str
|
||||
std::vector<nas_ref> env_argv; // command line arguments
|
||||
std::vector<nas_val*> memory; // gc memory
|
||||
std::queue<nas_val*> unused[gc_tsize]; // gc free list
|
||||
std::vector<var> strs; // reserved address for const vm_str
|
||||
std::vector<var> env_argv; // command line arguments
|
||||
std::vector<nas_val*> memory; // gc memory
|
||||
std::queue<nas_val*> unused[gc_tsize]; // gc free list
|
||||
|
||||
/* values for analysis */
|
||||
u64 size[gc_tsize];
|
||||
u64 count[gc_tsize];
|
||||
u64 allocc[gc_tsize];
|
||||
nasal_gc(
|
||||
u32& _pc,
|
||||
nas_ref*& _localr,
|
||||
nas_ref*& _memr,
|
||||
nas_ref& _funcr,
|
||||
nas_ref& _upvalr,
|
||||
nas_ref*& _canary,
|
||||
nas_ref*& _top,
|
||||
nas_ref* _stk):
|
||||
u64 acnt[gc_tsize];
|
||||
gc(u32& _pc, var*& _localr, var*& _memr, var& _funcr,
|
||||
var& _upvalr, var*& _canary, var*& _top, var* _stk):
|
||||
pc(_pc),localr(_localr),memr(_memr),funcr(_funcr),upvalr(_upvalr),
|
||||
canary(_canary),top(_top),stack(_stk),cort(nullptr),temp(nil){}
|
||||
void mark();
|
||||
void sweep();
|
||||
void init(const std::vector<string>&,const std::vector<string>&);
|
||||
void clear();
|
||||
void info();
|
||||
nas_ref alloc(const u8);
|
||||
nas_ref newstr(char);
|
||||
nas_ref newstr(const char*);
|
||||
nas_ref newstr(const string&);
|
||||
void ctxchg(nas_co&);
|
||||
void ctxreserve();
|
||||
void mark();
|
||||
void sweep();
|
||||
void init(const std::vector<string>&,const std::vector<string>&);
|
||||
void clear();
|
||||
void info();
|
||||
var alloc(const u8);
|
||||
var newstr(char);
|
||||
var newstr(const char*);
|
||||
var newstr(const string&);
|
||||
void ctxchg(nas_co&);
|
||||
void ctxreserve();
|
||||
};
|
||||
|
||||
/* gc functions */
|
||||
void nasal_gc::mark()
|
||||
void gc::mark()
|
||||
{
|
||||
std::queue<nas_ref> bfs;
|
||||
std::queue<var> bfs;
|
||||
// scan coroutine process stack when coroutine ptr is not null
|
||||
// scan main process stack when coroutine ptr is null
|
||||
// this scan process must execute because when running coroutine,
|
||||
// the nasal_co related to it will not update it's context(like `top`) until the coroutine suspends or exits.
|
||||
for(nas_ref* i=stack;i<=top;++i)
|
||||
// the nas_co related to it will not update it's context(like `top`) until the coroutine suspends or exits.
|
||||
for(var* i=stack;i<=top;++i)
|
||||
bfs.push(*i);
|
||||
bfs.push(funcr);
|
||||
bfs.push(upvalr);
|
||||
bfs.push(temp);
|
||||
if(cort) // scan main process stack
|
||||
{
|
||||
for(nas_ref* i=mctx.stack;i<=mctx.top;++i)
|
||||
for(var* i=mctx.stack;i<=mctx.top;++i)
|
||||
bfs.push(*i);
|
||||
bfs.push(mctx.funcr);
|
||||
bfs.push(mctx.upvalr);
|
||||
@@ -514,7 +522,7 @@ void nasal_gc::mark()
|
||||
|
||||
while(!bfs.empty())
|
||||
{
|
||||
nas_ref tmp=bfs.front();
|
||||
var tmp=bfs.front();
|
||||
bfs.pop();
|
||||
if(tmp.type<=vm_num || tmp.val.gcobj->mark) continue;
|
||||
tmp.val.gcobj->mark=GC_FOUND;
|
||||
@@ -541,28 +549,19 @@ void nasal_gc::mark()
|
||||
case vm_co:
|
||||
bfs.push(tmp.co().funcr);
|
||||
bfs.push(tmp.co().upvalr);
|
||||
for(nas_ref* i=tmp.co().stack;i<=tmp.co().top;++i)
|
||||
for(var* i=tmp.co().stack;i<=tmp.co().top;++i)
|
||||
bfs.push(*i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void nasal_gc::sweep()
|
||||
void gc::sweep()
|
||||
{
|
||||
for(auto i:memory)
|
||||
{
|
||||
if(i->mark==GC_UNCOLLECTED)
|
||||
{
|
||||
switch(i->type)
|
||||
{
|
||||
case vm_str: i->ptr.str->clear(); break;
|
||||
case vm_vec: i->ptr.vec->elems.clear(); break;
|
||||
case vm_hash: i->ptr.hash->elems.clear();break;
|
||||
case vm_func: i->ptr.func->clear(); break;
|
||||
case vm_upval:i->ptr.upval->clear(); break;
|
||||
case vm_obj: i->ptr.obj->clear(); break;
|
||||
case vm_co: i->ptr.co->clear(); break;
|
||||
}
|
||||
i->clear();
|
||||
unused[i->type-vm_str].push(i);
|
||||
i->mark=GC_COLLECTED;
|
||||
}
|
||||
@@ -570,13 +569,13 @@ void nasal_gc::sweep()
|
||||
i->mark=GC_UNCOLLECTED;
|
||||
}
|
||||
}
|
||||
void nasal_gc::init(const std::vector<string>& s,const std::vector<string>& argv)
|
||||
void gc::init(const std::vector<string>& s,const std::vector<string>& argv)
|
||||
{
|
||||
// initiaize function register
|
||||
funcr=nil;
|
||||
|
||||
for(u8 i=0;i<gc_tsize;++i)
|
||||
size[i]=count[i]=allocc[i]=0;
|
||||
size[i]=count[i]=acnt[i]=0;
|
||||
for(u8 i=0;i<gc_tsize;++i)
|
||||
for(u32 j=0;j<ini[i];++j)
|
||||
{
|
||||
@@ -602,7 +601,7 @@ void nasal_gc::init(const std::vector<string>& s,const std::vector<string>& argv
|
||||
env_argv[i].str()=argv[i];
|
||||
}
|
||||
}
|
||||
void nasal_gc::clear()
|
||||
void gc::clear()
|
||||
{
|
||||
for(auto i:memory)
|
||||
delete i;
|
||||
@@ -615,21 +614,22 @@ void nasal_gc::clear()
|
||||
strs.clear();
|
||||
env_argv.clear();
|
||||
}
|
||||
void nasal_gc::info()
|
||||
void gc::info()
|
||||
{
|
||||
const char* name[]={"str ","vec ","hash ","func ","upval","obj ","co "};
|
||||
std::cout<<"\ngarbage collector info(gc/alloc)\n";
|
||||
for(u8 i=0;i<gc_tsize;++i)
|
||||
if(count[i] || allocc[i])
|
||||
std::cout<<" "<<name[i]<<" | "<<count[i]<<","<<allocc[i]<<"\n";
|
||||
if(count[i] || acnt[i])
|
||||
std::cout<<" "<<name[i]<<" | "<<count[i]<<","<<acnt[i]<<"\n";
|
||||
std::cout<<"\nmemory allocator info(max size)\n";
|
||||
for(u8 i=0;i<gc_tsize;++i)
|
||||
std::cout<<" "<<name[i]<<" | "<<ini[i]+size[i]*incr[i]<<" (+"<<size[i]<<")\n";
|
||||
if(ini[i] || size[i])
|
||||
std::cout<<" "<<name[i]<<" | "<<ini[i]+size[i]*incr[i]<<" (+"<<size[i]<<")\n";
|
||||
}
|
||||
nas_ref nasal_gc::alloc(u8 type)
|
||||
var gc::alloc(u8 type)
|
||||
{
|
||||
const u8 index=type-vm_str;
|
||||
++allocc[index];
|
||||
++acnt[index];
|
||||
if(unused[index].empty())
|
||||
{
|
||||
++count[index];
|
||||
@@ -646,30 +646,30 @@ nas_ref nasal_gc::alloc(u8 type)
|
||||
unused[index].push(tmp);
|
||||
}
|
||||
}
|
||||
nas_ref ret={type,unused[index].front()};
|
||||
var ret={type,unused[index].front()};
|
||||
ret.val.gcobj->mark=GC_UNCOLLECTED;
|
||||
unused[index].pop();
|
||||
return ret;
|
||||
}
|
||||
nas_ref nasal_gc::newstr(char c)
|
||||
var gc::newstr(char c)
|
||||
{
|
||||
nas_ref s=alloc(vm_str);
|
||||
var s=alloc(vm_str);
|
||||
s.str()=c;
|
||||
return s;
|
||||
}
|
||||
nas_ref nasal_gc::newstr(const char* buff)
|
||||
var gc::newstr(const char* buff)
|
||||
{
|
||||
nas_ref s=alloc(vm_str);
|
||||
var s=alloc(vm_str);
|
||||
s.str()=buff;
|
||||
return s;
|
||||
}
|
||||
nas_ref nasal_gc::newstr(const string& buff)
|
||||
var gc::newstr(const string& buff)
|
||||
{
|
||||
nas_ref s=alloc(vm_str);
|
||||
var s=alloc(vm_str);
|
||||
s.str()=buff;
|
||||
return s;
|
||||
}
|
||||
void nasal_gc::ctxchg(nas_co& ctx)
|
||||
void gc::ctxchg(nas_co& ctx)
|
||||
{
|
||||
mctx.pc=pc;
|
||||
mctx.top=top;
|
||||
@@ -692,7 +692,7 @@ void nasal_gc::ctxchg(nas_co& ctx)
|
||||
|
||||
cort->status=nas_co::running;
|
||||
}
|
||||
void nasal_gc::ctxreserve()
|
||||
void gc::ctxreserve()
|
||||
{
|
||||
// pc=0 means this coroutine is finished
|
||||
cort->status=pc?nas_co::suspended:nas_co::dead;
|
||||
@@ -714,4 +714,13 @@ void nasal_gc::ctxreserve()
|
||||
stack=mctx.stack;
|
||||
cort=nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// use to print error log and return error value
|
||||
var nas_err(const string& err_f,const string& info)
|
||||
{
|
||||
std::cerr<<"[vm] "<<err_f<<": "<<info<<"\n";
|
||||
return {vm_none};
|
||||
}
|
||||
|
||||
typedef var (*mod)(var*,usize,gc*); // module function type
|
||||
typedef mod (*getptr)(const char*); // module function "get" type
|
||||
|
||||
@@ -1,33 +1,40 @@
|
||||
#ifndef __NASAL_IMPORT_H__
|
||||
#define __NASAL_IMPORT_H__
|
||||
#pragma once
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#define _CRT_SECURE_NO_DEPRECATE 1
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE 1
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define F_OK 0
|
||||
#endif
|
||||
|
||||
class nasal_import
|
||||
class linker
|
||||
{
|
||||
private:
|
||||
bool show_path;
|
||||
bool lib_loaded;
|
||||
nasal_err& nerr;
|
||||
error& err;
|
||||
std::vector<string> files;
|
||||
std::vector<string> envpath;
|
||||
bool imptchk(const nasal_ast&);
|
||||
bool imptchk(const ast&);
|
||||
bool exist(const string&);
|
||||
void linker(nasal_ast&,nasal_ast&&);
|
||||
string path(const nasal_ast&);
|
||||
void link(ast&,ast&&);
|
||||
string path(const ast&);
|
||||
string findf(const string&);
|
||||
nasal_ast fimpt(nasal_ast&);
|
||||
nasal_ast libimpt();
|
||||
nasal_ast load(nasal_ast&,u16);
|
||||
ast fimpt(ast&);
|
||||
ast libimpt();
|
||||
ast load(ast&,u16);
|
||||
public:
|
||||
nasal_import(nasal_err&);
|
||||
void link(nasal_parse&,const string&,bool);
|
||||
linker(error&);
|
||||
void link(parse&,const string&,bool);
|
||||
const std::vector<string>& filelist() const {return files;}
|
||||
};
|
||||
|
||||
nasal_import::nasal_import(nasal_err& e):lib_loaded(false),nerr(e){
|
||||
linker::linker(error& e):show_path(false),lib_loaded(false),err(e){
|
||||
#ifdef _WIN32
|
||||
char sep=';';
|
||||
#else
|
||||
@@ -47,7 +54,7 @@ nasal_import::nasal_import(nasal_err& e):lib_loaded(false),nerr(e){
|
||||
envpath.push_back(PATH.substr(last));
|
||||
}
|
||||
|
||||
string nasal_import::path(const nasal_ast& node)
|
||||
string linker::path(const ast& node)
|
||||
{
|
||||
if(node[1].type()==ast_callf)
|
||||
return node[1][0].str();
|
||||
@@ -61,7 +68,7 @@ string nasal_import::path(const nasal_ast& node)
|
||||
return fpath+".nas";
|
||||
}
|
||||
|
||||
string nasal_import::findf(const string& fname)
|
||||
string linker::findf(const string& fname)
|
||||
{
|
||||
std::vector<string> filepath={fname};
|
||||
for(auto&p:envpath)
|
||||
@@ -83,17 +90,17 @@ string nasal_import::findf(const string& fname)
|
||||
#endif
|
||||
if(!show_path)
|
||||
{
|
||||
nerr.err("link","cannot find file <"+fname+">");
|
||||
err.err("link","cannot find file <"+fname+">");
|
||||
return "";
|
||||
}
|
||||
string paths="";
|
||||
for(auto& i:filepath)
|
||||
paths+=" "+i+"\n";
|
||||
nerr.err("link","cannot find file <"+fname+"> in these paths:\n"+paths);
|
||||
err.err("link","cannot find file <"+fname+"> in these paths:\n"+paths);
|
||||
return "";
|
||||
}
|
||||
|
||||
bool nasal_import::imptchk(const nasal_ast& node)
|
||||
bool linker::imptchk(const ast& node)
|
||||
{
|
||||
// only these two kinds of node can be recognized as 'import':
|
||||
/*
|
||||
@@ -125,7 +132,7 @@ bool nasal_import::imptchk(const nasal_ast& node)
|
||||
);
|
||||
}
|
||||
|
||||
bool nasal_import::exist(const string& file)
|
||||
bool linker::exist(const string& file)
|
||||
{
|
||||
// avoid importing the same file
|
||||
for(auto& fname:files)
|
||||
@@ -135,17 +142,17 @@ bool nasal_import::exist(const string& file)
|
||||
return false;
|
||||
}
|
||||
|
||||
void nasal_import::linker(nasal_ast& root,nasal_ast&& add_root)
|
||||
void linker::link(ast& root,ast&& add_root)
|
||||
{
|
||||
// add children of add_root to the back of root
|
||||
for(auto& i:add_root.child())
|
||||
root.add(std::move(i));
|
||||
}
|
||||
|
||||
nasal_ast nasal_import::fimpt(nasal_ast& node)
|
||||
ast linker::fimpt(ast& node)
|
||||
{
|
||||
nasal_lexer lex(nerr);
|
||||
nasal_parse par(nerr);
|
||||
lexer lex(err);
|
||||
parse par(err);
|
||||
// get filename and set node to ast_null
|
||||
string filename=path(node);
|
||||
node.clear();
|
||||
@@ -153,68 +160,66 @@ nasal_ast nasal_import::fimpt(nasal_ast& node)
|
||||
// avoid infinite loading loop
|
||||
filename=findf(filename);
|
||||
if(!filename.length() || exist(filename))
|
||||
return {0,ast_root};
|
||||
return {0,0,ast_root};
|
||||
|
||||
// start importing...
|
||||
lex.scan(filename);
|
||||
par.compile(lex);
|
||||
nasal_ast tmp=std::move(par.ast());
|
||||
ast tmp=std::move(par.tree());
|
||||
// check if tmp has 'import'
|
||||
return load(tmp,files.size()-1);
|
||||
}
|
||||
|
||||
nasal_ast nasal_import::libimpt()
|
||||
ast linker::libimpt()
|
||||
{
|
||||
nasal_lexer lex(nerr);
|
||||
nasal_parse par(nerr);
|
||||
lexer lex(err);
|
||||
parse par(err);
|
||||
string filename=findf("lib.nas");
|
||||
if(!filename.length())
|
||||
return {0,ast_root};
|
||||
return {0,0,ast_root};
|
||||
|
||||
// avoid infinite loading loop
|
||||
if(exist(filename))
|
||||
return {0,ast_root};
|
||||
return {0,0,ast_root};
|
||||
|
||||
// start importing...
|
||||
lex.scan(filename);
|
||||
par.compile(lex);
|
||||
nasal_ast tmp=std::move(par.ast());
|
||||
ast tmp=std::move(par.tree());
|
||||
// check if tmp has 'import'
|
||||
return load(tmp,files.size()-1);
|
||||
}
|
||||
|
||||
nasal_ast nasal_import::load(nasal_ast& root,u16 fileindex)
|
||||
ast linker::load(ast& root,u16 fileindex)
|
||||
{
|
||||
nasal_ast new_root(0,ast_root);
|
||||
ast new_root(0,0,ast_root);
|
||||
if(!lib_loaded)
|
||||
{
|
||||
linker(new_root,libimpt());
|
||||
link(new_root,libimpt());
|
||||
lib_loaded=true;
|
||||
}
|
||||
for(auto& i:root.child())
|
||||
{
|
||||
if(imptchk(i))
|
||||
linker(new_root,fimpt(i));
|
||||
link(new_root,fimpt(i));
|
||||
else
|
||||
break;
|
||||
}
|
||||
// add root to the back of new_root
|
||||
nasal_ast file_head(0,ast_file);
|
||||
ast file_head(0,0,ast_file);
|
||||
file_head.set_num(fileindex);
|
||||
new_root.add(std::move(file_head));
|
||||
linker(new_root,std::move(root));
|
||||
link(new_root,std::move(root));
|
||||
return new_root;
|
||||
}
|
||||
|
||||
void nasal_import::link(nasal_parse& parse,const string& self,bool spath=false)
|
||||
void linker::link(parse& parse,const string& self,bool spath=false)
|
||||
{
|
||||
show_path=spath;
|
||||
// initializing
|
||||
files={self};
|
||||
// scan root and import files,then generate a new ast and return to import_ast
|
||||
// the main file's index is 0
|
||||
parse.ast()=load(parse.ast(),0);
|
||||
nerr.chkerr();
|
||||
parse.tree()=load(parse.tree(),0);
|
||||
err.chkerr();
|
||||
}
|
||||
|
||||
#endif
|
||||
217
nasal_lexer.h
@@ -1,42 +1,63 @@
|
||||
#ifndef __NASAL_LEXER_H__
|
||||
#define __NASAL_LEXER_H__
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define S_ISREG(m) (((m)&0xF000)==0x8000)
|
||||
#endif
|
||||
|
||||
#define ID(c) ((c=='_')||('a'<=c && c<='z')||('A'<=c&&c<='Z')||(c<0))
|
||||
#define HEX(c) (('0'<=c&&c<='9')||('a'<=c&&c<='f')||('A'<=c && c<='F'))
|
||||
#define OCT(c) ('0'<=c&&c<='7')
|
||||
#define DIGIT(c) ('0'<=c&&c<='9')
|
||||
#define STR(c) (c=='\''||c=='\"'||c=='`')
|
||||
// single operators have only one character
|
||||
#define SINGLE_OPERATOR(c) (c=='('||c==')'||c=='['||c==']'||c=='{'||c=='}'||c==','||c==';'||c=='|'||c==':'||\
|
||||
c=='?'||c=='`'||c=='&'||c=='@'||c=='%'||c=='$'||c=='^'||c=='\\')
|
||||
// calculation operators may have two chars, for example: += -= *= /= ~= != == >= <=
|
||||
#define CALC_OPERATOR(c) (c=='='||c=='+'||c=='-'||c=='*'||c=='!'||c=='/'||c=='<'||c=='>'||c=='~')
|
||||
#define NOTE(c) (c=='#')
|
||||
|
||||
enum tok:u32{
|
||||
tok_null=0, // null token (default token type)
|
||||
tok_num, // number basic token type
|
||||
tok_str, // string basic token type
|
||||
tok_id, // identifier basic token type
|
||||
tok_num, // number literal
|
||||
tok_str, // string literal
|
||||
tok_id, // identifier
|
||||
tok_for, // loop keyword for
|
||||
tok_forindex,// loop keyword forindex
|
||||
tok_foreach, // loop keyword foreach
|
||||
tok_while, // loop keyword while
|
||||
tok_var,tok_func,tok_break,tok_continue,
|
||||
tok_ret,tok_if,tok_elsif,tok_else,tok_nil,
|
||||
tok_lcurve,tok_rcurve,
|
||||
tok_lbracket,tok_rbracket,
|
||||
tok_lbrace,tok_rbrace,
|
||||
tok_semi,tok_and,tok_or,tok_comma,tok_dot,tok_ellipsis,tok_quesmark,
|
||||
tok_colon,tok_add,tok_sub,tok_mult,tok_div,tok_link,tok_not,
|
||||
tok_eq,
|
||||
tok_addeq,tok_subeq,tok_multeq,tok_diveq,tok_lnkeq,
|
||||
tok_cmpeq,tok_neq,tok_less,tok_leq,tok_grt,tok_geq,
|
||||
tok_eof // end of token list
|
||||
tok_var, // keyword for definition
|
||||
tok_func, // keyword for definition of function
|
||||
tok_break, // loop keyword break
|
||||
tok_continue,// loop keyword continue
|
||||
tok_ret, // function keyword return
|
||||
tok_if, // condition expression keyword if
|
||||
tok_elsif, // condition expression keyword elsif
|
||||
tok_else, // condition expression keyword else
|
||||
tok_nil, // nil literal
|
||||
tok_lcurve, // (
|
||||
tok_rcurve, // )
|
||||
tok_lbracket,// [
|
||||
tok_rbracket,// ]
|
||||
tok_lbrace, // {
|
||||
tok_rbrace, // }
|
||||
tok_semi, // ;
|
||||
tok_and, // operator and
|
||||
tok_or, // operator or
|
||||
tok_comma, // ,
|
||||
tok_dot, // .
|
||||
tok_ellipsis,// ...
|
||||
tok_quesmark,// ?
|
||||
tok_colon, // :
|
||||
tok_add, // operator +
|
||||
tok_sub, // operator -
|
||||
tok_mult, // operator *
|
||||
tok_div, // operator /
|
||||
tok_link, // operator ~
|
||||
tok_not, // operator !
|
||||
tok_eq, // operator =
|
||||
tok_addeq, // operator +=
|
||||
tok_subeq, // operator -=
|
||||
tok_multeq, // operator *=
|
||||
tok_diveq, // operator /=
|
||||
tok_lnkeq, // operator ~=
|
||||
tok_cmpeq, // operator ==
|
||||
tok_neq, // operator !=
|
||||
tok_less, // operator <
|
||||
tok_leq, // operator <=
|
||||
tok_grt, // operator >
|
||||
tok_geq, // operator >=
|
||||
tok_eof // <eof> end of token list
|
||||
};
|
||||
|
||||
struct{
|
||||
@@ -105,54 +126,100 @@ struct token
|
||||
}
|
||||
};
|
||||
|
||||
class nasal_lexer
|
||||
class lexer
|
||||
{
|
||||
private:
|
||||
u32 line;
|
||||
u32 column;
|
||||
usize ptr;
|
||||
string res;
|
||||
nasal_err& nerr;
|
||||
error& err;
|
||||
std::vector<token> tokens;
|
||||
|
||||
u32 get_type(const string&);
|
||||
void die(const string& info){nerr.err("lexer",line,column,info);}
|
||||
bool is_id(char);
|
||||
bool is_hex(char);
|
||||
bool is_oct(char);
|
||||
bool is_dec(char);
|
||||
bool is_str(char);
|
||||
bool is_single_opr(char);
|
||||
bool is_calc_opr(char);
|
||||
void die(const string& info){err.err("lexer",line,column,info);}
|
||||
void open(const string&);
|
||||
string utf8_gen();
|
||||
string id_gen();
|
||||
string num_gen();
|
||||
string str_gen();
|
||||
public:
|
||||
nasal_lexer(nasal_err& e):
|
||||
line(1),
|
||||
column(0),
|
||||
ptr(0),
|
||||
res(""),
|
||||
nerr(e){}
|
||||
lexer(error& e):
|
||||
line(1),column(0),
|
||||
ptr(0),res(""),
|
||||
err(e){}
|
||||
void scan(const string&);
|
||||
void print();
|
||||
const std::vector<token>& result() const {return tokens;}
|
||||
};
|
||||
|
||||
void nasal_lexer::open(const string& file)
|
||||
bool lexer::is_id(char c)
|
||||
{
|
||||
return (c=='_')||('a'<=c && c<='z')||('A'<=c&&c<='Z')||(c<0);
|
||||
}
|
||||
|
||||
bool lexer::is_hex(char c)
|
||||
{
|
||||
return ('0'<=c&&c<='9')||('a'<=c&&c<='f')||('A'<=c && c<='F');
|
||||
}
|
||||
|
||||
bool lexer::is_oct(char c)
|
||||
{
|
||||
return '0'<=c&&c<='7';
|
||||
}
|
||||
|
||||
bool lexer::is_dec(char c)
|
||||
{
|
||||
return '0'<=c&&c<='9';
|
||||
}
|
||||
|
||||
bool lexer::is_str(char c)
|
||||
{
|
||||
return c=='\''||c=='\"'||c=='`';
|
||||
}
|
||||
|
||||
bool lexer::is_single_opr(char c)
|
||||
{
|
||||
return (
|
||||
c=='('||c==')'||c=='['||c==']'||
|
||||
c=='{'||c=='}'||c==','||c==';'||
|
||||
c=='|'||c==':'||c=='?'||c=='`'||
|
||||
c=='&'||c=='@'||c=='%'||c=='$'||
|
||||
c=='^'||c=='\\'
|
||||
);
|
||||
}
|
||||
|
||||
bool lexer::is_calc_opr(char c)
|
||||
{
|
||||
return c=='='||c=='+'||c=='-'||c=='*'||c=='!'||c=='/'||c=='<'||c=='>'||c=='~';
|
||||
}
|
||||
|
||||
void lexer::open(const string& file)
|
||||
{
|
||||
struct stat buffer;
|
||||
if(stat(file.c_str(),&buffer)==0 && !S_ISREG(buffer.st_mode))
|
||||
{
|
||||
nerr.err("lexer","<"+file+"> is not a regular file.");
|
||||
nerr.chkerr();
|
||||
err.err("lexer","<"+file+"> is not a regular file");
|
||||
err.chkerr();
|
||||
}
|
||||
std::ifstream fin(file,std::ios::binary);
|
||||
if(fin.fail())
|
||||
nerr.err("lexer","failed to open <"+file+">.");
|
||||
err.err("lexer","failed to open <"+file+">");
|
||||
else
|
||||
nerr.load(file);
|
||||
err.load(file);
|
||||
std::stringstream ss;
|
||||
ss<<fin.rdbuf();
|
||||
res=ss.str();
|
||||
}
|
||||
|
||||
u32 nasal_lexer::get_type(const string& str)
|
||||
u32 lexer::get_type(const string& str)
|
||||
{
|
||||
for(u32 i=0;tok_table[i].str;++i)
|
||||
if(str==tok_table[i].str)
|
||||
@@ -160,7 +227,7 @@ u32 nasal_lexer::get_type(const string& str)
|
||||
return tok_null;
|
||||
}
|
||||
|
||||
string nasal_lexer::utf8_gen()
|
||||
string lexer::utf8_gen()
|
||||
{
|
||||
string str="";
|
||||
while(ptr<res.size() && res[ptr]<0)
|
||||
@@ -179,7 +246,7 @@ string nasal_lexer::utf8_gen()
|
||||
string utf_info="0x"+chrhex(tmp[0]);
|
||||
for(u32 i=1;i<tmp.size();++i)
|
||||
utf_info+=" 0x"+chrhex(tmp[i]);
|
||||
die("invalid utf-8 character `"+utf_info+"`, make sure it is utf8-text file.");
|
||||
die("invalid utf-8 character `"+utf_info+"`, make sure it is utf8-text file");
|
||||
std::exit(1);
|
||||
}
|
||||
str+=tmp;
|
||||
@@ -194,10 +261,10 @@ string nasal_lexer::utf8_gen()
|
||||
return str;
|
||||
}
|
||||
|
||||
string nasal_lexer::id_gen()
|
||||
string lexer::id_gen()
|
||||
{
|
||||
string str="";
|
||||
while(ptr<res.size() && (ID(res[ptr])||DIGIT(res[ptr])))
|
||||
while(ptr<res.size() && (is_id(res[ptr])||is_dec(res[ptr])))
|
||||
{
|
||||
if(res[ptr]<0) // utf-8
|
||||
str+=utf8_gen();
|
||||
@@ -210,18 +277,18 @@ string nasal_lexer::id_gen()
|
||||
return str;
|
||||
}
|
||||
|
||||
string nasal_lexer::num_gen()
|
||||
string lexer::num_gen()
|
||||
{
|
||||
// generate hex number
|
||||
if(ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='x')
|
||||
{
|
||||
string str="0x";
|
||||
ptr+=2;
|
||||
while(ptr<res.size() && HEX(res[ptr]))
|
||||
while(ptr<res.size() && is_hex(res[ptr]))
|
||||
str+=res[ptr++];
|
||||
column+=str.length();
|
||||
if(str.length()<3)// "0x"
|
||||
die("invalid number `"+str+"`.");
|
||||
die("invalid number `"+str+"`");
|
||||
return str;
|
||||
}
|
||||
// generate oct number
|
||||
@@ -229,28 +296,28 @@ string nasal_lexer::num_gen()
|
||||
{
|
||||
string str="0o";
|
||||
ptr+=2;
|
||||
while(ptr<res.size() && OCT(res[ptr]))
|
||||
while(ptr<res.size() && is_oct(res[ptr]))
|
||||
str+=res[ptr++];
|
||||
column+=str.length();
|
||||
if(str.length()<3)// "0o"
|
||||
die("invalid number `"+str+"`.");
|
||||
die("invalid number `"+str+"`");
|
||||
return str;
|
||||
}
|
||||
// generate dec number
|
||||
// dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
|
||||
string str="";
|
||||
while(ptr<res.size() && DIGIT(res[ptr]))
|
||||
while(ptr<res.size() && is_dec(res[ptr]))
|
||||
str+=res[ptr++];
|
||||
if(ptr<res.size() && res[ptr]=='.')
|
||||
{
|
||||
str+=res[ptr++];
|
||||
while(ptr<res.size() && DIGIT(res[ptr]))
|
||||
while(ptr<res.size() && is_dec(res[ptr]))
|
||||
str+=res[ptr++];
|
||||
// "xxxx." is not a correct number
|
||||
if(str.back()=='.')
|
||||
{
|
||||
column+=str.length();
|
||||
die("invalid number `"+str+"`.");
|
||||
die("invalid number `"+str+"`");
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
@@ -259,13 +326,13 @@ string nasal_lexer::num_gen()
|
||||
str+=res[ptr++];
|
||||
if(ptr<res.size() && (res[ptr]=='-' || res[ptr]=='+'))
|
||||
str+=res[ptr++];
|
||||
while(ptr<res.size() && DIGIT(res[ptr]))
|
||||
while(ptr<res.size() && is_dec(res[ptr]))
|
||||
str+=res[ptr++];
|
||||
// "xxxe(-|+)" is not a correct number
|
||||
if(str.back()=='e' || str.back()=='E' || str.back()=='-' || str.back()=='+')
|
||||
{
|
||||
column+=str.length();
|
||||
die("invalid number `"+str+"`.");
|
||||
die("invalid number `"+str+"`");
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
@@ -273,7 +340,7 @@ string nasal_lexer::num_gen()
|
||||
return str;
|
||||
}
|
||||
|
||||
string nasal_lexer::str_gen()
|
||||
string lexer::str_gen()
|
||||
{
|
||||
string str="";
|
||||
const char begin=res[ptr];
|
||||
@@ -295,11 +362,7 @@ string nasal_lexer::str_gen()
|
||||
case '0': str+='\0'; break;
|
||||
case 'a': str+='\a'; break;
|
||||
case 'b': str+='\b'; break;
|
||||
#ifdef _MSC_VER
|
||||
case 'e': str+='\033'; break;
|
||||
#else
|
||||
case 'e': str+='\e'; break;
|
||||
#endif
|
||||
case 't': str+='\t'; break;
|
||||
case 'n': str+='\n'; break;
|
||||
case 'v': str+='\v'; break;
|
||||
@@ -318,16 +381,16 @@ string nasal_lexer::str_gen()
|
||||
// check if this string ends with a " or '
|
||||
if(ptr++>=res.size())
|
||||
{
|
||||
die("get EOF when generating string.");
|
||||
die("get EOF when generating string");
|
||||
return str;
|
||||
}
|
||||
++column;
|
||||
if(begin=='`' && str.length()!=1)
|
||||
die("\'`\' is used for string that includes one character.");
|
||||
die("\'`\' is used for string that includes one character");
|
||||
return str;
|
||||
}
|
||||
|
||||
void nasal_lexer::scan(const string& file)
|
||||
void lexer::scan(const string& file)
|
||||
{
|
||||
line=1;
|
||||
column=0;
|
||||
@@ -348,29 +411,29 @@ void nasal_lexer::scan(const string& file)
|
||||
}
|
||||
}
|
||||
if(ptr>=res.size()) break;
|
||||
if(ID(res[ptr]))
|
||||
if(is_id(res[ptr]))
|
||||
{
|
||||
str=id_gen();
|
||||
u32 type=get_type(str);
|
||||
tokens.push_back({line,column,type?type:tok_id,str});
|
||||
}
|
||||
else if(DIGIT(res[ptr]))
|
||||
else if(is_dec(res[ptr]))
|
||||
{
|
||||
str=num_gen(); // make sure column is correct
|
||||
tokens.push_back({line,column,tok_num,str});
|
||||
}
|
||||
else if(STR(res[ptr]))
|
||||
else if(is_str(res[ptr]))
|
||||
{
|
||||
str=str_gen(); // make sure column is correct
|
||||
tokens.push_back({line,column,tok_str,str});
|
||||
}
|
||||
else if(SINGLE_OPERATOR(res[ptr]))
|
||||
else if(is_single_opr(res[ptr]))
|
||||
{
|
||||
str=res[ptr];
|
||||
++column;
|
||||
u32 type=get_type(str);
|
||||
if(!type)
|
||||
die("invalid operator `"+str+"`.");
|
||||
die("invalid operator `"+str+"`");
|
||||
tokens.push_back({line,column,type,str});
|
||||
++ptr;
|
||||
}
|
||||
@@ -383,7 +446,7 @@ void nasal_lexer::scan(const string& file)
|
||||
column+=str.length();
|
||||
tokens.push_back({line,column,get_type(str),str});
|
||||
}
|
||||
else if(CALC_OPERATOR(res[ptr]))
|
||||
else if(is_calc_opr(res[ptr]))
|
||||
{
|
||||
// get calculation operator
|
||||
str=res[ptr++];
|
||||
@@ -392,24 +455,22 @@ void nasal_lexer::scan(const string& file)
|
||||
column+=str.length();
|
||||
tokens.push_back({line,column,get_type(str),str});
|
||||
}
|
||||
else if(NOTE(res[ptr]))// avoid note, after this process ptr will point to a '\n', so next loop line counter+1
|
||||
else if(res[ptr]=='#')// avoid note, after this process ptr will point to a '\n', so next loop line counter+1
|
||||
while(++ptr<res.size() && res[ptr]!='\n');
|
||||
else
|
||||
{
|
||||
++column;
|
||||
char c=res[ptr++];
|
||||
die("invalid character 0x"+chrhex(c)+".");
|
||||
die("invalid character 0x"+chrhex(c));
|
||||
}
|
||||
}
|
||||
tokens.push_back({line,column,tok_eof,"eof"});
|
||||
tokens.push_back({line,column,tok_eof,"<eof>"});
|
||||
res="";
|
||||
nerr.chkerr();
|
||||
err.chkerr();
|
||||
}
|
||||
|
||||
void nasal_lexer::print()
|
||||
void lexer::print()
|
||||
{
|
||||
for(auto& tok:tokens)
|
||||
std::cout<<"("<<tok.line<<" | "<<rawstr(tok.str,128)<<")\n";
|
||||
}
|
||||
|
||||
#endif
|
||||
14
nasal_opt.h
@@ -1,7 +1,8 @@
|
||||
#ifndef __NASAL_OPT_H__
|
||||
#define __NASAL_OPT_H__
|
||||
#pragma once
|
||||
|
||||
void const_str(nasal_ast& root)
|
||||
#include <cmath>
|
||||
|
||||
void const_str(ast& root)
|
||||
{
|
||||
auto& vec=root.child();
|
||||
root.set_str(vec[0].str()+vec[1].str());
|
||||
@@ -9,7 +10,7 @@ void const_str(nasal_ast& root)
|
||||
root.set_type(ast_str);
|
||||
}
|
||||
|
||||
void const_num(nasal_ast& root)
|
||||
void const_num(ast& root)
|
||||
{
|
||||
auto& vec=root.child();
|
||||
f64 res;
|
||||
@@ -32,7 +33,7 @@ void const_num(nasal_ast& root)
|
||||
root.set_type(ast_num);
|
||||
}
|
||||
|
||||
void calc_const(nasal_ast& root)
|
||||
void calc_const(ast& root)
|
||||
{
|
||||
auto& vec=root.child();
|
||||
for(auto& i:vec)
|
||||
@@ -60,9 +61,8 @@ void calc_const(nasal_ast& root)
|
||||
vec[0].type()==ast_num && vec[1].type()==ast_num)
|
||||
const_num(root);
|
||||
}
|
||||
void optimize(nasal_ast& root)
|
||||
void optimize(ast& root)
|
||||
{
|
||||
for(auto& i:root.child())
|
||||
calc_const(i);
|
||||
}
|
||||
#endif
|
||||
514
nasal_parse.h
568
nasal_vm.h
16
stl/csv.nas
Normal file
@@ -0,0 +1,16 @@
|
||||
# lib csv.nas
|
||||
# ValKmjolnir 2022/10/15
|
||||
var read_csv=func(path,delimeter=",",endline="\n"){
|
||||
var context=io.fin(path);
|
||||
context=split(endline,context);
|
||||
forindex(var i;context){
|
||||
context[i]=split(delimeter,context[i]);
|
||||
}
|
||||
if(size(context)<=1){
|
||||
die("incorrect csv file <"~path~">: "~size(context)~" line(s).");
|
||||
}
|
||||
return {
|
||||
property:context[0],
|
||||
data:context[1:]
|
||||
};
|
||||
}
|
||||
22
stl/file.nas
@@ -36,3 +36,25 @@ var find_all_files=func(path){
|
||||
unix.closedir(dd);
|
||||
return res;
|
||||
}
|
||||
|
||||
var recursive_find_files=func(path){
|
||||
if(!io.exists(path))
|
||||
return nil;
|
||||
var dd=unix.opendir(path);
|
||||
var res={
|
||||
dir:path,
|
||||
files:[]
|
||||
};
|
||||
while(var n=unix.readdir(dd)){
|
||||
if(unix.isfile(path~"/"~n)){
|
||||
append(res.files,n);
|
||||
}elsif(unix.isdir(path~"/"~n) and n!="." and n!=".."){
|
||||
var tmp=recursive_find_files(path~"/"~n);
|
||||
if(tmp!=nil)
|
||||
append(res.files,tmp);
|
||||
}
|
||||
|
||||
}
|
||||
unix.closedir(dd);
|
||||
return res;
|
||||
}
|
||||
268
stl/json.nas
Normal file
@@ -0,0 +1,268 @@
|
||||
# lib json.nas
|
||||
# 2021 ValKmjolnir
|
||||
var JSON=func(){
|
||||
|
||||
var (
|
||||
j_eof,
|
||||
j_lbrace,
|
||||
j_rbrace,
|
||||
j_lbracket,
|
||||
j_rbracket,
|
||||
j_comma,
|
||||
j_colon,
|
||||
j_str,
|
||||
j_num,
|
||||
j_id
|
||||
)=(0,1,2,3,4,5,6,7,8,9);
|
||||
var j_content=[
|
||||
"eof",
|
||||
"`{`",
|
||||
"`}`",
|
||||
"`[`",
|
||||
"`]`",
|
||||
"`,`",
|
||||
"`:`",
|
||||
"string",
|
||||
"number",
|
||||
"identifier"
|
||||
];
|
||||
|
||||
var text='';
|
||||
var line=1;
|
||||
var text_size=0;
|
||||
var ptr=0;
|
||||
var token={content:'',type:''};
|
||||
var content={};
|
||||
var init=func(){
|
||||
text='';
|
||||
line=1;
|
||||
text_size=0;
|
||||
ptr=0;
|
||||
content={};
|
||||
token={content:'',type:''};
|
||||
}
|
||||
|
||||
var isnum=func(c){
|
||||
return '0'<=c and c<='9';
|
||||
}
|
||||
var isid=func(c){
|
||||
var tmp=c[0];
|
||||
return ('a'[0]<=tmp and tmp<='z'[0]) or
|
||||
('A'[0]<=tmp and tmp<='Z'[0]) or
|
||||
c=='_';
|
||||
}
|
||||
var check=func(){
|
||||
var c=text[ptr];
|
||||
return (
|
||||
c=='{' or c=='}' or
|
||||
c=='[' or c==']' or
|
||||
c==',' or c==':' or
|
||||
c=='\"' or c=='\'' or
|
||||
isnum(c) or isid(c)
|
||||
);
|
||||
}
|
||||
|
||||
var get=func(str){
|
||||
init();
|
||||
if(!size(str))
|
||||
die("empty string");
|
||||
text=split('',str);
|
||||
text_size=size(text);
|
||||
return;
|
||||
}
|
||||
var next=func(){
|
||||
while(ptr<text_size and !check()){
|
||||
if(text[ptr]=='\n')
|
||||
line+=1;
|
||||
ptr+=1;
|
||||
}
|
||||
if(ptr>=text_size){
|
||||
token.content="eof";
|
||||
token.type=j_eof;
|
||||
return;
|
||||
}
|
||||
|
||||
var c=text[ptr];
|
||||
if(c=='{'){
|
||||
token.content='{';
|
||||
token.type=j_lbrace;
|
||||
}elsif(c=='}'){
|
||||
token.content='}';
|
||||
token.type=j_rbrace;
|
||||
}elsif(c=='['){
|
||||
token.content='[';
|
||||
token.type=j_lbracket;
|
||||
}elsif(c==']'){
|
||||
token.content=']';
|
||||
token.type=j_rbracket;
|
||||
}elsif(c==','){
|
||||
token.content=',';
|
||||
token.type=j_comma;
|
||||
}elsif(c==':'){
|
||||
token.content=':';
|
||||
token.type=j_colon;
|
||||
}elsif(c=='\"' or c=='\''){
|
||||
var strbegin=c;
|
||||
var s="";
|
||||
ptr+=1;
|
||||
while(ptr<text_size and text[ptr]!=strbegin){
|
||||
s~=text[ptr];
|
||||
ptr+=1;
|
||||
}
|
||||
token.content=s;
|
||||
token.type=j_str;
|
||||
}elsif(isnum(c)){
|
||||
var s=c;
|
||||
ptr+=1;
|
||||
while(ptr<text_size and ((isnum(text[ptr]) or text[ptr]=='.'))){
|
||||
s~=text[ptr];
|
||||
ptr+=1;
|
||||
}
|
||||
ptr-=1;
|
||||
token.content=num(s);
|
||||
token.type=j_num;
|
||||
}elsif(isid(c)){
|
||||
var s=c;
|
||||
ptr+=1;
|
||||
while(ptr<text_size and (isid(text[ptr]) or isnum(text[ptr]))){
|
||||
s~=text[ptr];
|
||||
ptr+=1;
|
||||
}
|
||||
ptr-=1;
|
||||
token.content=s;
|
||||
token.type=j_id;
|
||||
}
|
||||
ptr+=1;
|
||||
return;
|
||||
}
|
||||
|
||||
var match=func(type){
|
||||
if(token.type!=type)
|
||||
print("line ",line,": expect ",j_content[type]," but get `",token.content,"`.\n");
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
var hash_gen=func(){
|
||||
var hash={};
|
||||
match(j_lbrace);
|
||||
member(hash);
|
||||
while(token.type==j_comma){
|
||||
match(j_comma);
|
||||
member(hash);
|
||||
}
|
||||
match(j_rbrace);
|
||||
return hash;
|
||||
}
|
||||
|
||||
var vec_gen=func(){
|
||||
var vec=[];
|
||||
match(j_lbracket);
|
||||
if(token.type==j_lbrace){
|
||||
append(vec,hash_gen());
|
||||
}elsif(token.type==j_lbracket){
|
||||
append(vec,vec_gen());
|
||||
}elsif(token.type==j_str or token.type==j_num){
|
||||
append(vec,token.content);
|
||||
next();
|
||||
}
|
||||
while(token.type==j_comma){
|
||||
match(j_comma);
|
||||
if(token.type==j_lbrace){
|
||||
append(vec,me.hash_gen());
|
||||
}elsif(token.type==j_lbracket){
|
||||
append(vec,vec_gen());
|
||||
}elsif(token.type==j_str or token.type==j_num){
|
||||
append(vec,token.content);
|
||||
next();
|
||||
}
|
||||
}
|
||||
match(j_rbracket);
|
||||
return vec;
|
||||
}
|
||||
|
||||
var member=func(hash){
|
||||
var name=token.content;
|
||||
if(token.type==j_rbrace){
|
||||
return;
|
||||
}
|
||||
if(token.type==j_str){
|
||||
match(j_str);
|
||||
}else{
|
||||
match(j_id);
|
||||
}
|
||||
match(j_colon);
|
||||
if(token.type==j_lbrace){
|
||||
hash[name]=hash_gen();
|
||||
}elsif(token.type==j_lbracket){
|
||||
hash[name]=vec_gen();
|
||||
}elsif(token.type==j_str or token.type==j_num){
|
||||
hash[name]=token.content;
|
||||
next();
|
||||
}
|
||||
return;
|
||||
}
|
||||
return {
|
||||
parse:func(str){
|
||||
if(typeof(str)!="str")
|
||||
die("JSON.parse: must use string");
|
||||
get(str);
|
||||
next();
|
||||
|
||||
match(j_lbrace);
|
||||
member(content);
|
||||
while(token.type==j_comma){
|
||||
match(j_comma);
|
||||
member(content);
|
||||
}
|
||||
match(j_rbrace);
|
||||
|
||||
var res=content;
|
||||
init();
|
||||
return res;
|
||||
},
|
||||
stringify:func(hash){
|
||||
if(typeof(hash)!="hash")
|
||||
die("JSON.stringify: must use hashmap");
|
||||
var s="";
|
||||
var gen=func(elem){
|
||||
var t=typeof(elem);
|
||||
if(t=="num"){
|
||||
s~=elem;
|
||||
}elsif(t=="str"){
|
||||
s~='"'~elem~'"';
|
||||
}elsif(t=="vec"){
|
||||
vgen(elem);
|
||||
}elsif(t=="hash"){
|
||||
hgen(elem);
|
||||
}else{
|
||||
s~='"undefined"';
|
||||
}
|
||||
}
|
||||
var vgen=func(v){
|
||||
s~="[";
|
||||
var vsize=size(v);
|
||||
for(var i=0;i<vsize;i+=1){
|
||||
gen(v[i]);
|
||||
if(i!=vsize-1)
|
||||
s~=",";
|
||||
}
|
||||
s~="]";
|
||||
}
|
||||
var hgen=func(h){
|
||||
s~="{";
|
||||
var k=keys(h);
|
||||
var vsize=size(k);
|
||||
for(var i=0;i<vsize;i+=1){
|
||||
s~=k[i]~":";
|
||||
gen(h[k[i]]);
|
||||
if(i!=vsize-1)
|
||||
s~=",";
|
||||
}
|
||||
s~="}";
|
||||
}
|
||||
hgen(hash);
|
||||
return s;
|
||||
}
|
||||
};
|
||||
}();
|
||||
@@ -49,7 +49,7 @@ var id=func(object){
|
||||
return __id(object);
|
||||
}
|
||||
|
||||
# int will get the integer of input number.
|
||||
# int will get the integer of input number/string.
|
||||
# but carefully use it, because int has range between -2147483648~2147483647
|
||||
var int=func(val){
|
||||
return __int(val);
|
||||
@@ -61,6 +61,11 @@ var floor=func(val){
|
||||
return __floor(val);
|
||||
}
|
||||
|
||||
# exit using std::exit
|
||||
var exit=func(val=-1){
|
||||
return __exit(val);
|
||||
}
|
||||
|
||||
# abort using std::abort
|
||||
var abort=func(){
|
||||
__abort();
|
||||
|
||||
20
stl/padding.nas
Normal file
@@ -0,0 +1,20 @@
|
||||
# padding.nas
|
||||
# ValKmjolnir 2022/9/4
|
||||
|
||||
var leftpad=func(s,len,char=" "){
|
||||
if(typeof(s)=="num")
|
||||
s=str(s);
|
||||
var strlen=size(s);
|
||||
for(var i=strlen;i<len;i+=1)
|
||||
s=char~s;
|
||||
return s;
|
||||
}
|
||||
|
||||
var rightpad=func(s,len,char=" "){
|
||||
if(typeof(s)=="num")
|
||||
s=str(s);
|
||||
var strlen=size(s);
|
||||
for(var i=strlen;i<len;i+=1)
|
||||
s~=char;
|
||||
return s;
|
||||
}
|
||||
@@ -4,8 +4,10 @@
|
||||
|
||||
var process_bar={
|
||||
bar:nil,
|
||||
high_resolution_bar:nil,
|
||||
spinner:nil
|
||||
};
|
||||
|
||||
process_bar.bar=func(){
|
||||
var bar={
|
||||
solid_triangle_right:"▶",
|
||||
@@ -62,6 +64,45 @@ process_bar.bar=func(){
|
||||
};
|
||||
};
|
||||
}();
|
||||
|
||||
# return a high resolution progress bar
|
||||
# example:
|
||||
# var bar=process_bar.high_resolution_bar(40);
|
||||
# for(var i=0;i<=1;i+=0.001){
|
||||
# print(bar.bar(i,40),'\r');
|
||||
# unix.sleep(0.001);
|
||||
# }
|
||||
# println();
|
||||
process_bar.high_resolution_bar=func(){
|
||||
var block=["▏","▎","▍","▌","▋","▊","▉","█"];
|
||||
return func(length){
|
||||
return {
|
||||
bar: func(number){
|
||||
if(number>1)
|
||||
number=1;
|
||||
if(number<0)
|
||||
number=0;
|
||||
var block_len=number*length;
|
||||
var complete_block=int(block_len);
|
||||
var decimal=block_len-complete_block;
|
||||
var progress=complete_block+(decimal!=0);
|
||||
var s="|";
|
||||
for(var i=0;i<complete_block;i+=1){
|
||||
s~="█";
|
||||
}
|
||||
if(decimal!=0){
|
||||
s~=block[int(decimal*10)/10*size(block)];
|
||||
}
|
||||
for(var i=0;i<length-progress;i+=1){
|
||||
s~=" ";
|
||||
}
|
||||
s~="|";
|
||||
return s;
|
||||
}
|
||||
};
|
||||
};
|
||||
}();
|
||||
|
||||
process_bar.spinner=func(){
|
||||
var generate_scrolling_spinner=func(s){
|
||||
if(typeof(s)!="str")
|
||||
|
||||
@@ -1,29 +1,23 @@
|
||||
# result.nas
|
||||
# ValKmjolnir 2021
|
||||
|
||||
var ResultTrait={
|
||||
Ok:func(val){
|
||||
me.ok=val;
|
||||
me.flag=0;
|
||||
return me;
|
||||
},
|
||||
Err:func(info){
|
||||
me.err=info;
|
||||
me.flag=1;
|
||||
return me;
|
||||
},
|
||||
unwrap:func(){
|
||||
if(me.flag)
|
||||
die(me.err);
|
||||
return me.ok;
|
||||
}
|
||||
};
|
||||
|
||||
var Result=func(){
|
||||
var (ok,err,flag)=(nil,"",1);
|
||||
return{
|
||||
ok:nil,
|
||||
err:"",
|
||||
flag:1,
|
||||
parents:[ResultTrait]
|
||||
Ok:func(val){
|
||||
ok=val;
|
||||
flag=0;
|
||||
return me;
|
||||
},
|
||||
Err:func(info){
|
||||
err=info;
|
||||
flag=1;
|
||||
return me;
|
||||
},
|
||||
unwrap:func(){
|
||||
if(flag)
|
||||
die(err);
|
||||
return ok;
|
||||
}
|
||||
};
|
||||
};
|
||||
42
stl/sort.nas
@@ -1,18 +1,30 @@
|
||||
# sort.nas
|
||||
# valkmjolnir 2021/4/2
|
||||
var sort=func(vec,left,right,cmp=func(a,b){return a<=b;}){
|
||||
if(left>=right) return nil;
|
||||
var (L,R,tmp)=(left,right,vec[left]);
|
||||
while(left<right){
|
||||
while(left<right and cmp(tmp,vec[right]))
|
||||
right-=1;
|
||||
while(left<right and cmp(vec[left],tmp))
|
||||
left+=1;
|
||||
if(left!=right)
|
||||
(vec[left],vec[right])=(vec[right],vec[left]);
|
||||
|
||||
# please make sure the compare function has the function like <= or >=
|
||||
# only using < or > may cause infinite loop or the program may crash
|
||||
var sort=func(){
|
||||
srand(); # be aware! this causes global changes
|
||||
var quick_sort_core=func(vec,left,right,cmp){
|
||||
if(left>=right) return nil;
|
||||
var base=left+int(rand()*(right-left));
|
||||
(vec[left],vec[base])=(vec[base],vec[left]);
|
||||
var (i,j,tmp)=(left,right,vec[left]);
|
||||
while(i!=j){
|
||||
while(i<j and cmp(tmp,vec[j]))
|
||||
j-=1;
|
||||
vec[i]=vec[j];
|
||||
while(i<j and cmp(vec[i],tmp))
|
||||
i+=1;
|
||||
vec[j]=vec[i];
|
||||
}
|
||||
vec[i]=tmp;
|
||||
quick_sort_core(vec,left,i-1,cmp);
|
||||
quick_sort_core(vec,i+1,right,cmp);
|
||||
return nil;
|
||||
}
|
||||
(vec[L],vec[left])=(vec[left],tmp);
|
||||
sort(vec,L,left-1,cmp);
|
||||
sort(vec,left+1,R,cmp);
|
||||
return nil;
|
||||
}
|
||||
return func(vec,cmp=func(a,b){return a<=b;}){
|
||||
quick_sort_core(vec,0,size(vec)-1,cmp);
|
||||
return nil;
|
||||
}
|
||||
}();
|
||||
9
stl/string.nas
Normal file
@@ -0,0 +1,9 @@
|
||||
# string.nas
|
||||
# ValKmjolnir 2022/10/5
|
||||
|
||||
var join=func(vec){
|
||||
var res="";
|
||||
foreach(var i;vec)
|
||||
res~=i;
|
||||
return res;
|
||||
}
|
||||
@@ -1,31 +1,33 @@
|
||||
import.stl.padding;
|
||||
|
||||
var char_ttf=[
|
||||
[" "," "," "," "," "," "],
|
||||
[" ████╗"," ██╔██║"," ██╔╝██║"," ███████║","██╔═══██║","╚═╝ ╚═╝"],
|
||||
[" █████╗ ","██╔══██╗","███████║","██╔══██║","██║ ██║","╚═╝ ╚═╝"],
|
||||
["██████╗ ","██╔══██╗","██████╔╝","██╔══██╗","██████╔╝","╚═════╝ "],
|
||||
[" ██████╗","██╔════╝","██║ ","██║ ","╚██████╗"," ╚═════╝"],
|
||||
["██████╗ ","██╔══██╗","██║ ██║","██║ ██║","██████╔╝","╚═════╝ "],
|
||||
["███████╗","██╔════╝","█████╗ ","██╔══╝ ","███████╗","╚══════╝"],
|
||||
["███████╗","██╔════╝","█████╗ ","██╔══╝ ","██║ ","╚═╝ "],
|
||||
[" █████╗ ","██╔═══╝ ","██║ ██╗ ","██║ ╚██╗","╚█████╔╝"," ╚════╝ "],
|
||||
[" ██████╗ ","██╔════╝ ","██║ ███╗","██║ ██║","╚██████╔╝"," ╚═════╝ "],
|
||||
["██╗ ██╗","██║ ██║","███████║","██╔══██║","██║ ██║","╚═╝ ╚═╝"],
|
||||
[" ██████╗"," ██╔═╝"," ██║ "," ██║ "," ██████╗"," ╚═════╝"],
|
||||
["██╗","██║","██║","██║","██║","╚═╝"],
|
||||
[" ██╗"," ██║"," ██║","██ ██║","╚█████╔╝"," ╚════╝ "],
|
||||
["██╗ ██╗","██║ ██╔╝","█████╔╝ ","██╔═██╗ ","██║ ██╗","╚═╝ ╚═╝"],
|
||||
["██╗ ","██║ ","██║ ","██║ ","███████╗","╚══════╝"],
|
||||
["██╗ ██╗","███╗ ███║","████████║","██╔██╔██║","██║╚═╝██║","╚═╝ ╚═╝"],
|
||||
["██╗ ██╗","███╗ ██║","█████╗██║","██╔█████║","██║ ╚███║","╚═╝ ╚══╝"],
|
||||
["███╗ ███╗","████╗ ████║","██╔████╔██║","██║╚██╔╝██║","██║ ╚═╝ ██║","╚═╝ ╚═╝"],
|
||||
["███╗ ██╗","████╗ ██║","██╔██╗ ██║","██║╚██╗██║","██║ ╚████║","╚═╝ ╚═══╝"],
|
||||
[" ██████╗ ","██╔═══██╗","██║ ██║","██║ ██║","╚██████╔╝"," ╚═════╝ "],
|
||||
["██████╗ ","██╔══██╗","██████╔╝","██╔═══╝ ","██║ ","╚═╝ "],
|
||||
[" ██████╗ ","██╔═══██╗","██║ ██║","██║ ██╔╝","╚████╔██╗"," ╚═══╝╚═╝"],
|
||||
[" ██████╗ ","██╔═══██╗","██║ ██║","██║▄▄ ██║","╚██████╔╝"," ╚══▀▀═╝ "],
|
||||
["██████╗ ","██╔══██╗","██████╔╝","██╔══██╗","██║ ██║","╚═╝ ╚═╝"],
|
||||
["███████╗","██╔════╝","███████╗","╚════██║","███████║","╚══════╝"],
|
||||
["████████╗","╚══██╔══╝"," ██║ "," ██║ "," ██║ "," ╚═╝ "],
|
||||
["██╗ ██╗","██║ ██║","██║ ██║","██║ ██║","╚██████╔╝"," ╚═════╝ "],
|
||||
["██╗ ██╗","██║ ██║","██║ ██║","╚██╗ ██╔╝"," ╚████╔╝ "," ╚═══╝ "],
|
||||
["██╗ ██╗","██║██╗██║","████████║","███╔═███║","██╔╝ ╚██║","╚═╝ ╚═╝"],
|
||||
["██╗ ██╗","██║ ██║","██║ █╗ ██║","██║███╗██║","╚███╔███╔╝"," ╚══╝╚══╝ "],
|
||||
["██╗ ██╗","╚██╗██╔╝"," ╚███╔╝ "," ██╔██╗ ","██╔╝╚██╗","╚═╝ ╚═╝"],
|
||||
["██╗ ██╗","╚██╗ ██╔╝"," ╚████╔╝ "," ╚██╔╝ "," ██║ "," ╚═╝ "],
|
||||
["████████╗","╚════██╔╝"," ██╔═╝ "," ██╔═╝ ","████████╗","╚═══════╝"],
|
||||
["███████╗","╚══███╔╝"," ███╔╝ "," ███╔╝ ","███████╗","╚══════╝"],
|
||||
];
|
||||
var trans_ttf=func(string){
|
||||
var str=["","","","","",""];
|
||||
@@ -45,49 +47,38 @@ var trans_ttf=func(string){
|
||||
println(i);
|
||||
return;
|
||||
}
|
||||
var curve1=func(){
|
||||
var shadow=["░","▒","▓","█","▀","▄","▐","▌"];
|
||||
rand(100);
|
||||
var s="";
|
||||
for(var i=0;i<10;i+=1){
|
||||
for(var j=0;j<40;j+=1)
|
||||
s~=shadow[int(8*rand())];
|
||||
s~='\n';
|
||||
}
|
||||
print(s);
|
||||
}
|
||||
var curve2=func(){
|
||||
var curve1=func(line=4){
|
||||
var table=["╚","═","╝","╔","║","╗"];
|
||||
rand(100);
|
||||
var s="";
|
||||
for(var i=0;i<10;i+=1){
|
||||
for(var j=0;j<40;j+=1)
|
||||
for(var i=0;i<line;i+=1){
|
||||
for(var j=0;j<45;j+=1)
|
||||
s~=table[int(6*rand())];
|
||||
s~='\n';
|
||||
}
|
||||
print(s);
|
||||
}
|
||||
var curve3=func(){
|
||||
var s=["","","","","",""];
|
||||
var cnt=0;
|
||||
foreach(var char;char_ttf){
|
||||
cnt+=1;
|
||||
forindex(var i;char)
|
||||
s[i]~=char[i];
|
||||
if(cnt==9){
|
||||
forindex(var i;s){
|
||||
println(s[i]);
|
||||
s[i]='';
|
||||
}
|
||||
cnt=0;
|
||||
}
|
||||
var curve2=func(line=2){
|
||||
var shadow=["░","▒","▓","█","▀","▄","▐","▌"];
|
||||
rand(100);
|
||||
var s="";
|
||||
for(var i=0;i<line;i+=1){
|
||||
for(var j=0;j<45;j+=1)
|
||||
s~=shadow[int(8*rand())];
|
||||
s~='\n';
|
||||
}
|
||||
return;
|
||||
print(s);
|
||||
}
|
||||
var curve4=func(){
|
||||
var arr=[0,1,2,3,4,5,6,7,8,0,1,2,3,4,5,6,7,8,0,1,2,3,4,5,6,7,8];
|
||||
for(var loop=0;loop<10;loop+=1){
|
||||
for(var i=26;i>=0;i-=1){
|
||||
var curve3=func(line=2){
|
||||
var arr=[
|
||||
0,1,2,3,4,5,6,7,8,
|
||||
0,1,2,3,4,5,6,7,8,
|
||||
0,1,2,3,4,5,6,7,8,
|
||||
0,1,2,3,4,5,6,7,8,
|
||||
0,1,2,3,4,5,6,7,8
|
||||
];
|
||||
for(var loop=0;loop<line;loop+=1){
|
||||
for(var i=size(arr)-1;i>=0;i-=1){
|
||||
var rand_index=int(i*rand());
|
||||
(arr[i],arr[rand_index])=(arr[rand_index],arr[i]);
|
||||
}
|
||||
@@ -100,19 +91,7 @@ var curve4=func(){
|
||||
}
|
||||
return;
|
||||
}
|
||||
var curve5=func(){
|
||||
for(var i=0;i<=9;i+=1)
|
||||
println(i,"\e["~i~"mh \e[0m");
|
||||
for(var i=30;i<=37;i+=1)
|
||||
println(i,"\e["~i~"mh \e[0m");
|
||||
for(var i=40;i<=47;i+=1)
|
||||
println(i,"\e["~i~"mh \e[0m");
|
||||
for(var i=90;i<=97;i+=1)
|
||||
println(i,"\e["~i~"mh \e[0m");
|
||||
for(var i=100;i<=107;i+=1)
|
||||
println(i,"\e["~i~"mh \e[0m");
|
||||
}
|
||||
var curve6=func(){
|
||||
var curve4=func(line=4){
|
||||
var shadow=["m░\e[0m","m▒\e[0m","m▓\e[0m","m█\e[0m","m▀\e[0m","m▄\e[0m","m▐\e[0m","m▌\e[0m"];
|
||||
var front=[
|
||||
"30","31","32","33","34","35","36","37",
|
||||
@@ -123,31 +102,47 @@ var curve6=func(){
|
||||
"100","101","102","103","104","105","106","107"
|
||||
];
|
||||
rand(time(0));
|
||||
for(var i=0;i<15;i+=1){
|
||||
for(var i=0;i<line;i+=1){
|
||||
for(var j=0;j<45;j+=1)
|
||||
print("\e["~front[16*rand()]~";"~back[16*rand()]~shadow[8*rand()]);
|
||||
print('\n');
|
||||
}
|
||||
}
|
||||
var curve7=func(){
|
||||
var curve5=func(line=4){
|
||||
var vec=["▀▄─","▄▀─","▀─▄","▄─▀"];
|
||||
for(var (y,p)=(0,0);y!=6;y+=1){
|
||||
for(var x=0;x!=16;x+=1)
|
||||
for(var (y,p)=(0,0);y!=line;y+=1){
|
||||
for(var x=0;x!=15;x+=1)
|
||||
print(vec[p]);
|
||||
print("\n");
|
||||
p+=1;
|
||||
p=p>=4?0:p;
|
||||
}
|
||||
}
|
||||
var ansi_escape_sequence=func(){
|
||||
for(var i=0;i<=9;i+=1)
|
||||
print(rightpad(i,3),":\e["~i~"mhi\e[0m ");
|
||||
print("\n");
|
||||
for(var i=30;i<=37;i+=1)
|
||||
print(rightpad(i,3),":\e["~i~"mhi\e[0m ");
|
||||
print("\n");
|
||||
for(var i=40;i<=47;i+=1)
|
||||
print(rightpad(i,3),":\e["~i~"mhi\e[0m ");
|
||||
print("\n");
|
||||
for(var i=90;i<=97;i+=1)
|
||||
print(rightpad(i,3),":\e["~i~"mhi\e[0m ");
|
||||
print("\n");
|
||||
for(var i=100;i<=107;i+=1)
|
||||
print(rightpad(i,3),":\e["~i~"mhi\e[0m ");
|
||||
print("\n");
|
||||
}
|
||||
|
||||
# enable unicode
|
||||
if(os.platform()=="windows")
|
||||
system("chcp 65001");
|
||||
trans_ttf("just for test");
|
||||
trans_ttf(" ValKmjolnir ");
|
||||
trans_ttf("just for fun");
|
||||
curve1();
|
||||
curve2();
|
||||
curve3();
|
||||
curve4();
|
||||
curve5();
|
||||
curve6();
|
||||
curve7();
|
||||
ansi_escape_sequence();
|
||||
|
||||
20
test/bf.nas
@@ -150,8 +150,20 @@ var (ptr,pc)=(0,0);
|
||||
var (code,inum,stack,char)=([],[],[],[]);
|
||||
var (add,mov,jt,jf,in,out)=(0,1,2,3,4,5);
|
||||
setsize(char,256);
|
||||
forindex(var i;char)
|
||||
char[i]=chr(i);
|
||||
|
||||
var color=[
|
||||
"\e[31m","\e[32m","\e[33m","\e[34m","\e[35m","\e[36m",
|
||||
"\e[90m","\e[91m","\e[92m","\e[93m","\e[94m","\e[95m","\e[96m"
|
||||
];
|
||||
func(){
|
||||
var cnt=0;
|
||||
forindex(var i;char){
|
||||
char[i]=color[cnt]~chr(i)~"\e[0m";
|
||||
cnt+=1;
|
||||
if(cnt>12)
|
||||
cnt=0;
|
||||
}
|
||||
}();
|
||||
|
||||
var funcs=[
|
||||
func{paper[ptr]+=inum[pc];},
|
||||
@@ -221,6 +233,10 @@ var bf=func(program){
|
||||
die("lack ]");
|
||||
return;
|
||||
}
|
||||
|
||||
# enable ANSI escape sequence
|
||||
if(os.platform()=="windows")
|
||||
system("color");
|
||||
len=size(code);
|
||||
for(pc=0;pc<len;pc+=1)
|
||||
funcs[code[pc]]();
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
var mandelbrot=
|
||||
"[A mandelbrot set fractal viewer in brainf*** written by Erik Bosman]
|
||||
+++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++++++++[[
|
||||
>>>>>>>>>]+[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-]>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+
|
||||
<<<<<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>>+>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
>+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+[>>>>>>[>>>>>>>[-]>>]<<<<<<<<<[<<<<<<<<<]>>
|
||||
>>>>>[-]+<<<<<<++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<+++++++[-[->>>
|
||||
>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[[-]>>>>>>[>>>>>
|
||||
>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>
|
||||
[>>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<
|
||||
<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>+++++++++++++++[[
|
||||
>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[
|
||||
>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[
|
||||
-<<+>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<
|
||||
<<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<
|
||||
[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>
|
||||
>>>>[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+
|
||||
<<<<<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>
|
||||
>>>>>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<
|
||||
+>>>>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<
|
||||
<]<+<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>
|
||||
>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<
|
||||
<<<]>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<
|
||||
<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->
|
||||
>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<
|
||||
<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]<<<<<<<[->+>>>-<<<<]>>>>>>>>>+++++++++++++++++++
|
||||
+++++++>>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>[<<<<<<<+<[-<+>>>>+<<[-]]>[-<<[->+>>>-
|
||||
<<<<]>>>]>>>>>>>>>>>>>[>>[-]>[-]>[-]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>>>>>>[>>>>>
|
||||
[-<<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>[-<<<<<<<<
|
||||
<+>>>>>>>>>]>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>>]+>[-
|
||||
]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>>>>>>>]<<<
|
||||
<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+>>]<
|
||||
<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[->>>>
|
||||
>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-]<->>>
|
||||
[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[>>>>>>[-<
|
||||
<<<<+>>>>>]<<<<<[->>>>>+<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>+>>>>>>>>
|
||||
]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+
|
||||
>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>
|
||||
[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-
|
||||
]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>>
|
||||
[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++
|
||||
+++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-<<<<<<<+
|
||||
>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[
|
||||
-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>>]>[-<<<<<<[->>>>>+<++<<<<]>>>>>[-<
|
||||
<<<<+>>>>>]<->+>]<[->+<]<<<<<[->>>>>+<<<<<]>>>>>>[-]<<<<<<+>>>>[-<<<<->>>>]+<<<<
|
||||
[->>>>->>>>>[>>[-<<->>]+<<[->>->[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]
|
||||
+>>>>>>[>>>>>>>>>]>+<]]+>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<<<<<<<<<<[<<<<<
|
||||
<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<
|
||||
[<<<<<<<<<]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<
|
||||
<<<+<[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<
|
||||
<<<<<+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<
|
||||
<<<<<<<<<<]>>>>[-]<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+<]>>>>>>>>]<<<
|
||||
<<<<<+<[>[->>>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>[->>>>+<<<<]>]<[->>>>-<<<<<<<
|
||||
<<<<<<<+>>>>>>>>>>]<]>>[->>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>>+<<<<
|
||||
]<<<<<<<<<<<]>>>>>>+<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>>>>>>>>>]<<<<<<<<<
|
||||
[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<<<<<<
|
||||
+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<<<<<<
|
||||
<<<<<]]>[-]>>[-]>[-]>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<
|
||||
<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[
|
||||
[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+
|
||||
[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>
|
||||
[-<<+>>]<<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<
|
||||
<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[
|
||||
>[-]<->>>[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[
|
||||
>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>
|
||||
>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>[-]>>>>+++++++++++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<
|
||||
<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<
|
||||
<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-
|
||||
<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>
|
||||
>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>>>
|
||||
[-<<<->>>]<<<[->>>+<<<]>>>>>>>>]<<<<<<<<+<[>[->+>[-<-<<<<<<<<<<+>>>>>>>>>>>>[-<<
|
||||
+>>]<]>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<<<]>>[-<+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<]>
|
||||
[-<<+>>]<<<<<<<<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>
|
||||
>>>>>>]<<<<<<<<+<[>[->+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>[-<+>]>]<[-<-<<<<<<<<<<+>>>>
|
||||
>>>>>>>]<<]>>>[-<<+>[-<-<<<<<<<<<<+>>>>>>>>>>>]>]<[-<+>]<<<<<<<<<<<<]>>>>>+<<<<<
|
||||
]>>>>>>>>>[>>>[-]>[-]>[-]>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>>>[-<<<<<
|
||||
<+>>>>>>]<<<<<<[->>>>>>+<<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>
|
||||
>]>>[-<<<<<<<[->>>>>+<++<<<<]>>>>>[-<<<<<+>>>>>]<->+>>]<<[->>+<<]<<<<<[->>>>>+<<
|
||||
<<<]+>>>>[-<<<<->>>>]+<<<<[->>>>->>>>>[>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<
|
||||
<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>[-<<->>]+<<[->>->[-<<<+>>>]<
|
||||
<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<
|
||||
<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+
|
||||
<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>[->>>+<<<]>]<[->>>-
|
||||
<<<<<<<<<<<<<+>>>>>>>>>>]<]>>[->>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>+<<<
|
||||
]<<<<<<<<<<<]>>>>>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]]>>>>[-<<<<+>
|
||||
>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<<[->>>-
|
||||
<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[
|
||||
->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<<<<<]]>>>>[-]<<<<]>>>>[-<<<<+>>
|
||||
>>]<<<<[->>>>+>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>[>>>>>>
|
||||
>>>]<<<<<<<<<[>[->>>>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<
|
||||
<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<
|
||||
<<<<]]>>>>>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>[-<<<<+
|
||||
>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<+>>>>>
|
||||
]<<<<<[->>>>>+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>
|
||||
>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>
|
||||
>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[-<<+
|
||||
>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>
|
||||
[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-
|
||||
]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>>
|
||||
[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<
|
||||
<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>
|
||||
>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<+>>>
|
||||
>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+
|
||||
<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>
|
||||
>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>
|
||||
>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<<<<]
|
||||
>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<<
|
||||
]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->>>+<
|
||||
<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>
|
||||
>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>->>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>]<<+>>>>[-<<<<
|
||||
->>>>]+<<<<[->>>>-<<<<<<.>>]>>>>[-<<<<<<<.>>>>>>>]<<<[-]>[-]>[-]>[-]>[-]>[-]>>>[
|
||||
>[-]>[-]>[-]>[-]>[-]>[-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-]>>>>]<<<<<<<<<
|
||||
[<<<<<<<<<]>+++++++++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+>>>>>>>>>+<<<<<<<<
|
||||
<<<<<<[<<<<<<<<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+[-]>>[>>>>>>>>>]<<<<<
|
||||
<<<<[>>>>>>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<[<<<<<<<<<]>>>>>>>[-]+>>>]<<<<
|
||||
<<<<<<]]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+>>[>+>>>>[-<<<<->>>>]<<<<[->>>
|
||||
>+<<<<]>>>>>>>>]<<+<<<<<<<[>>>>>[->>+<<]<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<
|
||||
<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<<<<<[->>>>>>+<<<<<<]<
|
||||
+<<<<<<<<<]>>>>>>>-<<<<[-]+<<<]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>->>[>>
|
||||
>>>[->>+<<]>>>>]<<<<<<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<
|
||||
<<<<[->>>>>>+<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+<<<
|
||||
<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<<<<<->>>>>]+<<<<<[->>>>>->>[-<<<<<<<+>>>>>>>]<<<<
|
||||
<<<[->>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>[-<
|
||||
<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<<<<<<<<<[<<<
|
||||
<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<
|
||||
<<[<<<<<<<<<]>>>>[-]<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>-<<<<<[<<<<<<<
|
||||
<<]]>>>]<<<<.>>>>>>>>>>[>>>>>>[-]>>>]<<<<<<<<<[<<<<<<<<<]>++++++++++[-[->>>>>>>>
|
||||
>+<<<<<<<<<]>>>>>>>>>]>>>>>+>>>>>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-<<<<<<
|
||||
<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+[-]>[>>>>>>>>>]<<<<<<<<<[>>>>>>>>[-<<<<<<<+>>>>>>
|
||||
>]<<<<<<<[->>>>>>>+<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+>>]<<<<<<<<<<]]>>>>>>>>[-<<<<<
|
||||
<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+>[>+>>>>>[-<<<<<->>>>>]<<<<<[->>>>>+<<<<<]>>>>>>
|
||||
>>]<+<<<<<<<<[>>>>>>[->>+<<]<<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-]<-
|
||||
>>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<]<+<<<<<<
|
||||
<<<]>>>>>>>>-<<<<<[-]+<<<]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>->[>>>
|
||||
>>>[->>+<<]>>>]<<<<<<<<<[>[-]<->>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<
|
||||
<<<<<[->>>>>>>+<<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>
|
||||
+>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<->>>>>>]+<
|
||||
<<<<<[->>>>>>->>[-<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<<
|
||||
<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>
|
||||
-<<[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>
|
||||
>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<<<++++
|
||||
+[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>->>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<[<<<<
|
||||
<<<<<]]>>>]";
|
||||
|
||||
var paper=[];
|
||||
var (ptr,pc)=(0,0);
|
||||
var (code,inum,stack,char)=([],[],[],[]);
|
||||
var (add,mov,jt,jf,in,out)=(0,1,2,3,4,5);
|
||||
setsize(char,256);
|
||||
|
||||
var color=[
|
||||
"\e[31m","\e[32m","\e[33m","\e[34m","\e[35m","\e[36m",
|
||||
"\e[90m","\e[91m","\e[92m","\e[93m","\e[94m","\e[95m","\e[96m"
|
||||
];
|
||||
func(){
|
||||
var cnt=0;
|
||||
forindex(var i;char){
|
||||
char[i]=color[cnt]~chr(i)~"\e[0m";
|
||||
cnt+=1;
|
||||
if(cnt>12)
|
||||
cnt=0;
|
||||
}
|
||||
}();
|
||||
|
||||
var funcs=[
|
||||
func{paper[ptr]+=inum[pc];},
|
||||
func{ptr+=inum[pc];},
|
||||
func{if(paper[ptr])pc=inum[pc];},
|
||||
func{if(!paper[ptr])pc=inum[pc];},
|
||||
func{paper[ptr]=input()[0];},
|
||||
func{print(char[paper[ptr]]);}
|
||||
];
|
||||
|
||||
var bf=func(program){
|
||||
setsize(paper,131072);
|
||||
var len=size(program);
|
||||
for(var i=0;i<len;i+=1){
|
||||
var c=chr(program[i]);
|
||||
if(c=='+' or c=='-'){
|
||||
append(code,add);
|
||||
append(inum,0);
|
||||
for(;i<len;i+=1){
|
||||
if(chr(program[i])=='+')
|
||||
inum[-1]+=1;
|
||||
elsif(chr(program[i])=='-')
|
||||
inum[-1]-=1;
|
||||
elsif(chr(program[i])!='\n'){
|
||||
i-=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif(c=='<' or c=='>'){
|
||||
append(code,mov);
|
||||
append(inum,0);
|
||||
for(;i<len;i+=1){
|
||||
if(chr(program[i])=='>')
|
||||
inum[-1]+=1;
|
||||
elsif(chr(program[i])=='<')
|
||||
inum[-1]-=1;
|
||||
elsif(chr(program[i])!='\n'){
|
||||
i-=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif(c==','){
|
||||
append(code,in);
|
||||
append(inum,0);
|
||||
}
|
||||
elsif(c=='.'){
|
||||
append(code,out);
|
||||
append(inum,0);
|
||||
}
|
||||
elsif(c=='['){
|
||||
append(code,jf);
|
||||
append(inum,0);
|
||||
append(stack,size(code)-1);
|
||||
}
|
||||
elsif(c==']'){
|
||||
if(!size(stack))
|
||||
die("lack [");
|
||||
var label=pop(stack);
|
||||
append(code,jt);
|
||||
append(inum,label-1);
|
||||
inum[label]=size(code)-2;
|
||||
}
|
||||
}
|
||||
if(size(stack)){
|
||||
die("lack ]");
|
||||
return;
|
||||
}
|
||||
len=size(code);
|
||||
for(pc=0;pc<len;pc+=1)
|
||||
funcs[code[pc]]();
|
||||
return;
|
||||
}
|
||||
|
||||
bf(mandelbrot);
|
||||
@@ -53,7 +53,8 @@ var bfs=func(begin,end){
|
||||
return;
|
||||
}
|
||||
|
||||
# enable ANSI escape sequence
|
||||
if(os.platform()=="windows")
|
||||
system("chcp 65001");
|
||||
system("color");
|
||||
print("\ec");
|
||||
bfs([0,0],[9,19]);
|
||||
10
test/bp.nas
@@ -26,7 +26,7 @@ var diffsigmoid=func(x){
|
||||
return x*(1-x);
|
||||
}
|
||||
|
||||
var (inum,hnum,onum)=(2,4,1);
|
||||
var (inum,hnum,onum)=(2,5,1);
|
||||
var training_set=[[0,0],[0,1],[1,0],[1,1]];
|
||||
var expect=[0,1,1,0];
|
||||
|
||||
@@ -112,8 +112,14 @@ while(error>0.0005){
|
||||
backward(i);
|
||||
}
|
||||
cnt+=1;
|
||||
if(cnt>=3e5)
|
||||
break;
|
||||
}
|
||||
if(cnt>=3e5){
|
||||
print("failed to train, ",cnt," epoch.\n");
|
||||
}else{
|
||||
print('finished after ',cnt,' epoch.\n');
|
||||
}
|
||||
print('finished after ',cnt,' epoch.\n');
|
||||
foreach(var v;training_set){
|
||||
run(v);
|
||||
print(v,': ',output[0].out,'\n');
|
||||
|
||||
191
test/calc.nas
@@ -1,92 +1,103 @@
|
||||
import.stl.padding;
|
||||
|
||||
var source=[
|
||||
"main.cpp ",
|
||||
"nasal_ast.h ",
|
||||
"nasal_builtin.h ",
|
||||
"nasal_codegen.h ",
|
||||
"nasal_dbg.h ",
|
||||
"nasal_err.h ",
|
||||
"nasal_gc.h ",
|
||||
"nasal_import.h ",
|
||||
"nasal_lexer.h ",
|
||||
"nasal_opt.h ",
|
||||
"nasal_parse.h ",
|
||||
"nasal_vm.h ",
|
||||
"nasal.h "
|
||||
"main.cpp",
|
||||
"nasal_ast.h",
|
||||
"nasal_builtin.h",
|
||||
"nasal_codegen.h",
|
||||
"nasal_dbg.h",
|
||||
"nasal_err.h",
|
||||
"nasal_gc.h",
|
||||
"nasal_import.h",
|
||||
"nasal_lexer.h",
|
||||
"nasal_opt.h",
|
||||
"nasal_parse.h",
|
||||
"nasal_vm.h",
|
||||
"nasal.h"
|
||||
];
|
||||
|
||||
var lib=[
|
||||
"fg_env.nas ",
|
||||
"file.nas ",
|
||||
"lib.nas ",
|
||||
"list.nas ",
|
||||
"log.nas ",
|
||||
"module.nas ",
|
||||
"process_bar.nas ",
|
||||
"queue.nas ",
|
||||
"result.nas ",
|
||||
"sort.nas ",
|
||||
"stack.nas "
|
||||
"fg_env.nas",
|
||||
"file.nas",
|
||||
"json.nas",
|
||||
"lib.nas",
|
||||
"list.nas",
|
||||
"log.nas",
|
||||
"module.nas",
|
||||
"padding.nas",
|
||||
"process_bar.nas",
|
||||
"queue.nas",
|
||||
"result.nas",
|
||||
"sort.nas",
|
||||
"stack.nas",
|
||||
"string.nas"
|
||||
];
|
||||
|
||||
var testfile=[
|
||||
"ascii-art.nas ",
|
||||
"auto_crash.nas ",
|
||||
"bf.nas ",
|
||||
"bfcolored.nas ",
|
||||
"bfconvertor.nas ",
|
||||
"bfs.nas ",
|
||||
"bigloop.nas ",
|
||||
"bp.nas ",
|
||||
"calc.nas ",
|
||||
"choice.nas ",
|
||||
"class.nas ",
|
||||
"coroutine.nas ",
|
||||
"diff.nas ",
|
||||
"exception.nas ",
|
||||
"fib.nas ",
|
||||
"filesystem.nas ",
|
||||
"hexdump.nas ",
|
||||
"httptest.nas ",
|
||||
"json.nas ",
|
||||
"leetcode1319.nas ",
|
||||
"lexer.nas ",
|
||||
"life.nas ",
|
||||
"loop.nas ",
|
||||
"mandel.nas ",
|
||||
"mandelbrot.nas ",
|
||||
"md5.nas ",
|
||||
"md5compare.nas ",
|
||||
"module_test.nas ",
|
||||
"nasal_test.nas ",
|
||||
"occupation.nas ",
|
||||
"pi.nas ",
|
||||
"prime.nas ",
|
||||
"qrcode.nas ",
|
||||
"quick_sort.nas ",
|
||||
"scalar.nas ",
|
||||
"snake.nas ",
|
||||
"tetris.nas ",
|
||||
"trait.nas ",
|
||||
"ascii-art.nas",
|
||||
"auto_crash.nas",
|
||||
"bf.nas",
|
||||
"bfconvertor.nas",
|
||||
"bfs.nas",
|
||||
"bigloop.nas",
|
||||
"bp.nas",
|
||||
"calc.nas",
|
||||
"choice.nas",
|
||||
"class.nas",
|
||||
"coroutine.nas",
|
||||
"diff.nas",
|
||||
"exception.nas",
|
||||
"fib.nas",
|
||||
"filesystem.nas",
|
||||
"hexdump.nas",
|
||||
"httptest.nas",
|
||||
"json.nas",
|
||||
"leetcode1319.nas",
|
||||
"lexer.nas",
|
||||
"life.nas",
|
||||
"loop.nas",
|
||||
"mandel.nas",
|
||||
"mandelbrot.nas",
|
||||
"mcpu.nas",
|
||||
"md5.nas",
|
||||
"md5compare.nas",
|
||||
"module_test.nas",
|
||||
"nasal_test.nas",
|
||||
"occupation.nas",
|
||||
"pi.nas",
|
||||
"ppmgen.nas",
|
||||
"prime.nas",
|
||||
"qrcode.nas",
|
||||
"quick_sort.nas",
|
||||
"scalar.nas",
|
||||
"snake.nas",
|
||||
"tetris.nas",
|
||||
"trait.nas",
|
||||
"turingmachine.nas",
|
||||
"utf8chk.nas ",
|
||||
"wavecollapse.nas ",
|
||||
"ycombinator.nas "
|
||||
"utf8chk.nas",
|
||||
"watchdog.nas",
|
||||
"wavecollapse.nas",
|
||||
"word_collector.nas",
|
||||
"ycombinator.nas"
|
||||
];
|
||||
|
||||
var module=[
|
||||
"fib.cpp ",
|
||||
"keyboard.cpp ",
|
||||
"nasocket.cpp ",
|
||||
"libfib.nas ",
|
||||
"libkey.nas ",
|
||||
"libsock.nas "
|
||||
"fib.cpp",
|
||||
"keyboard.cpp",
|
||||
"nasocket.cpp",
|
||||
"libfib.nas",
|
||||
"libkey.nas",
|
||||
"libsock.nas"
|
||||
];
|
||||
|
||||
var getname=func(s){
|
||||
var (len,ch)=(size(s),' '[0]);
|
||||
for(var i=0;i<len and s[i]!=ch;i+=1);
|
||||
return substr(s,0,i);
|
||||
var longest=func(vec...){
|
||||
var len=0;
|
||||
foreach(var v;vec)
|
||||
foreach(var f;v)
|
||||
len=size(f)>len?size(f):len;
|
||||
return len;
|
||||
}
|
||||
var padding_length=longest(source,lib,testfile,module);
|
||||
|
||||
var count=func(s,c){
|
||||
var cnt=0;
|
||||
@@ -95,21 +106,37 @@ var count=func(s,c){
|
||||
return cnt;
|
||||
}
|
||||
|
||||
var column=func(number){
|
||||
number=number>=1000?substr(str(number/1000),0,3)~'k':str(number);
|
||||
return rightpad(number,6);
|
||||
}
|
||||
|
||||
var calc=func(codetype,files,path=""){
|
||||
println(codetype);
|
||||
var (bytes,line,semi,line_cnt,semi_cnt)=(0,0,0,0,0);
|
||||
var (bytes,ctx,line,semi,line_cnt,semi_cnt)=(0,"",0,0,0,0);
|
||||
forindex(var i;files){
|
||||
var s=io.fin(getname(path~files[i]));
|
||||
var s=io.exists(path~files[i])?io.fin(path~files[i]):"";
|
||||
(line_cnt,semi_cnt)=(count(s,'\n'),count(s,';'));
|
||||
println(files[i],'| ',line_cnt,'\tline | ',semi_cnt,' \tsemi');
|
||||
println(rightpad(files[i],padding_length),'| ',
|
||||
column(line_cnt),'line | ',
|
||||
column(semi_cnt),'semi | ',
|
||||
rightpad(str(int(size(s)/1024)),6),'kb | ',
|
||||
md5(s),' |');
|
||||
bytes+=size(s);
|
||||
ctx~=s;
|
||||
line+=line_cnt;
|
||||
semi+=semi_cnt;
|
||||
}
|
||||
println('total: | ',line,'\tline | ',semi,' \tsemi');
|
||||
println(' | ',int(bytes/1024),'\tkb');
|
||||
println(rightpad("total:",padding_length),'| ',
|
||||
column(line),'line | ',
|
||||
column(semi),'semi | ',
|
||||
rightpad(str(int(bytes/1024)),6),'kb | ',
|
||||
md5(ctx),' |\n');
|
||||
return int(bytes/1024);
|
||||
}
|
||||
|
||||
var all=calc("source code:",source)+calc("lib:",lib,"stl/")+calc("test file:",testfile,"test/")+calc("module:",module,"module/");
|
||||
println('\ntotal: | ',all,'\tkb');
|
||||
var all=calc("source code:",source)
|
||||
+calc("lib:",lib,"stl/")
|
||||
+calc("test file:",testfile,"test/")
|
||||
+calc("module:",module,"module/");
|
||||
println(rightpad("total:",padding_length),'| ',rightpad(str(all),6),'kb');
|
||||
@@ -12,11 +12,11 @@ var fib=func(){
|
||||
}
|
||||
return;
|
||||
}
|
||||
# different coroutines don't share the same local scope
|
||||
var co=[coroutine.create(fib),coroutine.create(fib)];
|
||||
for(var i=0;i<45;i+=1){
|
||||
var res=[coroutine.resume(co[0]),coroutine.resume(co[1])];
|
||||
println('co[0]: ',res[0]==nil?nil:res[0][0],'\nco[1]: ',res[1]==nil?nil:res[1][0]);
|
||||
if(res[0]==nil or res[1]==nil or res[0][0]!=res[1][0])
|
||||
die("different coroutines don't share the same local scope");
|
||||
}
|
||||
|
||||
# test if coroutine can get upvalues
|
||||
@@ -28,30 +28,69 @@ func(){
|
||||
x+=1;
|
||||
}
|
||||
});
|
||||
for(var i=0;i<16;i+=1)
|
||||
println(coroutine.resume(co));
|
||||
for(var i=0;i<16;i+=1){
|
||||
var res=coroutine.resume(co);
|
||||
if(res==nil or res[0]!=x or res[1]!=i)
|
||||
die("coroutine should have the ability to get upvalues");
|
||||
}
|
||||
}();
|
||||
|
||||
# test crash in coroutines
|
||||
var co=coroutine.create(func{
|
||||
var b=func(){b()}
|
||||
coroutine.yield(b);
|
||||
b();
|
||||
coroutine.yield(0);
|
||||
});
|
||||
|
||||
println("coroutine yield: ",coroutine.resume(co));
|
||||
println("coroutine state:\e[32m ",coroutine.status(co),"\e[0m");
|
||||
println("coroutine error: ",coroutine.resume(co));
|
||||
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
|
||||
println("coroutine yield: ",coroutine.resume(co));
|
||||
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
|
||||
|
||||
var co=coroutine.create(func{
|
||||
var a=1;
|
||||
var b=func(){
|
||||
b();
|
||||
}
|
||||
coroutine.yield(b);
|
||||
coroutine.yield(b());
|
||||
});
|
||||
|
||||
println("coroutine yield: ",coroutine.resume(co));
|
||||
println("coroutine state:\e[32m ",coroutine.status(co),"\e[0m");
|
||||
println("coroutine error: ",coroutine.resume(co));
|
||||
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
|
||||
println("coroutine yield: ",coroutine.resume(co));
|
||||
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
|
||||
println("ok");
|
||||
|
||||
# pressure test
|
||||
var productor=func(){
|
||||
for(var i=0;;i+=1)
|
||||
coroutine.yield(i);
|
||||
}
|
||||
var total=4000; # ms
|
||||
var total=1000; # ms
|
||||
var co=coroutine.create(productor);
|
||||
var tm=maketimestamp();
|
||||
|
||||
if(os.platform()=="windows"){
|
||||
system("chcp 65001");
|
||||
system("color");
|
||||
}
|
||||
var counter=0;
|
||||
var bar=process_bar.bar("block","point","line",40);
|
||||
var bar=process_bar.high_resolution_bar(40);
|
||||
var consumer=func(){
|
||||
counter+=1;
|
||||
for(var i=0;i<5;i+=1)
|
||||
coroutine.resume(co);
|
||||
var rate=(tm.elapsedMSec()+1)/total;
|
||||
print(bar.bar(rate)," ",rate*100,"% \r");
|
||||
print(bar.bar(rate)," ",rate*100,"% \r");
|
||||
}
|
||||
|
||||
tm.stamp();
|
||||
while(tm.elapsedMSec()<total)
|
||||
consumer();
|
||||
println("\nexecute ",counter," tasks during ",total," ms, avg ",counter/total," tasks/ms.")
|
||||
println("\nexecute ",counter," tasks during ",total," ms, avg ",counter/total," tasks/ms.");
|
||||
|
||||
@@ -119,6 +119,6 @@ func(diff){
|
||||
print("\n");
|
||||
diff(
|
||||
io.fin("test/bf.nas"),
|
||||
io.fin("test/bfcolored.nas")
|
||||
io.fin("test/bfconvertor.nas")
|
||||
);
|
||||
}(myers);
|
||||
@@ -1,8 +1,8 @@
|
||||
var fib=func(x)
|
||||
{
|
||||
if(x<2) return x;
|
||||
return fib(x-1)+fib(x-2);
|
||||
if(x<2) return x;
|
||||
return fib(x-1)+fib(x-2);
|
||||
}
|
||||
for(var i=0;i<31;i+=1)
|
||||
print(fib(i),'\n');
|
||||
print(fib(i),'\n');
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
var fd=io.open("test/filesystem.nas");
|
||||
while((var line=io.readln(fd))!=nil)
|
||||
println(line);
|
||||
io.close(fd);
|
||||
println(io.stat("test/filesystem.nas"));
|
||||
|
||||
var files=func(dir){
|
||||
var dd=unix.opendir(dir);
|
||||
var files=func(path){
|
||||
if(!io.exists(path))
|
||||
return [];
|
||||
var dd=unix.opendir(path);
|
||||
var res=[];
|
||||
while(var n=unix.readdir(dd))
|
||||
append(res,n);
|
||||
@@ -22,17 +18,20 @@ var prt=func(s,path){
|
||||
foreach(var j;s)
|
||||
print("\e[34m",j,"\e[0m");
|
||||
if(unix.isdir(path~"/"~f)){
|
||||
println("\e[34m",i==last?"└─":"├─","\e[0m\e[36m",f," >\e[0m");
|
||||
append(s,i==last?" ":"│ ");
|
||||
println("\e[34m",i==last?" └─":" ├─","\e[0m\e[33m[",f,"]\e[36m>\e[0m");
|
||||
append(s,i==last?" ":" │ ");
|
||||
prt(s,path~"/"~f);
|
||||
pop(s);
|
||||
}elsif(unix.isfile(path~"/"~f)){
|
||||
println("\e[34m",i==last?"└─":"├─","\e[0m\e[32m",f,"\e[0m");
|
||||
println("\e[34m",i==last?" └─":" ├─","\e[0m\e[32m",f,"\e[0m");
|
||||
}else{
|
||||
println("\e[34m",i==last?"└─":"├─","\e[0m\e[91m",f,"\e[0m");
|
||||
println("\e[34m",i==last?" └─":" ├─","\e[0m\e[91m",f,"\e[0m");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println("\e[36mNasal-Interpreter >\e[0m");
|
||||
# enable unicode
|
||||
if(os.platform()=="windows")
|
||||
system("chcp 65001");
|
||||
println("\e[33m[",unix.getcwd(),"]\e[36m>\e[0m");
|
||||
prt([""],".");
|
||||
@@ -5,7 +5,10 @@ var http=func(){
|
||||
return {
|
||||
establish:func(ip,port){
|
||||
sd=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.IPPROTO_IP);
|
||||
socket.bind(sd,ip,port);
|
||||
if(socket.bind(sd,ip,port)<0){
|
||||
println("failed to bind socket "~sd~" at IP: "~ip~" port: "~port~".");
|
||||
return;
|
||||
}
|
||||
socket.listen(sd,1);
|
||||
println("[",os.time(),"] start server at [",ip,":",port,"]");
|
||||
},
|
||||
@@ -40,7 +43,6 @@ var http=func(){
|
||||
}();
|
||||
http.establish("127.0.0.1",8080);
|
||||
|
||||
|
||||
var highlight_style="
|
||||
<style>
|
||||
body{
|
||||
@@ -308,10 +310,10 @@ while(1){
|
||||
break;
|
||||
}
|
||||
elsif(path=="/favicon.ico")
|
||||
http.send(client,respond.ok(io.fin("./pic/favicon.ico")));
|
||||
http.send(client,respond.ok(io.fin("./doc/pic/favicon.ico")));
|
||||
elsif(path=="/license")
|
||||
http.send(client,respond.ok(io.fin("./LICENSE")));
|
||||
elsif(path=="/pic/nasal.png" or path=="/pic/benchmark.png" or path=="/pic/mandelbrot.png")
|
||||
elsif(path=="/doc/pic/nasal.png" or path=="/doc/pic/benchmark.png" or path=="/doc/pic/mandelbrot.png")
|
||||
http.send(client,respond.ok(io.fin("."~path)));
|
||||
else{
|
||||
var filename=substr(path,1,size(path)-1);
|
||||
|
||||
276
test/json.nas
@@ -1,278 +1,4 @@
|
||||
#lib json.nas
|
||||
var JSON=func(){
|
||||
|
||||
var (
|
||||
j_eof,
|
||||
j_lbrace,
|
||||
j_rbrace,
|
||||
j_lbracket,
|
||||
j_rbracket,
|
||||
j_comma,
|
||||
j_colon,
|
||||
j_str,
|
||||
j_num,
|
||||
j_id
|
||||
)=(
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9
|
||||
);
|
||||
var j_content=[
|
||||
"eof",
|
||||
"`{`",
|
||||
"`}`",
|
||||
"`[`",
|
||||
"`]`",
|
||||
"`,`",
|
||||
"`:`",
|
||||
"string",
|
||||
"number",
|
||||
"identifier"
|
||||
];
|
||||
|
||||
var text='';
|
||||
var line=1;
|
||||
var text_size=0;
|
||||
var ptr=0;
|
||||
var token={content:'',type:''};
|
||||
var content={};
|
||||
var init=func(){
|
||||
line=1;
|
||||
text_size=0;
|
||||
ptr=0;
|
||||
content={};
|
||||
token={content:'',type:''};
|
||||
text='';
|
||||
}
|
||||
|
||||
var isnum=func(c){
|
||||
return '0'<=c and c<='9';
|
||||
}
|
||||
var isid=func(c){
|
||||
var tmp=c[0];
|
||||
return ('a'[0]<=tmp and tmp<='z'[0]) or
|
||||
('A'[0]<=tmp and tmp<='Z'[0]) or
|
||||
c=='_';
|
||||
}
|
||||
var check=func(){
|
||||
var c=text[ptr];
|
||||
return (
|
||||
c=='{' or c=='}' or
|
||||
c=='[' or c==']' or
|
||||
c==',' or c==':' or
|
||||
c=='\"' or c=='\'' or
|
||||
isnum(c) or isid(c)
|
||||
);
|
||||
}
|
||||
|
||||
var get=func(str){
|
||||
init();
|
||||
if(!size(str))
|
||||
die("empty string");
|
||||
text=split('',str);
|
||||
text_size=size(text);
|
||||
return;
|
||||
}
|
||||
var next=func(){
|
||||
while(ptr<text_size and !check()){
|
||||
if(text[ptr]=='\n')
|
||||
line+=1;
|
||||
ptr+=1;
|
||||
}
|
||||
if(ptr>=text_size){
|
||||
token.content="eof";
|
||||
token.type=j_eof;
|
||||
return;
|
||||
}
|
||||
|
||||
var c=text[ptr];
|
||||
if(c=='{'){
|
||||
token.content='{';
|
||||
token.type=j_lbrace;
|
||||
}elsif(c=='}'){
|
||||
token.content='}';
|
||||
token.type=j_rbrace;
|
||||
}elsif(c=='['){
|
||||
token.content='[';
|
||||
token.type=j_lbracket;
|
||||
}elsif(c==']'){
|
||||
token.content=']';
|
||||
token.type=j_rbracket;
|
||||
}elsif(c==','){
|
||||
token.content=',';
|
||||
token.type=j_comma;
|
||||
}elsif(c==':'){
|
||||
token.content=':';
|
||||
token.type=j_colon;
|
||||
}elsif(c=='\"' or c=='\''){
|
||||
var strbegin=c;
|
||||
var s="";
|
||||
ptr+=1;
|
||||
while(ptr<text_size and text[ptr]!=strbegin){
|
||||
s~=text[ptr];
|
||||
ptr+=1;
|
||||
}
|
||||
token.content=s;
|
||||
token.type=j_str;
|
||||
}elsif(isnum(c)){
|
||||
var s=c;
|
||||
ptr+=1;
|
||||
while(ptr<text_size and ((isnum(text[ptr]) or text[ptr]=='.'))){
|
||||
s~=text[ptr];
|
||||
ptr+=1;
|
||||
}
|
||||
ptr-=1;
|
||||
token.content=num(s);
|
||||
token.type=j_num;
|
||||
}elsif(isid(c)){
|
||||
var s=c;
|
||||
ptr+=1;
|
||||
while(ptr<text_size and (isid(text[ptr]) or isnum(text[ptr]))){
|
||||
s~=text[ptr];
|
||||
ptr+=1;
|
||||
}
|
||||
ptr-=1;
|
||||
token.content=s;
|
||||
token.type=j_id;
|
||||
}
|
||||
ptr+=1;
|
||||
return;
|
||||
}
|
||||
|
||||
var match=func(type){
|
||||
if(token.type!=type)
|
||||
print("line ",line,": expect ",j_content[type]," but get `",token.content,"`.\n");
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
var hash_gen=func(){
|
||||
var hash={};
|
||||
match(j_lbrace);
|
||||
member(hash);
|
||||
while(token.type==j_comma){
|
||||
match(j_comma);
|
||||
member(hash);
|
||||
}
|
||||
match(j_rbrace);
|
||||
return hash;
|
||||
}
|
||||
|
||||
var vec_gen=func(){
|
||||
var vec=[];
|
||||
match(j_lbracket);
|
||||
if(token.type==j_lbrace)
|
||||
append(vec,hash_gen());
|
||||
elsif(token.type==j_lbracket)
|
||||
append(vec,vec_gen());
|
||||
elsif(token.type==j_str or token.type==j_num){
|
||||
append(vec,token.content);
|
||||
next();
|
||||
}
|
||||
while(token.type==j_comma){
|
||||
match(j_comma);
|
||||
if(token.type==j_lbrace)
|
||||
append(vec,me.hash_gen());
|
||||
elsif(token.type==j_lbracket)
|
||||
append(vec,vec_gen());
|
||||
elsif(token.type==j_str or token.type==j_num){
|
||||
append(vec,token.content);
|
||||
next();
|
||||
}
|
||||
}
|
||||
match(j_rbracket);
|
||||
return vec;
|
||||
}
|
||||
|
||||
var member=func(hash){
|
||||
var name=token.content;
|
||||
if(token.type==j_rbrace)
|
||||
return;
|
||||
if(token.type==j_str)
|
||||
match(j_str);
|
||||
else
|
||||
match(j_id);
|
||||
match(j_colon);
|
||||
if(token.type==j_lbrace)
|
||||
hash[name]=hash_gen();
|
||||
elsif(token.type==j_lbracket)
|
||||
hash[name]=vec_gen();
|
||||
elsif(token.type==j_str or token.type==j_num){
|
||||
hash[name]=token.content;
|
||||
next();
|
||||
}
|
||||
return;
|
||||
}
|
||||
return {
|
||||
parse:func(str){
|
||||
if(typeof(str)!="str")
|
||||
die("JSON.parse: must use string");
|
||||
get(str);
|
||||
next();
|
||||
|
||||
match(j_lbrace);
|
||||
member(content);
|
||||
while(token.type==j_comma){
|
||||
match(j_comma);
|
||||
member(content);
|
||||
}
|
||||
match(j_rbrace);
|
||||
|
||||
var res=content;
|
||||
init();
|
||||
return res;
|
||||
},
|
||||
stringify:func(hash){
|
||||
if(typeof(hash)!="hash")
|
||||
die("JSON.stringify: must use hashmap");
|
||||
var s="";
|
||||
var gen=func(elem){
|
||||
var t=typeof(elem);
|
||||
if(t=="num")
|
||||
s~=elem;
|
||||
elsif(t=="str")
|
||||
s~='"'~elem~'"';
|
||||
elsif(t=="vec")
|
||||
vgen(elem);
|
||||
elsif(t=="hash")
|
||||
hgen(elem);
|
||||
else
|
||||
s~='"undefined"';
|
||||
}
|
||||
var vgen=func(v){
|
||||
s~="[";
|
||||
var vsize=size(v);
|
||||
for(var i=0;i<vsize;i+=1){
|
||||
gen(v[i]);
|
||||
if(i!=vsize-1)
|
||||
s~=",";
|
||||
}
|
||||
s~="]";
|
||||
}
|
||||
var hgen=func(h){
|
||||
s~="{";
|
||||
var k=keys(h);
|
||||
var vsize=size(k);
|
||||
for(var i=0;i<vsize;i+=1){
|
||||
s~=k[i]~":";
|
||||
gen(h[k[i]]);
|
||||
if(i!=vsize-1)
|
||||
s~=",";
|
||||
}
|
||||
s~="}";
|
||||
}
|
||||
hgen(hash);
|
||||
return s;
|
||||
}
|
||||
};
|
||||
}();
|
||||
import.stl.json;
|
||||
|
||||
var ss=JSON.stringify({
|
||||
vec:[0,1,2],
|
||||
|
||||
@@ -29,8 +29,9 @@ var prt=func()
|
||||
}
|
||||
|
||||
func(){
|
||||
# enable ANSI escape sequence
|
||||
if(os.platform()=="windows")
|
||||
system("chcp 65001");
|
||||
system("color");
|
||||
print("\ec");
|
||||
rand(time(0));
|
||||
map=new_map();
|
||||
|
||||
172
test/mcpu.nas
Normal file
@@ -0,0 +1,172 @@
|
||||
var inst={
|
||||
inst_stop:0,
|
||||
inst_mov_reg_reg:1,
|
||||
inst_mov_reg_imm_low:2,
|
||||
inst_mov_reg_imm_high:3,
|
||||
inst_add:4,
|
||||
inst_sub:5,
|
||||
inst_mult:6,
|
||||
inst_div:7,
|
||||
inst_and:8,
|
||||
inst_or:9,
|
||||
inst_xor:10,
|
||||
inst_not:11,
|
||||
inst_nand:12,
|
||||
inst_shl:13,
|
||||
inst_shr:14,
|
||||
inst_jmp:15,
|
||||
inst_jt:16,
|
||||
inst_jf:17,
|
||||
inst_les:18,
|
||||
inst_grt:19,
|
||||
inst_leq:20,
|
||||
inst_geq:21,
|
||||
inst_eq:22,
|
||||
inst_in:23,
|
||||
inst_out:24
|
||||
};
|
||||
|
||||
var hex=func(){
|
||||
var vec=[];
|
||||
foreach(var i;['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'])
|
||||
foreach(var j;['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'])
|
||||
append(vec,i~j);
|
||||
return func(n){
|
||||
return vec[n];
|
||||
}
|
||||
}();
|
||||
|
||||
var hex32=func(n){
|
||||
return hex(bits.u32_and(n/math.pow(2,24),0xff))~
|
||||
hex(bits.u32_and(n/math.pow(2,16),0xff))~
|
||||
hex(bits.u32_and(n/math.pow(2,8),0xff))~
|
||||
hex(bits.u32_and(n,0xff));
|
||||
}
|
||||
|
||||
var machine=func(disk_file){
|
||||
|
||||
var reg=[];
|
||||
var reg_size=32;
|
||||
var pc=0;
|
||||
var ir=[0,0,0,0]; # 32 bit instruction word
|
||||
var mem=[];
|
||||
var mem_size=1024*1024*1; # memory size, byte
|
||||
var init=func(){
|
||||
println("[",os.time(),"] init ",reg_size," registers.");
|
||||
setsize(reg,reg_size); # 8 bit address wire
|
||||
for(var i=0;i<reg_size;i+=1)
|
||||
reg[i]=0;
|
||||
println("[",os.time(),"] init memory, memory size: ",mem_size/1024/1024,"MB.");
|
||||
setsize(mem,mem_size);
|
||||
for(var i=0;i<mem_size;i+=1)
|
||||
mem[i]=0;
|
||||
println("[",os.time(),"] init completed.");
|
||||
}
|
||||
init();
|
||||
var load=func(){
|
||||
var vec=split(" ",disk_file);
|
||||
println("[",os.time(),"] loading boot from disk: ",size(vec)," byte.");
|
||||
forindex(var i;vec)
|
||||
mem[i]=int("0x"~vec[i]);
|
||||
println("[",os.time(),"] loading complete.");
|
||||
}
|
||||
load();
|
||||
var ctx_info=func(){
|
||||
var cnt=0;
|
||||
println("pc : 0x",hex32(pc));
|
||||
println("instr : 0x",hex(ir[0]),hex(ir[1]),hex(ir[2]),hex(ir[3]));
|
||||
for(var i=0;i<reg_size;i+=1){
|
||||
print("reg[",hex(i),"]: 0x",hex32(reg[i])," ");
|
||||
if(cnt==3){
|
||||
print("\n");
|
||||
cnt=0;
|
||||
}else{
|
||||
cnt+=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
var exec=func(info=1){
|
||||
while(1){
|
||||
ir=[mem[pc],mem[pc+1],mem[pc+2],mem[pc+3]];
|
||||
if(info)ctx_info();
|
||||
var op=ir[0];
|
||||
if(op==inst.inst_stop){
|
||||
break;
|
||||
}elsif(op==inst.inst_mov_reg_reg){
|
||||
reg[ir[1]]=reg[ir[2]];
|
||||
}elsif(op==inst.inst_mov_reg_imm_low){
|
||||
reg[ir[1]]=bits.u32_and(reg[ir[1]],0xffff0000);
|
||||
reg[ir[1]]=bits.u32_or(reg[ir[1]],ir[2]*math.pow(2,8)+ir[3]);
|
||||
}elsif(op==inst.inst_mov_reg_imm_high){
|
||||
reg[ir[1]]=bits.u32_and(reg[ir[1]],0x0000ffff);
|
||||
reg[ir[1]]=bits.u32_or(reg[ir[1]],ir[2]*math.pow(2,24)+ir[3]*math.pow(2,16));
|
||||
}elsif(op==inst.inst_add){
|
||||
reg[ir[1]]=bits.u32_and(reg[ir[2]]+reg[ir[3]],0xffffffff);
|
||||
}elsif(op==inst.inst_sub){
|
||||
reg[ir[1]]=bits.u32_and(reg[ir[2]]-reg[ir[3]],0xffffffff);
|
||||
}elsif(op==inst.inst_mult){
|
||||
reg[ir[1]]=bits.u32_and(reg[ir[2]]*reg[ir[3]],0xffffffff);
|
||||
}elsif(op==inst.inst_div){
|
||||
reg[ir[1]]=bits.u32_and(reg[ir[2]]/reg[ir[3]],0xffffffff);
|
||||
}elsif(op==inst.inst_and){
|
||||
reg[ir[1]]=bits.u32_and(reg[ir[2]],reg[ir[3]]);
|
||||
}elsif(op==inst.inst_or){
|
||||
reg[ir[1]]=bits.u32_or(reg[ir[2]],reg[ir[3]]);
|
||||
}elsif(op==inst.inst_xor){
|
||||
reg[ir[1]]=bits.u32_xor(reg[ir[2]],reg[ir[3]]);
|
||||
}elsif(op==inst.inst_not){
|
||||
reg[ir[1]]=bits.u32_not(reg[ir[2]]);
|
||||
}elsif(op==inst.inst_nand){
|
||||
reg[ir[1]]=bits.u32_nand(reg[ir[2]],reg[ir[3]]);
|
||||
}elsif(op==inst.inst_shl){
|
||||
reg[ir[1]]=bits.u32_and(reg[ir[2]]*math.pow(2,reg[ir[3]]),0xffffffff);
|
||||
}elsif(op==inst.inst_shr){
|
||||
reg[ir[1]]=bits.u32_and(reg[ir[2]]/math.pow(2,reg[ir[3]]),0xffffffff);
|
||||
}elsif(op==inst.inst_jmp){
|
||||
pc=reg[ir[1]];
|
||||
}elsif(op==inst.inst_jt){
|
||||
pc=reg[ir[1]]?reg[ir[2]]:pc;
|
||||
}elsif(op==inst.inst_jf){
|
||||
pc=reg[ir[1]]?pc:reg[ir[2]];
|
||||
}elsif(op==inst.inst_les){
|
||||
reg[ir[1]]=reg[ir[2]]<reg[ir[3]];
|
||||
}elsif(op==inst.inst_grt){
|
||||
reg[ir[1]]=reg[ir[2]]>reg[ir[3]];
|
||||
}elsif(op==inst.inst_leq){
|
||||
reg[ir[1]]=reg[ir[2]]<=reg[ir[3]];
|
||||
}elsif(op==inst.inst_geq){
|
||||
reg[ir[1]]=reg[ir[2]]>=reg[ir[3]];
|
||||
}elsif(op==inst.inst_eq){
|
||||
reg[ir[1]]=reg[ir[2]]==reg[ir[3]];
|
||||
}elsif(op==inst.inst_in){
|
||||
reg[0]=0; # unfinished
|
||||
}elsif(op==inst.inst_out){
|
||||
println("reg[",ir[1],"]: 0x",hex32(reg[ir[1]]));
|
||||
}
|
||||
pc+=4;
|
||||
}
|
||||
};
|
||||
return {exec:exec};
|
||||
}(
|
||||
hex(inst.inst_mov_reg_imm_high)~" 01 ca fe "~ # reg[1]=0xcafe0000
|
||||
hex(inst.inst_mov_reg_imm_low)~" 01 ba be "~ # reg[1]=0xcafebabe
|
||||
hex(inst.inst_out)~" 01 00 00 "~ # output reg[1]
|
||||
hex(inst.inst_mov_reg_imm_low)~" 02 00 20 "~ # reg[2]=0x10
|
||||
hex(inst.inst_jmp)~" 02 00 00 "~ # jmp *reg[2]
|
||||
hex(inst.inst_out)~" 01 00 00 "~
|
||||
hex(inst.inst_out)~" 01 00 00 "~
|
||||
hex(inst.inst_out)~" 01 00 00 "~
|
||||
hex(inst.inst_out)~" 01 00 00 "~
|
||||
hex(inst.inst_out)~" 01 00 00 "~ # should jump here
|
||||
hex(inst.inst_jf)~" 01 02 00 "~ # should not jump
|
||||
hex(inst.inst_mov_reg_imm_low)~" 03 00 04 "~ # reg[3]=4
|
||||
hex(inst.inst_mov_reg_imm_low)~" 04 00 00 "~ # reg[4]=0
|
||||
hex(inst.inst_out)~" 04 00 00 "~ # output reg[4]
|
||||
hex(inst.inst_grt)~" 00 04 03 "~ # reg[0]=reg[4]>reg[3]
|
||||
hex(inst.inst_mov_reg_imm_low)~" 05 00 30 "~ # reg[5]=0x2c
|
||||
hex(inst.inst_mov_reg_imm_low)~" 06 00 01 "~ # reg[6]=1
|
||||
hex(inst.inst_add)~" 04 04 06 "~ # reg[4]+=reg[6]
|
||||
hex(inst.inst_jf)~" 00 05 00 " # jmp *reg[5] if reg[0]!=true
|
||||
);
|
||||
|
||||
machine.exec(0);
|
||||
@@ -13,7 +13,7 @@ var compare=func(){
|
||||
var total=end-begin;
|
||||
var timestamp=maketimestamp();
|
||||
timestamp.stamp();
|
||||
var bar=process_bar.bar(front:os.platform()=="windows"?"sharp":"block",back:"point",sep:"line",length:50);
|
||||
var bar=process_bar.high_resolution_bar(40);
|
||||
for(var i=begin;i<end;i+=1){
|
||||
var s="";
|
||||
for(var j=0;j<i;j+=1){
|
||||
@@ -24,7 +24,7 @@ var compare=func(){
|
||||
if(cmp(res,_md5(s))){
|
||||
die("error: "~str(i));
|
||||
}
|
||||
print(" ",bar.bar((i-begin+1)/total)," (",i-begin+1,"/",total,")\t",res," byte: ",byte," elapsed time: ",timestamp.elapsedMSec()," \r");
|
||||
print(" ",bar.bar((i-begin+1)/total)," (",i-begin+1,"/",total,")\t",res," byte: ",byte," time: ",timestamp.elapsedMSec()," \r");
|
||||
}
|
||||
print("\n");
|
||||
};
|
||||
@@ -32,47 +32,52 @@ var compare=func(){
|
||||
|
||||
var filechecksum=func(){
|
||||
var files=[
|
||||
"./stl/fg_env.nas", "./stl/file.nas",
|
||||
"./stl/lib.nas", "./stl/list.nas",
|
||||
"./stl/log.nas", "./stl/module.nas",
|
||||
"./stl/process_bar.nas", "./stl/queue.nas",
|
||||
"./stl/result.nas", "./stl/sort.nas",
|
||||
"./stl/stack.nas", "./test/ascii-art.nas",
|
||||
"./test/auto_crash.nas", "./test/bf.nas",
|
||||
"./test/bfcolored.nas", "./test/bfconvertor.nas",
|
||||
"./test/bfs.nas", "./test/bigloop.nas",
|
||||
"./test/bp.nas", "./test/calc.nas",
|
||||
"./test/choice.nas", "./test/class.nas",
|
||||
"./test/coroutine.nas", "./test/diff.nas",
|
||||
"./test/exception.nas", "./test/fib.nas",
|
||||
"./test/filesystem.nas", "./test/hexdump.nas",
|
||||
"./test/httptest.nas", "./test/json.nas",
|
||||
"./test/leetcode1319.nas", "./test/lexer.nas",
|
||||
"./test/life.nas", "./test/loop.nas",
|
||||
"./test/mandel.nas", "./test/mandelbrot.nas",
|
||||
"./test/md5.nas", "./test/md5compare.nas",
|
||||
"./test/module_test.nas", "./test/nasal_test.nas",
|
||||
"./test/occupation.nas", "./test/pi.nas",
|
||||
"./test/prime.nas", "./test/qrcode.nas",
|
||||
"./test/quick_sort.nas", "./test/scalar.nas",
|
||||
"./test/snake.nas", "./test/tetris.nas",
|
||||
"./test/trait.nas", "./test/turingmachine.nas",
|
||||
"./test/utf8chk.nas", "./test/wavecollapse.nas",
|
||||
"./test/ycombinator.nas", "LICENSE",
|
||||
"main.cpp", "makefile",
|
||||
"nasal_ast.h", "nasal_builtin.h",
|
||||
"nasal_codegen.h", "nasal_dbg.h",
|
||||
"nasal_err.h", "nasal_gc.h",
|
||||
"nasal_import.h", "nasal_lexer.h",
|
||||
"nasal_opt.h", "nasal_parse.h",
|
||||
"nasal_vm.h", "nasal.ebnf",
|
||||
"nasal.h", "README.md"
|
||||
"./stl/fg_env.nas", "./stl/file.nas",
|
||||
"./stl/json.nas",
|
||||
"./stl/lib.nas", "./stl/list.nas",
|
||||
"./stl/log.nas", "./stl/module.nas",
|
||||
"./stl/padding.nas", "./stl/process_bar.nas",
|
||||
"./stl/queue.nas", "./stl/result.nas",
|
||||
"./stl/sort.nas", "./stl/stack.nas",
|
||||
"./stl/string.nas",
|
||||
"./test/ascii-art.nas", "./test/auto_crash.nas",
|
||||
"./test/bf.nas", "./test/bfconvertor.nas",
|
||||
"./test/bfs.nas", "./test/bigloop.nas",
|
||||
"./test/bp.nas", "./test/calc.nas",
|
||||
"./test/choice.nas", "./test/class.nas",
|
||||
"./test/coroutine.nas", "./test/diff.nas",
|
||||
"./test/exception.nas", "./test/fib.nas",
|
||||
"./test/filesystem.nas", "./test/hexdump.nas",
|
||||
"./test/httptest.nas", "./test/json.nas",
|
||||
"./test/leetcode1319.nas", "./test/lexer.nas",
|
||||
"./test/life.nas", "./test/loop.nas",
|
||||
"./test/mandel.nas", "./test/mandelbrot.nas",
|
||||
"./test/mcpu.nas",
|
||||
"./test/md5.nas", "./test/md5compare.nas",
|
||||
"./test/module_test.nas", "./test/nasal_test.nas",
|
||||
"./test/occupation.nas", "./test/pi.nas",
|
||||
"./test/ppmgen.nas", "./test/prime.nas",
|
||||
"./test/qrcode.nas", "./test/quick_sort.nas",
|
||||
"./test/scalar.nas", "./test/snake.nas",
|
||||
"./test/tetris.nas", "./test/trait.nas",
|
||||
"./test/turingmachine.nas", "./test/utf8chk.nas",
|
||||
"./test/watchdog.nas", "./test/wavecollapse.nas",
|
||||
"./test/word_collector.nas",
|
||||
"./test/ycombinator.nas", "LICENSE",
|
||||
"main.cpp", "makefile",
|
||||
"nasal_ast.h", "nasal_builtin.h",
|
||||
"nasal_codegen.h", "nasal_dbg.h",
|
||||
"nasal_err.h", "nasal_gc.h",
|
||||
"nasal_import.h", "nasal_lexer.h",
|
||||
"nasal_opt.h", "nasal_parse.h",
|
||||
"nasal_vm.h", "nasal.ebnf",
|
||||
"nasal.h", "README.md"
|
||||
];
|
||||
var byte=0;
|
||||
var total=size(files);
|
||||
var timestamp=maketimestamp();
|
||||
timestamp.stamp();
|
||||
var bar=process_bar.bar(front:os.platform()=="windows"?"sharp":"block",back:"point",sep:"line",length:50);
|
||||
var bar=process_bar.high_resolution_bar(40);
|
||||
forindex(var i;files){
|
||||
var f=io.fin(files[i]);
|
||||
var res=md5(f);
|
||||
@@ -80,7 +85,7 @@ var filechecksum=func(){
|
||||
if(cmp(res,_md5(f))){
|
||||
die("error: "~files[i]);
|
||||
}
|
||||
print(" ",bar.bar((i+1)/total)," (",i+1,"/",total,")\t",res," byte: ",byte," elapsed time: ",timestamp.elapsedMSec()," \r");
|
||||
print(" ",bar.bar((i+1)/total)," (",i+1,"/",total,")\t",res," byte: ",byte," time: ",timestamp.elapsedMSec()," \r");
|
||||
}
|
||||
print("\n");
|
||||
}
|
||||
@@ -90,5 +95,7 @@ var randomchecksum=func(){
|
||||
compare(i,i+512);
|
||||
}
|
||||
|
||||
if(os.platform()=="windows")
|
||||
system("chcp 65001");
|
||||
filechecksum();
|
||||
randomchecksum();
|
||||
@@ -16,14 +16,20 @@ var cpu_stat=func(){
|
||||
};
|
||||
return cpu;
|
||||
}
|
||||
|
||||
var cpu_occupation=func(){
|
||||
var cpu0=cpu_stat();
|
||||
unix.sleep(0.5);
|
||||
var cpu1=cpu_stat();
|
||||
var t0=cpu0.user+cpu0.nice+cpu0.system+cpu0.idle+cpu0.iowait+cpu0.irq+cpu0.softirq;
|
||||
var t1=cpu1.user+cpu1.nice+cpu1.system+cpu1.idle+cpu1.iowait+cpu1.irq+cpu1.softirq;
|
||||
var interval=cpu1.idle-cpu0.idle;
|
||||
return t0==t1?0:(1-interval/(t1-t0))*100;
|
||||
while(1){
|
||||
var cpu0=cpu_stat();
|
||||
for(var i=0;i<5;i+=1){
|
||||
unix.sleep(0.1);
|
||||
coroutine.yield(nil);
|
||||
}
|
||||
var cpu1=cpu_stat();
|
||||
var t0=cpu0.user+cpu0.nice+cpu0.system+cpu0.idle+cpu0.iowait+cpu0.irq+cpu0.softirq;
|
||||
var t1=cpu1.user+cpu1.nice+cpu1.system+cpu1.idle+cpu1.iowait+cpu1.irq+cpu1.softirq;
|
||||
var interval=cpu1.idle-cpu0.idle;
|
||||
coroutine.yield(t0==t1?0:(1-interval/(t1-t0))*100);
|
||||
}
|
||||
}
|
||||
|
||||
var mem_occupation=func(){
|
||||
@@ -36,24 +42,28 @@ var mem_occupation=func(){
|
||||
}
|
||||
return mem_res;
|
||||
}
|
||||
|
||||
func(){
|
||||
if(os.platform()=="windows"){
|
||||
println("haven't supported yet.");
|
||||
return;
|
||||
}
|
||||
var co=coroutine.create(cpu_occupation);
|
||||
var bar=process_bar.high_resolution_bar(30);
|
||||
print("\ec");
|
||||
while(1){
|
||||
var mem=mem_occupation();
|
||||
var mem_occ=(mem.MemTotal-mem.MemFree)/mem.MemTotal*100;
|
||||
var cpu_occ=cpu_occupation();
|
||||
var key=libkey.nonblock();
|
||||
var bar=process_bar.bar("block","point","line",25);
|
||||
if(key!=nil and chr(key)=="q")
|
||||
break;
|
||||
println("\e[1;1H Memory total(GB) : \e[36m",mem.MemTotal/1024/1024,"\e[0m");
|
||||
println("\e[2;1H Memory free(GB) : \e[36m",mem.MemFree/1024/1024,"\e[0m");
|
||||
println("\e[3;1H Memory occupation(%): ",mem_occ>60?"\e[91m":"\e[32m",bar.bar(mem_occ/100)~" ",mem_occ,"\e[0m ");
|
||||
println("\e[4;1H CPU occupation(%) : ",cpu_occ>90?"\e[91m":"\e[32m",bar.bar(cpu_occ/100)~" ",cpu_occ,"\e[0m ");
|
||||
var cpu_occ=nil;
|
||||
while((cpu_occ=coroutine.resume(co)[0])==nil){
|
||||
var key=libkey.nonblock();
|
||||
if(key!=nil and chr(key)=="q")
|
||||
return;
|
||||
}
|
||||
println("\e[1;1H\e[1m Memory total(GB) : \e[0m\e[36m",mem.MemTotal/1024/1024,"\e[0m");
|
||||
println("\e[2;1H\e[1m Memory free(GB) : \e[0m\e[36m",mem.MemFree/1024/1024,"\e[0m");
|
||||
println("\e[3;1H\e[1m Memory occupation(%): \e[0m",mem_occ>60?"\e[91m":"\e[32m",bar.bar(mem_occ/100)~" ",mem_occ,"\e[0m ");
|
||||
println("\e[4;1H\e[1m CPU occupation(%) : \e[0m",cpu_occ>90?"\e[91m":"\e[32m",bar.bar(cpu_occ/100)~" ",cpu_occ,"\e[0m ");
|
||||
println("\e[5;1H Press 'q' to quit.");
|
||||
}
|
||||
}();
|
||||
39
test/ppmgen.nas
Normal file
@@ -0,0 +1,39 @@
|
||||
import.stl.process_bar;
|
||||
|
||||
var ppm=func(filename,width,height,RGB){
|
||||
# P3 use ASCII number
|
||||
# P6 use binary character
|
||||
var fd=io.open(filename,"wb");
|
||||
io.write(fd,"P3\n"~width~" "~height~"\n255\n");
|
||||
for(var i=0;i<height;i+=1){
|
||||
for(var j=0;j<width;j+=1)
|
||||
io.write(fd,RGB(i,j));
|
||||
io.write(fd,"\n");
|
||||
}
|
||||
io.close(fd);
|
||||
}
|
||||
|
||||
var width=1280;
|
||||
var height=720;
|
||||
var bar=(os.platform()=="windows")?
|
||||
process_bar.bar(front:"sharp",back:"point",sep:"line",length:50):
|
||||
process_bar.high_resolution_bar(50);
|
||||
var f=func(i,j){
|
||||
var (yMin,yMax,xMin,xMax)=(-1.35,1.35,-3.3,1.5);
|
||||
var (yDel,xDel)=(yMax-yMin,xMax-xMin);
|
||||
var (y,x)=((i/height)*yDel+yMin,(j/width)*xDel+xMin);
|
||||
var (x0,y0)=(x,y);
|
||||
for(var iter=0;iter<25;iter+=1){
|
||||
var (x1,y1)=((x0*x0)-(y0*y0)+x,2*x0*y0+y);
|
||||
(x0,y0)=(x1,y1);
|
||||
if((x0*x0)+(y0*y0)>4){
|
||||
break;
|
||||
}
|
||||
}
|
||||
var progress=(i*width+j+1)/(width*height);
|
||||
print(bar.bar(progress)," ",progress*100,"% \r");
|
||||
iter=iter==25?255:int(iter/25*255);
|
||||
return iter~" "~iter~" "~iter~" ";
|
||||
}
|
||||
ppm("a.ppm",width,height,f);
|
||||
println("\nfinished.");
|
||||
@@ -22,6 +22,7 @@ var code=[
|
||||
[1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
|
||||
];
|
||||
|
||||
# enable unicode
|
||||
if(os.platform()=="windows")
|
||||
system("chcp 65001");
|
||||
var texture=[" ","██"];
|
||||
|
||||
@@ -1,22 +1,7 @@
|
||||
var sort=func(vec,left,right){
|
||||
if(left>=right) return;
|
||||
var (L,R,tmp)=(left,right,vec[left]);
|
||||
while(left<right){
|
||||
while(left<right and tmp<=vec[right])
|
||||
right-=1;
|
||||
while(left<right and tmp>=vec[left])
|
||||
left+=1;
|
||||
if(left!=right)
|
||||
(vec[left],vec[right])=(vec[right],vec[left]);
|
||||
}
|
||||
(vec[L],vec[left])=(vec[left],tmp);
|
||||
sort(vec,L,left-1);
|
||||
sort(vec,left+1,R);
|
||||
return;
|
||||
}
|
||||
var vec=[];
|
||||
rand(time(0));
|
||||
for(var i=0;i<1e4;i+=1)
|
||||
append(vec,int(rand()*1e5));
|
||||
sort(vec,0,size(vec)-1);
|
||||
import.stl.sort;
|
||||
var vec=[];
|
||||
rand(time(0));
|
||||
for(var i=0;i<1e4;i+=1)
|
||||
append(vec,int(rand()*1e5));
|
||||
sort(vec);
|
||||
println(vec);
|
||||
@@ -183,6 +183,7 @@ var co=coroutine.create(func(){
|
||||
});
|
||||
|
||||
var main=func(){
|
||||
# enable unicode
|
||||
if(os.platform()=="windows")
|
||||
system("chcp 65001");
|
||||
print("\ec");
|
||||
|
||||
58
test/watchdog.nas
Normal file
@@ -0,0 +1,58 @@
|
||||
var os_time=func(){
|
||||
return "[\e[33;1m"~os.time()~"\e[0m] ";
|
||||
}
|
||||
var err_hd=func(){
|
||||
return "[\e[91;1merror\e[0m] ";
|
||||
}
|
||||
var info_hd=func(){
|
||||
return "[\e[96;1minfo\e[0m] ";
|
||||
}
|
||||
var modified_hd=func(){
|
||||
return "[\e[92;1mmodified\e[0m] ";
|
||||
}
|
||||
var usage=func(){
|
||||
println(os_time(),info_hd(),"\e[1musage: nasal watchdog.nas <filename> [\"argv\"]\e[0m");
|
||||
}
|
||||
|
||||
var argv=runtime.argv();
|
||||
if(size(argv)<1){
|
||||
println(os_time(),err_hd(),"\e[1mneed correct file path to watch\e[0m");
|
||||
usage();
|
||||
exit(-1);
|
||||
}
|
||||
var filename=argv[0];
|
||||
if(!io.exists(filename)){
|
||||
println(os_time(),err_hd(),"\e[1mfile <",filename,"> does not exist\e[0m");
|
||||
usage();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
var args=[];
|
||||
if(size(argv)==2){
|
||||
println(os_time(),info_hd(),"\e[1mwith argument(s) ",argv[1],"\e[0m");
|
||||
args=split(" ",argv[1]);
|
||||
}
|
||||
|
||||
var modified_time=fstat(filename).st_mtime;
|
||||
println(os_time(),info_hd(),"\e[1mwatching ",filename," ..\e[0m");
|
||||
while(1){
|
||||
unix.sleep(1);
|
||||
if(!io.exists(filename)){
|
||||
println(os_time(),err_hd(),"\e[1mfile <",filename,"> does not exist\e[0m");
|
||||
break;
|
||||
}
|
||||
var latest_modified_time=fstat(filename).st_mtime;
|
||||
if(latest_modified_time!=modified_time){
|
||||
modified_time=latest_modified_time;
|
||||
println(os_time(),modified_hd(),"\e[1m",filename,"\e[0m");
|
||||
var cmd=(os.platform()=="windows"?"":"./")~"nasal "~filename;
|
||||
foreach(var i;args)
|
||||
cmd~=" "~i;
|
||||
var ret=system(cmd);
|
||||
if(ret!=0){
|
||||
println(os_time(),err_hd(),"\e[1mprocess returned ",ret,"\e[0m");
|
||||
}else{
|
||||
println(os_time(),info_hd(),"\e[1mprocess returned ",ret,"\e[0m");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# wave collapse function 2022/4/10
|
||||
# by ValKmjolnir
|
||||
srand();
|
||||
var interval=1/60;
|
||||
var interval=1/120;
|
||||
var table=[
|
||||
# c ,w,a,s,d
|
||||
["═",0,1,0,1],
|
||||
@@ -94,6 +94,7 @@ var map=func(){
|
||||
}
|
||||
}();
|
||||
|
||||
# enable unicode
|
||||
if(os.platform()=="windows")
|
||||
system("chcp 65001");
|
||||
map.new(80);
|
||||
|
||||
56
test/word_collector.nas
Normal file
@@ -0,0 +1,56 @@
|
||||
import.stl.sort;
|
||||
|
||||
var to_lower=func(s){
|
||||
var tmp="";
|
||||
for(var i=0;i<size(s);i+=1){
|
||||
var c=s[i];
|
||||
if('a'[0]<=c and c<='z'[0])
|
||||
tmp~=chr(c);
|
||||
elsif('A'[0]<=c and c<='Z'[0])
|
||||
tmp~=chr(c-'A'[0]+'a'[0]);
|
||||
else
|
||||
tmp~=chr(c);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
var spliter=func(content){
|
||||
var token={};
|
||||
var len=size(content);
|
||||
var s="";
|
||||
for(var i=0;i<len;i+=1){
|
||||
var n=content[i];
|
||||
var c=chr(n);
|
||||
if(('a'[0]<=n and n<='z'[0]) or ('A'[0]<=n and n<='Z'[0]) or n=='\''[0] or n=='-'[0]){
|
||||
s~=c;
|
||||
}elsif(size(s)){
|
||||
if(s[0]!="-"[0] and s[0]!="'"[0] and s[-1]!="-"[0] and s[-1]!="'"[0])
|
||||
token[to_lower(s)]+=1;
|
||||
s="";
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
func(argv){
|
||||
if(size(argv)<1){
|
||||
println("no input files.");
|
||||
exit(-1);
|
||||
}
|
||||
var all_exists=1;
|
||||
foreach(var f;argv){
|
||||
if(!io.exists(f)){
|
||||
println("cannot open file <",f,">");
|
||||
all_exists=0;
|
||||
}
|
||||
}
|
||||
if(!all_exists){
|
||||
exit(-1);
|
||||
}
|
||||
var file_content="";
|
||||
foreach(var f;argv)
|
||||
file_content~=io.fin(f)~" ";
|
||||
var vec=keys(spliter(file_content));
|
||||
sort(vec,func(a,b){return cmp(a,b)<=0;});
|
||||
println(vec);
|
||||
}(runtime.argv());
|
||||