50 Commits
v10.0 ... next

Author SHA1 Message Date
ValKmjolnir
d121dcd630 🎨 improve format of code 2022-10-28 23:28:15 +08:00
ValKmjolnir
c705b75513 🚀 change module function parameter format to avoid warnings 2022-10-24 01:12:25 +08:00
ValKmjolnir
3ef8effe9a 🔥 change nasal_gc to gc 2022-10-23 01:29:20 +08:00
ValKmjolnir
3fd1b25f79 🔥 change class name.
nasal_lexer -> lexer
nasal_parse -> parse
nasal_codegen -> codegen
nasal_vm -> vm
nasal_gc -> gc
nasal_dbg -> debugger
nasal_import -> linker
nas_ref -> var
2022-10-21 01:29:29 +08:00
ValKmjolnir
025ff49ffc 🚀 add stl/csv.nas & ast name change 2022-10-19 00:54:21 +08:00
ValKmjolnir
7a93527948 add stl/json.nas & fix bug
bug: may cause program crash if stack overflow occurs on main stack
2022-10-08 21:34:47 +08:00
ValKmjolnir
405175061a 🚀 crashed coroutine will not make main thread crash. 2022-10-06 23:11:27 +08:00
Li Haokun
ae85791f01 Merge pull request #16 from sidi762/master
Build modules for macOS nightly builds and deliver everything (instead of just the binary) in the release
2022-10-06 17:23:14 +08:00
Sidi Liang
3cb5d0f2d9 Merge pull request #1 from sidi762/patch-1
Build modules for Mac nightly
2022-10-06 17:19:02 +08:00
Sidi Liang
a3f5dc01d3 Build modules for Mac nightly 2022-10-06 17:15:47 +08:00
ValKmjolnir
35d7772dd3 📝 update doc 2022-10-06 00:23:32 +08:00
ValKmjolnir
e25eb76e94 🚀 delete unnecessary codes & add stl/string.nas 2022-10-05 16:03:47 +08:00
ValKmjolnir
946aa020a5 🚀 add high resolution progress bar 2022-09-28 23:45:15 +08:00
ValKmjolnir
6ef22d3228 🚀 use std::ostream to unify nas_ref output 2022-09-23 21:45:08 +08:00
ValKmjolnir
c4cac512a6 🐛 fix compilation error of FindNextFile in other VS version. 2022-09-23 20:39:34 +08:00
ValKmjolnir
dc3770094a 🚀 update test file 2022-09-20 21:51:52 +08:00
ValKmjolnir
791de656c3 🚀 update ascii-art.nas and stl/padding.nas 2022-09-20 00:41:08 +08:00
ValKmjolnir
cff9f91bee 🚀 move pic directory into doc 2022-09-19 00:10:08 +08:00
ValKmjolnir
06f02ec0cb 📝 update doc 2022-09-17 18:23:27 +08:00
ValKmjolnir
24ae1c246f 📝 fix help info align 2022-09-15 23:37:46 +08:00
ValKmjolnir
0576459fbe 📝 add notes in test files & use system("color") to use ANSI esc seq 2022-09-14 23:15:36 +08:00
ValKmjolnir
518ce7fcb9 📝 add interesting gifs into docs 2022-09-13 23:00:48 +08:00
ValKmjolnir
0e682b7c07 📝 update docs 2022-09-13 22:14:17 +08:00
ValKmjolnir
26f4e1359f 🐛 fix bug that int() cannot convert numeric string 2022-09-12 22:45:35 +08:00
ValKmjolnir
aa5b1d3d66 🚀 import information output of dbg, vm and codegen 2022-09-11 17:22:00 +08:00
ValKmjolnir
6a6eab8db5 change parameter list of 2022-09-11 15:10:30 +08:00
ValKmjolnir
91b3074ce9 optimize stl/sort.nas and test/calc.nas 2022-09-10 15:45:25 +08:00
ValKmjolnir
10e579dabc 🐛 fix bug that word_collector.nas split some words incorrectly 2022-09-09 21:48:10 +08:00
ValKmjolnir
add5e0c2cd 📝 update test file & add new test file word_collector.nas 2022-09-09 01:00:09 +08:00
ValKmjolnir
1e0f0f8e7b 🐛 bug fix: fix sigsegv when parsing [1,2,3][]=1;, will report expected index value 2022-09-05 01:23:37 +08:00
ValKmjolnir
972ad49a4f improve error output info generated by codegen. 2022-09-05 00:41:36 +08:00
ValKmjolnir
a13e419518 📝 fix MSVC warning in nasal_builtin.h & improve error output. 2022-09-04 23:08:06 +08:00
ValKmjolnir
6c04487319 🚀 add new stl file padding.nas and update test files. 2022-09-04 17:53:00 +08:00
ValKmjolnir
5715c1df5f 🎨 improve error log output format. 2022-09-02 02:04:03 +08:00
ValKmjolnir
aa0023a23b 📝 use bold font in test/watchdog.nas 2022-09-01 00:04:14 +08:00
ValKmjolnir
f86ea2445f 🚀 change cpp standard to c++14 & add command line colorful info output.
and fix a bug that program may crash if there's an error when coroutine is running
2022-08-31 23:24:41 +08:00
ValKmjolnir
52a38709bb 📝 diable warning C4566 in MSVC 2022-08-31 01:06:57 +08:00
ValKmjolnir
b022b25cea 🚀 add colorful error info print. 2022-08-31 00:56:19 +08:00
ValKmjolnir
27ceeb517d 🐛 fix bug that make test failed 2022-08-29 00:48:06 +08:00
ValKmjolnir
8293f85c5b 🚀 add lib function exit() and add test file watchdog.nas to run the nasal file when it is changed. 2022-08-27 18:12:32 +08:00
ValKmjolnir
0e578b3e21 📝 update stl/file and test files. 2022-08-27 17:26:01 +08:00
ValKmjolnir
24ba300f3c 🔥 delete --opcnt and replace the function of -o by --optimize. 2022-08-25 19:54:03 +08:00
ValKmjolnir
5be6351b60 delete unnecessary prefix in die("") 2022-08-25 01:16:17 +08:00
ValKmjolnir
a91826607c optimize header file, now modules could generate smaller dynamic libs. 2022-08-24 22:08:47 +08:00
ValKmjolnir
987d3ce9e2 🚀 change indentation of nasal_ast::print & add new function
`nasal_ast::tree`.
2022-08-22 22:35:53 +08:00
ValKmjolnir
da8aa4744e 📝 add compilation time & update test/ppmgen.nas 2022-08-21 00:26:16 +08:00
ValKmjolnir
978957aca7 optimize str2num 2022-08-20 02:01:39 +08:00
ValKmjolnir
caf048aae4 several updates.
1. merge `--chkpath` `-cp` with `-d`

