Merge pull request #35 from ValKmjolnir/develop

📝 updatedocuments and scripts
This commit is contained in:
ValK
2023-11-17 00:19:35 +08:00
committed by GitHub
85 changed files with 3174 additions and 3098 deletions

786
README.md
View File

@@ -14,7 +14,7 @@
* [__Introduction__](#introduction)
* [__Compile__](#how-to-compile)
* [__Usage__](#how-to-use)
* [__Tutorial__](#tutorial)
* [__Tutorial__](./doc/tutorial.md)
* [__Release Notes__](./doc/dev.md#release-notes)
* [__Development History__](./doc/dev.md)
* [__Benchmark__](./doc/benchmark.md)
@@ -25,7 +25,11 @@
__Contact us if having great ideas to share!__
* __E-mail__: __lhk101lhk101@qq.com__(ValKmjolnir) __1467329765@qq.com__(Sidi762)
* __E-mail__:
* __lhk101lhk101@qq.com__ (ValKmjolnir)
* __1467329765@qq.com__ (Sidi762)
## __Introduction__
@@ -57,38 +61,35 @@ the interpreter a useful tool in your own projects.
## __How to Compile__
![windows](https://img.shields.io/badge/Microsoft-Windows-green?style=flat-square&logo=windows)
![macOS](https://img.shields.io/badge/Apple%20Inc.-MacOS-green?style=flat-square&logo=apple)
![linux](https://img.shields.io/badge/GNU-Linux-green?style=flat-square&logo=GNU)
![g++](https://img.shields.io/badge/GNU-g++-A42E2B?style=flat-square&logo=GNU)
![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 download the latest update source of the interpreter and build it! It's quite easy to build this interpreter, what you need are only two things: C++ compiler and the `make`. There is no third-party library used in this project.
__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.
### __Windows (MinGW-w64)__
### __`Windows (MinGW-w64)`__
![windows](https://img.shields.io/badge/Microsoft-Windows-green?style=flat-square&logo=windows)
Make sure your MinGW thread model is `posix thread model`, otherwise it may not have the thread library.
Make sure thread model is `posix thread model`, otherwise no thread library exists.
> mkdir build
>
> mingw32-make nasal.exe -j4
### __`Windows (Visual Studio)`__
### __Windows (Visual Studio)__
This project gives a [__CMakelists.txt__](./CMakeLists.txt) for you to create project in `Visual Studio`.
![windows](https://img.shields.io/badge/Microsoft-Windows-green?style=flat-square&logo=windows)
### __`Linux/macOS/Unix`__
There is a [__CMakelists.txt__](./CMakeLists.txt) to create project.
> mkdir build
>
> make -j4
### __Linux / macOS / Unix__
![linux](https://img.shields.io/badge/GNU-Linux-green?style=flat-square&logo=GNU) ![macOS](https://img.shields.io/badge/Apple%20Inc.-MacOS-green?style=flat-square&logo=apple)
> make -j
You could choose which compiler you want to use:
> make nasal CXX=...
> make nasal CXX=... -j
## __How to Use__
@@ -102,757 +103,6 @@ if (os.platform()=="windows") {
}
```
## __Tutorial__
Nasal is really __easy__ to learn.
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 type </summary>
__`none`__ is error type used to interrupt the execution.
This type is not created by user program.
__`nil`__ is a null type. Just like `null`.
```javascript
var spc = nil;
```
__`num`__ has 3 formats: `dec`, `hex` and `oct`. Using IEEE754 `double` to store.
```javascript
# this language use '#' to write notes
var n = 2.71828; # dec
var n = 2.147e16; # dec
var n = 1e-10; # dec
var n = 0xAA55; # hex
var n = 0o170001; # oct
# caution: true and false also useful in nasal now
var n = true; # in fact n is now 1.0
var n = false; # in face n is now 0.0
```
__`str`__ has 3 formats. The third one is used to declare a character.
```javascript
var s = 'str';
var s = "another string";
var s = `c`;
# some special characters is allowed in this language:
'\a'; '\b'; '\e'; '\f';
'\n'; '\r'; '\t'; '\v';
'\0'; '\\'; '\?'; '\'';
'\"';
```
__`vec`__ has unlimited length and can store all types of values.
```javascript
var vec = [];
var vec = [0, nil, {}, [], func(){return 0}];
append(vec, 0, 1, 2);
```
__`hash`__ is a hashmap (or like a `dict` in `python`) that stores values with strings/identifiers as the key.
```javascript
var hash = {
member1: nil,
member2: "str",
"member3": "member\'s name can also be a string constant",
funct: func() {
return me.member2~me.member3;
}
};
```
__`func`__ is a function type (in fact it is `lambda`).
```javascript
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;
}
var f = func(args...) {
var sum = 0;
foreach(var i; args) {
sum += i;
}
return sum;
}
```
__`upval`__ is used to store upvalues, used in __`vm`__ to make sure closure runs correctly.
__`ghost`__ 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>
Nasal has basic math operators `+` `-` `*` `/` and a special operator `~` that joints strings.
```javascript
1+2-(1+3)*(2+4)/(16-9);
"str1"~"str2";
```
For conditional expressions, operators `==` `!=` `<` `>` `<=` `>=` are used to compare two values.
`and` `or` have the same function as C/C++ `&&` `||`.
```javascript
1+1 and (1<0 or 1>0);
1<=0 and 1>=0;
1==0 or 1!=0;
```
Unary operators `-` `!` have the same function as C/C++.
```javascript
-1;
!0;
```
Bitwise operators `~` `|` `&` `^` have the same function as C/C++.
```javascript
# these operators will:
# 1. convert f64 to i32 (static_cast<int32_t>)
# 2. do the bitwise function
~0x80000000; # not 2147483647
0x8|0x1; # or
0x1&0x2; # and
0x8^0x1; # xor
```
Operators `=` `+=` `-=` `*=` `/=` `~=` `^=` `&=` `|=` are used in assignment expressions.
```javascript
a = b = c = d = 1;
a += 1;
a -= 1;
a *= 1;
a /= 1;
a ~= "string";
a ^= 0xff;
a &= 0xca;
a |= 0xba;
```
</details>
<details><summary> Definition </summary>
As follows.
```javascript
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
```
Nasal has many special global symbols:
```javascript
globals; # hashmap including all global symbols and their values
arg; # in global scope, arg is the command line arguments
# in local scope, arg is the dynamic arguments of this function call
```
For example:
```javascript
var a = 1;
println(globals); # will print {a:1}
```
```javascript
# nasal a b c
println(arg); # will print ["a", "b", "c"]
func() {
println(arg);
}(1, 2, 3); # will print [1, 2, 3]
```
</details>
<details><summary> Multi-assignment </summary>
The last one is often used to swap two variables.
```javascript
(a, b[0], c.d) = [0, 1, 2];
(a, b[1], c.e) = (0, 1, 2);
(a, b) = (b, a);
```
</details>
<details><summary> Conditional expression </summary>
In nasal there's a new key word `elsif`.
It has the same functions as `else if`.
```javascript
if (1) {
;
} elsif (2) {
;
} else if (3) {
;
} else {
;
}
```
</details>
<details><summary> Loop </summary>
While loop and for loop is simalar to C/C++.
```javascript
while(condition) {
continue;
}
for(var i = 0; i<10; i += 1) {
break;
}
```
Nasal has another two kinds of loops that iterates through a vector:
`forindex` will get the index of a vector. Index will be `0` to `size(elem)-1`.
```javascript
forindex(var i; elem) {
print(elem[i]);
}
```
`foreach` will get the element of a vector. Element will be `elem[0]` to `elem[size(elem)-1]`.
```javascript
foreach(var i; elem) {
print(i);
}
```
</details>
<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.
Use index to search one element in the string will get the __ascii number__ of this character.
If you want to get the character, use built-in function `chr()`.
```javascript
a[0];
a[-1, 1, 0:2, 0:, :3, :, nil:8, 3:nil, nil:nil];
"hello world"[0];
```
</details>
<details><summary> Special function call </summary>
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:[]);
```
</details>
<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);
```
There's an interesting test file `y-combinator.nas`,
try it for fun:
```javascript
var fib = func(f) {
return f(f);
}(
func(f) {
return func(x) {
if(x<2) return x;
return f(f)(x-1)+f(f)(x-2);
}
}
);
```
</details>
<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`:
```javascript
var f = func() {
var a = 1;
return func() {return a;};
}
print(f()());
```
Using closure makes it easier to OOP.
```javascript
var student = func(n, a) {
var (name, age) = (n, a);
return {
print_info: func() {println(name, ' ', age);},
set_age: func(a) {age = a;},
get_age: func() {return age;},
set_name: func(n) {name = n;},
get_name: func() {return name;}
};
}
```
</details>
<details><summary> Trait </summary>
Also there's another way to OOP, that is `trait`.
When a hash has a member named `parents` and the value type is vector,
then when you are trying to find a member that is not in this hash,
virtual machine will search the member in `parents`.
If there is a hash that has the member, you will get the member's value.
Using this mechanism, we could OOP like this, the result is `114514`:
```javascript
var trait = {
get: func {return me.val;},
set: func(x) {me.val = x;}
};
var class = {
new: func() {
return {
val: nil,
parents: [trait]
};
}
};
var a = class.new();
a.set(114514);
println(a.get());
```
First virtual machine cannot find member `set` in hash `a`, but in `a.parents` there's a hash `trait` has the member `set`, so we get the `set`.
variable `me` points to hash `a`, so we change the `a.val`.
And `get` has the same process.
And we must remind you that if you do this:
```javascript
var trait = {
get: func {return me.val;},
set: func(x) {me.val = x;}
};
var class = {
new: func() {
return {
val: nil,
parents: [trait]
};
}
};
var a = class.new();
var b = class.new();
a.set(114);
b.set(514);
println(a.get());
println(b.get());
var c = a.get;
var d = b.get;
println(c());
println(c());
println(d());
println(d());
```
You will get this result now:
```bash
114
514
514
514
514
514
```
Because `a.get` will set `me=a` in the `trait.get`. Then `b.get` do the `me=b`. So in fact c is `b.get` too after running `var d=b.get`.
If you want to use this trick to make the program running more efficiently, you must know this special mechanism.
</details>
<details><summary> Native functions and module import </summary>
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, 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++
// you could also use a macro to define one.
var builtin_print(context*, gc*);
```
Then complete this function using C++:
```C++
var builtin_print(context* ctx, gc* ngc) {
// find value with index begin from 1
// because local[0] is reserved for value 'me'
for(auto& i : ctx->localr[1].vec().elems) {
std::cout << i;
}
std::cout << std::flush;
// generate return 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(context* ctx, gc* ngc) {
auto hash = ctx->localr[1];
if (hash.type!=vm_hash && hash.type!=vm_map) {
return nas_err("keys", "\"hash\" must be hash");
}
// use gc.temp to store the gc-managed-value, to avoid being sweeped
auto res = ngc->temp = ngc->alloc(vm_vec);
auto& vec = res.vec().elems;
if (hash.type==vm_hash) {
for(const auto& iter : hash.hash().elems) {
vec.push_back(ngc->newstr(iter.first));
}
} else {
for(const auto& iter : hash.map().mapper) {
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++
nasal_builtin_table builtin[] = {
{"__print", builtin_print},
{nullptr, nullptr}
};
```
At last,warp the `__print` in a nasal file:
```javascript
var print = func(elems...) {
return __print(elems);
};
```
In fact the arguments that `__print` uses are not necessary.
So writting it like this is also right:
```javascript
var print = func(elems...) {
return __print;
};
```
If you don't warp built-in function in a normal nasal function,
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:
```javascript
use dirname.dirname.filename;
import("./dirname/dirname/filename.nas");
```
</details>
<details><summary> Modules (for lib developers) </summary>
If there is only one way to add your own functions into nasal,
that is really inconvenient.
Luckily, we have developed some useful native-functions to help you add modules that created by you.
Functions used to load dynamic libraries are added to `std/dylib.nas`:
```javascript
var dlopen = func(libname) {
...
}
var dlclose = func(lib) {
...
}
var dlcall = func(ptr, args...) {
...
}
var limitcall = func(arg_size = 0) {
...
}
```
As you could see, these functions are used to load dynamic libraries into the nasal runtime and execute.
Let's see how they work.
First, write a cpp file that you want to generate the dynamic lib, take the `fib.cpp` as the example(example codes are in `./module`):
```C++
// add header file nasal.h to get api
#include "nasal.h"
double fibonaci(double x) {
if (x<=2) {
return x;
}
return fibonaci(x-1)+fibonaci(x-2);
}
// module functions' parameter list example
var fib(var* args, usize size, gc* ngc) {
if (!size) {
return nas_err("fib", "lack arguments");
}
// the arguments are generated into a vm_vec: args
// get values from the vector that must be used here
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 ngc->alloc(type)
// usage of gc is the same as adding a native function
return var::num(fibonaci(num.tonum()));
}
// then put function name and address into this table
// make sure the end of the table is {nullptr,nullptr}
module_func_info func_tbl[] = {
{"fib", fib},
{nullptr, nullptr}
};
// 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" module_func_info* get() {
return func_tbl;
}
```
Next, compile this `fib.cpp` into dynamic lib.
Linux(`.so`):
`clang++ -c -O3 fib.cpp -fPIC -o fib.o`
`clang++ -shared -o libfib.so fib.o`
Mac(`.so` & `.dylib`): same as Linux.
Windows(`.dll`):
`g++ -c -O3 fib.cpp -fPIC -o fib.o`
`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 cross-platform program:
```javascript
use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
for(var i = 1; i<30; i += 1)
println(dylib.dlcall(fib, i));
dylib.dlclose(dlhandle.lib);
```
`dylib.dlopen` is used to load dynamic library and get the function address.
`dylib.dlcall` is used to call the function, the first argument is the function address, make sure this argument is `vm_obj` and `type=obj_extern`.
`dylib.dlclose` is used to unload the library, at the moment that you call the function, all the function addresses that got from it are invalid.
`dylib.limitcall` is used to get `dlcall` function that has limited parameter size, this function will prove the performance of your code because it does not use `vm_vec` to store the arguments, instead it uses local scope to store them, so this could avoid frequently garbage collecting. And the code above could also be written like this:
```javascript
use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
for(var i = 1; i<30; i += 1)
println(invoke(fib, i));
dylib.dlclose(dlhandle.lib);
```
If get this, Congratulations!
```bash
./nasal a.nas
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
```
</details>
<details><summary> Ghost Type (for lib developers) </summary>
It's quite easy to create a new ghost by yourself now.
Look at the example below:
```c++
const auto ghost_for_test = "ghost_for_test";
// declare destructor for ghost type
void ghost_for_test_destructor(void* ptr) {
std::cout << "ghost_for_test::destructor (0x";
std::cout << std::hex << reinterpret_cast<u64>(ptr) << std::dec << ") {\n";
delete static_cast<u32*>(ptr);
std::cout << " delete 0x" << std::hex;
std::cout << reinterpret_cast<u64>(ptr) << std::dec << ";\n";
std::cout << "}\n";
}
var create_new_ghost(var* args, usize size, gc* ngc) {
var res = ngc->alloc(vm_obj);
// create ghost type
res.ghost().set(ghost_for_test, ghost_for_test_destructor, new u32);
return res;
}
var set_new_ghost(var* args, usize size, gc* ngc) {
var res = args[0];
if (!res.object_check(ghost_for_test)) {
std::cout << "set_new_ghost: not ghost for test type.\n";
return nil;
}
f64 num = args[1].num();
*(reinterpret_cast<u32*>(res.ghost().pointer)) = static_cast<u32>(num);
std::cout << "set_new_ghost: successfully set ghost = " << num << "\n";
return nil;
}
var print_new_ghost(var* args, usize size, gc* ngc) {
var res = args[0];
// check ghost type by the type name
if (!res.object_check(ghost_for_test)) {
std::cout << "print_new_ghost: not ghost for test type.\n";
return nil;
}
std::cout << "print_new_ghost: " << res.ghost() << " result = "
<< *((u32*)res.ghost().pointer) << "\n";
return nil;
}
```
We use this function to create a new ghost type:
`void nas_ghost::set(const std::string&, nasal::nas_ghost::destructor, void*);`
`const std::string&` is the name of the ghost type.
`nasal::nas_ghost::destructor` is the pointer of the destructor of the ghost type.
`void*` is the pointer of the ghost type instance.
And we use this function to check if value is the correct ghost type:
`bool var::object_check(const std::string&);`
The parameter is the name of the ghost type.
</details>
## __Difference Between Andy's and This Interpreter__
![error](./doc/gif/error.gif)

View File

@@ -14,7 +14,7 @@
* [__简介__](#简介)
* [__编译__](#编译)
* [__使用方法__](#使用方法)
* [__教程__](#教程)
* [__教程__](../doc/tutorial_zh.md)
* [__发行日志__](../doc/dev_zh.md#发行日志)
* [__开发历史__](../doc/dev_zh.md)
* [__测试数据__](../doc/benchmark.md)
@@ -25,7 +25,11 @@
__如果有好的意见或建议欢迎联系我们!__
* __E-mail__: __lhk101lhk101@qq.com__(ValKmjolnir) __1467329765@qq.com__(Sidi762)
* __E-mail__:
* __lhk101lhk101@qq.com__ (ValKmjolnir)
* __1467329765@qq.com__(Sidi762)
## __简介__
@@ -47,39 +51,37 @@ __如果有好的意见或建议欢迎联系我们!__
## __编译__
![windows](https://img.shields.io/badge/Microsoft-Windows-green?style=flat-square&logo=windows)
![macOS](https://img.shields.io/badge/Apple%20Inc.-MacOS-green?style=flat-square&logo=apple)
![linux](https://img.shields.io/badge/GNU-Linux-green?style=flat-square&logo=GNU)
![g++](https://img.shields.io/badge/GNU-g++-A42E2B?style=flat-square&logo=GNU)
![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)
我们推荐下载最新代码包编译,这个项目非常小巧,没有使用任何第三方库,因此编译起来非常轻松,
只需要这两样东西: C++ 编译器以及make程序。
推荐下载最新代码包编译,这个项目非常小巧, 没有使用任何第三方库,因此编译起来非常轻松,
只需要这两样东西: C++ 编译器以及make程序。
__注意__: 如果你想直接下载发行版提供的zip/tar.gz压缩包来构建这个解释器在下载之前请阅读[__发行日志__](../doc/dev_zh.md#发行日志)以保证这个发行版的文件中不包含非常严重的bug。
### __Windows 平台 (MinGW-w64)__
### __`Windows` 平台(`MinGW-w64`)__
![windows](https://img.shields.io/badge/Microsoft-Windows-green?style=flat-square&logo=windows)
一定要确保您的 MinGW thread model 是 `posix thread model`, 否则可能存在没有 thread 库的问题
确保 thread model 是 `posix thread model`, 否则没有 thread 库。
> mkdir build
>
> mingw32-make nasal.exe -j4
### __`Windows` 平台(`Vistual Studio`)__
### __Windows 平台 (Vistual Studio)__
项目提供了 [__CMakeLists.txt__](../CMakeLists.txt) 用于在`Visual Studio`中用这种方式来创建项目。
![windows](https://img.shields.io/badge/Microsoft-Windows-green?style=flat-square&logo=windows)
### __`Linux/macOS/Unix` 平台__
项目提供了 [__CMakeLists.txt__](../CMakeLists.txt) 用于在`Visual Studio`中创建项目。
> mkdir build
>
> make -j4
### __Linux / macOS / Unix 平台__
![linux](https://img.shields.io/badge/GNU-Linux-green?style=flat-square&logo=GNU)
![macOS](https://img.shields.io/badge/Apple%20Inc.-MacOS-green?style=flat-square&logo=apple)
> make -j
你也可以通过如下的其中一行命令来指定你想要使用的编译器:
> make nasal CXX=...
> make nasal CXX=... -j
## __使用方法__
@@ -93,738 +95,6 @@ if (os.platform()=="windows") {
}
```
## __教程__
Nasal是非常容易上手的你甚至可以在15分钟之内看完这里的基本教程并且直接开始编写你想要的程序。
__如果你先前已经是C/C++, javascript选手那么几乎可以不用看这个教程……__ 在看完该教程之后,基本上你就完全掌握了这个语言:
<details><summary>基本类型</summary>
__`none`__ 是特殊的错误类型。这个类型用于终止虚拟机的执行,该类型只能由虚拟机在抛出错误时产生。
__`nil`__ 是空类型。类似于null。
```javascript
var spc = nil;
```
__`num`__ 有三种形式:十进制十六进制以及八进制。并且该类型使用IEEE754标准的浮点数`double`格式来存储。
```javascript
# 该语言用 '#' 来作为注释的开头
var n = 2.71828; # dec 十进制
var n = 2.147e16; # dec 十进制
var n = 1e-10; # dec 十进制
var n = 0xAA55; # hex 十六进制
var n = 0o170001; # oct 八进制
# 注意: true false 关键字在现在的 nasal 里也是可用的
var n = true; # n 实际上是数字 1.0
var n = false; # n 实际上是数字 0.0
```
__`str`__ 也有三种不同的格式。第三种只允许包含一个的字符。
```javascript
var s = 'str';
var s = "another string";
var s = `c`;
# 该语言也支持一些特别的转义字符:
'\a'; '\b'; '\e'; '\f';
'\n'; '\r'; '\t'; '\v';
'\0'; '\\'; '\?'; '\'';
'\"';
```
__`vec`__ 有不受限制的长度并且可以存储所有类型的数据。(当然不能超过可分配内存空间的长度)
```javascript
var vec = [];
var vec = [0, nil, {}, [], func(){return 0}];
append(vec, 0, 1, 2);
```
__`hash`__ 使用哈希表 (类似于`python`中的`dict`)通过键值对来存储数据。key可以是一个字符串也可以是一个标识符。
```javascript
var hash = {
member1: nil,
member2: "str",
"member3": "member\'s name can also be a string constant",
funct: func() {
return me.member2~me.member3;
}
};
```
__`func`__ 函数类型。(实际上在这个语言里函数是一种`lambda`表达式)
```javascript
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;
}
var f = func(args...) {
var sum = 0;
foreach(var i; args) {
sum += i;
}
return sum;
}
```
__`upval`__ 是存储闭包数据的特殊类型, 在 __`vm`__ 中使用,以确保闭包功能正常。
__`ghost`__ 是用来存储`C/C++`的一些复杂数据结构。这种类型的数据由内置函数生成。如果想为nasal添加新的数据结构, 可以看下文如何通过修改本项目来添加内置函数。
</details>
<details><summary>运算符</summary>
Nasal拥有基本的四种数学运算符 `+` `-` `*` `/`以及一个特别的运算符 `~`,用于拼接字符串。
```javascript
1+2-(1+3)*(2+4)/(16-9);
"str1"~"str2";
```
对于条件语句,可以使用`==` `!=` `<` `>` `<=` `>=`来比较数据。`and` `or` 与C/C++中 `&&` `||`运算符一致。
```javascript
1+1 and (1<0 or 1>0);
1<=0 and 1>=0;
1==0 or 1!=0;
```
单目运算符`-` `!`与C/C++中的运算符功能类似。
```javascript
-1;
!0;
```
位运算符`~` `|` `&` `^`与C/C++中的运算符功能类似。
```javascript
# 运行过程:
# 1. f64 强转为 i32 (static_cast<int32_t>)
# 2. 执行位运算符
~0x80000000; # 按位取反 2147483647
0x8|0x1; # 按位或
0x1&0x2; # 按位与
0x8^0x1; # 按位异或
```
赋值运算符`=` `+=` `-=` `*=` `/=` `~=` `^=` `&=` `|=`正如其名,用于进行赋值。
```javascript
a = b = c = d = 1;
a += 1;
a -= 1;
a *= 1;
a /= 1;
a ~= "string";
a ^= 0xff;
a &= 0xca;
a |= 0xba;
```
</details>
<details><summary>定义变量</summary>
如下所示。
```javascript
var a = 1; # 定义单个变量
var (a, b, c) = [0, 1, 2]; # 从数组中初始化多个变量
var (a, b, c) = (0, 1, 2); # 从元组中初始化多个变量
```
Nasal 有很多特别的全局变量:
```javascript
globals; # 包含所有全局声明变量名和对应数据的哈希表
arg; # 在全局作用域arg 是包含命令行参数的数组
# 在局部作用域arg 是函数调用时的动态参数数组
```
具体实例:
```javascript
var a = 1;
println(globals); # 输出 {a:1}
```
```javascript
# nasal a b c
println(arg); # 输出 ["a", "b", "c"]
func() {
println(arg);
}(1, 2, 3); # 输出 [1, 2, 3]
```
</details>
<details><summary>多变量赋值</summary>
最后这个语句通常用于交换两个变量的数据类似于Python中的操作。
```javascript
(a, b[0], c.d) = [0, 1, 2];
(a, b[1], c.e) = (0, 1, 2);
(a, b) = (b, a);
```
</details>
<details><summary>条件语句</summary>
nasal在提供`else if`的同时还有另外一个关键字`elsif`。该关键字与`else if`有相同的功能。
```javascript
if (1) {
;
} elsif (2) {
;
} else if (3) {
;
} else {
;
}
```
</details>
<details><summary>循环语句</summary>
while循环和for循环大体上与C/C++是一致的。
```javascript
while(condition) {
continue;
}
for(var i = 0; i<10; i += 1) {
break;
}
```
同时nasal还有另外两种直接遍历列表的循环方式:
`forindex` 会获取列表的下标,依次递增. 下标会从`0`递增到`size(elem)-1`结束。
```javascript
forindex(var i; elem) {
print(elem[i]);
}
```
`foreach`会依次直接获取列表中的数据. 这些数据会从`elem[0]`依次获取到`elem[size(elem)-1]`.
```javascript
foreach(var i; elem) {
print(i);
}
```
</details>
<details><summary>生成子列表(subvec)</summary>
nasal提供了下面第一句的类似语法来从列表中随机或者按照一个区间获取数据并且拼接生成一个新的列表。当然如果中括号内只有一个下标的话你会直接获得这个下标对应的数据而不是一个子列表。如果直接对string使用下标来获取内容的话会得到对应字符的 __ascii值__。如果你想进一步获得这个字符串,可以尝试使用内置函数`chr()`
```javascript
a[0];
a[-1, 1, 0:2, 0:, :3, :, nil:8, 3:nil, nil:nil];
"hello world"[0];
```
</details>
<details><summary>特殊函数调用语法</summary>
这种调用方式不是很高效,因为哈希表会使用字符串比对来找到数据存放的位置。
然而如果它用起来非常舒适,那效率也显得不是非常重要了……
```javascript
f(x:0, y:nil, z:[]);
```
</details>
<details><summary>lambda表达式</summary>
函数有这样一种直接编写函数体并且立即调用的方式:
```javascript
func(x, y) {
return x+y;
}(0, 1);
func(x) {
return 1/(1+math.exp(-x));
}(0.5);
```
测试文件中有一个非常有趣的文件`y-combinator.nas`,可以试一试:
```javascript
var fib = func(f) {
return f(f);
}(
func(f) {
return func(x) {
if(x<2) return x;
return f(f)(x-1)+f(f)(x-2);
}
}
);
```
</details>
<details><summary>闭包</summary>
闭包是一种特别的作用域,你可以从这个作用域中获取其保存的所有变量,
而这些变量原本不是你当前运行的函数的局部作用域中的。
下面这个例子里,结果是`1`:
```javascript
var f = func() {
var a = 1;
return func() {return a;};
}
print(f()());
```
如果善用闭包,你可以使用它来进行面向对象编程。
```javascript
var student = func(n, a) {
var (name, age) = (n, a);
return {
print_info: func() {println(name, ' ', age);},
set_age: func(a) {age = a;},
get_age: func() {return age;},
set_name: func(n) {name = n;},
get_name: func() {return name;}
};
}
```
</details>
<details><summary>特性与继承</summary>
当然,也有另外一种办法来面向对象编程,那就是利用`trait`
当一个hash类型中有一个成员的key是`parents`,并且该成员是一个数组的话,
那么当你试图从这个hash中寻找一个它自己没有的成员名时虚拟机会进一步搜索`parents`数组。
如果该数组中有一个hash类型有一个成员的key与当前你搜索的成员名一致
那么你会得到这个成员对应的值。
使用这个机制,我们可以进行面向对象编程,下面样例的结果是`114514`:
```javascript
var trait = {
get: func {return me.val;},
set: func(x) {me.val = x;}
};
var class = {
new: func() {
return {
val: nil,
parents: [trait]
};
}
};
var a = class.new();
a.set(114514);
println(a.get());
```
首先虚拟机会发现在`a`中找不到成员`set`,但是在`a.parents`中有个hash类型`trait`存在该成员,所以返回了这个成员的值。
成员`me`指向的是`a`自身,类似于一些语言中的`this`,所以我们通过这个函数,实际上修改了`a.val``get`函数的调用实际上也经过了相同的过程。
不过我们必须提醒你一点如果你在这个地方使用该优化来减少hash的搜索开销:
```javascript
var trait = {
get: func {return me.val;},
set: func(x) {me.val = x;}
};
var class = {
new: func() {
return {
val: nil,
parents: [trait]
};
}
};
var a = class.new();
var b = class.new();
a.set(114);
b.set(514);
println(a.get());
println(b.get());
var c = a.get;
var d = b.get;
println(c());
println(c());
println(d());
println(d());
```
那么你会发现现在虚拟机会输出这个结果:
```bash
114
514
514
514
514
514
```
因为执行`a.get`时在`trait.get`函数的属性中进行了`me=a`的操作。而`b.get`则执行了`me=b`的操作。所以在运行`var d=b.get`后实际上c也变成`b.get`了。
如果你想要用这种小技巧来让程序运行更高效的话,最好是要知道这里存在这样一个机制。
</details>
<details><summary>原生内置函数以及模块导入(import)语法</summary>
这个部分对于纯粹的使用者来说是不需要了解的,
它将告诉你我们是如何为解释器添加新的内置函数的。
如果你对此很感兴趣,那么这个部分可能会帮到你,并且……
__警告:__ 如果你 __不想__ 通过直接修改解释器源码来添加你自定义的函数,那么你应该看下一个节 __`模块`__ 的内容。
如果你确实是想修改源码来搞一个自己私人订制的解释器 ———— “我他妈就是想自己私人订制,你们他妈的管得着吗?”,
参考源码中关于内置函数的部分,以及`lib.nas`中是如何包装这些函数的,下面是其中一个样例:
定义新的内置函数:
```C++
// 你可以使用这个宏来直接定义一个新的内置函数
var builtin_print(context*, gc*);
```
然后用C++完成这个函数的函数体:
```C++
var builtin_print(context* ctx, gc* ngc) {
// 局部变量的下标其实是从 1 开始的
// 因为 local[0] 是保留给 'me' 的空间
for(auto& i : ctx->localr[1].vec().elems) {
std::cout << i;
}
std::cout << std::flush;
// 最后生成返回值,返回值必须是一个内置的类型,
// 可以使用ngc::alloc(type)来申请一个需要内存管理的复杂数据结构
// 或者用我们已经定义好的nil/one/zero这些可以直接使用
return nil;
}
```
当运行内置函数的时候内存分配器如果运行超过一次那么会有更大可能性多次触发垃圾收集器的mark-sweep。这个操作会在`gc::alloc`中触发。
如果先前获取的数值没有被正确存到可以被垃圾收集器索引到的地方,那么它会被错误地回收,这会导致严重的错误。
可以使用`gc::temp`来暂时存储一个会被返回的需要gc管理的变量这样可以防止内部所有的申请错误触发垃圾回收。如下所示
```C++
var builtin_keys(context* ctx, gc* ngc) {
auto hash = ctx->localr[1];
if (hash.type!=vm_hash && hash.type!=vm_map) {
return nas_err("keys", "\"hash\" must be hash");
}
// 使用gc.temp来存储gc管理的变量防止错误的回收
auto res = ngc->temp = ngc->alloc(vm_vec);
auto& vec = res.vec().elems;
if (hash.type==vm_hash) {
for(const auto& iter : hash.hash().elems) {
vec.push_back(ngc->newstr(iter.first));
}
} else {
for(const auto& iter : hash.map().mapper) {
vec.push_back(ngc->newstr(iter.first));
}
}
ngc->temp = nil;
return res;
}
```
这些工作都完成之后在内置函数注册表中填写它在nasal中的别名并且在表中填对这个函数的函数指针:
```C++
nasal_builtin_table builtin[] = {
{"__print", builtin_print},
{nullptr, nullptr}
};
```
最后将其包装到nasal文件中:
```javascript
var print = func(elems...) {
return __print(elems);
};
```
事实上`__print`后面跟着的传参列表不是必须要写的。所以这样写也对:
```javascript
var print = func(elems...) {
return __print;
};
```
如果你不把内置函数包装到一个普通的nasal函数中那么直接调用这个内置函数会在参数传入阶段出现 __segmentation fault(段错误)__。
在nasal文件中使用`import("文件名.nas")`可以导入该文件中你包装的所有内置函数,接下来你就可以使用他们了。
当然也有另外一种办法来导入这些nasal文件下面两种导入方式的效果是一样的
```javascript
use dirname.dirname.filename;
import("./dirname/dirname/filename.nas");
```
</details>
<details><summary>模块(开发者教程)</summary>
如果只有上文中那种方式来添加你自定义的函数到nasal中这肯定是非常麻烦的。
因此,我们实现了一组实用的内置函数来帮助你添加你自己创建的模块。
用于加载动态库的函数在`std/dylib.nas`中:
```javascript
var dlopen = func(libname) {
...
}
var dlclose = func(lib) {
...
}
var dlcall = func(ptr, args...) {
...
}
var limitcall = func(arg_size = 0) {
...
}
```
这些函数是用来加载动态库的这样nasal解释器可以根据用户需求灵活加载动态库来执行。让我们看看这些函数该如何使用。
首先用C++写个项目,并且编译成动态库。我们就拿`fib.cpp`作为例子来说明(样例代码可以在`./module`中找到):
```C++
// 这个头文件得加上因为我们需要拿到nasal的api
#include "nasal.h"
double fibonaci(double x) {
if (x<=2) {
return x;
}
return fibonaci(x-1)+fibonaci(x-2);
}
// 模块函数的参数列表一律以这个为准
var fib(var* args, usize size, gc* ngc) {
if (!size) {
return nas_err("fib", "lack arguments");
}
// 传参会给予一个var指针指向一个vm_vec的data()
var num = args[0];
// 如果你想让这个函数有更强的稳定性,那么一定要进行合法性检查
// nas_err会输出错误信息并返回错误类型让虚拟机终止执行
if(num.type!=vm_num) {
return nas_err("extern_fib", "\"num\" must be number");
}
// vm_num作为普通的数字类型不是内存管理的对象所以无需申请
// 如果需要返回内存管理的对象请使用ngc->alloc(type)
return var::num(fibonaci(num.tonum()));
}
// 然后将函数名字和函数地址放到一个表里,一定要记住表尾是{nullptr,nullptr}
module_func_info func_tbl[] = {
{"fib", fib},
{nullptr, nullptr}
};
// 必须实现这个函数, 这样nasal可以通过字符串名字获得函数指针
// 之所以用这种方式来获取函数指针, 是因为`var`是有构造函数的
// 有构造函数的类型作为返回值, 和C是不兼容的, 这导致
// 类似 "extern "C" var fib" 的写法会得到编译错误
extern "C" module_func_info* get() {
return func_tbl;
}
```
接着我们把`fib.cpp`编译成动态库。
Linux(`.so`):
`clang++ -c -O3 fib.cpp -fPIC -o fib.o`
`clang++ -shared -o libfib.so fib.o`
Mac(`.so` & `.dylib`): 和Linux下操作相同。
Windows(`.dll`):
`g++ -c -O3 fib.cpp -fPIC -o fib.o`
`g++ -shared -o libfib.dll fib.o`
好了那么我们可以写一个测试用的nasal代码来运行这个斐波那契函数了。
下面例子中`os.platform()`是用来检测当前运行的系统环境的,这样可以实现跨平台:
```javascript
use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
for(var i = 1; i<30; i += 1)
println(dylib.dlcall(fib, i));
dylib.dlclose(dlhandle.lib);
```
`dylib.dlopen`用于加载动态库并从动态库中获得函数地址。
`dylib.dlcall`用于调用函数,第一个参数是动态库函数的地址,这是个特殊类型,一定要保证这个参数是`vm_obj`类型并且`type=obj_extern`。
`dylib.dlclose`用于卸载动态库,当然,在这个函数调用之后,所有从该库中获取的函数都作废。
`dylib.limitcall`用于获取使用固定长度传参的 `dlcall` 函数,这种函数可以提高你的程序运行效率,因为它不需要用 `vm_vec` 来存储传入参数,而是使用局部作用域来直接存储,从而避免了频繁调用可能导致的频繁垃圾收集。所以上面展示的代码同样可以这样写:
```javascript
use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
for(var i = 1; i<30; i += 1)
println(invoke(fib, i));
dylib.dlclose(dlhandle.lib);
```
如果得到如下运行结果,恭喜你!
```bash
./nasal a.nas
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
```
</details>
<details><summary> 自定义类型(开发者教程) </summary>
创建一个自定义类型很容易。下面是使用示例:
```c++
const auto ghost_for_test = "ghost_for_test";
// 声明自定义类型的析构函数
void ghost_for_test_destructor(void* ptr) {
std::cout << "ghost_for_test::destructor (0x";
std::cout << std::hex << reinterpret_cast<u64>(ptr) << std::dec << ") {\n";
delete static_cast<u32*>(ptr);
std::cout << " delete 0x" << std::hex;
std::cout << reinterpret_cast<u64>(ptr) << std::dec << ";\n";
std::cout << "}\n";
}
var create_new_ghost(var* args, usize size, gc* ngc) {
var res = ngc->alloc(vm_obj);
// 创建自定义类型
res.ghost().set(ghost_for_test, ghost_for_test_destructor, new u32);
return res;
}
var set_new_ghost(var* args, usize size, gc* ngc) {
var res = args[0];
if (!res.object_check(ghost_for_test)) {
std::cout << "set_new_ghost: not ghost for test type.\n";
return nil;
}
f64 num = args[1].num();
*(reinterpret_cast<u32*>(res.ghost().pointer)) = static_cast<u32>(num);
std::cout << "set_new_ghost: successfully set ghost = " << num << "\n";
return nil;
}
var print_new_ghost(var* args, usize size, gc* ngc) {
var res = args[0];
// 用自定义类型的名字来检查是否是正确的自定义类型
if (!res.object_check(ghost_for_test)) {
std::cout << "print_new_ghost: not ghost for test type.\n";
return nil;
}
std::cout << "print_new_ghost: " << res.ghost() << " result = "
<< *((u32*)res.ghost().pointer) << "\n";
return nil;
}
```
我们使用下面这个函数来创建一个自定义类型:
`void nas_ghost::set(const std::string&, nasal::nas_ghost::destructor, void*);`
`const std::string&` 是自定义类型的类型名。
`nasal::nas_ghost::destructor` 是自定义类型的析构函数指针。
`void*` 是指向自定义类型实例的指针。
我们使用下面的这个函数检测是否是正确的自定义类型:
`bool var::object_check(const std::string&);`
参数是自定义类型的类型名。
</details>
## __与andy解释器的不同之处__
![error](../doc/gif/error.gif)

View File

@@ -110,3 +110,15 @@ 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](../doc/pic/mandelbrot.png)
## More nasal generated pictures
![mandelbrotset](../doc/pic/mandelbrotset.png)
![mandelbrotset_reverse](../doc/pic/mandelbrotset_reverse.png)
![burningship](../doc/pic/burningship.png)
![burningship_reverse](../doc/pic/burningship_reverse.png)
![feigenbaum](../doc/pic/feigenbaum.png)

View File

@@ -1,4 +1,4 @@
# __开发历史记录__
# __开发日志__
![buringship](./pic/burningship.png)

View File

@@ -44,6 +44,7 @@ In `std/example_module.nas`:
```nasal
var a = 1;
var _a = 1;
```
We analysed this file and generated the ast.
@@ -54,16 +55,20 @@ So the result is equal to:
```nasal
var example_module = func {
# source code begin
var a = 1;
var _a = 1;
# source code end
return {
a: a
# _a begins with underscore so do not export
};
}();
```
## Import a module
## Import a Module
Here is a module named `std/example_module.nas`:

View File

@@ -128,10 +128,10 @@
<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="/mandelbrotset.nas">mandelbrotset.nas</a></li>
<li><a href="/mcpu.nas">mcpu.nas</a></li>
<li><a href="/md5.nas">md5.nas</a></li>
<li><a href="/md5_self.nas">md5_self.nas</a></li>
<li><a href="/md5compare.nas">md5compare.nas</a></li>
</ul>
</td>

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

BIN
doc/pic/mandelbrotset.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

745
doc/tutorial.md Normal file
View File

@@ -0,0 +1,745 @@
# __Tutorial__
![mandelbrotset](../doc/pic/mandelbrotset.png)
Nasal is __easy__ to learn.
After reading this tutorial about 15 minutes,
You could totally use nasal.
## __Contents__
* [__Basic Type__](#basic-type)
* [__Operators__](#operators)
* [__Definition__](#definition)
* [__Multi-Assignment__](#multi-assignment)
* [__Conditional Expression__](#conditional-expression)
* [__Loop__](#loop)
* [__Subvec__](#subvec)
* [__Special function call__](#special-function-call)
* [__Lambda__](#lambda)
* [__Closure__](#closure)
* [__Trait__](#trait)
* [__Multi-Files/Modules Import__](#multi-filesmodules-import)
* [__Native Functions and Module Import__](#native-functions-and-module-import)
* [__C++ Modules (for lib developers)__](#c-modules-for-lib-developers)
* [__Ghost Type (for lib developers)__](#ghost-type-for-lib-developers)
## Basic Type
__`none`__ is error type used to interrupt the execution.
This type is not created by user program.
__`nil`__ is a null type. Just like `null`.
```javascript
var spc = nil;
```
__`num`__ has 3 formats: `dec`, `hex` and `oct`. Using IEEE754 `double` to store.
```javascript
# this language use '#' to write notes
var n = 2.71828; # dec
var n = 2.147e16; # dec
var n = 1e-10; # dec
var n = 0xAA55; # hex
var n = 0o170001; # oct
# caution: true and false also useful in nasal now
var n = true; # in fact n is now 1.0
var n = false; # in face n is now 0.0
```
__`str`__ has 3 formats. The third one is used to declare a character.
```javascript
var s = 'str';
var s = "another string";
var s = `c`;
# some special characters is allowed in this language:
'\a'; '\b'; '\e'; '\f';
'\n'; '\r'; '\t'; '\v';
'\0'; '\\'; '\?'; '\'';
'\"';
```
__`vec`__ has unlimited length and can store all types of values.
```javascript
var vec = [];
var vec = [0, nil, {}, [], func(){return 0}];
append(vec, 0, 1, 2);
```
__`hash`__ is a hashmap (or like a `dict` in `python`) that stores values with strings/identifiers as the key.
```javascript
var hash = {
member1: nil,
member2: "str",
"member3": "member\'s name can also be a string constant",
funct: func() {
return me.member2~me.member3;
}
};
```
__`func`__ is a function type (in fact it is `lambda`).
```javascript
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;
}
var f = func(args...) {
var sum = 0;
foreach(var i; args) {
sum += i;
}
return sum;
}
```
__`upval`__ is used to store upvalues, used in __`vm`__ to make sure closure runs correctly.
__`ghost`__ 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.
## Operators
Nasal has basic math operators `+` `-` `*` `/` and a special operator `~` that joints strings.
```javascript
1+2-(1+3)*(2+4)/(16-9);
"str1"~"str2";
```
For conditional expressions, operators `==` `!=` `<` `>` `<=` `>=` are used to compare two values.
`and` `or` have the same function as C/C++ `&&` `||`.
```javascript
1+1 and (1<0 or 1>0);
1<=0 and 1>=0;
1==0 or 1!=0;
```
Unary operators `-` `!` have the same function as C/C++.
```javascript
-1;
!0;
```
Bitwise operators `~` `|` `&` `^` have the same function as C/C++.
```javascript
# these operators will:
# 1. convert f64 to i32 (static_cast<int32_t>)
# 2. do the bitwise function
~0x80000000; # not 2147483647
0x8|0x1; # or
0x1&0x2; # and
0x8^0x1; # xor
```
Operators `=` `+=` `-=` `*=` `/=` `~=` `^=` `&=` `|=` are used in assignment expressions.
```javascript
a = b = c = d = 1;
a += 1;
a -= 1;
a *= 1;
a /= 1;
a ~= "string";
a ^= 0xff;
a &= 0xca;
a |= 0xba;
```
## Definition
As follows.
```javascript
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
```
Nasal has many special global symbols:
```javascript
globals; # hashmap including all global symbols and their values
arg; # in global scope, arg is the command line arguments
# in local scope, arg is the dynamic arguments of this function call
```
For example:
```javascript
var a = 1;
println(globals); # will print {a:1}
```
```javascript
# nasal a b c
println(arg); # will print ["a", "b", "c"]
func() {
println(arg);
}(1, 2, 3); # will print [1, 2, 3]
```
## Multi-assignment
The last one is often used to swap two variables.
```javascript
(a, b[0], c.d) = [0, 1, 2];
(a, b[1], c.e) = (0, 1, 2);
(a, b) = (b, a);
```
## Conditional expression
In nasal there's a new key word `elsif`.
It has the same functions as `else if`.
```javascript
if (1) {
;
} elsif (2) {
;
} else if (3) {
;
} else {
;
}
```
## Loop
While loop and for loop is simalar to C/C++.
```javascript
while(condition) {
continue;
}
for(var i = 0; i<10; i += 1) {
break;
}
```
Nasal has another two kinds of loops that iterates through a vector:
`forindex` will get the index of a vector. Index will be `0` to `size(elem)-1`.
```javascript
forindex(var i; elem) {
print(elem[i]);
}
```
`foreach` will get the element of a vector. Element will be `elem[0]` to `elem[size(elem)-1]`.
```javascript
foreach(var i; elem) {
print(i);
}
```
## Subvec
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.
Use index to search one element in the string will get the __ascii number__ of this character.
If you want to get the character, use built-in function `chr()`.
```javascript
a[0];
a[-1, 1, 0:2, 0:, :3, :, nil:8, 3:nil, nil:nil];
"hello world"[0];
```
## Special function call
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:[]);
```
## Lambda
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);
```
There's an interesting test file `y-combinator.nas`,
try it for fun:
```javascript
var fib = func(f) {
return f(f);
}(
func(f) {
return func(x) {
if(x<2) return x;
return f(f)(x-1)+f(f)(x-2);
}
}
);
```
## Closure
Closure means you could get the variable that is not in the local scope of a function that you called.
Here is an example, result is `1`:
```javascript
var f = func() {
var a = 1;
return func() {return a;};
}
print(f()());
```
Using closure makes it easier to OOP.
```javascript
var student = func(n, a) {
var (name, age) = (n, a);
return {
print_info: func() {println(name, ' ', age);},
set_age: func(a) {age = a;},
get_age: func() {return age;},
set_name: func(n) {name = n;},
get_name: func() {return name;}
};
}
```
## Trait
Also there's another way to OOP, that is `trait`.
When a hash has a member named `parents` and the value type is vector,
then when you are trying to find a member that is not in this hash,
virtual machine will search the member in `parents`.
If there is a hash that has the member, you will get the member's value.
Using this mechanism, we could OOP like this, the result is `114514`:
```javascript
var trait = {
get: func {return me.val;},
set: func(x) {me.val = x;}
};
var class = {
new: func() {
return {
val: nil,
parents: [trait]
};
}
};
var a = class.new();
a.set(114514);
println(a.get());
```
First virtual machine cannot find member `set` in hash `a`, but in `a.parents` there's a hash `trait` has the member `set`, so we get the `set`.
variable `me` points to hash `a`, so we change the `a.val`.
And `get` has the same process.
And we must remind you that if you do this:
```javascript
var trait = {
get: func {return me.val;},
set: func(x) {me.val = x;}
};
var class = {
new: func() {
return {
val: nil,
parents: [trait]
};
}
};
var a = class.new();
var b = class.new();
a.set(114);
b.set(514);
println(a.get());
println(b.get());
var c = a.get;
var d = b.get;
println(c());
println(c());
println(d());
println(d());
```
You will get this result now:
```bash
114
514
514
514
514
514
```
Because `a.get` will set `me=a` in the `trait.get`. Then `b.get` do the `me=b`. So in fact c is `b.get` too after running `var d=b.get`.
If you want to use this trick to make the program running more efficiently, you must know this special mechanism.
## Multi-Files/Modules Import</summary>
See more details in [namespace.md](./namespace.md)
## Native functions and module import
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, 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++
// you could also use a macro to define one.
var builtin_print(context*, gc*);
```
Then complete this function using C++:
```C++
var builtin_print(context* ctx, gc* ngc) {
// find value with index begin from 1
// because local[0] is reserved for value 'me'
for(auto& i : ctx->localr[1].vec().elems) {
std::cout << i;
}
std::cout << std::flush;
// generate return 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(context* ctx, gc* ngc) {
auto hash = ctx->localr[1];
if (hash.type!=vm_hash && hash.type!=vm_map) {
return nas_err("keys", "\"hash\" must be hash");
}
// use gc.temp to store the gc-managed-value, to avoid being sweeped
auto res = ngc->temp = ngc->alloc(vm_vec);
auto& vec = res.vec().elems;
if (hash.type==vm_hash) {
for(const auto& iter : hash.hash().elems) {
vec.push_back(ngc->newstr(iter.first));
}
} else {
for(const auto& iter : hash.map().mapper) {
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++
nasal_builtin_table builtin[] = {
{"__print", builtin_print},
{nullptr, nullptr}
};
```
At last,warp the `__print` in a nasal file:
```javascript
var print = func(elems...) {
return __print(elems);
};
```
In fact the arguments that `__print` uses are not necessary.
So writting it like this is also right:
```javascript
var print = func(elems...) {
return __print;
};
```
If you don't warp built-in function in a normal nasal function,
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:
```javascript
use dirname.dirname.filename;
import("./dirname/dirname/filename.nas");
```
## C++ Modules (for lib developers)
If there is only one way to add your own functions into nasal,
that is really inconvenient.
Luckily, we have developed some useful native-functions to help you add modules that created by you.
Functions used to load dynamic libraries are added to `std/dylib.nas`:
```javascript
var dlopen = func(libname) {
...
}
var dlclose = func(lib) {
...
}
var dlcall = func(ptr, args...) {
...
}
var limitcall = func(arg_size = 0) {
...
}
```
As you could see, these functions are used to load dynamic libraries into the nasal runtime and execute.
Let's see how they work.
First, write a cpp file that you want to generate the dynamic lib, take the `fib.cpp` as the example(example codes are in `./module`):
```C++
// add header file nasal.h to get api
#include "nasal.h"
double fibonaci(double x) {
if (x<=2) {
return x;
}
return fibonaci(x-1)+fibonaci(x-2);
}
// module functions' parameter list example
var fib(var* args, usize size, gc* ngc) {
if (!size) {
return nas_err("fib", "lack arguments");
}
// the arguments are generated into a vm_vec: args
// get values from the vector that must be used here
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 ngc->alloc(type)
// usage of gc is the same as adding a native function
return var::num(fibonaci(num.tonum()));
}
// then put function name and address into this table
// make sure the end of the table is {nullptr,nullptr}
module_func_info func_tbl[] = {
{"fib", fib},
{nullptr, nullptr}
};
// 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" module_func_info* get() {
return func_tbl;
}
```
Next, compile this `fib.cpp` into dynamic lib.
Linux(`.so`):
`clang++ -c -O3 fib.cpp -fPIC -o fib.o`
`clang++ -shared -o libfib.so fib.o`
Mac(`.so` & `.dylib`): same as Linux.
Windows(`.dll`):
`g++ -c -O3 fib.cpp -fPIC -o fib.o`
`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 cross-platform program:
```javascript
use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
for(var i = 1; i<30; i += 1)
println(dylib.dlcall(fib, i));
dylib.dlclose(dlhandle.lib);
```
`dylib.dlopen` is used to load dynamic library and get the function address.
`dylib.dlcall` is used to call the function, the first argument is the function address, make sure this argument is `vm_obj` and `type=obj_extern`.
`dylib.dlclose` is used to unload the library, at the moment that you call the function, all the function addresses that got from it are invalid.
`dylib.limitcall` is used to get `dlcall` function that has limited parameter size, this function will prove the performance of your code because it does not use `vm_vec` to store the arguments, instead it uses local scope to store them, so this could avoid frequently garbage collecting. And the code above could also be written like this:
```javascript
use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
for(var i = 1; i<30; i += 1)
println(invoke(fib, i));
dylib.dlclose(dlhandle.lib);
```
If get this, Congratulations!
```bash
./nasal a.nas
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
```
## Ghost Type (for lib developers)
It's quite easy to create a new ghost by yourself now.
Look at the example below:
```c++
const auto ghost_for_test = "ghost_for_test";
// declare destructor for ghost type
void ghost_for_test_destructor(void* ptr) {
std::cout << "ghost_for_test::destructor (0x";
std::cout << std::hex << reinterpret_cast<u64>(ptr) << std::dec << ") {\n";
delete static_cast<u32*>(ptr);
std::cout << " delete 0x" << std::hex;
std::cout << reinterpret_cast<u64>(ptr) << std::dec << ";\n";
std::cout << "}\n";
}
var create_new_ghost(var* args, usize size, gc* ngc) {
var res = ngc->alloc(vm_obj);
// create ghost type
res.ghost().set(ghost_for_test, ghost_for_test_destructor, new u32);
return res;
}
var set_new_ghost(var* args, usize size, gc* ngc) {
var res = args[0];
if (!res.object_check(ghost_for_test)) {
std::cout << "set_new_ghost: not ghost for test type.\n";
return nil;
}
f64 num = args[1].num();
*(reinterpret_cast<u32*>(res.ghost().pointer)) = static_cast<u32>(num);
std::cout << "set_new_ghost: successfully set ghost = " << num << "\n";
return nil;
}
var print_new_ghost(var* args, usize size, gc* ngc) {
var res = args[0];
// check ghost type by the type name
if (!res.object_check(ghost_for_test)) {
std::cout << "print_new_ghost: not ghost for test type.\n";
return nil;
}
std::cout << "print_new_ghost: " << res.ghost() << " result = "
<< *((u32*)res.ghost().pointer) << "\n";
return nil;
}
```
We use this function to create a new ghost type:
`void nas_ghost::set(const std::string&, nasal::nas_ghost::destructor, void*);`
`const std::string&` is the name of the ghost type.
`nasal::nas_ghost::destructor` is the pointer of the destructor of the ghost type.
`void*` is the pointer of the ghost type instance.
And we use this function to check if value is the correct ghost type:
`bool var::object_check(const std::string&);`
The parameter is the name of the ghost type.

726
doc/tutorial_zh.md Normal file
View File

@@ -0,0 +1,726 @@
# __教程__
![mandelbrotset](../doc/pic/mandelbrotset.png)
Nasal非常容易上手你可以在15分钟之内看完基本教程并直接开始编写程序。
## __目录__
* [__基本类型__](#基本类型)
* [__运算符__](#运算符)
* [__定义变量__](#定义变量)
* [__多变量赋值__](#多变量赋值)
* [__条件语句__](#条件语句)
* [__循环语句__](#循环语句)
* [__生成子列表(subvec)__](#生成子列表subvec)
* [__特殊函数调用语法__](#特殊函数调用语法)
* [__Lambda 表达式__](#lambda表达式)
* [__闭包__](#闭包)
* [__特性与继承__](#特性与继承)
* [__多文件/模块导入__](#多文件模块导入)
* [__原生内置函数以及模块导入__](#原生内置函数以及模块导入)
* [__C++ 模块(开发者教程)__](#c-模块开发者教程)
* [__自定义类型(开发者教程)__](#自定义类型开发者教程)
## 基本类型
__`none`__ 是特殊的错误类型。这个类型用于终止虚拟机的执行,该类型只能由虚拟机在抛出错误时产生。
__`nil`__ 是空类型。类似于null。
```javascript
var spc = nil;
```
__`num`__ 有三种形式:十进制十六进制以及八进制。并且该类型使用IEEE754标准的浮点数`double`格式来存储。
```javascript
# 该语言用 '#' 来作为注释的开头
var n = 2.71828; # dec 十进制
var n = 2.147e16; # dec 十进制
var n = 1e-10; # dec 十进制
var n = 0xAA55; # hex 十六进制
var n = 0o170001; # oct 八进制
# 注意: true false 关键字在现在的 nasal 里也是可用的
var n = true; # n 实际上是数字 1.0
var n = false; # n 实际上是数字 0.0
```
__`str`__ 也有三种不同的格式。第三种只允许包含一个的字符。
```javascript
var s = 'str';
var s = "another string";
var s = `c`;
# 该语言也支持一些特别的转义字符:
'\a'; '\b'; '\e'; '\f';
'\n'; '\r'; '\t'; '\v';
'\0'; '\\'; '\?'; '\'';
'\"';
```
__`vec`__ 有不受限制的长度并且可以存储所有类型的数据。(当然不能超过可分配内存空间的长度)
```javascript
var vec = [];
var vec = [0, nil, {}, [], func(){return 0}];
append(vec, 0, 1, 2);
```
__`hash`__ 使用哈希表 (类似于`python`中的`dict`)通过键值对来存储数据。key可以是一个字符串也可以是一个标识符。
```javascript
var hash = {
member1: nil,
member2: "str",
"member3": "member\'s name can also be a string constant",
funct: func() {
return me.member2~me.member3;
}
};
```
__`func`__ 函数类型。(实际上在这个语言里函数是一种`lambda`表达式)
```javascript
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;
}
var f = func(args...) {
var sum = 0;
foreach(var i; args) {
sum += i;
}
return sum;
}
```
__`upval`__ 是存储闭包数据的特殊类型, 在 __`vm`__ 中使用,以确保闭包功能正常。
__`ghost`__ 是用来存储`C/C++`的一些复杂数据结构。这种类型的数据由内置函数生成。如果想为nasal添加新的数据结构, 可以看下文如何通过修改本项目来添加内置函数。
## 运算符
Nasal拥有基本的四种数学运算符 `+` `-` `*` `/`以及一个特别的运算符 `~`,用于拼接字符串。
```javascript
1+2-(1+3)*(2+4)/(16-9);
"str1"~"str2";
```
对于条件语句,可以使用`==` `!=` `<` `>` `<=` `>=`来比较数据。`and` `or` 与C/C++中 `&&` `||`运算符一致。
```javascript
1+1 and (1<0 or 1>0);
1<=0 and 1>=0;
1==0 or 1!=0;
```
单目运算符`-` `!`与C/C++中的运算符功能类似。
```javascript
-1;
!0;
```
位运算符`~` `|` `&` `^`与C/C++中的运算符功能类似。
```javascript
# 运行过程:
# 1. f64 强转为 i32 (static_cast<int32_t>)
# 2. 执行位运算符
~0x80000000; # 按位取反 2147483647
0x8|0x1; # 按位或
0x1&0x2; # 按位与
0x8^0x1; # 按位异或
```
赋值运算符`=` `+=` `-=` `*=` `/=` `~=` `^=` `&=` `|=`正如其名,用于进行赋值。
```javascript
a = b = c = d = 1;
a += 1;
a -= 1;
a *= 1;
a /= 1;
a ~= "string";
a ^= 0xff;
a &= 0xca;
a |= 0xba;
```
## 定义变量
如下所示。
```javascript
var a = 1; # 定义单个变量
var (a, b, c) = [0, 1, 2]; # 从数组中初始化多个变量
var (a, b, c) = (0, 1, 2); # 从元组中初始化多个变量
```
Nasal 有很多特别的全局变量:
```javascript
globals; # 包含所有全局声明变量名和对应数据的哈希表
arg; # 在全局作用域arg 是包含命令行参数的数组
# 在局部作用域arg 是函数调用时的动态参数数组
```
具体实例:
```javascript
var a = 1;
println(globals); # 输出 {a:1}
```
```javascript
# nasal a b c
println(arg); # 输出 ["a", "b", "c"]
func() {
println(arg);
}(1, 2, 3); # 输出 [1, 2, 3]
```
## 多变量赋值
最后这个语句通常用于交换两个变量的数据类似于Python中的操作。
```javascript
(a, b[0], c.d) = [0, 1, 2];
(a, b[1], c.e) = (0, 1, 2);
(a, b) = (b, a);
```
## 条件语句
nasal在提供`else if`的同时还有另外一个关键字`elsif`。该关键字与`else if`有相同的功能。
```javascript
if (1) {
;
} elsif (2) {
;
} else if (3) {
;
} else {
;
}
```
## 循环语句
while循环和for循环大体上与C/C++是一致的。
```javascript
while(condition) {
continue;
}
for(var i = 0; i<10; i += 1) {
break;
}
```
同时nasal还有另外两种直接遍历列表的循环方式:
`forindex` 会获取列表的下标,依次递增. 下标会从`0`递增到`size(elem)-1`结束。
```javascript
forindex(var i; elem) {
print(elem[i]);
}
```
`foreach`会依次直接获取列表中的数据. 这些数据会从`elem[0]`依次获取到`elem[size(elem)-1]`.
```javascript
foreach(var i; elem) {
print(i);
}
```
## 生成子列表(subvec)
nasal提供了下面第一句的类似语法来从列表中随机或者按照一个区间获取数据并且拼接生成一个新的列表。当然如果中括号内只有一个下标的话你会直接获得这个下标对应的数据而不是一个子列表。如果直接对string使用下标来获取内容的话会得到对应字符的 __ascii值__。如果你想进一步获得这个字符串,可以尝试使用内置函数`chr()`
```javascript
a[0];
a[-1, 1, 0:2, 0:, :3, :, nil:8, 3:nil, nil:nil];
"hello world"[0];
```
## 特殊函数调用语法
这种调用方式不是很高效,因为哈希表会使用字符串比对来找到数据存放的位置。
然而如果它用起来非常舒适,那效率也显得不是非常重要了……
```javascript
f(x:0, y:nil, z:[]);
```
## lambda表达式
函数有这样一种直接编写函数体并且立即调用的方式:
```javascript
func(x, y) {
return x+y;
}(0, 1);
func(x) {
return 1/(1+math.exp(-x));
}(0.5);
```
测试文件中有一个非常有趣的文件`y-combinator.nas`,可以试一试:
```javascript
var fib = func(f) {
return f(f);
}(
func(f) {
return func(x) {
if(x<2) return x;
return f(f)(x-1)+f(f)(x-2);
}
}
);
```
## 闭包
闭包是一种特别的作用域,你可以从这个作用域中获取其保存的所有变量,
而这些变量原本不是你当前运行的函数的局部作用域中的。
下面这个例子里,结果是`1`:
```javascript
var f = func() {
var a = 1;
return func() {return a;};
}
print(f()());
```
如果善用闭包,你可以使用它来进行面向对象编程。
```javascript
var student = func(n, a) {
var (name, age) = (n, a);
return {
print_info: func() {println(name, ' ', age);},
set_age: func(a) {age = a;},
get_age: func() {return age;},
set_name: func(n) {name = n;},
get_name: func() {return name;}
};
}
```
## 特性与继承
当然,也有另外一种办法来面向对象编程,那就是利用`trait`
当一个hash类型中有一个成员的key是`parents`,并且该成员是一个数组的话,
那么当你试图从这个hash中寻找一个它自己没有的成员名时虚拟机会进一步搜索`parents`数组。
如果该数组中有一个hash类型有一个成员的key与当前你搜索的成员名一致
那么你会得到这个成员对应的值。
使用这个机制,我们可以进行面向对象编程,下面样例的结果是`114514`:
```javascript
var trait = {
get: func {return me.val;},
set: func(x) {me.val = x;}
};
var class = {
new: func() {
return {
val: nil,
parents: [trait]
};
}
};
var a = class.new();
a.set(114514);
println(a.get());
```
首先虚拟机会发现在`a`中找不到成员`set`,但是在`a.parents`中有个hash类型`trait`存在该成员,所以返回了这个成员的值。
成员`me`指向的是`a`自身,类似于一些语言中的`this`,所以我们通过这个函数,实际上修改了`a.val``get`函数的调用实际上也经过了相同的过程。
不过我们必须提醒你一点如果你在这个地方使用该优化来减少hash的搜索开销:
```javascript
var trait = {
get: func {return me.val;},
set: func(x) {me.val = x;}
};
var class = {
new: func() {
return {
val: nil,
parents: [trait]
};
}
};
var a = class.new();
var b = class.new();
a.set(114);
b.set(514);
println(a.get());
println(b.get());
var c = a.get;
var d = b.get;
println(c());
println(c());
println(d());
println(d());
```
那么你会发现现在虚拟机会输出这个结果:
```bash
114
514
514
514
514
514
```
因为执行`a.get`时在`trait.get`函数的属性中进行了`me=a`的操作。而`b.get`则执行了`me=b`的操作。所以在运行`var d=b.get`后实际上c也变成`b.get`了。
如果你想要用这种小技巧来让程序运行更高效的话,最好是要知道这里存在这样一个机制。
## 多文件/模块导入
详情可见 [namespace.md](./namespace.md)
## 原生内置函数以及模块导入
这个部分对于纯粹的使用者来说是不需要了解的,
它将告诉你我们是如何为解释器添加新的内置函数的。
如果你对此很感兴趣,那么这个部分可能会帮到你,并且……
__警告:__ 如果你 __不想__ 通过直接修改解释器源码来添加你自定义的函数,那么你应该看下一个节 __`模块`__ 的内容。
如果你确实是想修改源码来搞一个自己私人订制的解释器 ———— “我他妈就是想自己私人订制,你们他妈的管得着吗?”,
参考源码中关于内置函数的部分,以及`lib.nas`中是如何包装这些函数的,下面是其中一个样例:
定义新的内置函数:
```C++
// 你可以使用这个宏来直接定义一个新的内置函数
var builtin_print(context*, gc*);
```
然后用C++完成这个函数的函数体:
```C++
var builtin_print(context* ctx, gc* ngc) {
// 局部变量的下标其实是从 1 开始的
// 因为 local[0] 是保留给 'me' 的空间
for(auto& i : ctx->localr[1].vec().elems) {
std::cout << i;
}
std::cout << std::flush;
// 最后生成返回值,返回值必须是一个内置的类型,
// 可以使用ngc::alloc(type)来申请一个需要内存管理的复杂数据结构
// 或者用我们已经定义好的nil/one/zero这些可以直接使用
return nil;
}
```
当运行内置函数的时候内存分配器如果运行超过一次那么会有更大可能性多次触发垃圾收集器的mark-sweep。这个操作会在`gc::alloc`中触发。
如果先前获取的数值没有被正确存到可以被垃圾收集器索引到的地方,那么它会被错误地回收,这会导致严重的错误。
可以使用`gc::temp`来暂时存储一个会被返回的需要gc管理的变量这样可以防止内部所有的申请错误触发垃圾回收。如下所示
```C++
var builtin_keys(context* ctx, gc* ngc) {
auto hash = ctx->localr[1];
if (hash.type!=vm_hash && hash.type!=vm_map) {
return nas_err("keys", "\"hash\" must be hash");
}
// 使用gc.temp来存储gc管理的变量防止错误的回收
auto res = ngc->temp = ngc->alloc(vm_vec);
auto& vec = res.vec().elems;
if (hash.type==vm_hash) {
for(const auto& iter : hash.hash().elems) {
vec.push_back(ngc->newstr(iter.first));
}
} else {
for(const auto& iter : hash.map().mapper) {
vec.push_back(ngc->newstr(iter.first));
}
}
ngc->temp = nil;
return res;
}
```
这些工作都完成之后在内置函数注册表中填写它在nasal中的别名并且在表中填对这个函数的函数指针:
```C++
nasal_builtin_table builtin[] = {
{"__print", builtin_print},
{nullptr, nullptr}
};
```
最后将其包装到nasal文件中:
```javascript
var print = func(elems...) {
return __print(elems);
};
```
事实上`__print`后面跟着的传参列表不是必须要写的。所以这样写也对:
```javascript
var print = func(elems...) {
return __print;
};
```
如果你不把内置函数包装到一个普通的nasal函数中那么直接调用这个内置函数会在参数传入阶段出现 __segmentation fault(段错误)__。
在nasal文件中使用`import("文件名.nas")`可以导入该文件中你包装的所有内置函数,接下来你就可以使用他们了。
当然也有另外一种办法来导入这些nasal文件下面两种导入方式的效果是一样的
```javascript
use dirname.dirname.filename;
import("./dirname/dirname/filename.nas");
```
## C++ 模块(开发者教程)
如果只有上文中那种方式来添加你自定义的函数到nasal中这肯定是非常麻烦的。
因此,我们实现了一组实用的内置函数来帮助你添加你自己创建的模块。
用于加载动态库的函数在`std/dylib.nas`中:
```javascript
var dlopen = func(libname) {
...
}
var dlclose = func(lib) {
...
}
var dlcall = func(ptr, args...) {
...
}
var limitcall = func(arg_size = 0) {
...
}
```
这些函数是用来加载动态库的这样nasal解释器可以根据用户需求灵活加载动态库来执行。让我们看看这些函数该如何使用。
首先用C++写个项目,并且编译成动态库。我们就拿`fib.cpp`作为例子来说明(样例代码可以在`./module`中找到):
```C++
// 这个头文件得加上因为我们需要拿到nasal的api
#include "nasal.h"
double fibonaci(double x) {
if (x<=2) {
return x;
}
return fibonaci(x-1)+fibonaci(x-2);
}
// 模块函数的参数列表一律以这个为准
var fib(var* args, usize size, gc* ngc) {
if (!size) {
return nas_err("fib", "lack arguments");
}
// 传参会给予一个var指针指向一个vm_vec的data()
var num = args[0];
// 如果你想让这个函数有更强的稳定性,那么一定要进行合法性检查
// nas_err会输出错误信息并返回错误类型让虚拟机终止执行
if(num.type!=vm_num) {
return nas_err("extern_fib", "\"num\" must be number");
}
// vm_num作为普通的数字类型不是内存管理的对象所以无需申请
// 如果需要返回内存管理的对象请使用ngc->alloc(type)
return var::num(fibonaci(num.tonum()));
}
// 然后将函数名字和函数地址放到一个表里,一定要记住表尾是{nullptr,nullptr}
module_func_info func_tbl[] = {
{"fib", fib},
{nullptr, nullptr}
};
// 必须实现这个函数, 这样nasal可以通过字符串名字获得函数指针
// 之所以用这种方式来获取函数指针, 是因为`var`是有构造函数的
// 有构造函数的类型作为返回值, 和C是不兼容的, 这导致
// 类似 "extern "C" var fib" 的写法会得到编译错误
extern "C" module_func_info* get() {
return func_tbl;
}
```
接着我们把`fib.cpp`编译成动态库。
Linux(`.so`):
`clang++ -c -O3 fib.cpp -fPIC -o fib.o`
`clang++ -shared -o libfib.so fib.o`
Mac(`.so` & `.dylib`): 和Linux下操作相同。
Windows(`.dll`):
`g++ -c -O3 fib.cpp -fPIC -o fib.o`
`g++ -shared -o libfib.dll fib.o`
好了那么我们可以写一个测试用的nasal代码来运行这个斐波那契函数了。
下面例子中`os.platform()`是用来检测当前运行的系统环境的,这样可以实现跨平台:
```javascript
use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
for(var i = 1; i<30; i += 1)
println(dylib.dlcall(fib, i));
dylib.dlclose(dlhandle.lib);
```
`dylib.dlopen`用于加载动态库并从动态库中获得函数地址。
`dylib.dlcall`用于调用函数,第一个参数是动态库函数的地址,这是个特殊类型,一定要保证这个参数是`vm_obj`类型并且`type=obj_extern`。
`dylib.dlclose`用于卸载动态库,当然,在这个函数调用之后,所有从该库中获取的函数都作废。
`dylib.limitcall`用于获取使用固定长度传参的 `dlcall` 函数,这种函数可以提高你的程序运行效率,因为它不需要用 `vm_vec` 来存储传入参数,而是使用局部作用域来直接存储,从而避免了频繁调用可能导致的频繁垃圾收集。所以上面展示的代码同样可以这样写:
```javascript
use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib = dlhandle.fib;
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
for(var i = 1; i<30; i += 1)
println(invoke(fib, i));
dylib.dlclose(dlhandle.lib);
```
如果得到如下运行结果,恭喜你!
```bash
./nasal a.nas
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
```
## 自定义类型(开发者教程)
创建一个自定义类型很容易。下面是使用示例:
```c++
const auto ghost_for_test = "ghost_for_test";
// 声明自定义类型的析构函数
void ghost_for_test_destructor(void* ptr) {
std::cout << "ghost_for_test::destructor (0x";
std::cout << std::hex << reinterpret_cast<u64>(ptr) << std::dec << ") {\n";
delete static_cast<u32*>(ptr);
std::cout << " delete 0x" << std::hex;
std::cout << reinterpret_cast<u64>(ptr) << std::dec << ";\n";
std::cout << "}\n";
}
var create_new_ghost(var* args, usize size, gc* ngc) {
var res = ngc->alloc(vm_obj);
// 创建自定义类型
res.ghost().set(ghost_for_test, ghost_for_test_destructor, new u32);
return res;
}
var set_new_ghost(var* args, usize size, gc* ngc) {
var res = args[0];
if (!res.object_check(ghost_for_test)) {
std::cout << "set_new_ghost: not ghost for test type.\n";
return nil;
}
f64 num = args[1].num();
*(reinterpret_cast<u32*>(res.ghost().pointer)) = static_cast<u32>(num);
std::cout << "set_new_ghost: successfully set ghost = " << num << "\n";
return nil;
}
var print_new_ghost(var* args, usize size, gc* ngc) {
var res = args[0];
// 用自定义类型的名字来检查是否是正确的自定义类型
if (!res.object_check(ghost_for_test)) {
std::cout << "print_new_ghost: not ghost for test type.\n";
return nil;
}
std::cout << "print_new_ghost: " << res.ghost() << " result = "
<< *((u32*)res.ghost().pointer) << "\n";
return nil;
}
```
我们使用下面这个函数来创建一个自定义类型:
`void nas_ghost::set(const std::string&, nasal::nas_ghost::destructor, void*);`
`const std::string&` 是自定义类型的类型名。
`nasal::nas_ghost::destructor` 是自定义类型的析构函数指针。
`void*` 是指向自定义类型实例的指针。
我们使用下面的这个函数检测是否是正确的自定义类型:
`bool var::object_check(const std::string&);`
参数是自定义类型的类型名。

View File

@@ -44,7 +44,7 @@ var print_ghost = func(object) {
}
var test_ghost=func() {
var test_ghost = func() {
var ghost = create_ghost();
print_ghost(nil); # err
print_ghost(ghost); # random

View File

@@ -11,8 +11,8 @@ var (
var nb = lib.nas_noblock;
var call = dylib.limitcall(0);
return [
func(){return call(kb);},
func(){return call(gt);},
func(){return call(nb);}
func() {return call(kb);},
func() {return call(gt);},
func() {return call(nb);}
];
}();

View File

@@ -1,22 +1,22 @@
use std.dylib;
var socket=func(){
var lib=dylib.dlopen("libnasock"~(os.platform()=="windows"?".dll":".so"));
var socket = func() {
var lib = dylib.dlopen("libnasock"~(os.platform()=="windows"? ".dll":".so"));
var sock=lib.nas_socket;
var closesocket=lib.nas_closesocket;
var shutdown=lib.nas_shutdown;
var bind=lib.nas_bind;
var listen=lib.nas_listen;
var connect=lib.nas_connect;
var accept=lib.nas_accept;
var send=lib.nas_send;
var sendto=lib.nas_sendto;
var recv=lib.nas_recv;
var recvfrom=lib.nas_recvfrom;
var errno=lib.nas_errno;
var sock = lib.nas_socket;
var closesocket = lib.nas_closesocket;
var shutdown = lib.nas_shutdown;
var bind = lib.nas_bind;
var listen = lib.nas_listen;
var connect = lib.nas_connect;
var accept = lib.nas_accept;
var send = lib.nas_send;
var sendto = lib.nas_sendto;
var recv = lib.nas_recv;
var recvfrom = lib.nas_recvfrom;
var errno = lib.nas_errno;
var (invoke,invoke_i,invoke_ii,invoke_iii,invoke_iiii,invoke_iiiii)=(
var (invoke, invoke_i, invoke_ii, invoke_iii, invoke_iiii, invoke_iiiii) = (
dylib.limitcall(0),
dylib.limitcall(1),
dylib.limitcall(2),
@@ -26,36 +26,37 @@ var socket=func(){
);
return {
AF_UNSPEC:0,
AF_UNIX:1,
AF_INET:2,
AF_IMPLINK:3,
AF_PUP:4,
AF_CHAOS:5,
AF_IPX:6,
AF_NS:6,
AF_ISO:7,
AF_OSI:7,
AF_ECMA:8,
AF_DATAKIT:9,
AF_CCITT:10,
AF_SNA:11,
AF_DECnet:12,
AF_DLI:13,
AF_LAT:14,
AF_HYLINK:15,
AF_APPLETALK:16,
AF_NETBIOS:17,
AF_VOICEVIEW:18,
AF_FIREFOX:19,
AF_UNKNOWN1:20,
AF_BAN:21,
AF_MAX:22,
AF_UNIX: 1,
AF_INET: 2,
AF_IMPLINK: 3,
AF_PUP: 4,
AF_CHAOS: 5,
AF_IPX: 6,
AF_NS: 6,
AF_ISO: 7,
AF_OSI: 7,
AF_ECMA: 8,
AF_DATAKIT: 9,
AF_CCITT: 10,
AF_SNA: 11,
AF_DECnet: 12,
AF_DLI: 13,
AF_LAT: 14,
AF_HYLINK: 15,
AF_APPLETALK: 16,
AF_NETBIOS: 17,
AF_VOICEVIEW: 18,
AF_FIREFOX: 19,
AF_UNKNOWN1: 20,
AF_BAN: 21,
AF_MAX: 22,
SOCK_STREAM:1,
SOCK_DGRAM:2,
SOCK_RAW:3,
SOCK_RDM:4,
SOCK_SEQPACKET:5,
SOCKET_ERROR: -1,
SOCK_STREAM: 1,
SOCK_DGRAM: 2,
SOCK_RAW: 3,
SOCK_RDM: 4,
SOCK_SEQPACKET: 5,
IPPROTO_IP:0,IPPROTO_ICMP:1,IPPROTO_IGMP:2,IPPROTO_GGP:3,
IPPROTO_TCP:6,IPPROTO_PUP:12,IPPROTO_UDP:17,IPPROTO_IDP:22,
@@ -69,48 +70,49 @@ var socket=func(){
IPPORT_EFSSERVER:520,IPPORT_BIFFUDP:512,IPPORT_WHOSERVER:513,IPPORT_ROUTESERVER:520,
IPPORT_RESERVED:1024,
SHUT_RD :0x00,
SHUT_WR :0x01,
SHUT_RDWR:0x02,
SHUT_RD : 0x00,
SHUT_WR : 0x01,
SHUT_RDWR: 0x02,
MSG_OOB:0x1,
MSG_PEEK:0x2,
MSG_DONTROUTE:0x4,
MSG_OOB: 0x1,
MSG_PEEK: 0x2,
MSG_DONTROUTE: 0x4,
MSG_DONTWAIT: 0x40,
socket:func(af,type,proto){
return invoke_iii(sock,af,type,proto);
socket: func(af, type, proto = 0) {
return invoke_iii(sock, af, type, proto);
},
closesocket:func(sd){
return invoke_i(closesocket,sd);
closesocket: func(sd) {
return invoke_i(closesocket, sd);
},
shutdown: func(sd,how){
return invoke_ii(shutdown,sd,how);
shutdown: func(sd, how) {
return invoke_ii(shutdown, sd, how);
},
bind: func(sd,ip,port){
return invoke_iii(bind,sd,ip,port);
bind: func(sd, ip, port) {
return invoke_iii(bind, sd, ip, port);
},
listen: func(sd,backlog){
return invoke_ii(listen,sd,backlog);
listen: func(sd, backlog) {
return invoke_ii(listen, sd, backlog);
},
connect: func(sd,hostname,port){
return invoke_iii(connect,sd,hostname,port);
connect: func(sd, hostname, port) {
return invoke_iii(connect, sd, hostname, port);
},
accept: func(sd){
return invoke_i(accept,sd);
accept: func(sd) {
return invoke_i(accept, sd);
},
send: func(sd,buff,flags=0){
return invoke_iii(send,sd,buff,flags);
send: func(sd, buff, flags = 0) {
return invoke_iii(send, sd, buff, flags);
},
sendto: func(sd,hostname,port,buff,flags=0){
return invoke_iiiii(sendto,sd,hostname,port,buff,flags);
sendto: func(sd, hostname, port, buff, flags = 0) {
return invoke_iiiii(sendto, sd, hostname, port, buff, flags);
},
recv: func(sd,len,flags=0){
return invoke_iii(recv,sd,len,flags);
recv: func(sd, len, flags = 0) {
return invoke_iii(recv, sd, len, flags);
},
recvfrom: func(sd,len,flags=0){
return invoke_iii(recvfrom,sd,len,flags);
recvfrom: func(sd, len, flags = 0) {
return invoke_iii(recvfrom, sd, len, flags);
},
errno: func(){
errno: func() {
return invoke(errno);
}
};

View File

@@ -184,7 +184,7 @@ var nas_recv(var* args, usize size, gc* ngc) {
var res = ngc->temp = ngc->alloc(vm_hash);
auto& hash = res.hash().elems;
char* buf = new char[static_cast<int>(args[1].num())];
auto recvsize = recv(args[0].num(), buf,args[1].num(), args[2].num());
auto recvsize = recv(args[0].num(), buf, args[1].num(), args[2].num());
hash["size"] = var::num(static_cast<double>(recvsize));
buf[recvsize>=0? recvsize:0] = 0;
hash["str"] = ngc->newstr(buf);
@@ -231,6 +231,7 @@ var nas_recvfrom(var* args, usize size, gc* ngc) {
hash["str"] = ngc->newstr(buf);
delete[] buf;
hash["fromip"] = ngc->newstr(inet_ntoa(addr.sin_addr));
hash["port"] = var::num(ntohs(addr.sin_port));
ngc->temp = nil;
return res;
}

View File

@@ -1,12 +1,12 @@
# lib csv.nas
# ValKmjolnir 2022/10/15
var read = func(path, delimeter=",", endline="\n"){
var read = func(path, delimeter=",", endline="\n") {
var context = io.readfile(path);
context = split(endline, context);
forindex(var i;context){
forindex(var i;context) {
context[i] = split(delimeter,context[i]);
}
if(size(context)<=1){
if (size(context)<=1) {
die("incorrect csv file <"~path~">: "~size(context)~" line(s).");
}
return {

View File

@@ -7,7 +7,7 @@
var dlopen = func(libname) {
# find dynamic lib from local dir first
libname = (os.platform()=="windows"? ".\\":"./")~libname;
if(io.exists(libname))
if (io.exists(libname))
return __dlopen(libname);
# find dynamic lib through PATH
var envpath = split(os.platform()=="windows"? ";":":",unix.getenv("PATH"));
@@ -16,7 +16,7 @@ var dlopen = func(libname) {
var path = os.platform()=="windows"? "\\module\\":"/module/";
foreach(var p;envpath) {
p ~= path~libname;
if(io.exists(p)) {
if (io.exists(p)) {
libname = p;
break;
}
@@ -37,14 +37,14 @@ var dlcall = func(ptr, args...) {
# get dlcall function with limited parameter list
var limitcall = func(arg_size = 0) {
if(arg_size==0) {return func(ptr) {return __dlcall};}
elsif(arg_size==1) {return func(ptr, _0) {return __dlcall};}
elsif(arg_size==2) {return func(ptr, _0, _1) {return __dlcall};}
elsif(arg_size==3) {return func(ptr, _0, _1, _2) {return __dlcall};}
elsif(arg_size==4) {return func(ptr, _0, _1, _2, _3) {return __dlcall};}
elsif(arg_size==5) {return func(ptr, _0, _1, _2, _3, _4) {return __dlcall};}
elsif(arg_size==6) {return func(ptr, _0, _1, _2, _3, _4, _5) {return __dlcall};}
elsif(arg_size==7) {return func(ptr, _0, _1, _2, _3, _4, _5, _6) {return __dlcall};}
elsif(arg_size==8) {return func(ptr, _0, _1, _2, _3, _4, _5, _6, _7) {return __dlcall};}
if (arg_size==0) {return func(ptr) {return __dlcall};}
elsif (arg_size==1) {return func(ptr, _0) {return __dlcall};}
elsif (arg_size==2) {return func(ptr, _0, _1) {return __dlcall};}
elsif (arg_size==3) {return func(ptr, _0, _1, _2) {return __dlcall};}
elsif (arg_size==4) {return func(ptr, _0, _1, _2, _3) {return __dlcall};}
elsif (arg_size==5) {return func(ptr, _0, _1, _2, _3, _4) {return __dlcall};}
elsif (arg_size==6) {return func(ptr, _0, _1, _2, _3, _4, _5) {return __dlcall};}
elsif (arg_size==7) {return func(ptr, _0, _1, _2, _3, _4, _5, _6) {return __dlcall};}
elsif (arg_size==8) {return func(ptr, _0, _1, _2, _3, _4, _5, _6, _7) {return __dlcall};}
else {return func(ptr, args...) {return __dlcallv};}
}

View File

@@ -1,6 +1,7 @@
# flightgear developer environments simulator (beta)
# ValKmjolnir 2022
use std.runtime;
use std.coroutine;
println("-------------------------------------------------------------");
println(" FlightGear simulated-env for developers project, since 2019");
@@ -15,8 +16,8 @@ var fg_env_cli={
"--fg-env-help":{
info:"get help",
trigger:0,
f:func{
if(me.trigger)
f:func {
if (me.trigger)
return;
println("-------------------------------------------------------------");
println(" Help:");
@@ -29,8 +30,8 @@ var fg_env_cli={
"--fg-env-debug":{
info:"get property tree structure",
trigger:0,
f:func{
if(me.trigger)
f:func {
if (me.trigger)
return;
props.globals.debug();
me.trigger=1;
@@ -39,8 +40,8 @@ var fg_env_cli={
"--fg-env-mktmtest":{
info:"test maketimer",
trigger:0,
f:func{
if(me.trigger)
f:func {
if (me.trigger)
return;
maketimer_multi_coroutine_test(32);
me.trigger=1;
@@ -57,8 +58,8 @@ var fg_globals={
};
println("[\e[32m maketimer \e[0m] [",os.time(),"] new func add_event(name,interval,function)");
var add_event=func(name,interval,function){
fg_globals.event[name]=coroutine.create(func{
var add_event = func(name,interval,function) {
fg_globals.event[name]=coroutine.create(func {
var timestamp=maketimestamp();
timestamp.stamp();
while(timestamp.elapsedMSec()<interval*1000)
@@ -69,11 +70,11 @@ var add_event=func(name,interval,function){
}
println("[\e[32m maketimer \e[0m] [",os.time(),"] new func add_task(name,interval,function)");
var add_task=func(name,interval,function){
fg_globals.task[name]=coroutine.create(func{
var add_task = func(name,interval,function) {
fg_globals.task[name]=coroutine.create(func {
var counter=0;
var timestamp=maketimestamp();
while(1){
while(1) {
counter+=1;
timestamp.stamp();
while(timestamp.elapsedMSec()<interval*1000)
@@ -86,38 +87,38 @@ var add_task=func(name,interval,function){
}
println("[\e[32m maketimer \e[0m] [",os.time(),"] new func remove_task(name)");
var remove_task=func(name){
if(contains(fg_globals.task,name))
var remove_task = func(name) {
if (contains(fg_globals.task,name))
delete(fg_globals.task,name);
}
println("[\e[32m maketimer \e[0m] [",os.time(),"] new func remove_event(name)");
var remove_event=func(name){
if(contains(fg_globals.event,name))
var remove_event = func(name) {
if (contains(fg_globals.event,name))
delete(fg_globals.event,name);
}
println("[\e[32m maketimer \e[0m] [",os.time(),"] new func maketimer(interval,function)");
var maketimer=func(interval,function){
var maketimer = func(interval,function) {
var name="nasal-timer-";
var res={
start:func{
if(me.isRunning)
start:func {
if (me.isRunning)
return;
me.isRunning=1;
if(me.singleShot){
if (me.singleShot) {
add_event(name,interval,function);
}else{
} else {
add_task(name,interval,function);
}
},
stop:func{
if(me.isRunning){
stop:func {
if (me.isRunning) {
remove_task(name);
me.isRunning=0;
}
},
restart:func(itv){
restart:func(itv) {
interval=itv;
me.stop();
me.start();
@@ -131,9 +132,9 @@ var maketimer=func(interval,function){
}
println("[\e[32m settimer \e[0m] [",os.time(),"] new func settimer(function,interval,rt)");
var settimer=func(){
var settimer = func() {
var index=0;
return func(function,interval,realtime=1){
return func(function,interval,realtime=1) {
var name="nasal-settimer-"~index;
index+=1;
add_task(name,interval,function);
@@ -141,25 +142,25 @@ var settimer=func(){
}();
println("[\e[32m maketimer \e[0m] [",os.time(),"] test func simulation()");
var simulation=func(){
var simulation = func() {
var running=1;
while(running){
while(running) {
running=0;
foreach(var i;keys(fg_globals.task)){
if(!contains(fg_globals.task,i))
foreach(var i;keys(fg_globals.task)) {
if (!contains(fg_globals.task,i))
continue;
if(coroutine.resume(fg_globals.task[i])!=nil){
if (coroutine.resume(fg_globals.task[i])!=nil) {
running=1;
}else{
} else {
remove_task(i);
}
}
foreach(var i;keys(fg_globals.event)){
if(!contains(fg_globals.event,i))
foreach(var i;keys(fg_globals.event)) {
if (!contains(fg_globals.event,i))
continue;
if(coroutine.resume(fg_globals.event[i])!=nil){
if (coroutine.resume(fg_globals.event[i])!=nil) {
running=1;
}else{
} else {
remove_event(i);
}
}
@@ -167,14 +168,14 @@ var simulation=func(){
}
println("[\e[32m maketimer \e[0m] [",os.time(),"] test func maketimer_multi_coroutine_test(size)");
var maketimer_multi_coroutine_test=func(coroutine_size){
if(coroutine_size<1)
var maketimer_multi_coroutine_test = func(coroutine_size) {
if (coroutine_size<1)
return;
var task_vec=[];
setsize(task_vec,coroutine_size);
forindex(var i;task_vec)
task_vec[i]=func{};
task_vec[coroutine_size-1]=func{
task_vec[i] = func {};
task_vec[coroutine_size-1] = func {
println("\e[101m",coroutine_size," tasks invoked.\e[0m");
forindex(var i;task_vec)
task_vec[i].stop();
@@ -182,23 +183,23 @@ var maketimer_multi_coroutine_test=func(coroutine_size){
var event_vec=[];
setsize(event_vec,coroutine_size);
forindex(var i;event_vec)
event_vec[i]=func{};
event_vec[coroutine_size-1]=func{
event_vec[i] = func {};
event_vec[coroutine_size-1] = func {
println("\e[101m",coroutine_size," events invoked.\e[0m");
}
var set_vec=[];
setsize(set_vec,coroutine_size);
forindex(var i;set_vec)
set_vec[i]=func{};
set_vec[coroutine_size-1]=func{
set_vec[i] = func {};
set_vec[coroutine_size-1] = func {
println("\e[101m",coroutine_size," settimer invoked.\e[0m");
}
forindex(var i;task_vec){
forindex(var i;task_vec) {
task_vec[i]=maketimer((i+1)/10,task_vec[i]);
task_vec[i].start();
}
forindex(var i;event_vec){
forindex(var i;event_vec) {
event_vec[i]=maketimer((i+1)/10,event_vec[i]);
event_vec[i].singleShot=1;
event_vec[i].start();
@@ -209,7 +210,7 @@ var maketimer_multi_coroutine_test=func(coroutine_size){
}
println("[\e[32m geodinfo \e[0m] [",os.time(),"] init geodinfo(lat,lon)");
var geodinfo=func(lat,lon){
var geodinfo = func(lat,lon) {
return [nil,{
names:["Road","Freeway"]
}];
@@ -219,14 +220,14 @@ println("[\e[32m props \e[0m] [",os.time(),"] init props");
var props={
globals:nil,
Node:nil,
getNode:func(path,index){
getNode:func(path,index) {
path=split('/',path);
var tmp=me.globals;
var path_size=size(path);
for(var i=0;i<path_size-1;i+=1)
tmp=tmp.val[path[i]];
if(path_size>0){
if(contains(tmp.val,path[i]~'['~index~']'))
if (path_size>0) {
if (contains(tmp.val,path[i]~'['~index~']'))
return tmp.val[path[i]~'['~index~']'];
else
return tmp.val[path[i]];
@@ -238,89 +239,89 @@ var props={
println("[\e[32m props \e[0m] [",os.time(),"] init props.Node");
props.Node={
new:func(values=nil){
new:func(values=nil) {
var res={
parents:fg_env_props_node_traits,
val:{},
type:'GHOST',
parent:nil
};
if(typeof(values)=="hash")
if (typeof(values)=="hash")
res.val=values;
return res;
},
addChild:func(name){
if(!contains(me.val,name)){
addChild:func(name) {
if (!contains(me.val,name)) {
me.val[name]=props.Node.new();
me.val[name].parent=me;
return 1;
}
return 0;
},
addChildren:func(name,cnt=0){
for(var i=0;i<cnt;i+=1){
addChildren:func(name,cnt=0) {
for(var i=0;i<cnt;i+=1) {
var label=name~'['~i~']';
me.val[label]=props.Node.new();
me.val[label].parent=me;
}
return;
},
setValue:func(path,val){
setValue:func(path,val) {
path=split('/',path);
var tmp=me;
foreach(var label;path)
tmp=tmp.val[label];
tmp.val=val;
if(typeof(val)=='str'){
if(val=='true' or val=='false')
if (typeof(val)=='str') {
if (val=='true' or val=='false')
tmp.type='BOOL';
else
tmp.type='STRING';
}
elsif(typeof(val)=='num')
elsif (typeof(val)=='num')
tmp.type='DOUBLE';
return;
},
setIntValue:func(num){
setIntValue:func(num) {
me.val=num;
me.type='INT';
return;
},
setBoolValue:func(state){
setBoolValue:func(state) {
me.val=state;
me.type='BOOL';
return;
},
setDoubleValue:func(num){
setDoubleValue:func(num) {
me.val=num;
me.type='DOUBLE';
return;
},
getValue:func(){return me.val;},
getName:func(){
getValue:func() {return me.val;},
getName:func() {
var val=me.parent.val;
foreach(var k;keys(val))
if(val[k]==me)
if (val[k]==me)
return k;
return '';
},
getParent:func(){
getParent:func() {
return me.parent;
},
getPath:func(){
if(me.parent==nil) return '';
getPath:func() {
if (me.parent==nil) return '';
return me.parent.getPath()~'/'~me.getName();
},
equals:func(node){return me==node;},
debug:func(s=''){
if(typeof(me.val)=='hash'){
equals:func(node) {return me==node;},
debug:func(s='') {
if (typeof(me.val)=='hash') {
var key=keys(me.val);
if(!size(key)){
if (!size(key)) {
println("\e[91m{}\e[0m");
return;
}
println('\e[91m{\e[0m');
foreach(var k;key){
foreach(var k;key) {
print(s~" ","\e[34m",k,"\e[0m\e[95m:\e[0m");
me.val[k].debug(s~" ");
}
@@ -352,7 +353,7 @@ props.getNode("/consumables/fuel",1).addChild("total-gal_us");
props.getNode("/consumables/fuel/total-fuel-lbs",1).setValue('/',0);
props.getNode("/consumables/fuel/total-gal_us",1).setValue('/',0);
props.getNode("/consumables/fuel",1).addChildren("tank",4);
for(var i=0;i<4;i+=1){
for(var i=0;i<4;i+=1) {
props.getNode("/consumables/fuel/tank["~i~"]",1).addChild("level-lb");
props.getNode("/consumables/fuel/tank["~i~"]",1).addChild("level-lbs");
props.getNode("/consumables/fuel/tank["~i~"]",1).addChild("level-gal_us");
@@ -374,7 +375,7 @@ println("[\e[32m props \e[0m] [",os.time(),"] init /controls/anti-ice");
foreach(var i;['wing-heat','pitot-heat','wiper','window-heat'])
props.getNode("/controls/anti-ice",1).addChild(i);
props.getNode("/controls/anti-ice",1).addChildren("engine",2);
for(var i=0;i<2;i+=1){
for(var i=0;i<2;i+=1) {
props.getNode("/controls/anti-ice/engine["~i~"]",1).addChild("carb-heat");
props.getNode("/controls/anti-ice/engine["~i~"]",1).addChild("inlet-heat");
}
@@ -388,7 +389,7 @@ props.getNode("/controls/armament",1).addChild("master-arm");
props.getNode("/controls/armament",1).addChild("station-select");
props.getNode("/controls/armament",1).addChild("release-all");
props.getNode("/controls/armament",1).addChildren("station",4);
for(var i=0;i<4;i+=1){
for(var i=0;i<4;i+=1) {
props.getNode("/controls/armament/station["~i~"]",1).addChild("stick-size");
props.getNode("/controls/armament/station["~i~"]",1).addChild("release-stick");
props.getNode("/controls/armament/station["~i~"]",1).addChild("release-all");
@@ -406,7 +407,7 @@ println("[\e[32m props \e[0m] [",os.time(),"] init /controls/electric");
foreach(var i;['battery-switch','external-power','APU-generator'])
props.getNode("/controls/electric",1).addChild(i);
props.getNode("/controls/electric",1).addChildren("engine",2);
for(var i=0;i<2;i+=1){
for(var i=0;i<2;i+=1) {
props.getNode("/controls/electric/engine["~i~"]",1).addChild("generator");
props.getNode("/controls/electric/engine["~i~"]",1).addChild("bus-tie");
}
@@ -425,7 +426,7 @@ foreach(var i;['aileron','aileron-trim','elevator','elevator-trim','rudder','rud
println("[\e[32m props \e[0m] [",os.time(),"] init /controls/fuel");
props.getNode("/controls/fuel",1).addChild("dump-value");
props.getNode("/controls/fuel",1).addChildren("tank",4);
for(var i=0;i<4;i+=1){
for(var i=0;i<4;i+=1) {
foreach(var j;['fuel-selector','to_engine','to_tank'])
props.getNode("/controls/fuel/tank["~i~"]",1).addChild(j);
props.getNode("/controls/fuel/tank["~i~"]",1).addChildren("boost-pump",4);
@@ -440,7 +441,7 @@ for(var i=0;i<4;i+=1)
println("[\e[32m props \e[0m] [",os.time(),"] init /controls/hydraulic");
props.getNode("/controls/hydraulic",1).addChildren("system",2);
for(var i=0;i<2;i+=1){
for(var i=0;i<2;i+=1) {
props.getNode("/controls/hydraulic/system["~i~"]",1).addChild("engine-pump");
props.getNode("/controls/hydraulic/system["~i~"]",1).addChild("electric-pump");
}
@@ -466,7 +467,7 @@ println("[\e[32m props \e[0m] [",os.time(),"] init /controls/seat");
foreach(var i;['vertical-adjust','fore-aft-adjust','cmd_selector_valve'])
props.getNode("/controls/seat",1).addChild(i);
props.getNode("/controls/seat",1).addChildren("eject",3);
for(var i=0;i<3;i+=1){
for(var i=0;i<3;i+=1) {
props.getNode("/controls/seat/eject["~i~"]",1).addChild("initiate");
props.getNode("/controls/seat/eject["~i~"]",1).addChild("status");
}
@@ -536,17 +537,17 @@ props.getNode("/position/altitude-agl-ft",1).setValue('/',22.4704);
props.getNode("/orientation/heading-deg",1).setValue('/',90);
props.getNode("/controls/flight/rudder",1).setValue('/',0.114);
func(){
func() {
srand();
var tmp=nil;
var vec=[props.globals];
while(size(vec)){
while(size(vec)) {
tmp=[];
foreach(var i;vec){
if(typeof(i.val)=="hash"){
if(size(i.val)==0){
foreach(var i;vec) {
if (typeof(i.val)=="hash") {
if (size(i.val)==0) {
i.setDoubleValue(rand()*10);
}else{
} else {
foreach(var j;keys(i.val))
append(tmp,i.val[j]);
}
@@ -561,267 +562,6 @@ println("[\e[32m fg_env \e[0m] [",os.time(),"] init done");
println("-------------------------------------------------------------");
foreach(var a;runtime.argv())
if(contains(fg_env_cli,a)){
if (contains(fg_env_cli,a)) {
fg_env_cli[a].f();
}
# related doc: https://sourceforge.net/p/flightgear/fgdata/ci/next/tree/Docs/README.properties
# ================================================================================
# CONTROLS
# ================================================================================
# Flight Controls
# ---------------
# /controls/flight/aileron
# /controls/flight/aileron-trim
# /controls/flight/elevator
# /controls/flight/elevator-trim
# /controls/flight/rudder
# /controls/flight/rudder-trim
# /controls/flight/flaps
# /controls/flight/slats
# /controls/flight/BLC // Boundary Layer Control
# /controls/flight/spoilers
# /controls/flight/speedbrake
# /controls/flight/wing-sweep
# /controls/flight/wing-fold
# /controls/flight/drag-chute
# Engines
# -------
# /controls/engines/throttle_idle
# /controls/engines/engine[%d]/throttle
# /controls/engines/engine[%d]/starter
# /controls/engines/engine[%d]/fuel-pump
# /controls/engines/engine[%d]/fire-switch
# /controls/engines/engine[%d]/fire-bottle-discharge
# /controls/engines/engine[%d]/cutoff
# /controls/engines/engine[%d]/mixture
# /controls/engines/engine[%d]/propeller-pitch
# /controls/engines/engine[%d]/magnetos
# /controls/engines/engine[%d]/boost
# /controls/engines/engine[%d]/WEP
# /controls/engines/engine[%d]/cowl-flaps-norm
# /controls/engines/engine[%d]/feather
# /controls/engines/engine[%d]/ignition
# /controls/engines/engine[%d]/augmentation
# /controls/engines/engine[%d]/afterburner
# /controls/engines/engine[%d]/reverser
# /controls/engines/engine[%d]/water-injection
# /controls/engines/engine[%d]/condition
# Fuel
# ----
# /controls/fuel/dump-valve
# /controls/fuel/tank[%d]/fuel_selector
# /controls/fuel/tank[%d]/to_engine
# /controls/fuel/tank[%d]/to_tank
# /controls/fuel/tank[%d]/boost-pump[%d]
# /consumables/fuel/tank[%d]/level-lbs
# /consumables/fuel/tank[%d]/level-gal_us
# /consumables/fuel/tank[%d]/capacity-gal_us
# /consumables/fuel/tank[%d]/density-ppg
# /consumables/fuel/total-fuel-lbs
# /consumables/fuel/total-gal_us
# Gear
# ----
# /controls/gear/brake-left
# /controls/gear/brake-right
# /controls/gear/brake-parking
# /controls/gear/steering
# /controls/gear/gear-down
# /controls/gear/antiskid
# /controls/gear/tailhook
# /controls/gear/tailwheel-lock
# /controls/gear/wheel[%d]/alternate-extension
# Anti-Ice
# --------
# /controls/anti-ice/wing-heat
# /controls/anti-ice/pitot-heat
# /controls/anti-ice/wiper
# /controls/anti-ice/window-heat
# /controls/anti-ice/engine[%d]/carb-heat
# /controls/anti-ice/engine[%d]/inlet-heat
# Hydraulics
# ----------
# /controls/hydraulic/system[%d]/engine-pump
# /controls/hydraulic/system[%d]/electric-pump
# Electric
# --------
# /controls/electric/battery-switch
# /controls/electric/external-power
# /controls/electric/APU-generator
# /controls/electric/engine[%d]/generator
# /controls/electric/engine[%d]/bus-tie
# Pneumatic
# ---------
# /controls/pneumatic/APU-bleed
# /controls/pneumatic/engine[%d]/bleed
# Pressurization
# --------------
# /controls/pressurization/mode
# /controls/pressurization/dump
# /controls/pressurization/outflow-valve
# /controls/pressurization/pack[%d]/pack-on
# Lights
# ------
# /controls/lighting/landing-lights
# /controls/lighting/turn-off-lights
# /controls/lighting/formation-lights
# /controls/lighting/taxi-light
# /controls/lighting/logo-lights
# /controls/lighting/nav-lights
# /controls/lighting/beacon
# /controls/lighting/strobe
# /controls/lighting/panel-norm
# /controls/lighting/instruments-norm
# /controls/lighting/dome-norm
# Armament
# --------
# /controls/armament/master-arm
# /controls/armament/station-select
# /controls/armament/release-all
# /controls/armament/station[%d]/stick-size
# /controls/armament/station[%d]/release-stick
# /controls/armament/station[%d]/release-all
# /controls/armament/station[%d]/jettison-all
# Seat
# ----
# /controls/seat/vertical-adjust
# /controls/seat/fore-aft-adjust
# /controls/seat/cmd_selector_valve
# /controls/seat/eject[%d]/initiate
# /controls/seat/eject[%d]/status
# APU
# ---
# /controls/APU/off-start-run
# /controls/APU/fire-switch
# Autoflight
# ----------
# /controls/autoflight/autopilot[%d]/engage
# /controls/autoflight/autothrottle-arm
# /controls/autoflight/autothrottle-engage
# /controls/autoflight/heading-select
# /controls/autoflight/altitude-select
# /controls/autoflight/bank-angle-select
# /controls/autoflight/vertical-speed-select
# /controls/autoflight/speed-select
# /controls/autoflight/mach-select
# /controls/autoflight/vertical-mode
# /controls/autoflight/lateral-mode
# ================================================================================
# FDM (Aircraft settings)
# ================================================================================
# Position
# ---------------
# /position/latitude-deg
# /position/longitude-deg
# /position/altitude-ft
# Orientation
# -----------
# /orientation/roll-deg
# /orientation/pitch-deg
# /orientation/heading-deg
# /orientation/roll-rate-degps
# /orientation/pitch-rate-degps
# /orientation/yaw-rate-degps
# /orientation/side-slip-rad
# /orientation/side-slip-deg
# /orientation/alpha-deg
# Velocities
# ----------
# /velocities/airspeed-kt
# /velocities/mach
# /velocities/speed-north-fps
# /velocities/speed-east-fps
# /velocities/speed-down-fps
# /velocities/uBody-fps
# /velocities/vBody-fps
# /velocities/wBody-fps
# /velocities/vertical-speed-fps
# /velocities/glideslope
# Acceleration
# ------------
# /accelerations/nlf
# /accelerations/ned/north-accel-fps_sec
# /accelerations/ned/east-accel-fps_sec
# /accelerations/ned/down-accel-fps_sec
# /accelerations/pilot/x-accel-fps_sec
# /accelerations/pilot/y-accel-fps_sec
# /accelerations/pilot/z-accel-fps_sec
# Engines
# -------
# common:
# /engines/engine[%d]/fuel-flow-gph
# /engines/engine[%d]/fuel-flow_pph
# /engines/engine[%d]/thrust_lb
# /engines/engine[%d]/running
# /engines/engine[%d]/starter
# /engines/engine[%d]/cranking
# piston:
# /engines/engine[%d]/mp-osi
# /engines/engine[%d]/egt-degf
# /engines/engine[%d]/oil-temperature-degf
# /engines/engine[%d]/oil-pressure-psi
# /engines/engine[%d]/cht-degf
# /engines/engine[%d]/rpm
# turbine:
# /engines/engine[%d]/n1
# /engines/engine[%d]/n2
# /engines/engine[%d]/epr
# /engines/engine[%d]/augmentation
# /engines/engine[%d]/water-injection
# /engines/engine[%d]/ignition
# /engines/engine[%d]/nozzle-pos-norm
# /engines/engine[%d]/inlet-pos-norm
# /engines/engine[%d]/reversed
# /engines/engine[%d]/cutoff
# propeller:
# /engines/engine[%d]/rpm
# /engines/engine[%d]/pitch
# /engines/engine[%d]/torque
# ================================================================================
# LIGHT
# ================================================================================
# /sim/time/sun-angle-rad
# /rendering/scene/ambient/red
# /rendering/scene/ambient/ggreen
# /rendering/scene/ambient/blue
# /rendering/scene/diffuse/red
# /rendering/scene/diffuse/green
# /rendering/scene/diffuse/blue
# /rendering/scene/specular/red
# /rendering/scene/specular/green
# /rendering/scene/specular/blue

View File

@@ -8,7 +8,7 @@ var SEEK_CUR = io.SEEK_CUR;
var SEEK_END = io.SEEK_END;
var new = func(filename, mode="r"){
var new = func(filename, mode="r") {
if (!io.exists(filename)) {
return nil;
}
@@ -29,17 +29,17 @@ var new = func(filename, mode="r"){
};
}
var find_all_files_with_extension = func(path, extensions...){
var find_all_files_with_extension = func(path, extensions...) {
var in_vec = func(ext) {
foreach(var i;extensions) {
if (ext==i){
if (ext==i) {
return 1;
}
}
return 0;
}
var res = [];
foreach(var f;find_all_files(path)){
foreach(var f;find_all_files(path)) {
var tmp = split('.', f);
if (size(tmp)>1 and in_vec(tmp[-1])) {
append(res, f);
@@ -48,16 +48,17 @@ var find_all_files_with_extension = func(path, extensions...){
return res;
}
var find_all_files = func(path){
var find_all_files = func(path) {
if (!io.exists(path)) {
return [];
}
var dd = unix.opendir(path);
var res = [];
while(var n = unix.readdir(dd))
if(unix.isfile(path~"/"~n)) {
while(var n = unix.readdir(dd)) {
if (unix.isfile(path~"/"~n)) {
append(res, n);
}
}
unix.closedir(dd);
return res;
}

View File

@@ -11,8 +11,9 @@ var (
_j_colon,
_j_str,
_j_num,
_j_id
) = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
_j_id,
_j_bool
) = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
var _j_content = [
"eof",
@@ -24,11 +25,13 @@ var _j_content = [
"`:`",
"string",
"number",
"identifier"
"identifier",
"boolean"
];
var parse = func() {
var _parse_error = 0;
var parse = func() {
var text = "";
var line = 1;
var text_size = 0;
@@ -75,6 +78,7 @@ var parse = func() {
init();
if (!size(str)) {
println("json::parse: empty string");
_parse_error += 1;
str = "[]";
}
text = str;
@@ -89,7 +93,7 @@ var parse = func() {
}
ptr += 1;
}
if(ptr>=text_size) {
if (ptr>=text_size) {
token.content = "eof";
token.type = _j_eof;
return;
@@ -131,7 +135,13 @@ var parse = func() {
} elsif (isnum(c)) {
var s = c;
ptr += 1;
while(ptr<text_size and ((isnum(char(text[ptr])) or char(text[ptr])=='.'))) {
while(ptr<text_size and ((
isnum(char(text[ptr])) or
char(text[ptr])=='.' or
char(text[ptr])=='e' or
char(text[ptr])=='-' or
char(text[ptr])=='+'))
) {
s ~= char(text[ptr]);
ptr += 1;
}
@@ -148,14 +158,18 @@ var parse = func() {
ptr -= 1;
token.content = s;
token.type = _j_id;
if (s=="true" or s=="false") {
token.type = _j_bool;
}
}
ptr += 1;
return;
}
var match = func(type) {
if(token.type!=type) {
if (token.type!=type) {
println("json::parse: line ",line,": expect ",_j_content[type]," but get `",token.content,"`.");
_parse_error += 1;
}
next();
return;
@@ -176,7 +190,7 @@ var parse = func() {
hash[name] = hash_gen();
} elsif (token.type==_j_lbrkt) {
hash[name] = vec_gen();
} elsif (token.type==_j_str or token.type==_j_num) {
} elsif (token.type==_j_str or token.type==_j_num or token.type==_j_bool) {
hash[name] = token.content;
next();
}
@@ -222,8 +236,10 @@ var parse = func() {
}
return func(source) {
if(typeof(source)!="str") {
_parse_error = 0;
if (typeof(source)!="str") {
println("json::parse: must use string but get", typeof(str));
_parse_error += 1;
return [];
}
@@ -242,8 +258,10 @@ var parse = func() {
}();
var stringify = func(object) {
_parse_error = 0;
var object_type = typeof(object);
if(object_type!="hash" and object_type!="vec" and object_type!="namespace") {
if (object_type!="hash" and object_type!="vec" and object_type!="namespace") {
_parse_error += 1;
println("json::stringify: must use hashmap or vector, but get ", typeof(object));
return "[]";
}
@@ -281,7 +299,7 @@ var stringify = func(object) {
var k = keys(h);
var vsize = size(k);
for(var i = 0; i<vsize; i += 1) {
s ~= k[i]~":";
s ~= "\""~k[i]~"\":";
gen(h[k[i]]);
if (i!=vsize-1) {
s ~= ",";
@@ -296,4 +314,16 @@ var stringify = func(object) {
hgen(object);
}
return s;
}
var get_error = func() {
return _parse_error;
}
var check_error = func() {
if (_parse_error==0) {
return;
}
println("json: encounter ", _parse_error, " error(s), stop.");
exit(-1);
}

View File

@@ -1,12 +1,9 @@
# lib.nas
# 2019 ValKmjolnir
use std.coroutine;
use std.math;
use std.string;
use std.io;
use std.os;
use std.bits;
use std.unix;
# print is used to print all things in nasal, try and see how it works.
@@ -235,7 +232,7 @@ var println = func(elems...) {
var sort = func() {
srand(); # be aware! this causes global changes
var quick_sort_core = func(vec, left, right, cmp) {
if(left>=right) return nil;
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]);
@@ -301,7 +298,7 @@ var ghosttype = func(ghost_object) {
# get the index of val in the vec
var vecindex = func(vec, val) {
forindex(var i; vec) {
if(val==vec[i]) {
if (val==vec[i]) {
return i;
}
}
@@ -313,11 +310,11 @@ var isa = func(object, class) {
if (!ishash(object)) {
return false;
}
if(!contains(object, "parents") or !isvec(object.parents)) {
if (!contains(object, "parents") or !isvec(object.parents)) {
return false;
}
foreach(var elem; object.parents) {
if(elem==class or isa(elem, class)) {
if (elem==class or isa(elem, class)) {
return true;
}
}

View File

@@ -10,7 +10,7 @@ var new = func() {
prev: nil,
next: nil
};
if(end!=nil) {
if (end!=nil) {
end.next = tmp;
tmp.prev = end;
end = tmp;

View File

@@ -1,18 +1,18 @@
# log.nas
# ValKmjolnir 2022/6/14
var log=func(){
var log = func() {
var (log_date,log_time,prefix)=(1,1,"");
var os_time="";
var prt_core=func(elem){
var prt_core = func(elem) {
os_time=os.time();
print(prefix," ");
if(log_date and log_time)
if (log_date and log_time)
print(os_time," ");
elsif(log_date or log_time){
elsif (log_date or log_time) {
var s=split(" ",os_time);
if(log_date)
if (log_date)
print(s[0]," ");
if(log_time)
if (log_time)
print(s[1]," ");
}
foreach(var i;elem)
@@ -20,19 +20,19 @@ var log=func(){
print("\n");
}
return {
setflags:func(date,time){
setflags:func(date,time) {
log_date=!!date;
log_time=!!time;
},
setprefix:func(s){
if(typeof(s)!="str")
setprefix:func(s) {
if (typeof(s)!="str")
println("[log.nas] must use string as the prefix.");
prefix=s;
},
println:func(elem...){
println:func(elem...) {
prt_core(elem);
},
fatalln:func(elem...){
fatalln:func(elem...) {
prt_core(elem);
die("log:fatal error");
}

View File

@@ -1,5 +1,5 @@
var mat=func(width,height) {
var mat = func(width,height) {
var res=[];
setsize(res,width*height);
forindex(var i;res) {
@@ -12,14 +12,14 @@ var mat=func(width,height) {
};
}
var rand_init=func(a) {
var rand_init = func(a) {
var ref=a.mat;
forindex(var i;ref) {
ref[i]=rand()*2-1;
}
}
var mat_print=func(a) {
var mat_print = func(a) {
var (width,height,ref)=(a.width,a.height,a.mat);
for(var i=0;i<height;i+=1) {
for(var j=0;j<width;j+=1) {
@@ -29,8 +29,8 @@ var mat_print=func(a) {
}
}
var add=func(a,b) {
if(a.width!=b.width or a.height!=b.height) {
var add = func(a,b) {
if (a.width!=b.width or a.height!=b.height) {
println("matrix a: ",a);
println("matrix b: ",b);
die("width and height must be the same");
@@ -49,8 +49,8 @@ var add=func(a,b) {
return res;
}
var sub=func(a,b) {
if(a.width!=b.width or a.height!=b.height) {
var sub = func(a,b) {
if (a.width!=b.width or a.height!=b.height) {
println("matrix a: ",a);
println("matrix b: ",b);
die("width and height must be the same");
@@ -69,8 +69,8 @@ var sub=func(a,b) {
return res;
}
var hardamard=func(a,b) {
if(a.width!=b.width or a.height!=b.height) {
var hardamard = func(a,b) {
if (a.width!=b.width or a.height!=b.height) {
println("matrix a: ",a);
println("matrix b: ",b);
die("width and height must be the same");
@@ -89,7 +89,7 @@ var hardamard=func(a,b) {
return res;
}
var neg=func(a) {
var neg = func(a) {
var res=mat(a.width,a.height);
var (aref,ref)=(a.mat,res.mat);
forindex(var i;aref) {
@@ -98,7 +98,7 @@ var neg=func(a) {
return res;
}
var sum=func(a) {
var sum = func(a) {
var res=0;
var aref=a.mat;
forindex(var i;aref) {
@@ -107,7 +107,7 @@ var sum=func(a) {
return res;
}
var mult_num=func(a,c) {
var mult_num = func(a,c) {
var res=mat(a.width,a.height);
var ref=res.mat;
var aref=a.mat;
@@ -117,7 +117,7 @@ var mult_num=func(a,c) {
return res;
}
var trans=func(a) {
var trans = func(a) {
var res=mat(a.height,a.width);
var ref=res.mat;
var (a_width,a_height,aref)=(a.width,a.height,a.mat);
@@ -129,7 +129,7 @@ var trans=func(a) {
return res;
}
var activate=func(a,f) {
var activate = func(a,f) {
var res=mat(a.width,a.height);
var (aref,ref)=(a.mat,res.mat);
forindex(var i;aref) {
@@ -138,8 +138,8 @@ var activate=func(a,f) {
return res;
}
var mult=func(a,b) {
if(a.width!=b.height) {
var mult = func(a,b) {
if (a.width!=b.height) {
println("matrix a: ",a);
println("matrix b: ",b);
die("a.width must equal to b.height, but get a.width:"~str(a.width)~" and b.height"~str(b.height));
@@ -161,28 +161,28 @@ var mult=func(a,b) {
return res;
}
var sigmoid=func(x) {
var sigmoid = func(x) {
var t=math.exp(-x);
return 1/(1+t);
}
var diffsigmoid=func(x) {
var diffsigmoid = func(x) {
x=sigmoid(x);
return x*(1-x);
}
var tanh=func(x) {
var tanh = func(x) {
var t1=math.exp(x);
var t2=math.exp(-x);
return (t1-t2)/(t1+t2);
}
var difftanh=func(x) {
var difftanh = func(x) {
x=tanh(x);
return 1-x*x;
}
var bp_example=func() {
var bp_example = func() {
srand();
var lr=0.01;
var input=[
@@ -221,7 +221,7 @@ var bp_example=func() {
var total=1e6;
while(total>0.001) {
epoch+=1;
if(epoch>1e4) {
if (epoch>1e4) {
println("Training failed after ",epoch," epoch.");
break;
}
@@ -248,7 +248,7 @@ var bp_example=func() {
total+=sum(mult_num(mult(error,trans(error)),0.5));
}
}
if(epoch<=1e4) {
if (epoch<=1e4) {
println("Training succeeded after ",epoch," epoch.");
}

View File

@@ -4,35 +4,36 @@
# this provides safe usage of dylib
# when dylib is closed,
# all the invalid functions cannot be called
use std.dylib;
var module_call_func=func(fptr,args){
var module_call_func = func(fptr, args) {
return __dlcallv;
}
var extern={
new: func(fptr){
var isopen=1;
var extern = {
new: func(fptr) {
var isopen = 1;
return {
close:func(){isopen=0;},
call:func(args...){
close: func() {isopen = 0;},
call: func(args...) {
return isopen?module_call_func(fptr,args):nil;
}
};
}
};
var module={
new: func(name){
var lib=dylib.dlopen(name);
var f={};
var module = {
new: func(name) {
var lib = dylib.dlopen(name);
var f = {};
return {
get:func(symbol){
if(contains(f,symbol))
get: func(symbol) {
if (contains(f,symbol))
return f[symbol];
var fp=extern.new(dylib.dlsym(lib,symbol));
f[symbol]=fp;
var fp = extern.new(dylib.dlsym(lib,symbol));
f[symbol] = fp;
return fp;
},
close: func(){
foreach(var i;keys(f))
close: func() {
foreach(var i; keys(f))
f[i].close();
dylib.dlclose(lib);
}

145
std/phi.nas Normal file
View File

@@ -0,0 +1,145 @@
# used to get property tree from fgfs by httpd
# use --httpd=5500 to start fgfs
# and use this script to get property tree
# 2023/11/06 ValKmjolnir
use module.libsock;
use std.json;
var _raw_str = func(s) {
var v = split("", s);
var res = "";
foreach(var i; v) {
if (i=="\r") {
res ~= "\\r";
continue;
}
if (i=="\n") {
res ~= "\\n";
continue;
}
res ~= i;
}
return res;
}
var _get_time = func() {
return "["~os.time()~"]";
}
var _connect = func(hostname, port) {
var socket = libsock.socket;
var sd = socket.socket(
socket.AF_INET,
socket.SOCK_STREAM,
socket.IPPROTO_TCP
);
var ip_info = hostname~":"~port;
while((var err = socket.connect(sd, hostname, port))==socket.SOCKET_ERROR) {
println(_get_time(), " failed to connect ", ip_info, ": ", socket.errno());
unix.sleep(1);
}
println(_get_time(), " connect to ", ip_info, " succeeded");
return sd;
}
var new = func(hostname, port) {
var socket = libsock.socket;
var sd = _connect(hostname, port);
var getprop = func(path) {
if (size(path)==0 or path[0]!='/'[0]) {
println("node \"", path, "\" not found, invalid path");
return {path: path};
}
# GET header
var header = "GET /json"~path~" HTTP/1.1\r\n\r\n";
var res = socket.send(sd, header);
# get message head 1024
var message = socket.recv(sd, 1024);
if (find("404 Not Found", message.str)>=0) {
println("node \"", path, "\" not found, get 404 response");
return {path: path};
}
# get total message
var total_source = message.str;
# 0\r\n\r\n is the tail of chunked http info
while(find("0\r\n\r\n", total_source)<0) {
message = socket.recv(sd, 1024);
total_source ~= message.str;
}
# get json in this message
var begin_position = find("{", total_source);
var end_position = find("0\r\n\r\n", total_source);
var length = end_position-begin_position;
if (begin_position<0) {
println("node \"", path, "\" not found, invalid begin token");
return {path: path};
}
if (length<0) {
println("node \"", path, "\" not found, invalid end token");
return {path: path};
}
var data = substr(total_source, begin_position, length);
# parse this json and return
var props = json.parse(data);
if (json.get_error()) {
println("encounter error when parsing \"", path, "\"");
logprint(LOG_DEBUG, _raw_str(data));
return {path: path};
}
# empty prop node is not allowed...
if (size(props)==0) {
println("node \"", path, "\" not found, empty tree node");
}
return props;
}
var setprop = func(path, data) {
if (size(path)==0 or path[0]!='/'[0]) {
println("node \"", path, "\" not found, invalid path");
return {path: path};
}
# POST header
var header = "POST /json"~path~" HTTP/1.1\r\n\r\n";
# generate value
header ~= "{\"value\":\""~data~"\"}\r\n\r\n";
var res = socket.send(sd, header);
var message = socket.recv(sd, 1024);
}
return {
getprop: getprop,
setprop: setprop
};
}
var dump = func(tree, indent = "") {
if (size(tree)==0) {
return;
}
println(indent, "-------------------");
var tree_keys = keys(tree);
sort(tree_keys, func(a,b) {return cmp(a, b)<0;});
foreach(var key; tree_keys) {
if (key == "children") {
continue;
}
println(indent, key, " : \"", tree[key], "\"");
}
println(indent, "-------------------");
if (contains(tree, "children")) {
foreach(var i; tree.children) {
dump(i, indent~" ");
}
}
}

View File

@@ -2,49 +2,49 @@
# ValKmjolnir 2022/6/14
# this file is inspired by a Python lib: alive_progress
var bar=func(){
var bar={
solid_triangle_right:"▶",
hollow_triangle_right:"▷",
solid_triangle_left:"◀",
hollow_triangle_left:"◁",
solid_circle:"●",
hollow_circle:"○",
tick:"✔",
cross:"✘",
light_shadow:"░",
medium_shadow:"▒",
deep_shadow:"▓",
block:"█",
sharp:"#",
square:"√",
equal:"=",
space:" ",
point:".",
line:"━"
var bar = func() {
var bar = {
solid_triangle_right: "▶",
hollow_triangle_right: "▷",
solid_triangle_left: "◀",
hollow_triangle_left: "◁",
solid_circle: "●",
hollow_circle: "○",
tick: "✔",
cross: "✘",
light_shadow: "░",
medium_shadow: "▒",
deep_shadow: "▓",
block: "█",
sharp: "#",
square: "√",
equal: "=",
space: " ",
point: ".",
line: "━"
};
var separator={
angle_bracket:["<",">"],
line:["|","|"],
bracket:["[","]"],
space:[" "," "],
curve:["(",")"]
var separator = {
angle_bracket: ["<",">"],
line: ["|","|"],
bracket: ["[","]"],
space: [" "," "],
curve: ["(",")"]
};
return func(front="sharp",back="space",sep="line",length=20){
if(typeof(front)!="str" or !contains(bar,front))
return func(front = "sharp", back = "space", sep = "line", length = 20) {
if (typeof(front)!="str" or !contains(bar,front))
front="sharp";
if(typeof(back)!="str" or !contains(bar,back))
if (typeof(back)!="str" or !contains(bar,back))
back="space";
if(typeof(sep)!="str" or !contains(separator,sep))
if (typeof(sep)!="str" or !contains(separator,sep))
sep="line";
front=bar[front];
back=bar[back];
sep=separator[sep];
return {
bar:func(number){
if(number>1)
bar: func(number) {
if (number>1)
number=1;
if(number<0)
if (number<0)
number=0;
var finish_length=int(number*length);
var other=length-finish_length;
@@ -62,32 +62,32 @@ var 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){
# for(var i=0;i<=1;i+=0.001) {
# print(bar.bar(i,40),'\r');
# unix.sleep(0.001);
# }
# println();
var high_resolution_bar=func(){
var high_resolution_bar = func() {
var block=["▏","▎","▍","▌","▋","▊","▉","█"];
return func(length){
return func(length) {
return {
bar: func(number){
if(number>1)
bar: func(number) {
if (number>1)
number=1;
if(number<0)
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){
for(var i=0;i<complete_block;i+=1) {
s~="█";
}
if(decimal!=0){
if (decimal!=0) {
s~=block[int(decimal*10)/10*size(block)];
}
for(var i=0;i<length-progress;i+=1){
for(var i=0;i<length-progress;i+=1) {
s~=" ";
}
s~="|";
@@ -97,30 +97,30 @@ var high_resolution_bar=func(){
};
}();
var spinner=func(){
var generate_scrolling_spinner=func(s){
if(typeof(s)!="str")
var spinner = func() {
var generate_scrolling_spinner = func(s) {
if (typeof(s)!="str")
s="****";
if(size(s)>16)
if (size(s)>16)
s="****";
var vec=split("",s);
var res=[];
var len=size(vec);
var tmp="";
for(var i=0;i<len;i+=1){
for(var i=0;i<len;i+=1) {
tmp=pop(vec)~tmp;
append(res,tmp);
while(size(res[-1])!=16)
res[-1]~=" ";
}
tmp=res[-1];
while(tmp!=" "){
while(tmp!=" ") {
tmp=" "~substr(tmp,0,15);
append(res,tmp);
}
return res;
}
var spinner={
var spinner = {
rise:["▁","▂","▃","▄","▅","▆","▇","█","█","▇","▆","▅","▄","▃","▂","▁"],
vertical:["▏","▎","▍","▌","▋","▊","▉","▇","▇","▉","▊","▋","▌","▍","▎","▏"],
dot:["⠁","⠈","⠐","⠠","⢀","⡀","⠄","⠂"],
@@ -217,18 +217,18 @@ var spinner=func(){
wait:generate_scrolling_spinner("please wait"),
stars:generate_scrolling_spinner("********")
};
return func(type="classic",repeat=1){
if(typeof(type)!="str" or !contains(spinner,type))
return func(type = "classic", repeat = 1) {
if (typeof(type)!="str" or !contains(spinner,type))
type="classic";
type=spinner[type];
var counter=0;
return {
next:func(){
next: func() {
var s="";
for(var i=0;i<repeat;i+=1)
s~=type[counter];
counter+=1;
if(counter>=size(type))
if (counter>=size(type))
counter=0;
return s;
}
@@ -236,71 +236,71 @@ var spinner=func(){
};
}();
var default_bar=func(name="classic",length=20){
if(typeof(name)!="str")
var default_bar = func(name = "classic", length = 20) {
if (typeof(name)!="str")
name="classic";
if(name=="classic")
if (name=="classic")
return process_bar.bar("sharp","point","bracket",length);
elsif(name=="classic2")
elsif (name=="classic2")
return process_bar.bar("equal","point","bracket",length);
elsif(name=="classic3")
elsif (name=="classic3")
return process_bar.bar("sharp","point","line",length);
elsif(name=="classic4")
elsif (name=="classic4")
return process_bar.bar("equal","point","line",length);
elsif(name=="triangle")
elsif (name=="triangle")
return process_bar.bar("solid_triangle_right","hollow_triangle_right","angle_bracket",length);
elsif(name=="dots")
elsif (name=="dots")
return process_bar.bar("solid_circle","hollow_circle","curve",length);
elsif(name=="ticks")
elsif (name=="ticks")
return process_bar.bar("tick","space","line",length);
elsif(name=="deep_shadow")
elsif (name=="deep_shadow")
return process_bar.bar("deep_shadow","light_shadow","line",length);
elsif(name=="block")
elsif (name=="block")
return process_bar.bar("block","light_shadow","line",length);
elsif(name=="oneline")
elsif (name=="oneline")
return process_bar.bar("line","space","space",length);
else
return process_bar.bar("sharp","point","bracket",length);
}
var default_spinner=func(name="classic",repeat=1){
if(typeof(name)!="str")
var default_spinner = func(name = "classic", repeat = 1) {
if (typeof(name)!="str")
name="classic";
if(name=="rise")
if (name=="rise")
return process_bar.spinner("rise",repeat);
elsif(name=="vertical")
elsif (name=="vertical")
return process_bar.spinner("vertical",repeat);
elsif(name=="dot")
elsif (name=="dot")
return process_bar.spinner("dot",repeat);
elsif(name=="dots")
elsif (name=="dots")
return process_bar.spinner("dots",repeat);
elsif(name=="arrow")
elsif (name=="arrow")
return process_bar.spinner("arrow",repeat);
elsif(name=="classic")
elsif (name=="classic")
return process_bar.spinner("classic",repeat);
elsif(name=="balls")
elsif (name=="balls")
return process_bar.spinner("balls",repeat);
elsif(name=="dots_wave")
elsif (name=="dots_wave")
return process_bar.spinner("dots_wave",repeat);
elsif(name=="pulse")
elsif (name=="pulse")
return process_bar.spinner("pulse",repeat);
elsif(name=="wave")
elsif (name=="wave")
return process_bar.spinner("wave",repeat);
elsif(name=="short_wave")
elsif (name=="short_wave")
return process_bar.spinner("short_wave",repeat);
elsif(name=="fish")
elsif (name=="fish")
return process_bar.spinner("fish",repeat);
elsif(name=="happy")
elsif (name=="happy")
return process_bar.spinner("happy",repeat);
elsif(name=="wait")
elsif (name=="wait")
return process_bar.spinner("wait",repeat);
elsif(name=="stars")
elsif (name=="stars")
return process_bar.spinner("stars",repeat);
else
return process_bar.spinner("classic",repeat);
}
var show=func(){
var show = func() {
print("\ec");
var bars={
"classic ":process_bar.default_bar("classic",40),
@@ -333,12 +333,12 @@ var show=func(){
};
var bar_key=keys(bars);
var spin_key=keys(spinners);
for(var i=0;i<40;i+=1){
forindex(var j;bar_key){
for(var i=0; i<40; i+=1) {
forindex(var j; bar_key) {
var k=bar_key[j];
print("\e["~(j+1)~";1H["~k~"] "~bars[k].bar((i+1)/40));
}
forindex(var j;spin_key){
forindex(var j; spin_key) {
var k=spin_key[j];
print("\e["~(j+1+size(bars))~";1H["~k~"] |"~spinners[k].next()~"|");
}

View File

@@ -195,15 +195,15 @@ var Node = {
getPath : func {
var (name, index, parent) = (me.getName(), me.getIndex(), me.getParent());
if(index != 0) { name ~= "[" ~ index ~ "]"; }
if(parent != nil) { name = parent.getPath() ~ "/" ~ name; }
if (index != 0) { name ~= "[" ~ index ~ "]"; }
if (parent != nil) { name = parent.getPath() ~ "/" ~ name; }
return name;
},
getBoolValue : func {
var val = me.getValue();
var mytype = me.getType();
if((mytype == "STRING" or mytype == "UNSPECIFIED") and val == "false") return 0;
if ((mytype == "STRING" or mytype == "UNSPECIFIED") and val == "false") return 0;
return !!val;
},
@@ -216,7 +216,7 @@ var Node = {
},
remove : func {
if((var p = me.getParent()) == nil) return nil;
if ((var p = me.getParent()) == nil) return nil;
p.removeChild(me.getName(), me.getIndex());
},
@@ -300,7 +300,7 @@ var Node = {
#
Node.new = func(values = nil) {
var result = wrapNode(_new());
if(ishash(values)) {
if (ishash(values)) {
result.setValues(values);
}
return result;
@@ -316,18 +316,18 @@ Node.new = func(values = nil) {
#
Node.getValues = func {
var children = me.getChildren();
if(!size(children)) return me.getValue();
if (!size(children)) return me.getValue();
var val = {};
var numchld = {};
foreach(var c; children) {
var name = c.getName();
if(contains(numchld, name)) { var nc = numchld[name]; }
if (contains(numchld, name)) { var nc = numchld[name]; }
else {
var nc = size(me.getChildren(name));
numchld[name] = nc;
if(nc > 1 and !contains(val, name)) val[name] = [];
if (nc > 1 and !contains(val, name)) val[name] = [];
}
if(nc > 1) append(val[name], c.getValues());
if (nc > 1) append(val[name], c.getValues());
else val[name] = c.getValues();
}
return val;
@@ -346,13 +346,13 @@ Node.getValues = func {
#
Node.initNode = func(path = nil, value = 0, type = nil, force = 0) {
var prop = me.getNode(path or "", 1);
if(prop.getType() != "NONE") value = prop.getValue();
if(force) prop.clearValue();
if(type == nil) prop.setValue(value);
elsif(type == "DOUBLE") prop.setDoubleValue(value);
elsif(type == "INT") prop.setIntValue(value);
elsif(type == "BOOL") prop.setBoolValue(value);
elsif(type == "STRING") prop.setValue("" ~ value);
if (prop.getType() != "NONE") value = prop.getValue();
if (force) prop.clearValue();
if (type == nil) prop.setValue(value);
elsif (type == "DOUBLE") prop.setDoubleValue(value);
elsif (type == "INT") prop.setIntValue(value);
elsif (type == "BOOL") prop.setBoolValue(value);
elsif (type == "STRING") prop.setValue("" ~ value);
else die("initNode(): unsupported type '" ~ type ~ "'");
return prop;
}
@@ -363,7 +363,7 @@ Node.initNode = func(path = nil, value = 0, type = nil, force = 0) {
# to a key for a fun hack.
#
var dump = func {
if(size(arg) == 1) { var prefix = ""; var node = arg[0]; }
if (size(arg) == 1) { var prefix = ""; var node = arg[0]; }
else { var prefix = arg[0]; var node = arg[1]; }
var index = node.getIndex();
@@ -371,13 +371,13 @@ var dump = func {
var name = node.getName();
var val = node.getValue();
if(val == nil) { val = "nil"; }
if (val == nil) { val = "nil"; }
name = prefix ~ name;
if(index > 0) { name = name ~ "[" ~ index ~ "]"; }
if (index > 0) { name = name ~ "[" ~ index ~ "]"; }
print(name, " {", type, "} = ", val);
# Don't recurse into aliases, lest we get stuck in a loop
if(type != "ALIAS") {
if (type != "ALIAS") {
var children = node.getChildren();
foreach(var c; children) { dump(name ~ "/", c); }
}
@@ -413,12 +413,12 @@ var copy = func(src, dest, attr = 0) {
}
var type = src.getType();
var val = src.getValue();
if(type == "ALIAS" or type == "NONE") return;
elsif(type == "BOOL") dest.setBoolValue(val);
elsif(type == "INT" or type == "LONG") dest.setIntValue(val);
elsif(type == "FLOAT" or type == "DOUBLE") dest.setDoubleValue(val);
if (type == "ALIAS" or type == "NONE") return;
elsif (type == "BOOL") dest.setBoolValue(val);
elsif (type == "INT" or type == "LONG") dest.setIntValue(val);
elsif (type == "FLOAT" or type == "DOUBLE") dest.setDoubleValue(val);
else dest.setValue(val);
if(attr) dest.setAttribute(src.getAttribute());
if (attr) dest.setAttribute(src.getAttribute());
}
##
@@ -426,9 +426,9 @@ var copy = func(src, dest, attr = 0) {
# array) into Node objects.
#
var wrap = func(node) {
if(isghost(node)) {
if (isghost(node)) {
return wrapNode(node);
} elsif(isvec(node)) {
} elsif (isvec(node)) {
var v = node;
var n = size(v);
for(var i=0; i<n; i+=1) { v[i] = wrapNode(v[i]); }
@@ -468,13 +468,13 @@ var getNode = func return call(props.globals.getNode, arg, props.globals);
#
var setAll = func(base, child, value) {
var node = props.globals.getNode(base);
if(node == nil) return;
if (node == nil) return;
var name = node.getName();
node = node.getParent();
if(node == nil) return;
if (node == nil) return;
var children = node.getChildren();
foreach(var c; children)
if(c.getName() == name)
if (c.getName() == name)
c.getNode(child, 1).setValue(value);
}
@@ -513,19 +513,19 @@ var createNodeObjectsFromHash = func (property_list, namespace = nil) {
var nodeList = func {
var list = [];
foreach(var a; arg) {
if(isa(a, Node))
if (isa(a, Node))
append(list, a);
elsif(isscalar(a))
elsif (isscalar(a))
append(list, props.globals.getNode(a, 1));
elsif(isvec(a))
elsif (isvec(a))
foreach(var i; a)
list ~= nodeList(i);
elsif(ishash(a))
elsif (ishash(a))
foreach(var i; keys(a))
list ~= nodeList(a[i]);
elsif(isfunc(a))
elsif (isfunc(a))
list ~= nodeList(a());
elsif(isghost(a) and ghosttype(a) == "prop")
elsif (isghost(a) and ghosttype(a) == "prop")
append(list, wrapNode(a));
else
die("nodeList: invalid nil property");
@@ -541,8 +541,8 @@ var nodeList = func {
# The function returns nil on error.
#
var compileCondition = func(p) {
if(p == nil) return nil;
if(!isa(p, Node)) p = props.globals.getNode(p);
if (p == nil) return nil;
if (!isa(p, Node)) p = props.globals.getNode(p);
return _createCondition(p._g);
}
@@ -553,35 +553,35 @@ var compileCondition = func(p) {
# branch and returns nil on error.
#
var condition = func(p) {
if(p == nil) return 1;
if(!isa(p, Node)) p = props.globals.getNode(p);
if (p == nil) return 1;
if (!isa(p, Node)) p = props.globals.getNode(p);
return _cond_and(p)
}
var _cond_and = func(p) {
foreach(var c; p.getChildren())
if(!_cond(c)) return 0;
if (!_cond(c)) return 0;
return 1;
}
var _cond_or = func(p) {
foreach(var c; p.getChildren())
if(_cond(c)) return 1;
if (_cond(c)) return 1;
return 0;
}
var _cond = func(p) {
var n = p.getName();
if(n == "or") return _cond_or(p);
if(n == "and") return _cond_and(p);
if(n == "not") return !_cond_and(p);
if(n == "equals") return _cond_cmp(p, 0);
if(n == "not-equals") return !_cond_cmp(p, 0);
if(n == "less-than") return _cond_cmp(p, -1);
if(n == "greater-than") return _cond_cmp(p, 1);
if(n == "less-than-equals") return !_cond_cmp(p, 1);
if(n == "greater-than-equals") return !_cond_cmp(p, -1);
if(n == "property") return !!getprop(p.getValue());
if (n == "or") return _cond_or(p);
if (n == "and") return _cond_and(p);
if (n == "not") return !_cond_and(p);
if (n == "equals") return _cond_cmp(p, 0);
if (n == "not-equals") return !_cond_cmp(p, 0);
if (n == "less-than") return _cond_cmp(p, -1);
if (n == "greater-than") return _cond_cmp(p, 1);
if (n == "less-than-equals") return !_cond_cmp(p, 1);
if (n == "greater-than-equals") return !_cond_cmp(p, -1);
if (n == "property") return !!getprop(p.getValue());
logprint(LOG_ALERT, "condition: invalid operator ", n);
dump(p);
return nil;
@@ -589,17 +589,17 @@ var _cond = func(p) {
var _cond_cmp = func(p, op) {
var left = p.getChild("property", 0, 0);
if(left != nil) { left = getprop(left.getValue()); }
if (left != nil) { left = getprop(left.getValue()); }
else {
logprint(LOG_ALERT, "condition: no left value");
dump(p);
return nil;
}
var right = p.getChild("property", 1, 0);
if(right != nil) { right = getprop(right.getValue()); }
if (right != nil) { right = getprop(right.getValue()); }
else {
right = p.getChild("value", 0, 0);
if(right != nil) { right = right.getValue(); }
if (right != nil) { right = right.getValue(); }
else {
logprint(LOG_ALERT, "condition: no right value");
dump(p);
@@ -610,8 +610,8 @@ var _cond_cmp = func(p, op) {
if (left == nil) left = 0.0;
if (right == nil) right = 0.0;
if(op < 0) return left < right;
if(op > 0) return left > right;
if (op < 0) return left < right;
if (op > 0) return left > right;
return left == right;
}
@@ -622,7 +622,7 @@ var _cond_cmp = func(p, op) {
# in the binding.
#
var runBinding = func(node, module = nil) {
if(module != nil and node.getNode("module") == nil)
if (module != nil and node.getNode("module") == nil)
node.getNode("module", 1).setValue(module);
var cmd = node.getNode("command", 1).getValue() or "null";
condition(node.getNode("condition")) ? fgcommand(cmd, node) : 0;
@@ -702,13 +702,13 @@ var UpdateManager =
me.localType = me.property.getType();
if (me.localType == "INT" or me.localType == "LONG" or me.localType == "FLOAT" or me.localType == "DOUBLE")
{
if(me.lastval == nil or math.abs(me.lastval - me.curval) >= me.delta)
if (me.lastval == nil or math.abs(me.lastval - me.curval) >= me.delta)
{
me.lastval = me.curval;
me.changed(me.curval);
}
}
else if(me.lastval == nil or me.lastval != me.curval)
else if (me.lastval == nil or me.lastval != me.curval)
{
me.lastval = me.curval;
me.changed(me.curval);

View File

@@ -1,34 +1,34 @@
# queue.nas
# valkmjolnir 2021/3/31
var new=func(){
var (begin,end)=(nil,nil);
var new = func() {
var (begin, end) = (nil, nil);
return{
push:func(elem){
push: func(elem) {
var new_node={
elem:elem,
next:nil
};
if(begin==nil)
if (begin==nil)
begin=end=new_node;
else{
else {
end.next=new_node;
end=new_node;
}
},
pop:func(){
if(begin!=nil)
pop: func() {
if (begin!=nil)
begin=begin.next;
if(begin==nil)
if (begin==nil)
end=nil;
},
front:func(){
if(begin!=nil)
front: func() {
if (begin!=nil)
return begin.elem;
},
clear:func(){
clear: func() {
begin=end=nil;
},
empty:func(){
empty: func() {
return begin==nil;
}
};

View File

@@ -1,7 +1,7 @@
# string.nas
# ValKmjolnir 2022/10/5
var join = func(sep, vec){
var join = func(sep, vec) {
var len = size(vec);
var res = "";
for(var i = 0; i<len; i += 1) {

49
std/udp.nas Normal file
View File

@@ -0,0 +1,49 @@
use module.libsock;
var udp_server = func(hostname, port, retry_delay = 5) {
var socket = libsock.socket;
var server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM);
while(socket.bind(server, hostname, port) < 0) {
println("[", os.time(), "] failed to bind socket "~server~" at ", hostname, ":", port, ".");
unix.sleep(retry_delay);
println("[", os.time(), "] retrying...");
}
return {
sendto: func(ip, port, message) {
var res = socket.sendto(server, ip, port, message);
println("[", os.time(), "] send message to ", ip, ":", port, " ", res, " byte(s)");
return res;
},
recvfrom: func(length = 1024) {
var message = socket.recvfrom(server, length);
println("[", os.time(), "] get message \"", message.str, "\" from ", message.fromip, ":", message.port);
return message;
}
}
}
var udp_client = func(hostname = "", port = -1, retry_delay = 5) {
var socket = libsock.socket;
var client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM);
if (port > 0 and size(hostname) != 0) {
while(socket.bind(client, hostname, port)<0) {
println("[",os.time(),"] failed to bind socket "~client~" at ", hostname, ":", port, ".");
unix.sleep(retry_delay);
println("[",os.time(),"] retrying...");
}
}
return {
sendto: func(ip, port, message) {
var res = socket.sendto(client, ip, port, message);
println("[", os.time(), "] send message to ", ip, ":", port, " ", res, " byte(s)");
return res;
},
recvfrom: func(length = 1024) {
var message = socket.recvfrom(client, length);
println("[", os.time(), "] get message \"", message.str, "\" from ", message.fromip, ":", message.port);
return message;
}
}
}

View File

@@ -1,5 +1,6 @@
# unix.nas
# 2023 by ValKmjolnir
use std.bits;
var _S_IFDIR = 0x4000;
var _S_IFREG = 0x8000;

View File

@@ -31,14 +31,14 @@ var char_ttf=[
["███████╗","╚══███╔╝"," ███╔╝ "," ███╔╝ ","███████╗","╚══════╝"],
];
var trans_ttf=func(string){
var trans_ttf = func(string) {
var str=["","","","","",""];
for(var i=0;i<size(string);i+=1){
for(var i=0;i<size(string);i+=1) {
var number=string[i];
if(97<=number and number<=122)
if (97<=number and number<=122)
for(var j=0;j<6;j+=1)
str[j]~=char_ttf[number-96][j];
elsif(65<=number and number<=90)
elsif (65<=number and number<=90)
for(var j=0;j<6;j+=1)
str[j]~=char_ttf[number-64][j];
else
@@ -50,11 +50,11 @@ var trans_ttf=func(string){
return;
}
var curve1=func(line=4){
var curve1 = func(line=4) {
var table=["╚","═","╝","╔","║","╗"];
rand(100);
var s="";
for(var i=0;i<line;i+=1){
for(var i=0;i<line;i+=1) {
for(var j=0;j<90;j+=1)
s~=table[int(6*rand())];
s~='\n';
@@ -62,11 +62,11 @@ var curve1=func(line=4){
print(s);
}
var curve2=func(line=2){
var curve2 = func(line=2) {
var shadow=["░","▒","▓","█","▀","▄","▐","▌"];
rand(100);
var s="";
for(var i=0;i<line;i+=1){
for(var i=0;i<line;i+=1) {
for(var j=0;j<90;j+=1)
s~=shadow[int(8*rand())];
s~='\n';
@@ -74,7 +74,7 @@ var curve2=func(line=2){
print(s);
}
var curve3=func(line=2){
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,
@@ -87,8 +87,8 @@ var curve3=func(line=2){
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){
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]);
}
@@ -102,7 +102,7 @@ var curve3=func(line=2){
return;
}
var curve4=func(line=4){
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",
@@ -113,16 +113,16 @@ var curve4=func(line=4){
"100","101","102","103","104","105","106","107"
];
rand(time(0));
for(var i=0;i<line;i+=1){
for(var i=0;i<line;i+=1) {
for(var j=0;j<90;j+=1)
print("\e["~front[16*rand()]~";"~back[16*rand()]~shadow[8*rand()]);
print('\n');
}
}
var curve5=func(line=4){
var curve5 = func(line=4) {
var vec=["▀▄─","▄▀─","▀─▄","▄─▀"];
for(var (y,p)=(0,0);y!=line;y+=1){
for(var (y,p)=(0,0);y!=line;y+=1) {
for(var x=0;x!=30;x+=1)
print(vec[p]);
print("\n");
@@ -131,7 +131,7 @@ var curve5=func(line=4){
}
}
var ansi_escape_sequence=func(){
var ansi_escape_sequence = func() {
# decoration
for(var i=0;i<10;i+=1)
print("\e["~i~"m",padding.rightpad(i,4),"\e[0m");
@@ -194,7 +194,7 @@ var ansi_escape_sequence=func(){
}
# enable unicode
if(os.platform()=="windows"){
if (os.platform()=="windows") {
system("chcp 65001");
}

View File

@@ -10,30 +10,30 @@ var dt=0.01;
var intergral=0;
var derivative=0;
var previous_error=0;
var position_change = func(position_val,value){
if(position_val+value>180)
var position_change = func(position_val,value) {
if (position_val+value>180)
position_val += value-360;
else if(position_val+value<-180)
else if (position_val+value<-180)
position_val += value+360;
else
position_val += value;
return position_val;
}
var road_check_func = func(){
var road_check_func = func() {
var lat = props.getNode("/position/latitude-deg",1).getValue();
var lon = props.getNode("/position/longitude-deg",1).getValue();
var position_info = geodinfo(lat,lon);
var position_names = position_info[1].names;
if((position_names[0]=="Freeway") or (position_names[0]=="Road")){
if ((position_names[0]=="Freeway") or (position_names[0]=="Road")) {
var car_heading = 0;
var lat_change = 0;
var lon_change = 0;
var left_range = 0;
var right_range = 0;
for(var i=0;i>-0.00005;i-=0.000001){
for(var i=0;i>-0.00005;i-=0.000001) {
car_heading = props.getNode("/orientation/heading-deg",1).getValue();
lat_change = math.sin(D2R*car_heading);
lon_change = -math.cos(D2R*car_heading);
@@ -41,12 +41,12 @@ var road_check_func = func(){
lon = props.getNode("/position/longitude-deg",1).getValue()+0.0001*math.sin(D2R*car_heading);
var other_position_info = geodinfo(position_change(lat,i*lat_change),position_change(lon,i*lon_change));
var other_names = other_position_info[1].names;
if((other_names[0]=="Freeway") or (other_names[0]=="Road"))
if ((other_names[0]=="Freeway") or (other_names[0]=="Road"))
right_range += 1;
else
break;
}
for(var i=0;i<0.00005;i+=0.000001){
for(var i=0;i<0.00005;i+=0.000001) {
car_heading = props.getNode("/orientation/heading-deg",1).getValue();
lat_change = math.sin(D2R*car_heading);
lon_change = -math.cos(D2R*car_heading);
@@ -54,7 +54,7 @@ var road_check_func = func(){
lon = props.getNode("/position/longitude-deg",1).getValue()+0.0001*math.sin(D2R*car_heading);
var other_position_info = geodinfo(position_change(lat,i*lat_change),position_change(lon,i*lon_change));
var other_names = other_position_info[1].names;
if((other_names[0]=="Freeway") or (other_names[0]=="Road"))
if ((other_names[0]=="Freeway") or (other_names[0]=="Road"))
left_range+=1;
else
break;
@@ -64,9 +64,9 @@ var road_check_func = func(){
derivative=(error-previous_error)/dt;
var (Kp,Ki,Kd)=(1/900,0.05,0.005);
# print("change p ",Kp*error*error,' i ',Ki*intergral,' d ',Kd*derivative);
if(error<0)
if (error<0)
props.getNode("/", 1).setValue("/controls/flight/rudder",-Kp*error*error+Ki*intergral+Kd*derivative);
else if(error>0)
else if (error>0)
props.getNode("/", 1).setValue("/controls/flight/rudder",Kp*error*error+Ki*intergral+Kd*derivative);
else
props.getNode("/", 1).setValue("/controls/flight/rudder",0);
@@ -81,12 +81,12 @@ var road_check_func = func(){
};
var road_check_timer = maketimer(0.01,road_check_func);
var toggle_auto_pilot = func(){
if(!road_check_timer.isRunning){
var toggle_auto_pilot = func() {
if (!road_check_timer.isRunning) {
intergral=0;
road_check_timer.start();
props.getNode("/sim/messages/copilot",1).setValue('/',"ze dong sheng teaan see tong yee tse yung. Auto Sheng Teaan System Activated!");
}else{
} else {
road_check_timer.stop();
props.getNode("/sim/messages/copilot",1).setValue('/',"ze dong sheng teaan see tong yee guan bee. Auto Sheng Teaan System is off.");
}

View File

@@ -147,7 +147,7 @@ var mandelbrot=
var (ptr,pc,paper,inum)=(0,0,[],[]);
var character=func() {
var character = func() {
var res=[];
setsize(res,256);
forindex(var i;res) {
@@ -159,55 +159,55 @@ var character=func() {
var (add,mov,jt,jf,in,out)=(
func {paper[ptr]+=inum[pc];},
func {ptr+=inum[pc];},
func {if(paper[ptr])pc=inum[pc];},
func {if(!paper[ptr])pc=inum[pc];},
func {if (paper[ptr])pc=inum[pc];},
func {if (!paper[ptr])pc=inum[pc];},
func {paper[ptr]=input()[0];},
func {print(character[paper[ptr]]);}
);
var codegen=func(program) {
var codegen = func(program) {
var (code,stack)=([],[]);
var len=size(program);
for(var i=0;i<len;i+=1) {
var c=chr(program[i]);
if(c=='+' or c=='-') {
if (c=='+' or c=='-') {
append(code,add);
append(inum,0);
for(;i<len;i+=1) {
if(chr(program[i])=='+') {
if (chr(program[i])=='+') {
inum[-1]+=1;
} elsif(chr(program[i])=='-') {
} elsif (chr(program[i])=='-') {
inum[-1]-=1;
} elsif(chr(program[i])!='\n') {
} elsif (chr(program[i])!='\n') {
i-=1;
break;
}
}
} elsif(c=='<' or c=='>') {
} elsif (c=='<' or c=='>') {
append(code,mov);
append(inum,0);
for(;i<len;i+=1){
if(chr(program[i])=='>') {
for(;i<len;i+=1) {
if (chr(program[i])=='>') {
inum[-1]+=1;
} elsif(chr(program[i])=='<') {
} elsif (chr(program[i])=='<') {
inum[-1]-=1;
} elsif(chr(program[i])!='\n') {
} elsif (chr(program[i])!='\n') {
i-=1;
break;
}
}
} elsif(c==',') {
} elsif (c==',') {
append(code,in);
append(inum,0);
} elsif(c=='.') {
} elsif (c=='.') {
append(code,out);
append(inum,0);
} elsif(c=='[') {
} elsif (c=='[') {
append(code,jf);
append(inum,0);
append(stack,size(code)-1);
} elsif(c==']') {
if(!size(stack)) {
} elsif (c==']') {
if (!size(stack)) {
die("lack [");
}
var label=pop(stack);
@@ -217,7 +217,7 @@ var codegen=func(program) {
}
}
if(size(stack)) {
if (size(stack)) {
die("lack "~size(stack)~" \"]\"");
return;
}
@@ -225,9 +225,9 @@ var codegen=func(program) {
return code;
}
var bf=func(program) {
var bf = func(program) {
# enable ANSI escape sequence
if(os.platform()=="windows") {
if (os.platform()=="windows") {
system("color");
}

View File

@@ -145,7 +145,7 @@ var mandelbrot=
+[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>->>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<[<<<<
<<<<<]]>>>]";
var padding=func(len) {
var padding = func(len) {
var res="";
for(var i=0;i<len;i+=1) {
res~=" ";
@@ -153,64 +153,64 @@ var padding=func(len) {
return res;
}
var bf=func(program) {
var bf = func(program) {
var stack=[];
var len=size(program);
var f="#automatically generated by bfconvertor.nas\nvar ptr=0;\nvar paper=[];\nsetsize(paper,131072);\n";
for(var i=0;i<len;i+=1) {
var c=chr(program[i]);
if(c=='+' or c=='-') {
if (c=='+' or c=='-') {
var cnt=0;
for(;i<len;i+=1) {
if(chr(program[i])=='+') {
if (chr(program[i])=='+') {
cnt+=1;
} elsif(chr(program[i])=='-') {
} elsif (chr(program[i])=='-') {
cnt-=1;
} elsif(chr(program[i])!='\n') {
} elsif (chr(program[i])!='\n') {
i-=1;
break;
}
}
if(cnt!=0) {
if (cnt!=0) {
f~=padding(size(stack));
}
if(cnt>0) {
if (cnt>0) {
f~="paper[ptr]+="~cnt~";\n";
} elsif(cnt<0) {
} elsif (cnt<0) {
f~="paper[ptr]-="~(-cnt)~";\n";
}
} elsif(c=='<' or c=='>') {
} elsif (c=='<' or c=='>') {
var cnt=0;
for(;i<len;i+=1) {
if(chr(program[i])=='>') {
if (chr(program[i])=='>') {
cnt+=1;
} elsif(chr(program[i])=='<') {
} elsif (chr(program[i])=='<') {
cnt-=1;
} elsif(chr(program[i])!='\n') {
} elsif (chr(program[i])!='\n') {
i-=1;
break;
}
}
if(cnt!=0) {
if (cnt!=0) {
f~=padding(size(stack));
}
if(cnt>0) {
if (cnt>0) {
f~="ptr+="~cnt~";\n";
} elsif(cnt<0) {
} elsif (cnt<0) {
f~="ptr-="~(-cnt)~";\n";
}
} elsif(c==',') {
} elsif (c==',') {
f~=padding(size(stack));
f~="paper[ptr]=input()[0];\n";
} elsif(c=='.') {
} elsif (c=='.') {
f~=padding(size(stack));
f~="print(chr(paper[ptr]));\n";
} elsif(c=='[') {
} elsif (c=='[') {
f~=padding(size(stack));
f~="while(paper[ptr]) {\n";
append(stack,0);
} elsif(c==']') {
if(!size(stack)) {
} elsif (c==']') {
if (!size(stack)) {
println("lack [");
return;
}
@@ -219,7 +219,7 @@ var bf=func(program) {
f~="}\n";
}
}
if(size(stack)) {
if (size(stack)) {
println("lack ]");
return;
}

View File

@@ -3,15 +3,15 @@ use std.queue;
rand(time(0));
var pixel=[' ','#','.','*'];
var map=[];
for(var i=0;i<10;i+=1){
for(var i=0;i<10;i+=1) {
append(map,[]);
for(var j=0;j<20;j+=1)
append(map[i],(rand()>0.7));
}
var prt=func(){
var prt = func() {
var s="\e[0;0H+--------------------+\n";
for(var i=0;i<10;i+=1){
for(var i=0;i<10;i+=1) {
s~="|";
for(var j=0;j<20;j+=1)
s~=pixel[map[i][j]];
@@ -22,27 +22,27 @@ var prt=func(){
unix.sleep(1/800);
}
var bfs=func(begin,end){
var bfs = func(begin,end) {
var move=[[1,0],[0,1],[-1,0],[0,-1]];
var que=queue.new();
que.push(begin);
map[begin[0]][begin[1]]=2;
map[end[0]][end[1]]=0;
if(map[1][0]==1 and map[0][1]==1)
if (map[1][0]==1 and map[0][1]==1)
map[1][0]=0;
while(!que.empty()){
while(!que.empty()) {
var vertex=que.front();
que.pop();
foreach(var i;move){
foreach(var i;move) {
var x=vertex[0]+i[0];
var y=vertex[1]+i[1];
if(x==end[0] and y==end[1]){
if (x==end[0] and y==end[1]) {
map[x][y]=3;
prt();
print("reached.\n");
return;
}
if(0<=x and x<10 and 0<=y and y<20 and map[x][y]==0){
if (0<=x and x<10 and 0<=y and y<20 and map[x][y]==0) {
que.push([x,y]);
map[x][y]=2;
}
@@ -54,7 +54,7 @@ var bfs=func(begin,end){
}
# enable ANSI escape sequence
if(os.platform()=="windows")
if (os.platform()=="windows")
system("color");
print("\ec");
bfs([0,0],[9,19]);

View File

@@ -2,7 +2,7 @@ use std.mat;
rand(time(0));
var new_neuron=func(){
var new_neuron = func() {
return {
in:0,
out:0,
@@ -12,18 +12,18 @@ var new_neuron=func(){
};
}
var tanh=func(x){
var tanh = func(x) {
var (a,b)=(math.exp(x),math.exp(-x));
return (a-b)/(a+b);
}
var difftanh=func(x){
var difftanh = func(x) {
x=tanh(x);
return 1-x*x;
}
var sigmoid=func(x){
var sigmoid = func(x) {
return 1/(1+math.exp(-x));
}
var diffsigmoid=func(x){
var diffsigmoid = func(x) {
x=sigmoid(x);
return x*(1-x);
}
@@ -33,7 +33,7 @@ var training_set=[[0,0],[0,1],[1,0],[1,1]];
var expect=[0,1,1,0];
var hidden=[];
for(var i=0;i<hnum;i+=1){
for(var i=0;i<hnum;i+=1) {
append(hidden,new_neuron());
for(var j=0;j<inum;j+=1)
append(hidden[i].w,rand()>0.5?-2*rand():2*rand());
@@ -41,22 +41,22 @@ for(var i=0;i<hnum;i+=1){
}
var output=[];
for(var i=0;i<onum;i+=1){
for(var i=0;i<onum;i+=1) {
append(output,new_neuron());
for(var j=0;j<hnum;j+=1)
append(output[i].w,rand()>0.5?-2*rand():2*rand());
output[i].bia=rand()>0.5?-5*rand():5*rand();
}
var forward=func(x){
var forward = func(x) {
var input=training_set[x];
for(var i=0;i<hnum;i+=1){
for(var i=0;i<hnum;i+=1) {
hidden[i].in=hidden[i].bia;
for(var j=0;j<inum;j+=1)
hidden[i].in+=hidden[i].w[j]*input[j];
hidden[i].out=tanh(hidden[i].in);
}
for(var i=0;i<onum;i+=1){
for(var i=0;i<onum;i+=1) {
output[i].in=output[i].bia;
for(var j=0;j<hnum;j+=1)
output[i].in+=output[i].w[j]*hidden[j].out;
@@ -64,15 +64,15 @@ var forward=func(x){
}
return;
}
var run=func(vec){
var run = func(vec) {
var input=vec;
for(var i=0;i<hnum;i+=1){
for(var i=0;i<hnum;i+=1) {
hidden[i].in=hidden[i].bia;
for(var j=0;j<inum;j+=1)
hidden[i].in+=hidden[i].w[j]*input[j];
hidden[i].out=tanh(hidden[i].in);
}
for(var i=0;i<onum;i+=1){
for(var i=0;i<onum;i+=1) {
output[i].in=output[i].bia;
for(var j=0;j<hnum;j+=1)
output[i].in+=output[i].w[j]*hidden[j].out;
@@ -80,24 +80,24 @@ var run=func(vec){
}
return;
}
var get_error=func(x){
var get_error = func(x) {
return 0.5*(expect[x]-output[0].out)*(expect[x]-output[0].out);
}
var backward=func(x){
var backward = func(x) {
var input=training_set[x];
output[0].diff=(expect[x]-output[0].out)*diffsigmoid(output[0].in);
for(var i=0;i<hnum;i+=1){
for(var i=0;i<hnum;i+=1) {
hidden[i].diff=0;
for(var j=0;j<onum;j+=1)
hidden[i].diff+=output[j].w[i]*output[j].diff;
hidden[i].diff*=difftanh(hidden[i].in);
}
for(var i=0;i<hnum;i+=1){
for(var i=0;i<hnum;i+=1) {
hidden[i].bia+=hidden[i].diff;
for(var j=0;j<inum;j+=1)
hidden[i].w[j]+=hidden[i].diff*input[j];
}
for(var i=0;i<onum;i+=1){
for(var i=0;i<onum;i+=1) {
output[i].bia+=output[i].diff;
for(var j=0;j<hnum;j+=1)
output[i].w[j]+=output[i].diff*hidden[j].out;
@@ -106,23 +106,23 @@ var backward=func(x){
}
var (cnt,error)=(0,100);
while(error>0.0005){
while(error>0.0005) {
error=0;
for(var i=0;i<4;i+=1){
for(var i=0;i<4;i+=1) {
forward(i);
error+=get_error(i);
backward(i);
}
cnt+=1;
if(cnt>=1e4)
if (cnt>=1e4)
break;
}
if(cnt>=3e5){
if (cnt>=3e5) {
print("failed to train, ",cnt," epoch.\n");
}else{
} else {
print('finished after ',cnt,' epoch.\n');
}
foreach(var v;training_set){
foreach(var v;training_set) {
run(v);
print(v,': ',output[0].out,'\n');
}

View File

@@ -2,18 +2,18 @@ use std.padding;
use std.file;
var source=file.find_all_files_with_extension("./src","cpp","h");
sort(source,func(a,b){return cmp(a,b)<0});
sort(source,func(a,b) {return cmp(a,b)<0});
var lib=file.find_all_files_with_extension("./std","nas");
sort(lib,func(a,b){return cmp(a,b)<0});
sort(lib,func(a,b) {return cmp(a,b)<0});
var testfile=file.find_all_files_with_extension("./test","nas");
sort(testfile,func(a,b){return cmp(a,b)<0});
sort(testfile,func(a,b) {return cmp(a,b)<0});
var module=file.find_all_files_with_extension("./module","cpp","nas");
sort(module,func(a,b){return cmp(a,b)<0});
sort(module,func(a,b) {return cmp(a,b)<0});
var longest=func(vec...){
var longest = func(vec...) {
var len=0;
foreach(var v;vec)
foreach(var f;v)
@@ -22,41 +22,41 @@ var longest=func(vec...){
}
var padding_length=longest(source,lib,testfile,module);
var blank=func(s){
if(!size(s)){
var blank = func(s) {
if (!size(s)) {
return 1;
}
var space=[" "[0],"\n"[0],"\t"[0],"\r"[0]];
for(var i=0;i<size(s);i+=1){
for(var i=0;i<size(s);i+=1) {
var flag=0;
foreach(var j;space){
if(s[i]==j){
foreach(var j;space) {
if (s[i]==j) {
flag=1;
}
}
if(!flag){
if (!flag) {
return 0;
}
}
return 1;
}
var count=func(s,c){
var count = func(s,c) {
var cnt=0;
foreach(var i;split(c,s))
cnt+=!blank(i);
return cnt;
}
var column=func(number){
var column = func(number) {
number=number>=1000?substr(str(number/1000),0,4)~'k':str(number);
return padding.leftpad(number,6);
}
var calc=func(codetype,files,path=""){
var calc = func(codetype,files,path="") {
println(codetype);
var (bytes,ctx,line,semi,line_cnt,semi_cnt)=(0,"",0,0,0,0);
forindex(var i;files){
forindex(var i;files) {
var s=io.exists(path~files[i])?io.readfile(path~files[i]):"";
(line_cnt,semi_cnt)=(count(s,'\n'),count(s,';'));
println(padding.rightpad(files[i],padding_length),'|',

View File

@@ -1,21 +1,21 @@
var condition_true=1;
var condition_false=0;
if(condition_true) {
if (condition_true) {
var a=1;
} else if(!condition_false) {
} else if (!condition_false) {
var b=1;
} elsif(!condition_true and condition_false) {
} elsif (!condition_true and condition_false) {
print("impossible");
} else {
var c=1;
var d=1;
}
if(condition_true)
if (condition_true)
var a=1;
else if(!condition_false)
else if (!condition_false)
var b=1;
elsif(!condition_true and condition_false)
elsif (!condition_true and condition_false)
print("impossible");
else
var c=1;

View File

@@ -1,4 +1,4 @@
var student=func(n,a){
var student = func(n,a) {
return {
print_info:func println(n,' ',a),
set_age: func(age) a=age,
@@ -19,31 +19,31 @@ s.set_name('Sidi Liang');
s.print_info();
println(s.get_age(),' ',s.get_name());
# flightgear nasal-console cannot use this kind of object initializing
var m=func(){
var m = func() {
var (_1,_2)=(0,1);
return {
a:func(){
a:func() {
print(_1,' ',_2,'\n');
},
b:func(x){
b:func(x) {
_1=x;
},
c:func(x){
c:func(x) {
_2=x;
},
d:func(x){
return func{
d:func(x) {
return func {
print(_1,' ',_2,' ',x,'\n');
};
},
g:func(x){
g:func(x) {
var y=x;
return func{
return func {
print(_1,' ',_2,' ',x,' ',y,'\n');
}
},
h:func(){
return func(x){
h:func() {
return func(x) {
_1=x;
}
}

View File

@@ -24,7 +24,7 @@
use module.libmat;
use std.runtime;
func(){
func() {
# allocate more spaces
for(var i = 0; i<10; i+=1) {
runtime.gc.extend("str");
@@ -71,61 +71,61 @@ var (rotateX,rotateY,rotateZ)=(
libmat.vec3.rz,
);
var use_raw=func(){
vec2=func(x,y){return [x,y];}
vec2add=func(v1,v2){return [v1[0]+v2[0],v1[1]+v2[1]];}
vec2sub=func(v1,v2){return [v1[0]-v2[0],v1[1]-v2[1]];}
vec2mul=func(v1,v2){return [v1[0]*v2[0],v1[1]*v2[1]];}
vec2div=func(v1,v2){return [v1[0]/v2[0],v1[1]/v2[1]];}
vec3=func(x,y,z){return [x,y,z];}
vec3add=func(v1,v2){return [v1[0]+v2[0],v1[1]+v2[1],v1[2]+v2[2]];}
vec3sub=func(v1,v2){return [v1[0]-v2[0],v1[1]-v2[1],v1[2]-v2[2]];}
vec3mul=func(v1,v2){return [v1[0]*v2[0],v1[1]*v2[1],v1[2]*v2[2]];}
vec3div=func(v1,v2){return [v1[0]/v2[0],v1[1]/v2[1],v1[2]/v2[2]];}
vec3neg=func(v){return [-v[0],-v[1],-v[2]];}
vec2len=func(v){var (x,y)=(v[0],v[1]); return sqrt(x*x+y*y);}
vec3len=func(v){var (x,y,z)=(v[0],v[1],v[2]); return sqrt(x*x+y*y+z*z);}
vec3norm=func(v){var t=vec3len(v); return vec3div(v,[t,t,t]);}
vec3dot=func(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];}
rotateX=func(a,angle){return [a[0],a[2]*sin(angle)+a[1]*cos(angle),a[2]*cos(angle)-a[1]*sin(angle)];}
rotateY=func(a,angle){return [a[0]*cos(angle)-a[2]*sin(angle),a[1],a[0]*sin(angle)+a[2]*cos(angle)];}
rotateZ=func(a,angle){return [a[0]*cos(angle)-a[1]*sin(angle),a[0]*sin(angle)+a[1]*cos(angle),a[2]];}
var use_raw = func() {
vec2 = func(x,y) {return [x,y];}
vec2add = func(v1,v2) {return [v1[0]+v2[0],v1[1]+v2[1]];}
vec2sub = func(v1,v2) {return [v1[0]-v2[0],v1[1]-v2[1]];}
vec2mul = func(v1,v2) {return [v1[0]*v2[0],v1[1]*v2[1]];}
vec2div = func(v1,v2) {return [v1[0]/v2[0],v1[1]/v2[1]];}
vec3 = func(x,y,z) {return [x,y,z];}
vec3add = func(v1,v2) {return [v1[0]+v2[0],v1[1]+v2[1],v1[2]+v2[2]];}
vec3sub = func(v1,v2) {return [v1[0]-v2[0],v1[1]-v2[1],v1[2]-v2[2]];}
vec3mul = func(v1,v2) {return [v1[0]*v2[0],v1[1]*v2[1],v1[2]*v2[2]];}
vec3div = func(v1,v2) {return [v1[0]/v2[0],v1[1]/v2[1],v1[2]/v2[2]];}
vec3neg = func(v) {return [-v[0],-v[1],-v[2]];}
vec2len = func(v) {var (x,y)=(v[0],v[1]); return sqrt(x*x+y*y);}
vec3len = func(v) {var (x,y,z)=(v[0],v[1],v[2]); return sqrt(x*x+y*y+z*z);}
vec3norm = func(v) {var t=vec3len(v); return vec3div(v,[t,t,t]);}
vec3dot = func(a,b) {return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];}
rotateX = func(a,angle) {return [a[0],a[2]*sin(angle)+a[1]*cos(angle),a[2]*cos(angle)-a[1]*sin(angle)];}
rotateY = func(a,angle) {return [a[0]*cos(angle)-a[2]*sin(angle),a[1],a[0]*sin(angle)+a[2]*cos(angle)];}
rotateZ = func(a,angle) {return [a[0]*cos(angle)-a[1]*sin(angle),a[0]*sin(angle)+a[1]*cos(angle),a[2]];}
}
var clamp=func(value,_min,_max){
var clamp = func(value,_min,_max) {
return max(min(value,_max),_min);
}
var sign=func(a){
var sign = func(a) {
return (0<a)-(a<0);
}
var step=func(edge,x){
var step = func(edge,x) {
return x>edge;
}
var vec3abs=func(v){
var vec3abs = func(v) {
return [abs(v[0]),abs(v[1]),abs(v[2])];
}
var vec3sign=func(v){
var vec3sign = func(v) {
return [sign(v[0]),sign(v[1]),sign(v[2])];
}
var vec3step=func(edge,v){
var vec3step = func(edge,v) {
return [step(edge[0],v[0]),step(edge[1],v[1]),step(edge[2],v[2])];
}
var vec3reflect=func(rd,n){
var vec3reflect = func(rd,n) {
var d=vec3dot(n,rd);
return vec3sub(rd,vec3mul(n,vec3mul([2,2,2],[d,d,d])));
}
var sphere=func(ro,rd,r) {
var sphere = func(ro,rd,r) {
var b=vec3dot(ro,rd);
var c=vec3dot(ro,ro)-r*r;
var h=b*b-c;
if(h<0.0) return [-1.0,-1.0];
if (h<0.0) return [-1.0,-1.0];
h=sqrt(h);
return [-b-h,-b+h];
}
var box=func(ro,rd,boxSize,outNormal) {
var box = func(ro,rd,boxSize,outNormal) {
var m=vec3div([1.0,1.0,1.0],rd);
var n=vec3mul(m,ro);
var k=vec3mul(vec3abs(m),boxSize);
@@ -143,11 +143,11 @@ var box=func(ro,rd,boxSize,outNormal) {
return [tN, tF];
}
var plane=func(ro,rd,p,w) {
var plane = func(ro,rd,p,w) {
return -(vec3dot(ro,p)+w)/vec3dot(rd,p);
}
var main=func(frame) {
var main = func(frame) {
var height=15*2;
var width=int(height*1/0.618)*2;
@@ -171,10 +171,10 @@ var main=func(frame) {
print("\e[2J");
var stamp=maketimestamp();
for(var t=0;t<frame;t+=1){
for(var t=0;t<frame;t+=1) {
stamp.stamp();
for(var i=0;i<width;i+=1){
for(var j=0;j<height;j+=1){
for(var i=0;i<width;i+=1) {
for(var j=0;j<height;j+=1) {
var uv=vec2sub(vec2mul(vec2div([i,j],[width,height]),vec2_2_2),vec2_1_1);
uv[0]*=aspect*pixelAspect;
var ro=[-6,0,0];
@@ -184,30 +184,30 @@ var main=func(frame) {
ro=rotateZ(ro,t*0.03);
rd=rotateZ(rd,t*0.03);
var diff=1;
for (var k=0;k<5;k+=1){
for (var k=0;k<5;k+=1) {
var minIt=99999;
var intersection=sphere(vec3sub(ro,spherePos),rd,1);
var n=vec3_000;
var albedo=1;
if(intersection[0]>0){
if (intersection[0]>0) {
var itPoint=vec3add(vec3sub(ro,spherePos),vec3mul(rd,[intersection[0],intersection[0],intersection[0]]));
minIt=intersection[0];
n=vec3norm(itPoint);
}
var boxN=[0,0,0];
intersection=box(ro,rd,vec3_111,boxN);
if(intersection[0]>0 and intersection[0]<minIt){
if (intersection[0]>0 and intersection[0]<minIt) {
minIt=intersection[0];
n=boxN;
}
var tmp=plane(ro,rd,vec3_00n1,1);
intersection=[tmp,tmp];
if(intersection[0]>0 and intersection[0]<minIt){
if (intersection[0]>0 and intersection[0]<minIt) {
minIt=intersection[0];
n=vec3_00n1;
albedo=0.5;
}
if(minIt<99999){
if (minIt<99999) {
diff*=(vec3dot(n,light)*0.5+0.5)*albedo;
ro=vec3add(ro,vec3mul(rd,[minIt-0.01,minIt-0.01,minIt-0.01]));
rd=vec3reflect(rd,n);
@@ -220,9 +220,9 @@ var main=func(frame) {
}
}
var s="";
forindex(var index;screen){
forindex(var index;screen) {
s~=screen[index];
if(index+1-int((index+1)/width)*width==0)
if (index+1-int((index+1)/width)*width==0)
s~="\n";
}
var elt=stamp.elapsedMSec()/1000;
@@ -233,9 +233,9 @@ var main=func(frame) {
var st=maketimestamp();
var run=[0,0];
var frame=1e3;
if(size(runtime.argv())!=0){
if (size(runtime.argv())!=0) {
var n=num(runtime.argv()[0]);
if(!math.isnan(n)){
if (!math.isnan(n)) {
frame=n;
}
}

View File

@@ -1,49 +1,50 @@
# coroutine.nas by ValKmjolnir
# 2022/5/19
use std.coroutine;
use std.process_bar;
use std.padding;
if(os.platform()=="windows"){
if (os.platform()=="windows") {
system("chcp 65001");
system("color");
}
var fib=func(){
var fib = func() {
var (a,b)=(1,1);
coroutine.yield(a);
coroutine.yield(b);
while(1){
while(1) {
(a,b)=(b,a+b);
coroutine.yield(b);
}
return;
}
var co=[coroutine.create(fib),coroutine.create(fib)];
for(var i=0;i<45;i+=1){
for(var i=0;i<45;i+=1) {
var res=[coroutine.resume(co[0]),coroutine.resume(co[1])];
if(res[0]==nil or res[1]==nil or res[0][0]!=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
func(){
func() {
var x=1;
var co=coroutine.create(func(){
for(var j=0;j<128;j+=1){
var co=coroutine.create(func() {
for(var j=0;j<128;j+=1) {
coroutine.yield(x,i,j);
x+=1;
}
});
for(var i=0;i<16;i+=1){
for(var i=0;i<16;i+=1) {
var res=coroutine.resume(co);
if(res==nil or res[0]!=x or res[1]!=i)
if (res==nil or res[0]!=x or res[1]!=i)
die("coroutine should have the ability to get upvalues");
}
}();
# test coroutine.resume passing arguments to coroutine
func{
var co=coroutine.create(func(){
func {
var co=coroutine.create(func() {
var (a,b)=coroutine.yield(a+b);
println("coroutine.yield get ",a," ",b);
(a,b)=coroutine.yield(a+b);
@@ -56,8 +57,8 @@ func{
}();
# test crash in coroutines
var co=coroutine.create(func{
var b=func(){b()}
var co=coroutine.create(func {
var b = func() {b()}
coroutine.yield(b);
b();
coroutine.yield(0);
@@ -70,9 +71,9 @@ 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 co=coroutine.create(func {
var a=1;
var b=func(){
var b = func() {
b();
}
coroutine.yield(b);
@@ -88,9 +89,9 @@ println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
println("ok");
# pressure test
for(var t=0;t<10;t+=1){
var productor=func(){
while(1){
for(var t=0;t<10;t+=1) {
var productor = func() {
while(1) {
coroutine.yield(i);
}
}
@@ -100,11 +101,11 @@ for(var t=0;t<10;t+=1){
var counter=0;
var bar=process_bar.high_resolution_bar(40);
var consumer=func(){
var consumer = func() {
counter+=1;
for(var i=0;i<t+1;i+=1)
coroutine.resume(co);
if(counter-int(counter/1000)*1000==0){
if (counter-int(counter/1000)*1000==0) {
var rate=counter/2e5;
print(" ",bar.bar(rate)," ",
padding.leftpad(str(int(rate*100)),3),"% | ",

View File

@@ -1,7 +1,7 @@
use std.padding;
use std.process_bar;
var mess=func(vec) {
var mess = func(vec) {
srand();
var s=size(vec);
for(var i=s-1;i>=0;i-=1) {
@@ -10,7 +10,7 @@ var mess=func(vec) {
}
}
var project=func(n) {
var project = func(n) {
# get(s) :- color(_, s, _).
var ts=maketimestamp();
@@ -24,7 +24,7 @@ var project=func(n) {
for(var i=0;i<n;i+=1) {
color[i]=[i,"color "~i,i+n*10];
# generate process bar, every 0.2%
if((i-last_step)/n>1/500) {
if ((i-last_step)/n>1/500) {
last_step=i;
print(" ",bar.bar((i+1)/n)," ",
padding.leftpad(str(int((i+1)/n*100)),3),"% | \r");
@@ -45,7 +45,7 @@ var project=func(n) {
println(padding.rightpad(str(cnt),7)," in ",ts.elapsedMSec()/1000," s");
}
var select=func(n) {
var select = func(n) {
# get(s) :- color(_, _, x), message(x, s).
var ts=maketimestamp();
@@ -62,7 +62,7 @@ var select=func(n) {
color[i]=[i,"color "~i,i+n*10];
message[i]=[i+n*10,"message "~i];
# generate process bar, every 0.2%
if((i-last_step)/n>1/500) {
if ((i-last_step)/n>1/500) {
last_step=i;
print(" ",bar.bar((i+1)/n)," ",
padding.leftpad(str(int((i+1)/n*100)),3),"% | \r");
@@ -75,8 +75,8 @@ var select=func(n) {
mess(message);
ts.stamp();
sort(color,func(a,b){return a[2]<b[2]});
sort(message,func(a,b){return a[0]<b[0]});
sort(color,func(a,b) {return a[2]<b[2]});
sort(message,func(a,b) {return a[0]<b[0]});
var cnt=0;
foreach(var c;color) {
@@ -86,10 +86,10 @@ var select=func(n) {
while(left<=right) {
var mid=int((left+right)/2);
var res=message[mid][0];
if(data==res) {
if (data==res) {
cnt+=1;
break;
} else if(data>res) {
} else if (data>res) {
left=mid+1;
} else {
right=mid-1;
@@ -100,7 +100,7 @@ var select=func(n) {
println(padding.rightpad(str(cnt),7)," in ",ts.elapsedMSec()/1000," s");
}
var cartesian=func(n) {
var cartesian = func(n) {
# get(x, y, z, a, b) :- color(x, y, z), message(a, b).
var ts=maketimestamp();
@@ -117,7 +117,7 @@ var cartesian=func(n) {
color[i]=[i,"color "~i,i+n*10];
message[i]=[i+n*10,"message "~i];
# generate process bar, every 0.2%
if((i-last_step)/n>1/500) {
if ((i-last_step)/n>1/500) {
last_step=i;
print(" ",bar.bar((i+1)/n)," ",
padding.leftpad(str(int((i+1)/n*100)),3),"% | \r");

View File

@@ -1,4 +1,4 @@
var myers=func(src,dst,show_table=0){
var myers = func(src,dst,show_table=0) {
(src,dst)=(split("\n",src),split("\n",dst));
append(src,"");
append(dst,"");
@@ -6,12 +6,12 @@ var myers=func(src,dst,show_table=0){
var mat=[];
setsize(mat,dst_len*src_len);
forindex(var i;mat){
forindex(var i;mat) {
mat[i]=0;
}
var visited=[];
setsize(visited,dst_len*src_len);
forindex(var i;visited){
forindex(var i;visited) {
visited[i]=0;
}
@@ -19,15 +19,15 @@ var myers=func(src,dst,show_table=0){
forindex(var x;src)
mat[y*src_len+x]=(src[x]==dst[y]);
if(show_table){
if (show_table) {
var curve=[
["+---","| "],
["+---","| \\ "]
];
var s="";
forindex(var y;dst){
forindex(var t;curve[0]){
forindex(var x;src){
forindex(var y;dst) {
forindex(var t;curve[0]) {
forindex(var x;src) {
s~=curve[mat[y*src_len+x]][t];
}
s~=["+","|"][t]~"\n";
@@ -40,23 +40,23 @@ var myers=func(src,dst,show_table=0){
var (total,path,vec)=([],[],[[0,0,-1]]);
visited[0]=1;
while(size(vec)){
while(size(vec)) {
append(total,vec);
var tmp=[];
forindex(var i;vec){
forindex(var i;vec) {
var elem=vec[i];
var (x,y)=(elem[1],elem[0]);
# find solution
if(x==src_len-1 and y==dst_len-1){
if (x==src_len-1 and y==dst_len-1) {
append(path,vec[i]);
for(var (prev,iter)=(elem[2],size(total)-1);iter>0;iter-=1){
for(var (prev,iter)=(elem[2],size(total)-1);iter>0;iter-=1) {
var t=total[iter-1][prev];
append(path,t);
prev=t[2];
}
if(show_table){
if (show_table) {
for(var t=size(path)-1;t>=0;t-=1)
print("("~path[t][1]~","~path[t][0]~")",t==0?"":"->");
println();
@@ -66,16 +66,16 @@ var myers=func(src,dst,show_table=0){
for(var t=0;t<size(path)/2;t+=1)
(path[t],path[-1-t])=(path[-1-t],path[t]);
# print diff
for(var t=1;t<size(path);t+=1){
for(var t=1;t<size(path);t+=1) {
var (prev_x,prev_y)=(path[t-1][1],path[t-1][0]);
var (x,y)=(path[t][1],path[t][0]);
var (sub_x,sub_y)=(x-prev_x,y-prev_y);
if(sub_x==1 and sub_y==1){
if(show_table)
if (sub_x==1 and sub_y==1) {
if (show_table)
println(" ",src[prev_x]);
}elsif(sub_x==1 and sub_y==0){
} elsif (sub_x==1 and sub_y==0) {
println("\e[31m - ",src[prev_x],"\e[0m");
}elsif(sub_x==0 and sub_y==1){
} elsif (sub_x==0 and sub_y==1) {
println("\e[32m + ",dst[prev_y],"\e[0m");
}
}
@@ -83,18 +83,18 @@ var myers=func(src,dst,show_table=0){
}
# do bfs
if(mat[y*src_len+x]==1){
if(x+1<src_len and y+1<dst_len and visited[(y+1)*src_len+x+1]==0){
if (mat[y*src_len+x]==1) {
if (x+1<src_len and y+1<dst_len and visited[(y+1)*src_len+x+1]==0) {
append(tmp,[y+1,x+1,i]);
visited[(y+1)*src_len+x+1]=1;
}
}
else{
if(x+1<src_len and visited[y*src_len+x+1]==0){
else {
if (x+1<src_len and visited[y*src_len+x+1]==0) {
append(tmp,[y,x+1,i]);
visited[y*src_len+x+1]=1;
}
if(y+1<dst_len and visited[(y+1)*src_len+x]==0){
if (y+1<dst_len and visited[(y+1)*src_len+x]==0) {
append(tmp,[y+1,x,i]);
visited[(y+1)*src_len+x]=1;
}
@@ -104,7 +104,7 @@ var myers=func(src,dst,show_table=0){
}
}
func(diff){
func(diff) {
diff(
"var a=0;\nvar b=1;\nprint(\"hello \",a);\nvar c=2;\nc=[];\nvar d=3;\nvar l=list();\nvar q=queue();\n",
"var a=0;\nvar b=1;\nb=[];\nprintln(\"hello \",a);\nvar c=2;\nvar d=3;\nprintln(\"hello world!\");\nvar l=list();\nvar q=queue();\n",

View File

@@ -2,7 +2,7 @@ use std.runtime;
var mod = math.mod;
var main=func(run_time){
var main = func(run_time) {
var ts=maketimestamp();
var (sin,cos)=(math.sin,math.cos);
@@ -14,14 +14,14 @@ var main=func(run_time){
setsize(b,1760);
print("\e[2J");
for(var run=0;run<run_time;run+=1){
for(var run=0;run<run_time;run+=1) {
ts.stamp();
forindex(var i;b){
forindex(var i;b) {
b[i]=" ";
z[i]=0;
}
for(var j=0;j<6.28;j+=0.07){
for(var i=0;i<6.28;i+=0.02){
for(var j=0;j<6.28;j+=0.07) {
for(var i=0;i<6.28;i+=0.02) {
var (c,d,e,f,g)=(sin(i),cos(j),sin(A),sin(j),cos(A));
var h=d+2;
var D=1/(c*h*e+f*g+5);
@@ -31,7 +31,7 @@ var main=func(run_time){
var y=int(12+15*D*(l*h*n+t*m));
var o=int(x+80*y);
var N=int(8*((f*e-c*d*g)*m-c*d*e-f*g-l*d*n));
if(22>y and y>0 and x>0 and 80>x and D>z[o]){
if (22>y and y>0 and x>0 and 80>x and D>z[o]) {
z[o]=D;
b[o]=chars[N>0?N:0];
}
@@ -49,8 +49,8 @@ var main=func(run_time){
}
}
if(size(runtime.argv()) and !math.isnan(num(runtime.argv()[0]))){
if (size(runtime.argv()) and !math.isnan(num(runtime.argv()[0]))) {
main(num(runtime.argv()[0]));
}else{
} else {
main(5e2);
}

View File

@@ -1,22 +1,22 @@
var ResultTrait={
Ok:func(val){
Ok:func(val) {
me.ok=val;
me.flag=0;
return me;
},
Err:func(info){
Err:func(info) {
me.err=info;
me.flag=1;
return me;
},
unwrap:func(){
if(me.flag)
unwrap:func() {
if (me.flag)
die(me.err);
return me.ok;
}
};
var Result=func(){
var Result = func() {
return{
ok:nil,
err:"",
@@ -25,11 +25,11 @@ var Result=func(){
};
};
var a=func(){
var a = func() {
return Result().Ok("hello world");
}
var b=func(){
var b = func() {
return Result().Err("exception test");
}

View File

@@ -37,12 +37,13 @@ var RGB = func(h, w) {
}
var progress = (h*width+w+1)/(width*height);
if(progress*100-int(progress*100)==0){
if (progress*100-int(progress*100)==0) {
print(bar.bar(progress), " ", progress*100, "% \r");
}
var c = char(res);
return c~c~c;
}
ppm("feigenbaum.ppm", width, height, RGB);
println();

View File

@@ -1,8 +1,6 @@
var fib=func(x)
{
if(x<2) return 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)
print(fib(i),'\n');

View File

@@ -1,5 +1,5 @@
var files=func(path){
if(!io.exists(path))
var files = func(path) {
if (!io.exists(path))
return [];
var dd=unix.opendir(path);
var res=[];
@@ -8,30 +8,30 @@ var files=func(path){
unix.closedir(dd);
return res;
}
var prt=func(s,path){
var prt = func(s,path) {
var vec=files(path);
var last=size(vec)-1;
forindex(var i;vec){
forindex(var i;vec) {
var f=vec[i];
if(f=="." or f=="..")
if (f=="." or f=="..")
continue;
foreach(var j;s)
print("\e[34m",j,"\e[0m");
if(unix.isdir(path~"/"~f)){
if (unix.isdir(path~"/"~f)) {
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)){
} elsif (unix.isfile(path~"/"~f)) {
println("\e[34m",i==last?" └─":" ├─","\e[0m\e[32m",f,"\e[0m");
}else{
} else {
println("\e[34m",i==last?" └─":" ├─","\e[0m\e[91m",f,"\e[0m");
}
}
}
# enable unicode
if(os.platform()=="windows")
if (os.platform()=="windows")
system("chcp 65001");
println("\e[33m[",unix.getcwd(),"]\e[36m>\e[0m");
prt([""],".");

View File

@@ -4,7 +4,7 @@ use std.file;
use std.runtime;
# init
var hex=func(){
var hex = func() {
var hex_num=[
'0','1','2','3',
'4','5','6','7',
@@ -12,8 +12,8 @@ var hex=func(){
'c','d','e','f'
];
var res=[];
foreach(var i;hex_num){
foreach(var j;hex_num){
foreach(var i;hex_num) {
foreach(var j;hex_num) {
append(res,i~j);
}
}
@@ -21,11 +21,11 @@ var hex=func(){
}();
# read file
var s=func(){
var s = func() {
var filename = file.find_all_files_with_extension("./src","cpp","h");
if(size(runtime.argv())!=0){
if (size(runtime.argv())!=0) {
var argv=runtime.argv();
if(argv[0]=="-h" or argv[0]=="--h"){
if (argv[0]=="-h" or argv[0]=="--h") {
println("usage:");
println(" nasal hexdump.nas | get all files' hexdump.");
println(" nasal hexdump.nas [file] | get single file's hexdump.");
@@ -46,24 +46,24 @@ var cnt=0;
var hex_index=[0,0,0,0];
# print binary in text format
var textprint=func(index){
var textprint = func(index) {
var info="";
if(os.platform()=="windows"){
if (os.platform()=="windows") {
for(var i=index-cnt;i<index;i+=1)
info~=(s[i]<32 or s[i]>=127)?".":chr(s[i]);
}else{
} else {
for(var i=index-cnt;i<index;i+=1)
info~=(s[i]<32 or s[i]==127)?".":chr(s[i]);
}
for(var i=cnt;i<16;i+=1){
for(var i=cnt;i<16;i+=1) {
info~=".";
}
return " |"~info~"|\n";
}
# print index
var indexprint=func(index){
forindex(var i;hex_index){
var indexprint = func(index) {
forindex(var i;hex_index) {
hex_index[i]=index-int(index/256)*256;
index=int(index/256);
}
@@ -74,25 +74,25 @@ var indexprint=func(index){
}
# main
func(){
if(!size(s)){
func() {
if (!size(s)) {
return;
}
var info=indexprint(0);
for(var i=0;i<size(s);i+=1){
if(cnt==16){
for(var i=0;i<size(s);i+=1) {
if (cnt==16) {
info~=textprint(i);
print(info);
cnt=0;
info=indexprint(i);
}elsif(cnt==8)
} elsif (cnt==8)
info~=" ";
cnt+=1;
info~=hex[s[i]]~" ";
}
for(var l=cnt;l<16;l+=1)
info~=" ";
if(cnt<=8)
if (cnt<=8)
info~=" ";
info~=textprint(i);
print(info);

View File

@@ -2,12 +2,12 @@ use module.libsock;
var socket = libsock.socket;
var http=func(){
var http = func() {
var sd=nil;
return {
establish:func(ip,port){
establish:func(ip,port) {
sd=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.IPPROTO_IP);
while(socket.bind(sd,ip,port)<0){
while(socket.bind(sd,ip,port)<0) {
println("[",os.time(),"] failed to bind socket "~sd~" at IP: "~ip~" port: "~port~".");
unix.sleep(5);
println("[",os.time(),"] retrying...");
@@ -15,21 +15,21 @@ var http=func(){
socket.listen(sd,1);
println("[",os.time(),"] start server at [",ip,":",port,"]");
},
shutdown:func(){
shutdown:func() {
println("[",os.time(),"] shutdown server");
socket.closesocket(sd);
},
accept:func(){
accept:func() {
return socket.accept(sd);
},
disconnect:func(client,log=0){
if(log)
disconnect:func(client,log=0) {
if (log)
println("[",os.time(),"] [",client.ip,"] disconnected");
return socket.closesocket(client.sd);
},
recv:func(client){
recv:func(client) {
var data=socket.recv(client.sd,2048);
if(!data.size){
if (!data.size) {
println("[",os.time(),"] [",client.ip,"] closed connection");
return nil;
}
@@ -38,7 +38,7 @@ var http=func(){
println("[",os.time(),"] [",client.ip,"] request ",type," [",path,"]");
return {type:type,path:path};
},
send:func(client,content){
send:func(client,content) {
println("[",os.time(),"] [",client.ip,"] get size ",size(content)," byte(s)");
return socket.send(client.sd,content);
}
@@ -75,7 +75,7 @@ var highlight_style="
code.note {color: #808080;}
</style>";
var html_read_file=func(filename){
var html_read_file = func(filename) {
var timer=maketimestamp();
timer.stamp();
var keyword=["var","func","for","while","foreach","forindex","break","continue","return","if","else","elsif","nil"];
@@ -83,152 +83,152 @@ var html_read_file=func(filename){
var (s,index,len)=("",-1,size(file_text));
var content="";
var next=func(){
if(index+1>=len)
var next = func() {
if (index+1>=len)
return index+1;
index+=1;
s=char(file_text[index]);
return index;
}
var prev=func(){
var prev = func() {
index-=1;
s=char(file_text[index]);
}
while(1){
if(next()>=len)
while(1) {
if (next()>=len)
break;
if(s==">")
if (s==">")
content~="<code class=\"opr\">&gt;</code>";
elsif(s=="<")
elsif (s=="<")
content~="<code class=\"opr\">&lt;</code>";
elsif(s=="[" or s=="]" or s=="(" or s==")" or s=="{" or s=="}")
elsif (s=="[" or s=="]" or s=="(" or s==")" or s=="{" or s=="}")
content~="<code class=\"brace\">"~s~"</code>";
elsif(s=="=" or s=="," or s==";" or s==":" or s=="|" or s=="&" or s=="!" or s=="?" or s=="+" or s=="-" or s=="*" or s=="/" or s=="~" or s==".")
elsif (s=="=" or s=="," or s==";" or s==":" or s=="|" or s=="&" or s=="!" or s=="?" or s=="+" or s=="-" or s=="*" or s=="/" or s=="~" or s==".")
content~="<code class=\"opr\">"~s~"</code>";
elsif(s=="_" or ("a"[0]<=s[0] and s[0]<="z"[0]) or ("A"[0]<=s[0] and s[0]<="Z"[0]) or s[0]<0 or s[0]>=128){
elsif (s=="_" or ("a"[0]<=s[0] and s[0]<="z"[0]) or ("A"[0]<=s[0] and s[0]<="Z"[0]) or s[0]<0 or s[0]>=128) {
var tmp=""~s; # generate a new string
while(1){
if(next()>=len)
while(1) {
if (next()>=len)
break;
if(s=="_" or ("a"[0]<=s[0] and s[0]<="z"[0]) or ("A"[0]<=s[0] and s[0]<="Z"[0]) or ("0"[0]<=s[0] and s[0]<="9"[0]) or s[0]<0 or s[0]>=128)
if (s=="_" or ("a"[0]<=s[0] and s[0]<="z"[0]) or ("A"[0]<=s[0] and s[0]<="Z"[0]) or ("0"[0]<=s[0] and s[0]<="9"[0]) or s[0]<0 or s[0]>=128)
tmp~=s;
else{
else {
prev();
break;
}
}
var is_key=0;
foreach(var i;keyword)
if(tmp==i){
if (tmp==i) {
is_key=1;
content~="<code class=\"key\">"~tmp~"</code>";
break;
}
if(!is_key)
if (!is_key)
content~="<code class=\"id\">"~tmp~"</code>";
}elsif("0"[0]<=s[0] and s[0]<="9"[0]){
} elsif ("0"[0]<=s[0] and s[0]<="9"[0]) {
content~="<code class=\"num\">"~s;
if(next()>=len){
if (next()>=len) {
content~="</code>";
break;
}
if(s=="o"){
if (s=="o") {
content~="o";
while(1){
if(next()>=len)
while(1) {
if (next()>=len)
break;
if("0"[0]<=s[0] and s[0]<="7"[0])
if ("0"[0]<=s[0] and s[0]<="7"[0])
content~=s;
else
break;
}
content~="</code>";
prev();
}elsif(s=="x"){
} elsif (s=="x") {
content~="x";
while(1){
if(next()>=len)
while(1) {
if (next()>=len)
break;
if(("0"[0]<=s[0] and s[0]<="9"[0]) or ("a"[0]<=s[0] and s[0]<='f') or ("A"[0]<=s[0] or s[0]<="F"))
if (("0"[0]<=s[0] and s[0]<="9"[0]) or ("a"[0]<=s[0] and s[0]<='f') or ("A"[0]<=s[0] or s[0]<="F"))
content~=s;
else
break;
}
content~="</code>";
prev();
}elsif(("0"[0]<=s[0] and s[0]<="9"[0]) or s=="." or s=="e"){
while("0"[0]<=s[0] and s[0]<="9"[0]){
} elsif (("0"[0]<=s[0] and s[0]<="9"[0]) or s=="." or s=="e") {
while("0"[0]<=s[0] and s[0]<="9"[0]) {
content~=s;
if(next()>=len)
if (next()>=len)
break;
}
if(s=="."){
if (s==".") {
content~=s;
if(next()>=len)
if (next()>=len)
break;
}
while("0"[0]<=s[0] and s[0]<="9"[0]){
while("0"[0]<=s[0] and s[0]<="9"[0]) {
content~=s;
if(next()>=len)
if (next()>=len)
break;
}
if(s=="e"){
if (s=="e") {
content~=s;
if(next()>=len)
if (next()>=len)
break;
if(s=="-" or s=="+"){
if (s=="-" or s=="+") {
content~=s;
if(next()>=len)
if (next()>=len)
break;
}
}
while("0"[0]<=s[0] and s[0]<="9"[0]){
while("0"[0]<=s[0] and s[0]<="9"[0]) {
content~=s;
if(next()>=len)
if (next()>=len)
break;
}
prev();
content~="</code>";
}else{
} else {
prev();
content~="</code>";
}
}elsif(s=="\"" or s=="'" or s=="`"){
} elsif (s=="\"" or s=="'" or s=="`") {
var quot=s~""; # generate a new string
content~="<code class=\"str\">"~s;
while(1){
if(next()>=len)
while(1) {
if (next()>=len)
break;
if(s==quot){
if (s==quot) {
content~=s~"</code>";
break;
}elsif(s=="\\"){
} elsif (s=="\\") {
content~=s;
if(next()>=len)
if (next()>=len)
break;
content~=s;
}elsif(s==">"){
} elsif (s==">") {
content~="&gt;";
}elsif(s=="<"){
} elsif (s=="<") {
content~="&lt;";
}else{
} else {
content~=s;
}
}
}elsif(s=="#"){
} elsif (s=="#") {
content~="<code class=\"note\">"~s;
while(1){
if(next()>=len)
while(1) {
if (next()>=len)
break;
if(s=="\n" or s=="\r"){
if (s=="\n" or s=="\r") {
content~=s;
break;
}elsif(s==">"){
} elsif (s==">") {
content~="&gt;";
}elsif(s=="<"){
} elsif (s=="<") {
content~="&lt;";
}else{
} else {
content~=s;
}
}
@@ -242,11 +242,11 @@ var html_read_file=func(filename){
}
var respond={
ok:func(html){
ok:func(html) {
println("[",os.time(),"] respond 200 OK");
return "Http/1.1 200 OK\n\n"~html~"\n";
},
not_found:func(){
not_found:func() {
println("[",os.time(),"] respond 404 NOT FOUND");
return "Http/1.1 404 NOT FOUND\n\n<!DOCTYPE html>
<head>
@@ -260,7 +260,7 @@ var respond={
</body>
</html>\n";
},
teapot:func(){
teapot:func() {
println("[",os.time(),"] respond 418 I'm a teapot");
return "Http/1.1 418 I'm a teapot\n\n<!DOCTYPE html>
<head>
@@ -276,7 +276,7 @@ var respond={
}
};
var files=func(){
var files = func() {
var res={};
var dd=unix.opendir("./test");
while((var name=unix.readdir(dd))!=nil)
@@ -284,61 +284,61 @@ var files=func(){
return res;
}();
while(1){
while(1) {
var client=http.accept();
var data=http.recv(client);
if(data==nil){
if (data==nil) {
http.disconnect(client);
continue;
}
if(data.type=="GET"){
if (data.type=="GET") {
var path=data.path;
var args=split("?",path);
var tmp={};
if(size(args)==2){
if (size(args)==2) {
path=args[0];
args=split("=",args[1]);
for(var i=0;i<size(args);i+=2)
tmp[args[i]]=args[i+1];
}
if(path=="/" or path=="/index"){
if(contains(tmp,"filename") and contains(files,tmp.filename)){
if (path=="/" or path=="/index") {
if (contains(tmp,"filename") and contains(files,tmp.filename)) {
var filename=tmp.filename;
var page="<!DOCTYPE html><head><title> "~filename~" </title><meta charset=\"utf-8\">"~highlight_style~"</head>\n<body><pre>\n";
var page_back="</pre>\n</body>\n</html>\n";
http.send(client,respond.ok(page~html_read_file("./test/"~filename)~page_back));
}else{
} else {
http.send(client,respond.ok(io.readfile("./doc/nasal-http-test-web.html")));
}
}
elsif(path=="/shutdown"){
elsif (path=="/shutdown") {
http.send(client,respond.ok("http server shutdown."));
break;
}
elsif(path=="/favicon.ico")
elsif (path=="/favicon.ico")
http.send(client,respond.ok(io.readfile("./doc/pic/favicon.ico")));
elsif(path=="/license")
elsif (path=="/license")
http.send(client,respond.ok(io.readfile("./LICENSE")));
elsif(path=="/doc/pic/nasal.png" or
elsif (path=="/doc/pic/nasal.png" or
path=="/doc/pic/social.png" or
path=="/doc/pic/benchmark.png" or
path=="/doc/pic/mandelbrot.png" or
path=="/doc/pic/feigenbaum.png" or
path=="/doc/pic/burningship.png")
http.send(client,respond.ok(io.readfile("."~path)));
else{
else {
var filename=substr(path,1,size(path)-1);
if(contains(files,filename)){
if (contains(files,filename)) {
var page="<!DOCTYPE html><head><title> "~filename~" </title><meta charset=\"utf-8\">"~highlight_style~"</head>\n<body><pre>\n";
var page_back="</pre>\n</body>\n</html>\n";
http.send(client,respond.ok(page~html_read_file("./test/"~filename)~page_back));
}
elsif(filename=="teapot")
elsif (filename=="teapot")
http.send(client,respond.teapot());
else
http.send(client,respond.not_found());
}
}elsif(data.type=="POST"){
} elsif (data.type=="POST") {
http.send(client,respond.not_found);
}
http.disconnect(client);

View File

@@ -13,7 +13,7 @@ var ss = json.stringify({
emptyvec:[],
empty:[{}],
empty_an:[[[[[[{}]]]]]],
function:func(){}
function:func() {}
});
println(ss, "\n");
@@ -30,7 +30,7 @@ var ss = json.stringify([{
emptyhash:{},
emptyvec:[],
empty_an:[[[[[{}]]]]],
function:func(){}
function:func() {}
}]);
println(ss, "\n");

View File

@@ -4,16 +4,16 @@ use std.runtime;
var socket = libsock.socket;
var gettime=func(){
var gettime = func() {
return split(" ",os.time())[1];
}
var jsonRPC=func(){
var jsonRPC = func() {
var sd=nil;
return {
establish:func(ip,port) {
sd=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.IPPROTO_IP);
if(socket.bind(sd,ip,port)<0) {
if (socket.bind(sd,ip,port)<0) {
println("[",gettime(),"] failed to bind socket ",sd," at ",ip,":",port);
return 0;
}
@@ -42,23 +42,23 @@ var jsonRPC=func(){
println("[",gettime(),"] disconnected");
return socket.closesocket(client.sd);
},
recv:func(client){
recv:func(client) {
var data=socket.recv(client.sd,2048);
if(data.size<=0){
if (data.size<=0) {
println("[",gettime(),"] closed connection, recv failed");
return nil;
}
println("[",gettime(),"] receive ",data.str);
return data.str;
},
send:func(client,content){
send:func(client,content) {
println("[",gettime(),"] sending ",content);
return socket.send(client.sd,content);
}
};
}();
var server=func(ip,port) {
var server = func(ip,port) {
var methods={
callHello:func(vec) {
var res="hello ";
@@ -103,7 +103,7 @@ var server=func(ip,port) {
jsonRPC.disconnect(client);
}
var client=func(ip,port) {
var client = func(ip,port) {
srand();
var call_id=1;
var methods=["callHello","notExist","onRandom"];

View File

@@ -2,28 +2,27 @@
var n=4;
var input=[[0,1],[0,2],[1,2]];
var find_root=func(x,parent)
{
var find_root = func(x,parent) {
while(parent[x]!=nil)
x=parent[x];
return x;
}
var union_root=func(x,y,parent)
{
var union_root = func(x,y,parent) {
var x_root=find_root(x,parent);
var y_root=find_root(y,parent);
if(x_root==y_root) return 0;
if (x_root==y_root) return 0;
else parent[x_root]=y_root;
return 1;
}
var makeConnect=func(n,connections)
{
if(size(connections)<n-1) return -1;
var makeConnect = func(n,connections) {
if (size(connections)<n-1) return -1;
var cnt=n-1;
var parent=[];
setsize(parent,n);
foreach(var i;connections)
if(union_root(i[0],i[1],parent))
if (union_root(i[0],i[1],parent))
cnt-=1;
return cnt;
}

View File

@@ -1,28 +1,27 @@
var lexer=func(file)
{
var lexer = func(file) {
var (ptr,token)=(0,[]);
var s=io.readfile(file);
var len=size(s);
var line=0;
var gen=func(tok){
var gen = func(tok) {
append(token,{
line:line,
token:tok
});
}
return {
jmp_note:func(){
jmp_note:func() {
while(ptr<len and s[ptr]!='\n'[0])
ptr+=1;
if(ptr<len and s[ptr]=='\n'[0])
if (ptr<len and s[ptr]=='\n'[0])
line+=1;
ptr+=1;
},
id_gen:func(){
id_gen:func() {
var tmp="";
while(ptr<len){
while(ptr<len) {
var c=s[ptr];
if(('a'[0]<=c and c<='z'[0])
if (('a'[0]<=c and c<='z'[0])
or ('A'[0]<=c and c<='Z'[0])
or ('0'[0]<=c and c<='9'[0])
or c=='_'[0])
@@ -33,142 +32,142 @@ var lexer=func(file)
}
gen(tmp);
},
str_gen:func(){
str_gen:func() {
var str="";
var mark=chr(s[ptr]);
ptr+=1;
while(ptr<len and chr(s[ptr])!=mark){
if(chr(s[ptr])=='\\'){
while(ptr<len and chr(s[ptr])!=mark) {
if (chr(s[ptr])=='\\') {
ptr+=1;
var c=chr(s[ptr]);
if (c=='a' ) str~='\a';
elsif(c=='b' ) str~='\b';
elsif(c=='e' ) str~='\e';
elsif(c=='f' ) str~='\f';
elsif(c=='n' ) str~='\n';
elsif(c=='r' ) str~='\r';
elsif(c=='t' ) str~='\t';
elsif(c=='v' ) str~='\v';
elsif(c=='?' ) str~='\?';
elsif(c=='0' ) str~='\0';
elsif(c=='\\') str~='\\';
elsif(c=='\'') str~='\'';
elsif(c=='\"') str~='\"';
elsif (c=='b' ) str~='\b';
elsif (c=='e' ) str~='\e';
elsif (c=='f' ) str~='\f';
elsif (c=='n' ) str~='\n';
elsif (c=='r' ) str~='\r';
elsif (c=='t' ) str~='\t';
elsif (c=='v' ) str~='\v';
elsif (c=='?' ) str~='\?';
elsif (c=='0' ) str~='\0';
elsif (c=='\\') str~='\\';
elsif (c=='\'') str~='\'';
elsif (c=='\"') str~='\"';
else str~=c;
}else{
if(s[ptr]=='\n'[0])
} else {
if (s[ptr]=='\n'[0])
line+=1;
str~=chr(s[ptr]);
}
ptr+=1;
}
if(ptr>=len)
if (ptr>=len)
print("read eof when generating string.\n");
ptr+=1;
gen(str);
},
num_gen:func(){
num_gen:func() {
var number=chr(s[ptr]);
ptr+=1;
if(ptr<len and chr(s[ptr])=='x'){
if (ptr<len and chr(s[ptr])=='x') {
ptr+=1;
while(ptr<len and
('a'[0]<=s[ptr] and s[ptr]<='f'[0]
or '0'[0]<=s[ptr] and s[ptr]<='9'[0])){
or '0'[0]<=s[ptr] and s[ptr]<='9'[0])) {
number~=chr(s[ptr]);
ptr+=1;
}
gen(num(number));
return;
}elsif(ptr<len and chr(s[ptr])=='o'){
} elsif (ptr<len and chr(s[ptr])=='o') {
ptr+=1;
while(ptr<len and ('0'[0]<=s[ptr] and s[ptr]<='7'[0])){
while(ptr<len and ('0'[0]<=s[ptr] and s[ptr]<='7'[0])) {
number~=chr(s[ptr]);
ptr+=1;
}
gen(num(number));
return;
}
while(ptr<len and ('0'[0]<=s[ptr] and s[ptr]<='9'[0])){
while(ptr<len and ('0'[0]<=s[ptr] and s[ptr]<='9'[0])) {
number~=chr(s[ptr]);
ptr+=1;
}
if(ptr<len and chr(s[ptr])=='.'){
if (ptr<len and chr(s[ptr])=='.') {
number~=chr(s[ptr]);
ptr+=1;
while(ptr<len and ('0'[0]<=s[ptr] and s[ptr]<='9'[0])){
while(ptr<len and ('0'[0]<=s[ptr] and s[ptr]<='9'[0])) {
number~=chr(s[ptr]);
ptr+=1;
}
}
if(chr(s[ptr])=='e' or chr(s[ptr])=='E'){
if (chr(s[ptr])=='e' or chr(s[ptr])=='E') {
number~=chr(s[ptr]);
ptr+=1;
if(chr(s[ptr])=='-' or chr(s[ptr])=='+'){
if (chr(s[ptr])=='-' or chr(s[ptr])=='+') {
number~=chr(s[ptr]);
ptr+=1;
}
while(ptr<len and ('0'[0]<=s[ptr] and s[ptr]<='9'[0])){
while(ptr<len and ('0'[0]<=s[ptr] and s[ptr]<='9'[0])) {
number~=chr(s[ptr]);
ptr+=1;
}
}
var last_c=chr(number[-1]);
if(last_c=='.' or last_c=='e' or last_c=='E' or last_c=='-' or last_c=='+')
if (last_c=='.' or last_c=='e' or last_c=='E' or last_c=='-' or last_c=='+')
println("error number: ",number);
gen(num(number));
},
opr_gen:func(){
opr_gen:func() {
var c=chr(s[ptr]);
if(c=='+' or c=='-' or c=='~' or c=='/' or c=='*' or c=='>' or c=='<' or c=='!' or c=='='){
if (c=='+' or c=='-' or c=='~' or c=='/' or c=='*' or c=='>' or c=='<' or c=='!' or c=='=') {
var tmp=c;
ptr+=1;
if(ptr<len and chr(s[ptr])=='='){
if (ptr<len and chr(s[ptr])=='=') {
tmp~=chr(s[ptr]);
ptr+=1;
}
gen(tmp);
return;
}elsif(c=='.'){
if(ptr+2<len and chr(s[ptr+1])=='.' and chr(s[ptr+2])=='.'){
} elsif (c=='.') {
if (ptr+2<len and chr(s[ptr+1])=='.' and chr(s[ptr+2])=='.') {
gen("...");
ptr+=3;
}
else{
else {
gen(".");
ptr+=1;
}
return;
}
elsif(c!=' ' and c!='\t' and c!='\n' and c!='\r' and s[ptr]>0)
elsif (c!=' ' and c!='\t' and c!='\n' and c!='\r' and s[ptr]>0)
gen(c);
ptr+=1;
return;
},
compile:func(){
compile:func() {
line=1;
while(ptr<len){
while(ptr<len) {
var c=s[ptr];
if(c=='#'[0])
if (c=='#'[0])
me.jmp_note();
elsif(c=='\n'[0]){
elsif (c=='\n'[0]) {
line+=1;
ptr+=1;
}
elsif('a'[0]<=c and c<='z'[0]
elsif ('a'[0]<=c and c<='z'[0]
or 'A'[0]<=c and c<='Z'[0]
or c=='_'[0])
me.id_gen();
elsif(c=='\''[0] or c=='\"'[0])
elsif (c=='\''[0] or c=='\"'[0])
me.str_gen();
elsif('0'[0]<=c and c<='9'[0])
elsif ('0'[0]<=c and c<='9'[0])
me.num_gen();
else
me.opr_gen();
}
return;
},
get_token:func(){return token;}
get_token:func() {return token;}
};
}

View File

@@ -1,19 +1,19 @@
use std.process_bar;
use std.runtime;
var new_map=func(width,height){
var new_map = func(width,height) {
var tmp=[];
setsize(tmp,height);
forindex(var i;tmp){
forindex(var i;tmp) {
tmp[i]=[];
setsize(tmp[i],width);
}
return tmp;
}
var prt=func(map){
var prt = func(map) {
var s='\e[H';
foreach(var line;map){
foreach(var line;map) {
foreach(var elem;line)
s~=elem~' ';
s~='\n';
@@ -22,16 +22,16 @@ var prt=func(map){
unix.sleep(1/160);
}
var run=func(width,height){
var run = func(width,height) {
var check=func(_width,_height){
if(_height>=height) _height=0;
if(_width>=width) _width=0;
var check = func(_width,_height) {
if (_height>=height) _height=0;
if (_width>=width) _width=0;
return map[_height][_width]=='O';
}
# enable ANSI escape sequence
if(os.platform()=="windows")
if (os.platform()=="windows")
system("color");
print("\ec");
rand(time(0));
@@ -42,13 +42,13 @@ var run=func(width,height){
forindex(var j;map[i])
map[i][j]=rand()<0.45?'O':'.';
for(var r=0;r<100;r+=1){
for(var r=0;r<100;r+=1) {
prt(map);
for(var i=0;i<height;i+=1)
for(var j=0;j<width;j+=1){
for(var j=0;j<width;j+=1) {
var cnt=check(j,i+1)+check(j+1,i)+check(j,i-1)+check(j-1,i)+check(j+1,i+1)+check(j-1,i-1)+check(j+1,i-1)+check(j-1,i+1);
if(cnt==2) tmp[i][j]=map[i][j];
elsif(cnt==3) tmp[i][j]='O';
if (cnt==2) tmp[i][j]=map[i][j];
elsif (cnt==3) tmp[i][j]='O';
else tmp[i][j]='.';
}
(map,tmp)=(tmp,map);
@@ -56,10 +56,10 @@ var run=func(width,height){
return;
};
var ppm_gen=func(width,height){
var ppm_gen = func(width,height) {
var pixels=width*height;
var new_map=func(){
var new_map = func() {
var tmp=[];
setsize(tmp,pixels);
return tmp;
@@ -68,9 +68,9 @@ var ppm_gen=func(width,height){
# iteration counter and trigger for ppm/data generator
var iter_to_print=0;
var init=func(){
var init = func() {
var res=new_map();
if(io.exists(".life_data")) {
if (io.exists(".life_data")) {
var vec=split("\n",io.readfile(".life_data"));
if (num(vec[0])!=width or num(vec[1])!=height) {
die("incorrect width or height: "~vec[0]~":"~str(width)~" / "~vec[1]~":"~str(height))
@@ -78,7 +78,7 @@ var ppm_gen=func(width,height){
iter_to_print=num(vec[2]);
var data=vec[3];
var n="1"[0];
for(var i=0;i<pixels;i+=1){
for(var i=0;i<pixels;i+=1) {
res[i]=data[i]==n?1:0;
}
return res;
@@ -94,23 +94,23 @@ var ppm_gen=func(width,height){
return res;
}
var store=func(){
var store = func() {
var fd=io.open(".life_data","w");
io.write(fd,str(width)~"\n"~str(height)~"\n"~str(iter_to_print)~"\n");
for(var i=0;i<pixels;i+=1){
for(var i=0;i<pixels;i+=1) {
io.write(fd,map[i]==1?"1":"0");
}
io.close(fd);
}
var gen=func(filename){
var gen = func(filename) {
# P3 use ASCII number
# P6 use binary character
var fd=io.open(filename,"wb");
io.write(fd,"P6\n"~width~" "~height~"\n255\n");
var white=char(255)~char(255)~char(255);
var black=char(0)~char(0)~char(0);
for(var i=0;i<pixels;i+=1){
for(var i=0;i<pixels;i+=1) {
io.write(fd,map[i]==1?white:black);
}
io.close(fd);
@@ -121,27 +121,27 @@ var ppm_gen=func(width,height){
var map=init();
var tmp=new_map();
var check=func(_width,_height){
if(_height>=height) _height=0;
if(_width>=width) _width=0;
var check = func(_width,_height) {
if (_height>=height) _height=0;
if (_width>=width) _width=0;
return map[_height*width+_width]==1;
}
for(var r=0;r<1001;r+=1){
for(var r=0;r<1001;r+=1) {
ts.stamp();
for(var i=0;i<height;i+=1){
for(var j=0;j<width;j+=1){
for(var i=0;i<height;i+=1) {
for(var j=0;j<width;j+=1) {
var cnt=check(j,i+1)+check(j+1,i)+check(j,i-1)+check(j-1,i)+check(j+1,i+1)+check(j-1,i-1)+check(j+1,i-1)+check(j-1,i+1);
if(cnt==2) tmp[i*width+j]=map[i*width+j];
elsif(cnt==3) tmp[i*width+j]=1;
if (cnt==2) tmp[i*width+j]=map[i*width+j];
elsif (cnt==3) tmp[i*width+j]=1;
else tmp[i*width+j]=0;
}
}
(map,tmp)=(tmp,map);
var calc_tm=ts.elapsedMSec();
var duration=int(calc_tm/1000*(1e3-r));
if(r-int(r/10)*10==0) {
if(r){
if (r-int(r/10)*10==0) {
if (r) {
store();
}
gen("iteration_"~str(iter_to_print)~".ppm");

View File

@@ -1,5 +1,5 @@
for(;;)break;
for(;;){
for(;;) {
var a=1;
break;
}
@@ -10,7 +10,7 @@ for(var i=1;i<10;i+=1)
print("\n");
while(1)break;
var j=0;
while(j<10){
while(j<10) {
print(j," ");
j+=1;
}
@@ -19,7 +19,7 @@ print("\n");
forindex(var j;[0,1,2,3])
print(j," ");
print("\n");
forindex(var j;[0,1,2,3]){
forindex(var j;[0,1,2,3]) {
var a=j;
print(a*a," ");
}
@@ -27,15 +27,15 @@ print("\n");
foreach(var j;[0,1,2,3])
print([0,1,2,3][j]," ");
print("\n");
foreach(var j;[0,1,2,3]){
foreach(var j;[0,1,2,3]) {
var a=[0,1,2,3][j];
print(a*a-1," ");
}
print("\n");
var f=func(){
var f = func() {
var x=0;
return func(){x+=1;};
return func() {x+=1;};
}();
for(var i=0;i<4e6;i+=1)
f();

View File

@@ -1,16 +1,16 @@
var (yMin,yMax,xMin,xMax,line)=(-0.2,0.2,-1.5,-1.0,"");
var (yDel,xDel)=(yMax-yMin,xMax-xMin);
for(var yPixel=0;yPixel<24;yPixel+=1){
for(var yPixel=0;yPixel<24;yPixel+=1) {
var y=(yPixel/24)*yDel+yMin;
for(var xPixel=0;xPixel<80;xPixel+=1){
for(var xPixel=0;xPixel<80;xPixel+=1) {
var x=(xPixel/80)*xDel+xMin;
var pixel=" ";
var (x0,y0)=(x,y);
for(var iter=0;iter<80;iter+=1){
for(var iter=0;iter<80;iter+=1) {
var x1=(x0*x0)-(y0*y0)+x;
var y1=2*x0*y0+y;
(x0,y0)=(x1,y1);
if((x0*x0)+(y0*y0)>4){
if ((x0*x0)+(y0*y0)>4) {
pixel=chr(" .:;+=xX$&"[iter/8]);
break;
}

View File

@@ -1,3 +1,5 @@
use std.bits;
var inst={
inst_stop:0,
inst_mov_reg_reg:1,
@@ -26,24 +28,24 @@ var inst={
inst_out:24
};
var hex=func(){
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 func(n) {
return vec[n];
}
}();
var hex32=func(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 machine = func(disk_file) {
var reg=[];
var reg_size=32;
@@ -51,7 +53,7 @@ var pc=0;
var ir=[0,0,0,0]; # 32 bit instruction word
var mem=[];
var mem_size=1024*1024*4; # memory size, byte
var init=func(){
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)
@@ -63,7 +65,7 @@ var init=func(){
println("[",os.time(),"] init completed.");
}
init();
var load=func(){
var load = func() {
var vec=split(" ",disk_file);
println("[",os.time(),"] loading boot from disk: ",size(vec)," byte.");
forindex(var i;vec)
@@ -71,77 +73,77 @@ var load=func(){
println("[",os.time(),"] loading complete.");
}
load();
var ctx_info=func(){
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){
for(var i=0;i<reg_size;i+=1) {
print("reg[",hex(i),"]: 0x",hex32(reg[i])," ");
if(cnt==3){
if (cnt==3) {
print("\n");
cnt=0;
}else{
} else {
cnt+=1;
}
}
}
var exec=func(info=1){
var exec = func(info=1) {
println("[",os.time(),"] executing ...");
while(1){
while(1) {
ir=[mem[pc],mem[pc+1],mem[pc+2],mem[pc+3]];
if(info)ctx_info();
if (info)ctx_info();
var op=ir[0];
if(op==inst.inst_stop){
if (op==inst.inst_stop) {
break;
}elsif(op==inst.inst_mov_reg_reg){
} elsif (op==inst.inst_mov_reg_reg) {
reg[ir[1]]=reg[ir[2]];
}elsif(op==inst.inst_mov_reg_imm_low){
} 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){
} 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){
} elsif (op==inst.inst_add) {
reg[ir[1]]=bits.u32_and(reg[ir[2]]+reg[ir[3]],0xffffffff);
}elsif(op==inst.inst_sub){
} elsif (op==inst.inst_sub) {
reg[ir[1]]=bits.u32_and(reg[ir[2]]-reg[ir[3]],0xffffffff);
}elsif(op==inst.inst_mult){
} elsif (op==inst.inst_mult) {
reg[ir[1]]=bits.u32_and(reg[ir[2]]*reg[ir[3]],0xffffffff);
}elsif(op==inst.inst_div){
} elsif (op==inst.inst_div) {
reg[ir[1]]=bits.u32_and(reg[ir[2]]/reg[ir[3]],0xffffffff);
}elsif(op==inst.inst_and){
} elsif (op==inst.inst_and) {
reg[ir[1]]=bits.u32_and(reg[ir[2]],reg[ir[3]]);
}elsif(op==inst.inst_or){
} elsif (op==inst.inst_or) {
reg[ir[1]]=bits.u32_or(reg[ir[2]],reg[ir[3]]);
}elsif(op==inst.inst_xor){
} elsif (op==inst.inst_xor) {
reg[ir[1]]=bits.u32_xor(reg[ir[2]],reg[ir[3]]);
}elsif(op==inst.inst_not){
} elsif (op==inst.inst_not) {
reg[ir[1]]=bits.u32_not(reg[ir[2]]);
}elsif(op==inst.inst_nand){
} elsif (op==inst.inst_nand) {
reg[ir[1]]=bits.u32_nand(reg[ir[2]],reg[ir[3]]);
}elsif(op==inst.inst_shl){
} 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){
} 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){
} elsif (op==inst.inst_jmp) {
pc=reg[ir[1]];
}elsif(op==inst.inst_jt){
} elsif (op==inst.inst_jt) {
pc=reg[ir[1]]?reg[ir[2]]:pc;
}elsif(op==inst.inst_jf){
} elsif (op==inst.inst_jf) {
pc=reg[ir[1]]?pc:reg[ir[2]];
}elsif(op==inst.inst_les){
} elsif (op==inst.inst_les) {
reg[ir[1]]=reg[ir[2]]<reg[ir[3]];
}elsif(op==inst.inst_grt){
} elsif (op==inst.inst_grt) {
reg[ir[1]]=reg[ir[2]]>reg[ir[3]];
}elsif(op==inst.inst_leq){
} elsif (op==inst.inst_leq) {
reg[ir[1]]=reg[ir[2]]<=reg[ir[3]];
}elsif(op==inst.inst_geq){
} elsif (op==inst.inst_geq) {
reg[ir[1]]=reg[ir[2]]>=reg[ir[3]];
}elsif(op==inst.inst_eq){
} elsif (op==inst.inst_eq) {
reg[ir[1]]=reg[ir[2]]==reg[ir[3]];
}elsif(op==inst.inst_in){
} elsif (op==inst.inst_in) {
reg[0]=0; # unfinished
}elsif(op==inst.inst_out){
} elsif (op==inst.inst_out) {
println("reg[",ir[1],"]: 0x",hex32(reg[ir[1]]));
}
pc+=4;

View File

@@ -1,32 +1,34 @@
var check=func(x){
if(x<0x100000000)
use std.bits;
var check = func(x) {
if (x<0x100000000)
return x;
return x-floor(x/0x100000000)*0x100000000;
}
var u32_bits_and=func(x,y){
var u32_bits_and = func(x,y) {
return bits.u32_and(check(x),check(y));
}
var u32_bits_or=func(x,y){
var u32_bits_or = func(x,y) {
return bits.u32_or(check(x),check(y));
}
var u32_bits_xor=func(x,y){
var u32_bits_xor = func(x,y) {
return bits.u32_xor(check(x),check(y));
}
var u32_bits_not=func(x){
var u32_bits_not = func(x) {
return bits.u32_not(check(x));
}
var hex32str=func(){
var hex32str = func() {
var ch=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];
var tbl=[];
setsize(tbl,256);
for(var i=0;i<16;i+=1){
for(var i=0;i<16;i+=1) {
for(var j=0;j<16;j+=1)
tbl[i*16+j]=ch[i]~ch[j];
}
return func(num){
return func(num) {
var res="";
for(var i=0;i<4;i+=1){
for(var i=0;i<4;i+=1) {
res~=tbl[u32_bits_and(num,0xff)];
num=floor(num/256);
}
@@ -34,7 +36,7 @@ var hex32str=func(){
};
}();
var md5=func(){
var md5 = func() {
var K=[
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
@@ -59,42 +61,42 @@ var md5=func(){
0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9
];
var l=func(num,cx){
for(var i=0;i<cx;i+=1){
var l = func(num,cx) {
for(var i=0;i<cx;i+=1) {
num=check(num*2);
}
return num;
}
var r=func(num,cx){
var r = func(num,cx) {
num=check(num);
for(var i=0;i<cx;i+=1){
for(var i=0;i<cx;i+=1) {
num=num/2;
}
return floor(num);
}
var rol=func(num,cx){
var rol = func(num,cx) {
return u32_bits_or(l(num,cx),r(num,32-cx));
}
# round 1
var F=func(x,y,z){
var F = func(x,y,z) {
return u32_bits_or(
u32_bits_and(x,y),
u32_bits_and(u32_bits_not(x),z)
);
}
# round 2
var G=func(x,y,z){
var G = func(x,y,z) {
return u32_bits_or(
u32_bits_and(x,z),
u32_bits_and(y,u32_bits_not(z))
);
}
# round 3
var H=func(x,y,z){
var H = func(x,y,z) {
return u32_bits_xor(u32_bits_xor(x,y),z);
}
# round 4
var I=func(x,y,z){
var I = func(x,y,z) {
return u32_bits_xor(
y,
u32_bits_or(x,u32_bits_not(z))
@@ -107,21 +109,21 @@ var md5=func(){
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I
];
return func(s){
return func(s) {
var (s_size,len,res)=(size(s),size(s)*8,[]);
setsize(res,s_size);
for(var i=0;i<s_size;i+=1){
for(var i=0;i<s_size;i+=1) {
res[i]=s[i];
}
# +------len------+--1~512--+--64--+
# | text | fill | size |
# +---------------+---------+------+ N*512 bit
var (mod,res_size)=(s_size-floor(s_size/64)*64,0);
if(mod==56){
if (mod==56) {
res_size=s_size+64;
}elsif(mod<56){
} elsif (mod<56) {
res_size=floor(s_size/64)*64+56;
}elsif(mod>56){
} elsif (mod>56) {
res_size=floor(s_size/64)*64+120; # 512+448=960 960/8=120
}
setsize(res,res_size);
@@ -132,11 +134,11 @@ var md5=func(){
# little endian
setsize(res,size(res)+8);
var (s_size,lower32,higher32)=(size(res),check(len),check(len/math.pow(2,32)));
for(var i=4;i>0;i-=1){
for(var i=4;i>0;i-=1) {
res[s_size-4-i]=floor(lower32-floor(lower32/256)*256);
lower32=floor(lower32/256);
}
for(var i=4;i>0;i-=1){
for(var i=4;i>0;i-=1) {
res[s_size-i]=floor(higher32-floor(higher32/256)*256);
higher32=floor(higher32/256);
}
@@ -146,7 +148,7 @@ var md5=func(){
# this may only work when string's length is under 1<<51
var tmp=[];
setsize(tmp,size(res)/4);
for(var i=0;i<size(res);i+=4){
for(var i=0;i<size(res);i+=4) {
tmp[i/4]=res[i+3]*math.pow(2,24)+
res[i+2]*math.pow(2,16)+
res[i+1]*math.pow(2,8)+
@@ -160,9 +162,9 @@ var md5=func(){
var D=0x10325476;
res_size=size(res);
for(var i=0;i<res_size;i+=16){
for(var i=0;i<res_size;i+=16) {
var (f,a,b,c,d)=(0,A,B,C,D);
for(var j=0;j<64;j+=1){
for(var j=0;j<64;j+=1) {
f=functions[j](b,c,d);
(a,b,c,d)=(d,check(b+rol(a+f+K[j]+res[i+idx[j]],S[j])),b,c);
}
@@ -173,7 +175,7 @@ var md5=func(){
}();
# check if md5 runs correctly
var md5check=func(){
var md5check = func() {
var test_set=[
"md5",
"github.com",
@@ -200,9 +202,9 @@ var md5check=func(){
"a7916c5ce54e73b7ddf6a286b36d976d",
"ec6d5b197ba019db23c719112f3f70b7"
];
forindex(var i;test_set){
forindex(var i;test_set) {
var res=md5(test_set[i]);
if(cmp(res,result[i]))
if (cmp(res,result[i]))
println(
"md5 cannot work:\n",
" test \""~test_set[i]~"\"\n",

View File

@@ -23,7 +23,7 @@ var compare = func() {
}
byte += size(s);
var res = md5(s);
if(cmp(res, md5_self.md5(s))) {
if (cmp(res, md5_self.md5(s))) {
die("error: "~str(i));
}
if (i-begin-int((i-begin)/4)*4==0) {
@@ -79,7 +79,7 @@ var filechecksum = func() {
var f = source[i];
var res = md5(f);
byte += size(f);
if(cmp(res, md5_self.md5(f))){
if (cmp(res, md5_self.md5(f))) {
die("error: "~files[i]);
}
print(
@@ -98,7 +98,7 @@ var randomchecksum = func() {
}
}
if(os.platform()=="windows") {
if (os.platform()=="windows") {
system("chcp 65001");
}
filechecksum();

View File

@@ -4,35 +4,35 @@ use module.libfib;
println(keys(libfib));
libfib.test_ghost();
var libfib=func(){
var libfib = func() {
var (dd,fib,qfib)=(nil,nil,nil);
var invoke=dylib.limitcall(1);
return {
open:func(){
if(dd==nil){
open:func() {
if (dd==nil) {
dd=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
fib=dd.fib;
qfib=dd.quick_fib;
}else{
} else {
println("[info ] already loaded.");
}
},
close:func(){
if(dd==nil){
close:func() {
if (dd==nil) {
println("[error ] already closed.");
return;
}
dylib.dlclose(dd.lib);
(dd,fib,qfib)=(nil,nil,nil);
},
fib:func(x){
if(fib!=nil)
fib:func(x) {
if (fib!=nil)
return invoke(fib,x);
println("[error ] cannot call fib.");
return nil;
},
qfib:func(x){
if(qfib!=nil)
qfib:func(x) {
if (qfib!=nil)
return invoke(qfib,x);
println("[error ] cannot call qfib.");
return nil;
@@ -55,7 +55,7 @@ println("[result] ",libfib.fib(35));
println("[result] ",libfib.qfib(35));
libfib.close();
var speed_test=func(){
var speed_test = func() {
var d=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
println("[dylib ] ",d);
var fd=d.quick_fib;
@@ -63,14 +63,14 @@ var speed_test=func(){
var invoke=dylib.limitcall(1);
var tm=maketimestamp();
for(var t=0;t<10;t+=1){
for(var t=0;t<10;t+=1) {
tm.stamp();
for(var i=0;i<5e5;i+=1){
for(var i=0;i<5e5;i+=1) {
invoke(fd,40);
}
println("[time ] limited call: ",int(5e5/tm.elapsedMSec())," call/ms");
tm.stamp();
for(var i=0;i<5e5;i+=1){
for(var i=0;i<5e5;i+=1) {
vec_call(fd,40);
}
println("[time ] dynamic call: ",int(5e5/tm.elapsedMSec())," call/ms");

View File

@@ -2,13 +2,13 @@
# Sidi Liang
var w = 1;
var x = "hello";
var f = func(){
var f = func() {
println("f is called");
}
var f2 = func(){
var f2 = func() {
return 2;
}
var f3 = func(){
var f3 = func() {
return "numb";
}
var y = [w, x];
@@ -44,23 +44,23 @@ println(z.numb); #//1
println(z.listt[2][1]); #//hello
println(z1.hashh.listt[2][1]); #//hello
println(y2[3].hashh.listt[2][1]);#//hello
println(f); #//func(..){..}
println(f); #//func(..) {..}
f(); #//f is called
println(z.funcc); #//func(..){..}
println(z.funcc); #//func(..) {..}
z.funcc(); #//f is called
println(z.funcccall); #//func(..){..}
println(z.funcccall); #//func(..) {..}
z2.listt2[3].hashh.funcc(); #//f is called
println(y1[f2()][w]); #//hello
println(true,' ',false); #//1 0
# ValKmjolnir
func(){
func() {
var tm=maketimestamp();
var duration=0;
var f1=func(){}
var f2=func(){var a=1;return a+1;}
var f3=func(){var (a,b)=(1,1);return a+b+1;}
var f1 = func() {}
var f2 = func() {var a=1;return a+1;}
var f3 = func() {var (a,b)=(1,1);return a+b+1;}
tm.stamp();
for(var i=0;i<1e6;i+=1);
duration=tm.elapsedMSec();
@@ -70,7 +70,7 @@ func(){
duration=tm.elapsedMSec();
println(str(int(1e6/duration))," calc/ms");
tm.stamp();
for(var i=0;i<1e6;i+=1)func{}();
for(var i=0;i<1e6;i+=1)func {}();
duration=tm.elapsedMSec();
println(str(int(1e6/duration))," calc/ms");
tm.stamp();
@@ -79,7 +79,7 @@ func(){
println(str(int(1e6/duration))," calc/ms");
tm.stamp();
for(var i=0;i<1e6;i+=1)
func{
func {
var a=1;
return a+1;
}();
@@ -91,7 +91,7 @@ func(){
println(str(int(1e6/duration))," calc/ms");
tm.stamp();
for(var i=0;i<1e6;i+=1)
func{
func {
var (a,b)=(1,1);
return a+b+1;
}();

View File

@@ -1,3 +1,4 @@
use std.coroutine;
use std.process_bar;
use module.libkey;
use std.runtime;
@@ -5,12 +6,12 @@ use std.runtime;
var is_windows_platform=os.platform()=="windows";
var is_macos_platform=os.platform()=="macOS";
if(is_windows_platform){
if (is_windows_platform) {
system("chcp 65001");
}
var cpu_stat=func(){
if(is_windows_platform or is_macos_platform)
var cpu_stat = func() {
if (is_windows_platform or is_macos_platform)
return nil;
var cpu=split("\n",io.readfile("/proc/stat"))[0];
cpu=split(" ",cpu);
@@ -27,21 +28,21 @@ var cpu_stat=func(){
return cpu;
}
var cpu_occupation=func(){
var cpu_occupation = func() {
var first_in=1;
while(1){
while(1) {
var cpu0=cpu_stat();
if(first_in){
if (first_in) {
unix.sleep(0.1);
first_in=0;
}else{
for(var i=0;i<10;i+=1){
} else {
for(var i=0;i<10;i+=1) {
unix.sleep(0.1);
coroutine.yield(nil);
}
}
var cpu1=cpu_stat();
if(is_windows_platform or is_macos_platform){
if (is_windows_platform or is_macos_platform) {
coroutine.yield(0);
continue;
}
@@ -52,12 +53,12 @@ var cpu_occupation=func(){
}
}
var mem_occupation=func(){
if(is_windows_platform or is_macos_platform)
var mem_occupation = func() {
if (is_windows_platform or is_macos_platform)
return {MemTotal:math.inf,MemFree:math.inf};
var meminfo=split("\n",io.readfile("/proc/meminfo"));
var mem_res={};
forindex(var i;meminfo){
forindex(var i;meminfo) {
var tmp=split(" ",meminfo[i])[0:1];
tmp[0]=substr(tmp[0],0,size(tmp[0])-1);
mem_res[tmp[0]]=num(tmp[1]);
@@ -65,33 +66,33 @@ var mem_occupation=func(){
return mem_res;
}
var random_generator=func(){
var random_generator = func() {
var rise=[" ","▁","▂","▃","▄","▅","▆","▇","█"];
var total=0;
var statistics=[];
setsize(statistics,70);
while(1){
for(var i=0;i<10;i+=1){
while(1) {
for(var i=0;i<10;i+=1) {
total+=1;
var u=rand()*rand()*(rand()>0.5?-1:1);
statistics[int(size(statistics)/2+u*size(statistics)/2)]+=1;
}
var s=["","",""];
foreach(var st;statistics){
foreach(var st;statistics) {
var max_rate=100/size(statistics);
var rate=st/total*100;
for(var i=size(s)-1;i>=0;i-=1){
if(rate>=max_rate){
for(var i=size(s)-1;i>=0;i-=1) {
if (rate>=max_rate) {
s[i]~="█";
rate-=max_rate;
}else{
} else {
s[i]~=rise[rate/max_rate*size(rise)];
rate=0;
}
}
}
var tmp="";
for(var i=0;i<size(statistics);i+=1){
for(var i=0;i<size(statistics);i+=1) {
tmp~="-";
}
println("\e[16;1H \e[32m|",s[0],"|\e[0m");
@@ -102,11 +103,11 @@ var random_generator=func(){
}
}
func(){
func() {
var limited_loop=(size(runtime.argv())!=0 and !math.isnan(num(runtime.argv()[0])));
if(limited_loop){
if (limited_loop) {
limited_loop=num(runtime.argv()[0]);
}else{
} else {
limited_loop=-1;
}
@@ -122,28 +123,28 @@ func(){
var bar=process_bar.high_resolution_bar(48);
print("\ec");
while(limited_loop!=0){
while(limited_loop!=0) {
limited_loop=limited_loop<0?limited_loop:limited_loop-1;
var mem=mem_occupation();
var mem_occ=(mem.MemTotal-mem.MemFree)/mem.MemTotal*100;
if(math.isnan(mem_occ) or mem_occ<0 or mem_occ>100){
if (math.isnan(mem_occ) or mem_occ<0 or mem_occ>100) {
mem_occ=0;
}
var cpu_occ=nil;
while((cpu_occ=coroutine.resume(co)[0])==nil){
while((cpu_occ=coroutine.resume(co)[0])==nil) {
var key=libkey.nonblock();
coroutine.resume(rd);
if(key!=nil and chr(key)=="q")
if (key!=nil and chr(key)=="q")
return;
}
if(is_windows_platform or is_macos_platform){
if (is_windows_platform or is_macos_platform) {
# sorry this is not real data
cpu_occ=rand()*10;
mem_occ=rand()*10+40;
}
for(var i=0;i<size(cpu_occupation_log)-1;i+=1){
for(var i=0;i<size(cpu_occupation_log)-1;i+=1) {
cpu_occupation_log[i]=cpu_occupation_log[i+1];
mem_occupation_log[i]=mem_occupation_log[i+1];
}
@@ -158,19 +159,19 @@ func(){
println("\e[6;1H\e[1m CPU occupation(%) : \e[0m",cpu_occ>90?"\e[91m":"\e[32m",bar.bar(cpu_occ/100)~" ",cpu_occ,"\e[0m ");
var tmp="";
for(var i=0;i<70;i+=1){
for(var i=0;i<70;i+=1) {
tmp~="-";
}
var s=["","",""];
foreach(var occ;cpu_occupation_log){
foreach(var occ;cpu_occupation_log) {
var max_rate=50/size(s);
var rate=occ;
for(var i=size(s)-1;i>=0;i-=1){
if(rate>=max_rate){
for(var i=size(s)-1;i>=0;i-=1) {
if (rate>=max_rate) {
s[i]~="█";
rate-=max_rate;
}else{
} else {
s[i]~=rise[rate/max_rate*size(rise)];
rate=0;
}
@@ -183,14 +184,14 @@ func(){
println("\e[11;1H \e[32m+"~tmp~"+\e[0m");
var s=["","",""];
foreach(var occ;mem_occupation_log){
foreach(var occ;mem_occupation_log) {
var max_rate=100/size(s);
var rate=occ;
for(var i=size(s)-1;i>=0;i-=1){
if(rate>=max_rate){
for(var i=size(s)-1;i>=0;i-=1) {
if (rate>=max_rate) {
s[i]~="█";
rate-=max_rate;
}else{
} else {
s[i]~=rise[rate/max_rate*size(rise)];
rate=0;
}

View File

@@ -1,25 +1,25 @@
var is_prime=func(x){
var is_prime = func(x) {
for(var i=2;i<x;i+=1)
if(x/i==int(x/i))
if (x/i==int(x/i))
return 0;
return 1;
}
var is_prime_sqrt=func(x){
var is_prime_sqrt = func(x) {
for(var i=2;i<=math.sqrt(x);i+=1)
if(x/i==int(x/i))
if (x/i==int(x/i))
return 0;
return 1;
}
var primes=[];
var filter=func(x){
foreach(var i;primes){
if(x/i==int(x/i))
var filter = func(x) {
foreach(var i;primes) {
if (x/i==int(x/i))
return 0;
if(x>=i){
if (x>=i) {
for(var j=i+1;j<=math.sqrt(x);j+=1)
if(x/j==int(x/j))
if (x/j==int(x/j))
return 0;
append(primes,x);
return 1;
@@ -29,10 +29,10 @@ var filter=func(x){
return 1;
}
func(){
func() {
var cnt=0;
for(var i=2;i<50000;i+=1)
if(filter(i))
if (filter(i))
cnt+=1;
println(cnt);
}();

View File

@@ -31,10 +31,10 @@ var code=[
];
# enable unicode
if(os.platform()=="windows")
if (os.platform()=="windows")
system("chcp 65001");
var texture=[" ","██"];
for(var i=0;i<size(code);i+=1){
for(var i=0;i<size(code);i+=1) {
for(var j=0;j<size(code[i]);j+=1)
print(texture[code[i][j]]);
print('\n');

View File

@@ -1,12 +1,12 @@
var var_sort=func(){
var var_sort = func() {
srand(); # be aware! this causes global changes
var quick_sort_core=func(vec,left,right){
if(left>=right) return nil;
var quick_sort_core = func(vec,left,right) {
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) {
while(i<j and tmp<vec[j])
j-=1;
vec[i]=vec[j];
@@ -20,7 +20,7 @@ var var_sort=func(){
quick_sort_core(vec,i+1,right);
return nil;
}
return func(vec){
return func(vec) {
quick_sort_core(vec,0,size(vec)-1);
return nil;
}
@@ -38,10 +38,10 @@ for(var i=1;i<1e4;i+=1) {
}
}
var test=func(n){
var test = func(n) {
var a=[];
setsize(a,n);
for(var i=0;i<n;i+=1){
for(var i=0;i<n;i+=1) {
a[i]=int(rand()*n);
}
var ts=maketimestamp();
@@ -51,7 +51,7 @@ var test=func(n){
var a=[];
setsize(a,n);
for(var i=0;i<n;i+=1){
for(var i=0;i<n;i+=1) {
a[i]=int(rand()*n);
}
ts.stamp();
@@ -59,6 +59,6 @@ var test=func(n){
println("[time] ",str(n)," in ",ts.elapsedMSec()/1000," sec (lambda cmp)");
}
for(var i=1000;i<1e6;i*=10){
for(var i=1000;i<1e6;i*=10) {
test(i);
}

View File

@@ -99,7 +99,7 @@ var innerFunc = func {
# what the ?: does in C. The last semicolon in a code block is
# optional, to make this prettier.
#
var abs = func(n) { if(n<0) { -n } else { n } }
var abs = func(n) { if (n<0) { -n } else { n } }
#
# But for those who don't like typing, the ternary operator works like
@@ -119,7 +119,7 @@ var listNode = { data : ["what", "ever"], next : nil };
#
var toggle = 0;
var a = nil;
if(a and a.field == 42) {
if (a and a.field == 42) {
toggle = !toggle; # doesn't crash when a is nil
}
@@ -213,8 +213,8 @@ for(var i=0; i<size(string); i+=1) { ascii_sum += string[i]; }
#
# You can use backquotes to write UTF8 character constants
#
if(`A` != 65) { print("ASCII violation bug!\n"); }
if(`©` != 169) { print("Unicode violation bug!\n"); }
if (`A` != 65) { print("ASCII violation bug!\n"); }
if (`©` != 169) { print("Unicode violation bug!\n"); }
#
# And you can mutate strings by assigning to their indices, as long as
@@ -225,7 +225,7 @@ if(`©` != 169) { print("Unicode violation bug!\n"); }
var ascii_lc = func(string) {
var mutable = string ~ "";
for(var i=0; i<size(mutable); i+=1) {
if(mutable[i] >= `A` and mutable[i] <= `Z`) {
if (mutable[i] >= `A` and mutable[i] <= `Z`) {
mutable[i] += (`a` - `A`);
}
}
@@ -290,9 +290,9 @@ var completelyDone = dummyFunc;
for(#OUTER;
var i=0; i<100; i = i+1) {
for(var j=0; j<100; j = j+1) {
if(doneWithInnerLoopEarly()) {
if (doneWithInnerLoopEarly()) {
break;
} elsif(completelyDone()) {
} elsif (completelyDone()) {
break #OUTER;
}
}
@@ -308,21 +308,21 @@ for(#OUTER;
##
var dump = func(o) {
var result = "";
if(typeof(o) == "scalar") {
if (typeof(o) == "scalar") {
var n = num(o);
if(n == nil) { result = result ~ '"' ~ o ~ '"'; }
if (n == nil) { result = result ~ '"' ~ o ~ '"'; }
else { result = result ~ o; }
} elsif(typeof(o) == "vector") {
} elsif (typeof(o) == "vector") {
result = result ~ "[ ";
if(size(o) > 0) { result = result ~ dump(o[0]); }
if (size(o) > 0) { result = result ~ dump(o[0]); }
for(i=1; i<size(o); i=i+1) {
result = result ~ ", " ~ dump(o[i]);
}
result = result ~ " ]";
} elsif(typeof(o) == "hash") {
} elsif (typeof(o) == "hash") {
var ks = keys(o);
result = result ~ "{ ";
if(size(o) > 0) {
if (size(o) > 0) {
var k = ks[0];
result = result ~ k ~ ":" ~ dump(o[k]);
}
@@ -348,7 +348,7 @@ var dump = func(o) {
# normal function definition. Oh well, every language has a syntactic
# quirk or two...)
#
var a = (func(n){ n + 1 })(232); # "a" now equals 233
var a = (func(n) { n + 1 })(232); # "a" now equals 233
#
# Functional programming B. All expressions have a value, the last
@@ -357,7 +357,7 @@ var a = (func(n){ n + 1 })(232); # "a" now equals 233
# (assignment, duh) have side effects. e.g. The "if" expression works
# both for code flow and as the ?: expression in C/C++.
#
var factorial = func(n) { if(n == 0) { 1 }
var factorial = func(n) { if (n == 0) { 1 }
else { n * factorial(n-1) } }
print(factorial(10), "\n");

View File

@@ -55,19 +55,19 @@ var hash_4={
};
# function
var func_1=func(){return 1;}
var prt=func(x){println(x);return nil;}
var func_with_dynamic_id=func(a,b,c,d...){return [a,b,c,d];}
var func_with_lack_para=func(a,b,c=1,d=2){return a+b+c+d;}
var func_with_func_para=func(a,f){return f(a);}
var func_1 = func() {return 1;}
var prt = func(x) {println(x);return nil;}
var func_with_dynamic_id = func(a,b,c,d...) {return [a,b,c,d];}
var func_with_lack_para = func(a,b,c=1,d=2) {return a+b+c+d;}
var func_with_func_para = func(a,f) {return f(a);}
func_with_lack_para(a:1, b:2, c:3, d:4);
func_with_lack_para(b:1, c:3, a:4, d:1);
func_with_func_para(f:func prt,a:1);
func_with_func_para(func func_1(),func(x){return x;});
func_with_func_para(func func_1(),func(x) {return x;});
func_with_func_para(func_1(),func_1);
prt(func func_1());
var test_func_ret_number_1=func func_1(); # 1
var test_func_ret_number_1 = func func_1(); # 1
var test_func_ret_number_2=func_1(); # 1
var source={
@@ -77,7 +77,7 @@ var source={
println(source['member_2']());
println(source.member_2());
var test_func=func{return 1;}
var test_func = func {return 1;}
println(func test_func()); # 1
println(test_func()); # 1
println(func test_func); # nothing
@@ -87,9 +87,9 @@ println(({str:"what?"})["str"]); # what?
println(({str:"what?"}).str); # what?
# lambda
(func(x){return x>0? x:0;})(12);
(func{println("hello world");})();
(((func(x){return 1.0/math.exp(x);})))(0);
(func(x) {return x>0? x:0;})(12);
(func {println("hello world");})();
(((func(x) {return 1.0/math.exp(x);})))(0);
# flexible definition & assignment
var (r,g,b)=[0x00,0x10,0xff];
@@ -127,7 +127,7 @@ nil and 1+7*8;
{num:0}.num or {what_is_the_secret_of_universe:42}["what_is_the_secret_of_universe"];
"123"~"456"-123456*2/2;
var hash={str:'hello',f:func{return me.str;}};
var hash={str:'hello',f:func {return me.str;}};
var tmp_f=hash.f;
hash=1;
println(tmp_f());
@@ -136,16 +136,16 @@ println(tmp_f());
# when generating local_scope for function f,
# nasal_gc will not count 'me' as one reference of this hash
var h1={str:'hello',f:func{return me.str;}};
var h2={str:'world',f:func{return nil;}};
var h1={str:'hello',f:func {return me.str;}};
var h2={str:'world',f:func {return nil;}};
h2.f=h1.f;
println(h2.f());
# print 'world'
# this means that 'me' in hash's functions
# only points to the hash this function belongs to
var f1=func(){println(1);return 1;}
var f2=func(){println(2);return 0;}
var f1 = func() {println(1);return 1;}
var f2 = func() {println(2);return 0;}
f1() or f2();
# print '1'
# this means that when using 'or' or 'and',
@@ -158,12 +158,12 @@ print(
abs(1),'\n',
abs(-1),'\n',
systime(),'\n',
isfunc(func{}),' ',isfunc([]),'\n',
isfunc(func {}),' ',isfunc([]),'\n',
ishash({}),' ',ishash([]),'\n',
isint(114.514),' ',isint(114514),'\n',
isnum("0xaa55"),' ',isnum("?"),'\n',
isscalar(0.618),' ',isscalar("hello"),' ',isscalar([]),'\n',
isstr("hello"),' ',isstr(func{}),'\n',
isstr("hello"),' ',isstr(func {}),'\n',
isvec([]),' ',isvec("[]"),'\n',
vecindex([0,1,2,3,4],1),'\n',
vecindex(["apple","banana"],"apple")!=nil,'\n'
@@ -179,13 +179,13 @@ println(find("x", "abcdef")); # prints -1
println(find("cd", "abcdef")); # prints 2
var a={
new: func(x=0){
new: func(x=0) {
return {
x:x,
parents:[a]
};
},
new2: func(x=0){
new2: func(x=0) {
return {
x:x,
parents:a
@@ -195,17 +195,17 @@ var a={
println(isa(a.new(),a)); # 1
println(isa(a.new2(),a));# 0
var a=[10,-10,0,1,2,3,nil,"string","hello",[],[0,1,2,3],{},{a:0,b:1,c:2},func{}];
var a=[10,-10,0,1,2,3,nil,"string","hello",[],[0,1,2,3],{},{a:0,b:1,c:2},func {}];
println("type\tsize\tnum\tsrc");
foreach(var i;a){
foreach(var i;a) {
println(typeof(i),'\t',size(i),'\t',num(i),'\t',i);
}
foreach(i;a){
foreach(i;a) {
;
}
println(runtime.argv());
println(globals.arg);
func(a,b,c,d="只有红茶可以吗"){
func(a,b,c,d="只有红茶可以吗") {
println(a,' ',b,' ',c,' ',d,' true: ',true,' false: ',false);
}(c:1919810,b:514,a:114);
@@ -220,7 +220,7 @@ var h=split(" ","0 1 2 3 4 5 6 7 8 9 a b c d e f");
for(var a=0;a<16;a+=1) {
for(var b=0;b<16;b+=1) {
for(var c=0;c<16;c+=1) {
if(((a^b)&c)!=(a^(b&c))) {
if (((a^b)&c)!=(a^(b&c))) {
println("0x"~h[a],"^","0x"~h[b],"&","0x"~h[c]," -> a^b&c = 0x",h[a^b&c]," (a^b)&c = 0x",h[(a^b)&c]," a^(b&c) = 0x",h[(a^(b&c))]);
}
}

View File

@@ -1,13 +1,14 @@
use module.libkey;
use std.list;
use std.runtime;
use std.coroutine;
var game=func(x,y){
var game = func(x,y) {
rand(time(0));
var texture=[" ","██","\e[91m██\e[0m"];
var edge0="╔";
var edge1="╚";
for(var i=0;i<x;i+=1){
for(var i=0;i<x;i+=1) {
edge0~="══";
edge1~="══";
}
@@ -16,7 +17,7 @@ var game=func(x,y){
var vec=[];
setsize(vec,x);
for(var i=0;i<x;i+=1){
for(var i=0;i<x;i+=1) {
vec[i]=[];
setsize(vec[i],y);
for(var j=0;j<y;j+=1)
@@ -31,7 +32,7 @@ var game=func(x,y){
var move='w';
var gameover=0;
var setapple=func(){
var setapple = func() {
var (cord_x,cord_y)=(int(rand()*x),int(rand()*y));
while(vec[cord_x][cord_y]!=0)
(cord_x,cord_y)=(int(rand()*x),int(rand()*y));
@@ -40,13 +41,13 @@ var game=func(x,y){
setapple();
return {
print:func(){
print:func() {
var s="";
var (fx,fy)=snake.front();
for(var i=0;i<y;i+=1){
for(var i=0;i<y;i+=1) {
s~="║";
for(var j=0;j<x;j+=1){
if(fx==j and fy==i)
for(var j=0;j<x;j+=1) {
if (fx==j and fy==i)
s~="\e[93m"~texture[vec[j][i]]~"\e[0m";
else
s~=texture[vec[j][i]];
@@ -55,66 +56,66 @@ var game=func(x,y){
}
print('\e[1;1H'~edge0~s~edge1);
},
next:func(){
next:func() {
var (fx,fy)=snake.front();
var eat=0;
if(move=="w" and fy-1>=0){
if (move=="w" and fy-1>=0) {
snake.push_front([fx,fy-1]);
if(vec[fx][fy-1]==1)
if (vec[fx][fy-1]==1)
gameover=1;
elsif(vec[fx][fy-1]==2)
elsif (vec[fx][fy-1]==2)
eat=1;
vec[fx][fy-1]=1;
}elsif(move=='a' and fx-1>=0){
} elsif (move=='a' and fx-1>=0) {
snake.push_front([fx-1,fy]);
if(vec[fx-1][fy]==1)
if (vec[fx-1][fy]==1)
gameover=1;
elsif(vec[fx-1][fy]==2)
elsif (vec[fx-1][fy]==2)
eat=1;
vec[fx-1][fy]=1;
}elsif(move=='s' and fy+1<y){
} elsif (move=='s' and fy+1<y) {
snake.push_front([fx,fy+1]);
if(vec[fx][fy+1]==1)
if (vec[fx][fy+1]==1)
gameover=1;
elsif(vec[fx][fy+1]==2)
elsif (vec[fx][fy+1]==2)
eat=1;
vec[fx][fy+1]=1;
}elsif(move=='d' and fx+1<x){
} elsif (move=='d' and fx+1<x) {
snake.push_front([fx+1,fy]);
if(vec[fx+1][fy]==1)
if (vec[fx+1][fy]==1)
gameover=1;
elsif(vec[fx+1][fy]==2)
elsif (vec[fx+1][fy]==2)
eat=1;
vec[fx+1][fy]=1;
}else{
} else {
gameover=1;
}
if(!gameover and !eat){
if (!gameover and !eat) {
var (bx,by)=snake.back();
vec[bx][by]=0;
snake.pop_back();
}
if(eat and snake.length()!=x*y)
if (eat and snake.length()!=x*y)
setapple();
elsif(snake.length()==x*y)
elsif (snake.length()==x*y)
gameover=2;
},
move:func(c){
move:func(c) {
move=c;
},
gameover:func(){
gameover:func() {
return gameover;
}
}
}
var co=coroutine.create(func(){
while(1){
var co=coroutine.create(func() {
while(1) {
var moved=-1;
for(var i=0;i<30;i+=1){
for(var i=0;i<30;i+=1) {
var ch=libkey.nonblock();
if(moved==-1 and ch!=nil){
if (moved==-1 and ch!=nil) {
moved=ch;
}
coroutine.yield(nil);
@@ -124,43 +125,44 @@ var co=coroutine.create(func(){
}
});
var main=func(argv){
var main = func(argv) {
var should_skip=(size(argv)!=0 and argv[0]=="--skip");
# enable unicode
if(os.platform()=="windows")
if (os.platform()=="windows")
system("chcp 65001");
print("\ec");
var g=game(15,10);
g.print();
print("\rpress any key to start...");
if(!should_skip){
if (!should_skip) {
libkey.getch();
}
print("\r \r");
var counter=20;
while(1){
while(1) {
while((var ch=coroutine.resume(co)[0])==nil);
if(ch!=nil and ch!=-1){
if(ch=='q'[0])
if (ch!=nil and ch!=-1) {
if (ch=='q'[0]) {
break;
elsif(ch=='p'[0]){
} elsif (ch=='p'[0]) {
print("\rpress any key to continue...");
libkey.getch();
print("\r \r");
} elsif (ch=='w'[0] or ch=='s'[0] or ch=='a'[0] or ch=='d'[0]) {
g.move(chr(ch));
}
g.move(chr(ch));
}
g.next();
if(g.gameover())
if (g.gameover())
break;
g.print();
}
println(g.gameover()<=1?"game over.":"you win!");
println("press 'q' to quit.");
if(should_skip){
if (should_skip) {
return;
}
while(libkey.getch()!='q'[0]);

View File

@@ -60,8 +60,8 @@ var blockshape=[
var color_count=0;
var counter=0;
var package=[0,1,2,3,4,5,6];
var exchange=func(){
for(var i=6;i>=0;i-=1){
var exchange = func() {
for(var i=6;i>=0;i-=1) {
var index=int(i*rand());
(package[i],package[index])=(package[index],package[i]);
}
@@ -74,12 +74,12 @@ var block={
type:nil,
shape:nil,
color:nil,
new:func(x=0,y=0){
new:func(x=0,y=0) {
(me.x,me.y)=(x,y);
me.rotate=0;
me.type=blocktype[package[counter]];
counter+=1;
if(counter==7){
if (counter==7) {
exchange();
counter=0;
}
@@ -88,18 +88,18 @@ var block={
me.color=color_count;
color_count+=1;
if(color_count>=size(color))
if (color_count>=size(color))
color_count=0;
return {parents:[block]};
}
};
var mapgen=func(mapx,mapy){
var mapgen = func(mapx,mapy) {
var (score,gameover)=(0,0);
var (empty,unset,full)=(0,1,2);
if(mapx<1 or mapy<1)
if (mapx<1 or mapy<1)
die("map_x or map_y must be greater than 1");
# use in print
@@ -111,7 +111,7 @@ var mapgen=func(mapx,mapy){
# generate new map
var map=[];
for(var y=0;y<mapy;y+=1){
for(var y=0;y<mapy;y+=1) {
var tmp=[];
for(var x=0;x<mapx;x+=1)
append(tmp,empty);
@@ -119,12 +119,12 @@ var mapgen=func(mapx,mapy){
}
var blk=nil;
var new_block=func(){
var new_block = func() {
blk=block.new(int(mapx/2),0);
# check if has enough place to place a new block
foreach(var i;blk.shape)
if(map[blk.y+i[1]][blk.x+i[0]]>=full){
if (map[blk.y+i[1]][blk.x+i[0]]>=full) {
gameover=1;
return;
}
@@ -135,17 +135,17 @@ var mapgen=func(mapx,mapy){
new_block(); # initialize the first block
# color print
var map_print=func(){
var map_print = func() {
var s="\e[1;1H"~head;
for(var y=0;y<mapy;y+=1){
for(var y=0;y<mapy;y+=1) {
s~="\e[32m║\e[0m";
for(var x=0;x<mapx;x+=1){
for(var x=0;x<mapx;x+=1) {
var c=map[y][x];
if(c==empty)
if (c==empty)
s~=" ";
elsif(c==unset)
elsif (c==unset)
s~=color[blk.color]~"██\e[0m";
elsif(c>=full)
elsif (c>=full)
s~=color[c-full]~"██\e[0m";
}
s~="\e[32m║\e[0m\n";
@@ -154,12 +154,12 @@ var mapgen=func(mapx,mapy){
print(s,"\e[31ms\e[32mc\e[33mo\e[34mr\e[35me\e[36m: \e[0m",score,'\n');
}
var moveleft=func(){
var moveleft = func() {
var (x,y)=(blk.x-1,blk.y);
foreach(var i;blk.shape){
if(x+i[0]<0)
foreach(var i;blk.shape) {
if (x+i[0]<0)
return;
if(map[y+i[1]][x+i[0]]>=full)
if (map[y+i[1]][x+i[0]]>=full)
return;
}
# update block state and map
@@ -171,12 +171,12 @@ var mapgen=func(mapx,mapy){
map_print();
}
var moveright=func(){
var moveright = func() {
var (x,y)=(blk.x+1,blk.y);
foreach(var i;blk.shape){
if(x+i[0]>=mapx)
foreach(var i;blk.shape) {
if (x+i[0]>=mapx)
return;
if(map[y+i[1]][x+i[0]]>=full)
if (map[y+i[1]][x+i[0]]>=full)
return;
}
# update block state and map
@@ -188,14 +188,14 @@ var mapgen=func(mapx,mapy){
map_print();
}
var rotate=func(){
var rotate = func() {
var (r,x,y)=(blk.rotate,blk.x,blk.y);
r=(r+1>=size(blk.type))?0:r+1;
var shape=blockshape[blk.type[r]];
foreach(var i;shape){
if(x+i[0]>=mapx or x+i[0]<0 or y+i[1]>=mapy or y+i[1]<0)
foreach(var i;shape) {
if (x+i[0]>=mapx or x+i[0]<0 or y+i[1]>=mapy or y+i[1]<0)
return;
if(map[y+i[1]][x+i[0]]>=full)
if (map[y+i[1]][x+i[0]]>=full)
return;
}
@@ -209,17 +209,17 @@ var mapgen=func(mapx,mapy){
map_print();
}
var fall=func(){
var fall = func() {
var (x,y)=(blk.x,blk.y+1);
# check if falls to the edge of other blocks or map
var sethere=0;
foreach(var i;blk.shape)
if(y+i[1]>=mapy or map[y+i[1]][x+i[0]]>=full){
if (y+i[1]>=mapy or map[y+i[1]][x+i[0]]>=full) {
sethere=1;
break;
}
# set block here and generate a new block
if(sethere){
if (sethere) {
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=blk.color+full;
checkmap();
@@ -236,19 +236,19 @@ var mapgen=func(mapx,mapy){
map_print();
}
var checkmap=func(){
var checkmap = func() {
var lines=1;
for(var y=mapy-1;y>=0;y-=1){
for(var y=mapy-1;y>=0;y-=1) {
# check if this line is full of blocks
var tmp=0;
for(var x=0;x<mapx;x+=1){
if(map[y][x]<full)
for(var x=0;x<mapx;x+=1) {
if (map[y][x]<full)
break;
tmp+=map[y][x];
}
# if is full, clear this line and
# all the lines above fall one block
if(x==mapx){
if (x==mapx) {
score+=lines*tmp;
lines*=2;
for(var t=y;t>=1;t-=1)
@@ -268,15 +268,15 @@ var mapgen=func(mapx,mapy){
rotate:rotate,
fall:fall,
checkmap:checkmap,
gameover:func(){return gameover;}
gameover:func() {return gameover;}
};
}
var main=func(argv){
var main = func(argv) {
var should_skip=(size(argv)!=0 and argv[0]=="--skip");
var init_counter=should_skip?5:30;
# windows use chcp 65001 to output unicode
if(os.platform()=="windows")
if (os.platform()=="windows")
system("chcp 65001");
print(
@@ -296,41 +296,41 @@ var main=func(argv){
exchange();
var map=mapgen(mapx:12,mapy:18);
if(!should_skip){
if (!should_skip) {
libkey.getch();
}
print("\ec");
map.print();
var counter=init_counter;
while(1){
while(1) {
# nonblock input one character
var ch=libkey.nonblock();
if(ch){
if(ch=='a'[0]) # move left
if (ch) {
if (ch=='a'[0]) # move left
map.moveleft();
elsif(ch=='d'[0]) # move right
elsif (ch=='d'[0]) # move right
map.moveright();
elsif(ch=='w'[0]) # rotate
elsif (ch=='w'[0]) # rotate
map.rotate();
elsif(ch=='s'[0]) # move down
elsif (ch=='s'[0]) # move down
map.fall();
elsif(ch=='q'[0]) # quit the game
elsif (ch=='q'[0]) # quit the game
break;
if(ch=='p'[0]){ # pause the game
if (ch=='p'[0]) { # pause the game
print("\rpress any key to continue...");
libkey.getch();
print("\r ");
}
map.checkmap();
if(map.gameover())
if (map.gameover())
break;
}
if(!counter){
if (!counter) {
# automatically fall one block and check
map.fall();
map.checkmap();
if(map.gameover())
if (map.gameover())
break;
counter=init_counter;
}
@@ -348,7 +348,7 @@ var main=func(argv){
"\e[36m'\e[94mq\e[95m' ",
"\e[35mt\e[36mo \e[94mq\e[95mu\e[91mi\e[92mt\e[0m\n"
);
if(!should_skip){
if (!should_skip) {
while(libkey.getch()!='q'[0]);
}
};

View File

@@ -1,11 +1,11 @@
var trait={
get:func{return me.val;},
set:func(x){me.val=x;}
get:func {return me.val;},
set:func(x) {me.val=x;}
};
var class={
new:func(){
new:func() {
return {
val:nil,
parents:[trait]
@@ -14,25 +14,25 @@ var class={
};
var class2={
new:func(){
new:func() {
return {
val:nil,
parents:[trait],
set:func(x){me.val=typeof(x);}
set:func(x) {me.val=typeof(x);}
};
}
};
var class_obj=[];
for(var i=0;i<10;i+=1){
for(var i=0;i<10;i+=1) {
append(class_obj,class.new());
class_obj[i].set(i);
}
for(var i=0;i<10;i+=1){
for(var i=0;i<10;i+=1) {
append(class_obj,class2.new());
class_obj[10+i].set(i);
}
foreach(var object;class_obj){
foreach(var object;class_obj) {
println(object.get(),' ',keys(object));
}

View File

@@ -8,8 +8,8 @@ var table=[
];
var operand={
new:func(symbol,changed_symbol,move,next_state){
if(move!='L' and move!='R' and move!='S')
new:func(symbol,changed_symbol,move,next_state) {
if (move!='L' and move!='R' and move!='S')
die("invalid move type:"+move);
return {
symbol:symbol,
@@ -22,27 +22,27 @@ var operand={
var machine={
states:{},
add:func(state,operand){
if(!contains(me.states,state))
add:func(state,operand) {
if (!contains(me.states,state))
me.states[state]=[operand];
else{
else {
foreach(var i;me.states[state])
if(i.symbol==operand.symbol or i.symbol==nil){
if (i.symbol==operand.symbol or i.symbol==nil) {
println(i);
die("conflict operand");
}
append(me.states[state],operand);
}
},
load:func(data){
foreach(var opr;data){
load:func(data) {
foreach(var opr;data) {
var (nstat,sym,csym,move,nextstat)=opr;
me.add(nstat,operand.new(sym,csym,move,nextstat));
}
}
};
var prt=func(state,pointer,paper,act=nil){
var prt = func(state,pointer,paper,act=nil) {
print(act!=nil?act:'','\n\t');
var s='';
foreach(var i;paper)
@@ -53,43 +53,43 @@ var prt=func(state,pointer,paper,act=nil){
s~=' ';
print(s,'^\n',state," ");
}
var run=func(table,start,stop){
var run = func(table,start,stop) {
var paper=['0','1','1','1','0','1','0','a'];
var pointer=0;
machine.load(table);
print("states: ",keys(machine.states),'\n');
if(!contains(machine.states,start))
if (!contains(machine.states,start))
die(start~" is not a valid node");
if(!contains(machine.states,stop))
if (!contains(machine.states,stop))
die(stop~" is not a valid node");
var (state,pointer)=(start,0);
prt(state,pointer,paper);
while(state!=stop){
if(!contains(machine.states,state))
while(state!=stop) {
if (!contains(machine.states,state))
die("no matching function for state:"~state);
var found=0;
foreach(var action;machine.states[state]){
foreach(var action;machine.states[state]) {
var (sym,csym,move,next)=(
action.symbol,
action.changed_symbol,
action.move,
action.next_state
);
if(sym==paper[pointer] or sym==nil){
if(sym!=nil)
if (sym==paper[pointer] or sym==nil) {
if (sym!=nil)
paper[pointer]=csym;
if(move=='L') pointer-=1;
elsif(move=='R') pointer+=1;
if (move=='L') pointer-=1;
elsif (move=='R') pointer+=1;
(state,found)=(next,1);
break;
}
}
if(!found)
if (!found)
die("no matching function for state:"~state);
prt(state,pointer,paper,[sym,csym,move,next]);

18
test/udptest.nas Normal file
View File

@@ -0,0 +1,18 @@
use std.udp;
var argument = arg[0];
if (argument=="server") {
var server = udp.udp_server("127.0.0.1", 5506);
while(1) {
var message = server.recvfrom();
server.sendto(message.fromip, message.port, "from server");
}
} elsif (argument=="client") {
var client = udp.udp_client();
while(1) {
client.sendto("127.0.0.1", 5506, "hello");
var message = client.recvfrom();
println(message);
unix.sleep(1);
}
}

View File

@@ -1,4 +1,4 @@
var unicode测试=func(){
var unicode测试 = func() {
var 输出=print;
var 测试成功=[
"unicode: utf-8支持测试成功",
@@ -9,7 +9,7 @@ var unicode测试=func(){
输出(内容~"\n");
}
var emoji测试=func(){
var emoji测试 = func() {
var 💻=print;
var 🎤="\n";
var 🤣="🤣 笑嘻了";
@@ -47,21 +47,21 @@ var emoji测试=func(){
💻(📄,🗄️[📄],🎤);
}
var dotsgen=func(){
var dotsgen = func() {
var dots=[];
var s="";
for(var i=0;i<256;i+=1){
for(var i=0;i<256;i+=1) {
var v0=s[0];
var v1=s[1]+int(i/64);
var v2=s[2]+i;
if(v2>191){
if (v2>191) {
v2-=int(i/64)*64;
}
var tmp=char(v0)~char(v1)~char(v2);
append(dots,tmp);
}
forindex(var i;dots){
forindex(var i;dots) {
print(dots[i],(i+1-int((i+1)/32)*32==0)?"\n":"");
}
return dots;

View File

@@ -1,50 +1,50 @@
use std.runtime;
var os_time=func(){
var os_time = func() {
return "[\e[33;1m"~os.time()~"\e[0m] ";
}
var err_hd=func(){
var err_hd = func() {
return "[\e[91;1merror\e[0m] ";
}
var info_hd=func(){
var info_hd = func() {
return "[\e[96;1minfo\e[0m] ";
}
var modified_hd=func(){
var modified_hd = func() {
return "[\e[92;1mmodified\e[0m] ";
}
var usage=func(){
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){
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)){
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){
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){
while(1) {
unix.sleep(1);
if(!io.exists(filename)){
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){
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;
@@ -52,9 +52,9 @@ while(1){
cmd~=" "~i;
println(os_time(),info_hd(),"\e[1mexecuting command \"",cmd,"\"\e[0m");
var ret=system(cmd);
if(ret!=0){
if (ret!=0) {
println(os_time(),err_hd(),"\e[1mprocess returned ",ret,"\e[0m");
}else{
} else {
println(os_time(),info_hd(),"\e[1mprocess returned ",ret,"\e[0m");
}
}

View File

@@ -27,35 +27,35 @@ var table=[
[" ",0,0,0,0]
];
var map=func(){
var map = func() {
var (vec,x,s)=(nil,nil,size(table));
var generator=func(){
var generator = func() {
var tmp=[];
foreach(var elem;table)
if(elem[1]==vec[0][0][3] and elem[2]==0)
if (elem[1]==vec[0][0][3] and elem[2]==0)
append(tmp,elem);
vec[1][0]=tmp[rand()*size(tmp)];
for(var j=1;j<x;j+=1){
if(vec[0][j][3]==0 and vec[1][j-1][4]==0 and rand()>0.5){
for(var j=1;j<x;j+=1) {
if (vec[0][j][3]==0 and vec[1][j-1][4]==0 and rand()>0.5) {
vec[1][j]=table[-1];
continue;
}
tmp=[];
foreach(var elem;table)
if(elem[2]==vec[1][j-1][4] and elem[1]==vec[0][j][3]){
if((j==x-1 and elem[4]==0) or j<x-1)
if (elem[2]==vec[1][j-1][4] and elem[1]==vec[0][j][3]) {
if ((j==x-1 and elem[4]==0) or j<x-1)
append(tmp,elem);
}
vec[1][j]=tmp[rand()*size(tmp)];
}
}
return {
new:func(_x=10){
new:func(_x=10) {
x=_x;
vec=[[],[]];
for(var i=0;i<2;i+=1){
for(var i=0;i<2;i+=1) {
setsize(vec[i],x);
for(var j=0;j<x;j+=1)
vec[i][j]=table[-1];
@@ -63,15 +63,15 @@ var map=func(){
var tmp=[];
foreach(var elem;table)
if(elem[1]==0 and elem[2]==0)
if (elem[1]==0 and elem[2]==0)
append(tmp,elem);
vec[0][0]=tmp[rand()*size(tmp)];
for(var i=1;i<x;i+=1){
for(var i=1;i<x;i+=1) {
tmp=[];
foreach(var elem;table)
if(elem[2]==vec[0][i-1][4] and elem[1]==0){
if((i==x-1 and elem[4]==0) or i<x-1)
if (elem[2]==vec[0][i-1][4] and elem[1]==0) {
if ((i==x-1 and elem[4]==0) or i<x-1)
append(tmp,elem);
}
vec[0][i]=tmp[rand()*size(tmp)];
@@ -79,14 +79,14 @@ var map=func(){
me.print(0);
generator();
},
print:func(index){
print:func(index) {
var str="";
foreach(var _x;vec[index])
str~=_x[0];
str~="\n";
print(str);
},
next:func(){
next:func() {
(vec[0],vec[1])=(vec[1],vec[0]);
generator();
}
@@ -94,11 +94,11 @@ var map=func(){
}();
# enable unicode
if(os.platform()=="windows")
if (os.platform()=="windows")
system("chcp 65001");
map.new(90);
for(var iter=0;iter<40;iter+=1){
for(var iter=0;iter<40;iter+=1) {
map.print(1);
map.next();
}

View File

@@ -1,12 +1,12 @@
use std.runtime;
var to_lower=func(s){
var to_lower = func(s) {
var tmp="";
for(var i=0;i<size(s);i+=1){
for(var i=0;i<size(s);i+=1) {
var c=s[i];
if('a'[0]<=c and c<='z'[0])
if ('a'[0]<=c and c<='z'[0])
tmp~=chr(c);
elsif('A'[0]<=c and c<='Z'[0])
elsif ('A'[0]<=c and c<='Z'[0])
tmp~=chr(c-'A'[0]+'a'[0]);
else
tmp~=chr(c);
@@ -14,23 +14,23 @@ var to_lower=func(s){
return tmp;
}
var spliter=func(content){
var spliter = func(content) {
var token={};
var len=size(content);
var s="";
for(var i=0;i<len;i+=1){
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])){
if (('a'[0]<=n and n<='z'[0]) or ('A'[0]<=n and n<='Z'[0])) {
s~=c;
}elsif(c=='.' or c==',' or c=='-' or c=='\'' or c=='\"' or c=='!' or c=='?'){
if(size(s)) {
} elsif (c=='.' or c==',' or c=='-' or c=='\'' or c=='\"' or c=='!' or c=='?') {
if (size(s)) {
token[to_lower(s)]+=1;
}
token[c]+=1;
s="";
}elsif(size(s)){
if(s[0]!="-"[0] and s[0]!="'"[0] and s[-1]!="-"[0] and s[-1]!="'"[0])
} 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="";
}
@@ -38,25 +38,25 @@ var spliter=func(content){
return token;
}
func(argv){
if(size(argv)<1){
func(argv) {
if (size(argv)<1) {
println("no input files.");
exit(-1);
}
var all_exists=1;
foreach(var f;argv){
if(!io.exists(f)){
foreach(var f;argv) {
if (!io.exists(f)) {
println("cannot open file <",f,">");
all_exists=0;
}
}
if(!all_exists){
if (!all_exists) {
exit(-1);
}
var file_content="";
foreach(var f;argv)
file_content~=io.readfile(f)~" ";
var vec=keys(spliter(file_content));
sort(vec,func(a,b){return cmp(a,b)<=0;});
sort(vec,func(a,b) {return cmp(a,b)<=0;});
println(vec);
}(runtime.argv());

View File

@@ -1,15 +1,16 @@
# Y combinator by ValKmjolnir
var fib=func(f){
var fib = func(f) {
return f(f);
}(
func(f){
return func(x){
if(x<2) return x;
var tmp=f(f);
func(f) {
return func(x) {
if (x<2) return x;
var tmp = f(f);
return tmp(x-1)+tmp(x-2);
}
}
);
for(var i=1;i<31;i+=1)
for(var i = 1; i<31; i += 1) {
println(fib(i));
}

View File

@@ -20,40 +20,40 @@ func {
}
for(var i=0; i<COUNT; i=i+1) {
var obj = v[i];
if(obj.fielda != i) { print("Ack!\n"); return; }
if(obj.fieldb != i) { print("Ack!\n"); return; }
if(obj.fieldc != i) { print("Ack!\n"); return; }
if(obj.fieldd != i) { print("Ack!\n"); return; }
if (obj.fielda != i) { print("Ack!\n"); return; }
if (obj.fieldb != i) { print("Ack!\n"); return; }
if (obj.fieldc != i) { print("Ack!\n"); return; }
if (obj.fieldd != i) { print("Ack!\n"); return; }
if(obj.fielda != i) { print("Ack!\n"); return; }
if(obj.fieldb != i) { print("Ack!\n"); return; }
if(obj.fieldc != i) { print("Ack!\n"); return; }
if(obj.fieldd != i) { print("Ack!\n"); return; }
if (obj.fielda != i) { print("Ack!\n"); return; }
if (obj.fieldb != i) { print("Ack!\n"); return; }
if (obj.fieldc != i) { print("Ack!\n"); return; }
if (obj.fieldd != i) { print("Ack!\n"); return; }
if(obj.fielda != i) { print("Ack!\n"); return; }
if(obj.fieldb != i) { print("Ack!\n"); return; }
if(obj.fieldc != i) { print("Ack!\n"); return; }
if(obj.fieldd != i) { print("Ack!\n"); return; }
if (obj.fielda != i) { print("Ack!\n"); return; }
if (obj.fieldb != i) { print("Ack!\n"); return; }
if (obj.fieldc != i) { print("Ack!\n"); return; }
if (obj.fieldd != i) { print("Ack!\n"); return; }
if(obj.fielda != i) { print("Ack!\n"); return; }
if(obj.fieldb != i) { print("Ack!\n"); return; }
if(obj.fieldc != i) { print("Ack!\n"); return; }
if(obj.fieldd != i) { print("Ack!\n"); return; }
if (obj.fielda != i) { print("Ack!\n"); return; }
if (obj.fieldb != i) { print("Ack!\n"); return; }
if (obj.fieldc != i) { print("Ack!\n"); return; }
if (obj.fieldd != i) { print("Ack!\n"); return; }
if(obj.fielda != i) { print("Ack!\n"); return; }
if(obj.fieldb != i) { print("Ack!\n"); return; }
if(obj.fieldc != i) { print("Ack!\n"); return; }
if(obj.fieldd != i) { print("Ack!\n"); return; }
if (obj.fielda != i) { print("Ack!\n"); return; }
if (obj.fieldb != i) { print("Ack!\n"); return; }
if (obj.fieldc != i) { print("Ack!\n"); return; }
if (obj.fieldd != i) { print("Ack!\n"); return; }
if(obj.fielda != i) { print("Ack!\n"); return; }
if(obj.fieldb != i) { print("Ack!\n"); return; }
if(obj.fieldc != i) { print("Ack!\n"); return; }
if(obj.fieldd != i) { print("Ack!\n"); return; }
if (obj.fielda != i) { print("Ack!\n"); return; }
if (obj.fieldb != i) { print("Ack!\n"); return; }
if (obj.fieldc != i) { print("Ack!\n"); return; }
if (obj.fieldd != i) { print("Ack!\n"); return; }
if(obj.fielda != i) { print("Ack!\n"); return; }
if(obj.fieldb != i) { print("Ack!\n"); return; }
if(obj.fieldc != i) { print("Ack!\n"); return; }
if(obj.fieldd != i) { print("Ack!\n"); return; }
if (obj.fielda != i) { print("Ack!\n"); return; }
if (obj.fieldb != i) { print("Ack!\n"); return; }
if (obj.fieldc != i) { print("Ack!\n"); return; }
if (obj.fieldd != i) { print("Ack!\n"); return; }
}
}
}();
@@ -69,7 +69,7 @@ print("cos(32) = ", math.cos(angle), "\n");
print("s^2 + c^s = ",
math.sin(angle)*math.sin(angle)+math.cos(angle)*math.cos(angle), "\n");
func{for(var j=0; j<10; j=j+1) {
func {for(var j=0; j<10; j=j+1) {
print(j, "/10\n");
# Make some tables to store stuff. This will clobber the contents
@@ -87,7 +87,7 @@ func{for(var j=0; j<10; j=j+1) {
# Check that we get back what we put in
for(i=0; i<65536; i=i+1) {
if(v[i] != h2[h1[v[i]~""]~""][0]) {
if (v[i] != h2[h1[v[i]~""]~""][0]) {
print("Ack!\n");
return;
}

29
tools/compiling_test.nas Normal file
View File

@@ -0,0 +1,29 @@
use std.file;
var check = func(dir_name) {
var ts = maketimestamp();
var f = file.find_all_files_with_extension(dir_name, "nas");
var res = [];
foreach(var k; f) {
ts.stamp();
if (system("nasal -c "~dir_name~"/"~k~" 1>/dev/null 2>/dev/null")!=0) {
println("\e[31merror\e[0m ", dir_name, "/", k);
append(res, dir_name~"/"~k);
}
println("compiling ", dir_name, "/", k, " in \e[32m", ts.elapsedMSec(), "\e[0m ms");
}
return res;
}
var result = [
check("./std"),
check("./module"),
check("./tools"),
check("./test")
];
println();
foreach(var i; result) {
foreach(var j; i) {
println("\e[31merror\e[0m ", j);
}
}

View File

@@ -0,0 +1,48 @@
use std.phi;
var tips = func() {
println("usage:");
println(" nasal <this_file> <hostname> <port>");
}
if (size(arg)<2) {
println("require hostname and port.");
tips();
exit(-1);
}
if (size(arg)>2) {
println("too many arguments, only require hostname and port.");
tips();
exit(-1);
}
var connect = phi.new(arg[0], num(arg[1]));
var count = 0;
var recursive_get_prop = func(path = "/") {
count += 1;
if (math.mod(count, 50)==0) {
println("get ", count," nodes, now: \"", path, "\"");
}
var props = connect.getprop(path);
var tree = {};
foreach(var key; keys(props)) {
if (key=="children") {
tree.children = [];
continue;
}
tree[key] = props[key];
}
if (!contains(props, "children")) {
return tree;
}
foreach(var child; props.children) {
var node = recursive_get_prop(child.path);
append(tree.children, node);
}
return tree;
}
# takes about 5 min to get whole tree
var props = recursive_get_prop("/");
phi.dump(props);

View File

@@ -1,9 +1,9 @@
println("[",os.time(),"] (=.=) auto push, please wait...");
println("[", os.time(), "] (=.=) auto push, please wait...");
while(system("git push")!=0) {
println("[",os.time(),"] (ToT) failed to push, retrying...");
println("[", os.time(), "] (ToT) failed to push, retrying...");
unix.sleep(0.5);
}
println("[",os.time(),"] (^o^) auto push complete.");
println("[", os.time(), "] (^o^) auto push complete.");