2. complete test/ppmgen.nas

3. update comments about why we don't use `atof` to convert string to
number

4. update .gitignore
2022-08-19 23:25:46 +08:00
ValKmjolnir
692f8ccefe update doc & notes, optimize code 2022-08-18 20:41:33 +08:00
ValKmjolnir
007b83bed5 📝 add test file ppmgen.nas 2022-08-17 21:09:22 +08:00
70 changed files with 4020 additions and 3385 deletions

View File

@@ -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
View File

@@ -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
View File

@@ -1,16 +1,8 @@
# __Nasal Scripting Language__
```C++
__ _
/\ \ \__ _ ___ __ _| |
/ \/ / _` / __|/ _` | |
/ /\ / (_| \__ \ (_| | |
\_\ \/ \__,_|___/\__,_|_|
```
![GitHub code size](https://img.shields.io/github/languages/code-size/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github)
![GitHub release(latest by date)](https://img.shields.io/github/v/release/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github)
![in dev](https://img.shields.io/badge/dev-v10.0-blue?style=flat-square&logo=github)
![in dev](https://img.shields.io/badge/dev-v10.1-blue?style=flat-square&logo=github)
[![license](https://img.shields.io/badge/license-MIT-green?style=flat-square&logo=github)](./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
![clang++](https://img.shields.io/badge/LLVM-clang++-262D3A?style=flat-square&logo=LLVM)
![vs](https://img.shields.io/badge/Visual_Studio-MSVC-5C2D91?style=flat-square&logo=visualstudio)
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).
![usage](./doc/gif/help.gif)
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
![error](./doc/gif/error.gif)
<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__
![stackoverflow](./doc/gif/stackoverflow.gif)
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__
![dbg](./doc/gif/dbg.gif)
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>

View File

@@ -1,19 +1,11 @@
# __Nasal 脚本语言__
```C++
__ _
/\ \ \__ _ ___ __ _| |
/ \/ / _` / __|/ _` | |
/ /\ / (_| \__ \ (_| | |
\_\ \/ \__,_|___/\__,_|_|
```
![GitHub code size](https://img.shields.io/github/languages/code-size/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github)
![GitHub release(latest by date)](https://img.shields.io/github/v/release/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github)
![in dev](https://img.shields.io/badge/dev-v10.0-blue?style=flat-square&logo=github)
![in dev](https://img.shields.io/badge/dev-v10.1-blue?style=flat-square&logo=github)
[![license](https://img.shields.io/badge/license-MIT-green?style=flat-square&logo=github)](../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解释器?__
![vs](https://img.shields.io/badge/Visual_Studio-MSVC-5C2D91?style=flat-square&logo=visualstudio)
我们推荐你下载最新更新的代码包来直接编译,这个项目非常小巧因此你可以非常快速地将它编译出来。
__注意__: 如果你想直接下载发行版提供的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程序。
![usage](../doc/gif/help.gif)
使用这个命令查看解释器的版本:
> ./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`定义变量
![error](../doc/gif/error.gif)
<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>
## __堆栈追踪信息__
![stackoverflow](../doc/gif/stackoverflow.gif)
当解释器崩溃时,它会反馈错误产生过程的堆栈追踪信息:
<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>
## __调试器__
![dbg](../doc/gif/dbg.gif)
在`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>

View File

@@ -1,6 +1,6 @@
# __Benchmark__
![benchmark](../pic/benchmark.png)
![benchmark](../doc/pic/benchmark.png)
## 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:
![mandelbrot](../pic/mandelbrot.png)
![mandelbrot](../doc/pic/mandelbrot.png)

View File

@@ -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__
![op](../doc/gif/opcode.gif)
### 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`.

View File

@@ -91,6 +91,8 @@ __该项目于2019/7/25正式开始__。
## __字节码虚拟机__
![op](../doc/gif/opcode.gif)
### 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/biglooptest/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

Binary file not shown.

After

Width:  |  Height:  |  Size: 867 KiB

BIN
doc/gif/error.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
doc/gif/help.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

BIN
doc/gif/opcode.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

BIN
doc/gif/stackoverflow.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@@ -60,8 +60,8 @@
</p>
</text>
<h2>&nbsp;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>

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -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`,编译。

View File

@@ -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
View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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
View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

16
stl/csv.nas Normal file
View 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:]
};
}

View File

@@ -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
View 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;
}
};
}();

View File

@@ -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
View 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;
}

View File

@@ -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")

View File

@@ -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;
}
};
};

View File

@@ -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
View 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;
}

View File

@@ -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();

View File

@@ -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]]();

View File

@@ -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);

View File

@@ -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]);

View File

@@ -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');

View File

@@ -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');

View File

@@ -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.");

View File

@@ -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);

View File

@@ -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');

View File

@@ -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([""],".");

View File

@@ -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);

View File

@@ -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],

View File

@@ -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
View 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);

View File

@@ -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();

View File

@@ -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
View 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.");

View File

@@ -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=[" ","██"];

View File

@@ -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);

View File

@@ -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
View 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");
}
}
}

View File

@@ -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
View 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());