commit
97adfc9ea4
325
README.md
325
README.md
|
@ -4,7 +4,7 @@
|
|||
|
||||

|
||||

|
||||

|
||||

|
||||
[](./LICENSE)
|
||||
|
||||
> This document is also available in: [__中文__](./doc/README_zh.md) | [__English__](./README.md)
|
||||
|
@ -25,7 +25,7 @@
|
|||
|
||||
__Contact us if having great ideas to share!__
|
||||
|
||||
* __E-mail__: __lhk101lhk101@qq.com__
|
||||
* __E-mail__: __lhk101lhk101@qq.com__(ValKmjolnir) __1467329765@qq.com__(Sidi762)
|
||||
|
||||
## __Introduction__
|
||||
|
||||
|
@ -97,8 +97,9 @@ You could choose which compiler you want to use:
|
|||
If your system is `Windows` and you want to output unicode, you could write this in nasal code:
|
||||
|
||||
```javascript
|
||||
if(os.platform()=="windows")
|
||||
if (os.platform()=="windows") {
|
||||
system("chcp 65001");
|
||||
}
|
||||
```
|
||||
|
||||
## __Tutorial__
|
||||
|
@ -183,15 +184,16 @@ var f=func(x,y,z,deft=1){
|
|||
}
|
||||
var f = func(args...) {
|
||||
var sum = 0;
|
||||
foreach(var i;args)
|
||||
foreach(var i; args) {
|
||||
sum += i;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
```
|
||||
|
||||
__`upval`__ is used to store upvalues, used in __`vm`__ to make sure closure runs correctly.
|
||||
|
||||
__`obj`__ is used to store other complex `C/C++` data types.
|
||||
__`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>
|
||||
|
@ -323,10 +325,12 @@ if(1){
|
|||
While loop and for loop is simalar to C/C++.
|
||||
|
||||
```javascript
|
||||
while(condition)
|
||||
while(condition) {
|
||||
continue;
|
||||
for(var i=0;i<10;i+=1)
|
||||
}
|
||||
for(var i = 0; i<10; i += 1) {
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
Nasal has another two kinds of loops that iterates through a vector:
|
||||
|
@ -334,15 +338,17 @@ 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)
|
||||
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)
|
||||
foreach(var i; elem) {
|
||||
print(i);
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
@ -532,31 +538,17 @@ Definition:
|
|||
|
||||
```C++
|
||||
// you could also use a macro to define one.
|
||||
nas_native(builtin_print);
|
||||
var builtin_print(context*, gc*);
|
||||
```
|
||||
|
||||
Then complete this function using C++:
|
||||
|
||||
```C++
|
||||
var builtin_print(var* local,gc& ngc)
|
||||
{
|
||||
var builtin_print(context* ctx, gc* ngc) {
|
||||
// find value with index begin from 1
|
||||
// because local[0] is reserved for value 'me'
|
||||
var vec=local[1];
|
||||
// main process
|
||||
// also check number of arguments and type here
|
||||
// if get an error,use nas_err
|
||||
for(auto& i:vec.vec().elems)
|
||||
switch(i.type)
|
||||
{
|
||||
case vm_none: std::cout<<"undefined"; break;
|
||||
case vm_nil: std::cout<<"nil"; break;
|
||||
case vm_num: std::cout<<i.num(); break;
|
||||
case vm_str: std::cout<<i.str(); break;
|
||||
case vm_vec: std::cout<<i.vec(); break;
|
||||
case vm_hash: std::cout<<i.hash(); break;
|
||||
case vm_func: std::cout<<"func(..){..}";break;
|
||||
case vm_obj: std::cout<<"<object>"; break;
|
||||
for(auto& i : ctx->localr[1].vec().elems) {
|
||||
std::cout << i;
|
||||
}
|
||||
std::cout << std::flush;
|
||||
// generate return value,
|
||||
|
@ -572,17 +564,24 @@ The value got before will be collected, but stil in use in this builtin function
|
|||
So use `gc::temp` in builtin functions to temprorarily store the gc-managed value that you want to return later. Like this:
|
||||
|
||||
```C++
|
||||
var builtin_keys(var* local,gc& ngc)
|
||||
{
|
||||
var hash=local[1];
|
||||
if(hash.type!=vm_hash)
|
||||
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
|
||||
var res=ngc.temp=ngc.alloc(vm_vec);
|
||||
auto res = ngc->temp = ngc->alloc(vm_vec);
|
||||
auto& vec = res.vec().elems;
|
||||
for(auto& iter:hash.hash().elems)
|
||||
vec.push_back(ngc.newstr(iter.first));
|
||||
ngc.temp=nil;
|
||||
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;
|
||||
}
|
||||
```
|
||||
|
@ -590,12 +589,7 @@ var builtin_keys(var* local,gc& ngc)
|
|||
After that, register the built-in function's name(in nasal) and the function's pointer in this table:
|
||||
|
||||
```C++
|
||||
struct func
|
||||
{
|
||||
const char* name;
|
||||
var (*func)(var*,gc&);
|
||||
} builtin[]=
|
||||
{
|
||||
nasal_builtin_table builtin[] = {
|
||||
{"__print", builtin_print},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
@ -625,7 +619,7 @@ Use `import("filename.nas")` to get the nasal file including your built-in funct
|
|||
Also there's another way of importing nasal files, the two way of importing have the same function:
|
||||
|
||||
```javascript
|
||||
import.dirname.dirname.filename;
|
||||
use dirname.dirname.filename;
|
||||
import("./dirname/dirname/filename.nas");
|
||||
```
|
||||
|
||||
|
@ -728,7 +722,7 @@ Windows(`.dll`):
|
|||
Then we write a test nasal file to run this fib function, using `os.platform()` we could write a cross-platform program:
|
||||
|
||||
```javascript
|
||||
import.std.dylib;
|
||||
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)
|
||||
|
@ -745,7 +739,7 @@ dylib.dlclose(dlhandle.lib);
|
|||
`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
|
||||
import.std.dylib;
|
||||
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
|
||||
|
@ -812,19 +806,31 @@ void ghost_for_test_destructor(void* ptr) {
|
|||
var create_new_ghost(var* args, usize size, gc* ngc) {
|
||||
var res = ngc->alloc(vm_obj);
|
||||
// create ghost type
|
||||
res.obj().set(ghost_for_test, ghost_for_test_destructor, new u32);
|
||||
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.objchk(ghost_for_test)) {
|
||||
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.obj() << " result = "
|
||||
<< *((u32*)res.obj().ptr) << "\n";
|
||||
std::cout << "print_new_ghost: " << res.ghost() << " result = "
|
||||
<< *((u32*)res.ghost().pointer) << "\n";
|
||||
return nil;
|
||||
}
|
||||
```
|
||||
|
@ -841,7 +847,7 @@ We use this function to create a new ghost type:
|
|||
|
||||
And we use this function to check if value is the correct ghost type:
|
||||
|
||||
`bool var::objchk(const std::string&);`
|
||||
`bool var::object_check(const std::string&);`
|
||||
|
||||
The parameter is the name of the ghost type.
|
||||
|
||||
|
@ -901,8 +907,7 @@ it will print trace back information:
|
|||
Function `die` is used to throw error and crash immediately.
|
||||
|
||||
```javascript
|
||||
func()
|
||||
{
|
||||
func() {
|
||||
println("hello");
|
||||
die("error occurred this line");
|
||||
return;
|
||||
|
@ -912,17 +917,27 @@ func()
|
|||
```javascript
|
||||
hello
|
||||
[vm] error: error occurred this line
|
||||
[vm] native function error.
|
||||
trace back:
|
||||
0x000000ac 40 00 00 00 25 callb 0x25 <__die@0x41afc0> (lib.nas:131)
|
||||
0x000004f6 3e 00 00 00 01 callfv 0x1 (a.nas:4)
|
||||
0x000004fa 3e 00 00 00 00 callfv 0x0 (a.nas:6)
|
||||
vm stack (0x7fffcd21bc68 <sp+80>, limit 10, total 12):
|
||||
0x0000005b | null |
|
||||
...
|
||||
0x00000057 | str | <0x138ff60> error occurred t...
|
||||
...
|
||||
0x00000052 | nil |
|
||||
[vm] error: error occurred in native function
|
||||
|
||||
call trace (main)
|
||||
call func@0x557513935710() {entry: 0x850}
|
||||
|
||||
trace back (main)
|
||||
0x000547 4c 00 00 16 callb 0x16 <__die@0x557512441780>(std/lib.nas:150)
|
||||
0x000856 4a 00 00 01 callfv 0x1(a.nas:3)
|
||||
0x00085a 4a 00 00 00 callfv 0x0(a.nas:5)
|
||||
|
||||
stack (0x5575138e8c40, limit 10, total 14)
|
||||
0x00000d | null |
|
||||
0x00000c | pc | 0x856
|
||||
0x00000b | addr | 0x5575138e8c50
|
||||
0x00000a | nil |
|
||||
0x000009 | nil |
|
||||
0x000008 | str | <0x5575138d9190> error occurred t...
|
||||
0x000007 | nil |
|
||||
0x000006 | func | <0x5575139356f0> entry:0x850
|
||||
0x000005 | pc | 0x85a
|
||||
0x000004 | addr | 0x0
|
||||
```
|
||||
|
||||
</details>
|
||||
|
@ -942,18 +957,31 @@ func(f){
|
|||
```
|
||||
|
||||
```javascript
|
||||
[vm] stack overflow
|
||||
trace back:
|
||||
0x000004fb 3e 00 00 00 01 callfv 0x1 (a.nas:5)
|
||||
0x000004fb 1349 same call(s)
|
||||
0x000004f3 3e 00 00 00 01 callfv 0x1 (a.nas:2)
|
||||
0x000004ff 3e 00 00 00 01 callfv 0x1 (a.nas:3)
|
||||
vm stack (0x7fffd3781d58 <sp+80>, limit 10, total 8108):
|
||||
0x00001ffb | func | <0x15f8d90> entry:0x4f9
|
||||
0x00001ffa | func | <0x15f8d90> entry:0x4f9
|
||||
0x00001ff9 | pc | 0x4fb
|
||||
...
|
||||
0x00001ff2 | addr | 0x7fffd37a16e8
|
||||
[vm] error: stack overflow
|
||||
|
||||
call trace (main)
|
||||
call func@0x564106058620(f) {entry: 0x859}
|
||||
--> 583 same call(s)
|
||||
call func@0x5641060586c0(f) {entry: 0x851}
|
||||
|
||||
trace back (main)
|
||||
0x000859 45 00 00 01 calll 0x1(a.nas:5)
|
||||
0x00085b 4a 00 00 01 callfv 0x1(a.nas:5)
|
||||
0x00085b 582 same call(s)
|
||||
0x000853 4a 00 00 01 callfv 0x1(a.nas:2)
|
||||
0x00085f 4a 00 00 01 callfv 0x1(a.nas:3)
|
||||
|
||||
stack (0x56410600be00, limit 10, total 4096)
|
||||
0x000fff | func | <0x564106058600> entry:0x859
|
||||
0x000ffe | pc | 0x85b
|
||||
0x000ffd | addr | 0x56410601bd20
|
||||
0x000ffc | nil |
|
||||
0x000ffb | nil |
|
||||
0x000ffa | func | <0x564106058600> entry:0x859
|
||||
0x000ff9 | nil |
|
||||
0x000ff8 | func | <0x564106058600> entry:0x859
|
||||
0x000ff7 | pc | 0x85b
|
||||
0x000ff6 | addr | 0x56410601bcb0
|
||||
```
|
||||
|
||||
</details>
|
||||
|
@ -969,11 +997,13 @@ func(){
|
|||
```
|
||||
|
||||
```javascript
|
||||
[vm] callv: must call a vector/hash/string
|
||||
trace back:
|
||||
0x000004f4 3b 00 00 00 00 callv 0x0 (a.nas:3)
|
||||
vm stack (0x7fffff539c28 <sp+80>, limit 10, total 1):
|
||||
0x00000050 | num | 0
|
||||
[vm] error: must call a vector/hash/string but get number
|
||||
|
||||
trace back (main)
|
||||
0x000854 47 00 00 00 callv 0x0(a.nas:3)
|
||||
|
||||
stack (0x564993f462b0, limit 10, total 1)
|
||||
0x000000 | num | 0
|
||||
```
|
||||
|
||||
</details>
|
||||
|
@ -985,35 +1015,48 @@ Use command __`-d`__ or __`--detail`__ the trace back info will show more detail
|
|||
```javascript
|
||||
hello
|
||||
[vm] error: error occurred this line
|
||||
[vm] error: native function error
|
||||
[vm] error: error occurred in native function
|
||||
|
||||
call trace (main)
|
||||
call func@0x55dcb5b8fbf0() {entry: 0x850}
|
||||
|
||||
trace back (main)
|
||||
0x000000b0 40 00 00 00 2b callb 0x2b <__die@0x41c380> (lib.nas:131)
|
||||
0x00000553 3e 00 00 00 01 callfv 0x1 (test.nas:4)
|
||||
0x00000557 3e 00 00 00 00 callfv 0x0 (test.nas:6)
|
||||
vm stack (0x7fffe0ffed90 <sp+63>, limit 10, total 12)
|
||||
0x0000004a | null |
|
||||
0x00000049 | pc | 0x553
|
||||
0x00000048 | addr | 0x7fffe0ffeda0
|
||||
...
|
||||
0x00000041 | nil |
|
||||
0x000547 4c 00 00 16 callb 0x16 <__die@0x55dcb3c41780>(std/lib.nas:150)
|
||||
0x000856 4a 00 00 01 callfv 0x1(a.nas:3)
|
||||
0x00085a 4a 00 00 00 callfv 0x0(a.nas:5)
|
||||
|
||||
stack (0x55dcb5b43120, limit 10, total 14)
|
||||
0x00000d | null |
|
||||
0x00000c | pc | 0x856
|
||||
0x00000b | addr | 0x55dcb5b43130
|
||||
0x00000a | nil |
|
||||
0x000009 | nil |
|
||||
0x000008 | str | <0x55dcb5b33670> error occurred t...
|
||||
0x000007 | nil |
|
||||
0x000006 | func | <0x55dcb5b8fbd0> entry:0x850
|
||||
0x000005 | pc | 0x85a
|
||||
0x000004 | addr | 0x0
|
||||
|
||||
registers (main)
|
||||
[ pc ] | pc | 0xb0
|
||||
[ global ] | addr | 0x7fffe0ffe9a0
|
||||
[ localr ] | addr | 0x7fffe0ffedf0
|
||||
[pc ] | pc | 0x547
|
||||
[global] | addr | 0x55dcb5b53130
|
||||
[local ] | addr | 0x55dcb5b43190
|
||||
[memr ] | addr | 0x0
|
||||
[ canary ] | addr | 0x7fffe1002990
|
||||
[ top ] | addr | 0x7fffe0ffee40
|
||||
[ funcr ] | func | <0x677cd0> entry:0xb0
|
||||
[ upvalr ] | nil |
|
||||
global (0x7fffe0ffe9a0 <sp+0>)
|
||||
0x00000000 | func | <0x65fb00> entry:0x5
|
||||
0x00000001 | func | <0x65fb20> entry:0xd
|
||||
[canary] | addr | 0x55dcb5b53110
|
||||
[top ] | addr | 0x55dcb5b431f0
|
||||
[funcr ] | func | <0x55dcb5b65620> entry:0x547
|
||||
[upval ] | nil |
|
||||
|
||||
global (0x55dcb5b53130)
|
||||
0x000000 | nmspc| <0x55dcb5b33780> namespace [95 val]
|
||||
0x000001 | vec | <0x55dcb5b64c20> [0 val]
|
||||
...
|
||||
0x0000003d | func | <0x66bf00> entry:0x51f
|
||||
0x0000003e | hash | <0x65ffa0> {5 val}
|
||||
local (0x7fffe0ffedf0 <sp+45>)
|
||||
0x00000000 | nil |
|
||||
0x00000001 | str | <0x6cb630> error occurred t...
|
||||
0x00005e | func | <0x55dcb5b8fc70> entry:0x846
|
||||
|
||||
local (0x55dcb5b43190 <+7>)
|
||||
0x000000 | nil |
|
||||
0x000001 | str | <0x55dcb5b33670> error occurred t...
|
||||
0x000002 | nil |
|
||||
```
|
||||
|
||||
</details>
|
||||
|
@ -1038,16 +1081,18 @@ source code:
|
|||
for(var i=0;i<31;i+=1)
|
||||
print(fib(i),'\n');
|
||||
|
||||
|
||||
next bytecode:
|
||||
--> 0x00000000 01 00 00 00 41 intg 0x41 (test/fib.nas:0)
|
||||
0x00000001 0b 00 00 00 05 newf 0x5 (lib.nas:6)
|
||||
0x00000002 02 00 00 00 02 intl 0x2 (lib.nas:6)
|
||||
0x00000003 0f 00 00 00 00 dyn 0x0 ("elems") (lib.nas:6)
|
||||
0x00000004 32 00 00 00 07 jmp 0x7 (lib.nas:6)
|
||||
0x00000005 40 00 00 00 00 callb 0x0 <__print@0x419c80> (lib.nas:7)
|
||||
0x00000006 4a 00 00 00 00 ret 0x0 (lib.nas:7)
|
||||
0x00000007 03 00 00 00 00 loadg 0x0 (lib.nas:6)
|
||||
vm stack (0x7fffd0259138 <sp+65>, limit 10, total 0)
|
||||
0x000848 4a 00 00 01 callfv 0x1(std/lib.nas:427)
|
||||
0x000849 3d 00 00 00 pop 0x0(std/lib.nas:427)
|
||||
0x00084a 07 00 00 00 pnil 0x0(std/lib.nas:423)
|
||||
0x00084b 56 00 00 00 ret 0x0(std/lib.nas:423)
|
||||
0x00084c 03 00 00 5e loadg 0x5e(std/lib.nas:423)
|
||||
--> 0x00084d 0b 00 08 51 newf 0x851(test/fib.nas:1)
|
||||
0x00084e 02 00 00 03 intl 0x3(test/fib.nas:1)
|
||||
0x00084f 0d 00 00 08 para 0x8 (x)(test/fib.nas:1)
|
||||
|
||||
stack (0x55ccd0a1b9d0, limit 10, total 0)
|
||||
>>
|
||||
```
|
||||
|
||||
|
@ -1070,23 +1115,26 @@ source code:
|
|||
for(var i=0;i<31;i+=1)
|
||||
print(fib(i),'\n');
|
||||
|
||||
|
||||
next bytecode:
|
||||
0x00000548 0c 00 00 00 aa happ 0xaa ("running") (lib.nas:503)
|
||||
0x00000549 03 00 00 00 3e loadg 0x3e (lib.nas:498)
|
||||
0x0000054a 0b 00 00 05 4e newf 0x54e (test/fib.nas:1)
|
||||
0x0000054b 02 00 00 00 02 intl 0x2 (test/fib.nas:1)
|
||||
0x0000054c 0d 00 00 00 1b para 0x1b ("x") (test/fib.nas:1)
|
||||
0x0000054d 32 00 00 05 5d jmp 0x55d (test/fib.nas:1)
|
||||
--> 0x0000054e 39 00 00 00 01 calll 0x1 (test/fib.nas:3)
|
||||
0x0000054f 2d 00 00 00 03 lessc 0x3 (2) (test/fib.nas:3)
|
||||
vm stack (0x7fffd0259138 <sp+65>, limit 10, total 7)
|
||||
0x00000047 | pc | 0x566
|
||||
0x00000046 | addr | 0x0
|
||||
0x00000045 | nil |
|
||||
0x00000044 | num | 0
|
||||
0x00000043 | nil |
|
||||
0x00000042 | nil |
|
||||
0x00000041 | func | <0x88d2f0> entry:0x5
|
||||
0x000850 3e 00 08 60 jmp 0x860(test/fib.nas:1)
|
||||
--> 0x000851 45 00 00 01 calll 0x1(test/fib.nas:3)
|
||||
0x000852 39 00 00 07 lessc 0x7 (2)(test/fib.nas:3)
|
||||
0x000853 40 00 08 56 jf 0x856(test/fib.nas:3)
|
||||
0x000854 45 00 00 01 calll 0x1(test/fib.nas:3)
|
||||
0x000855 56 00 00 00 ret 0x0(test/fib.nas:3)
|
||||
0x000856 44 00 00 5f callg 0x5f(test/fib.nas:4)
|
||||
0x000857 45 00 00 01 calll 0x1(test/fib.nas:4)
|
||||
|
||||
stack (0x55ccd0a1b9d0, limit 10, total 8)
|
||||
0x000007 | pc | 0x869
|
||||
0x000006 | addr | 0x0
|
||||
0x000005 | nil |
|
||||
0x000004 | nil |
|
||||
0x000003 | num | 0
|
||||
0x000002 | nil |
|
||||
0x000001 | nil |
|
||||
0x000000 | func | <0x55ccd0a58fa0> entry:0x487
|
||||
>>
|
||||
```
|
||||
|
||||
|
@ -1114,3 +1162,22 @@ Nasal REPL interpreter version 11.0 (Oct 7 2023 17:28:31)
|
|||
|
||||
>>>
|
||||
```
|
||||
|
||||
Try import `std/json.nas`~
|
||||
|
||||
```bash
|
||||
[nasal-repl] Initializating enviroment...
|
||||
[nasal-repl] Initialization complete.
|
||||
|
||||
Nasal REPL interpreter version 11.1 (Nov 1 2023 23:37:30)
|
||||
.h, .help | show help
|
||||
.e, .exit | quit the REPL
|
||||
.q, .quit | quit the REPL
|
||||
.c, .clear | clear the screen
|
||||
.s, .source | show source code
|
||||
|
||||
>>> use std.json;
|
||||
{stringify:func(..) {..},parse:func(..) {..}}
|
||||
|
||||
>>>
|
||||
```
|
||||
|
|
334
doc/README_zh.md
334
doc/README_zh.md
|
@ -4,7 +4,7 @@
|
|||
|
||||

|
||||

|
||||

|
||||

|
||||
[](../LICENSE)
|
||||
|
||||
> 这篇文档包含多语言版本: [__中文__](../doc/README_zh.md) | [__English__](../README.md)
|
||||
|
@ -25,7 +25,7 @@
|
|||
|
||||
__如果有好的意见或建议,欢迎联系我们!__
|
||||
|
||||
* __E-mail__: __lhk101lhk101@qq.com__
|
||||
* __E-mail__: __lhk101lhk101@qq.com__(ValKmjolnir) __1467329765@qq.com__(Sidi762)
|
||||
|
||||
## __简介__
|
||||
|
||||
|
@ -88,8 +88,9 @@ __注意__: 如果你想直接下载发行版提供的zip/tar.gz压缩包来构
|
|||
如果你是 `Windows` 用户且想正常输出unicode,在nasal代码里写这个来开启unicode代码页:
|
||||
|
||||
```javascript
|
||||
if(os.platform()=="windows")
|
||||
if (os.platform()=="windows") {
|
||||
system("chcp 65001");
|
||||
}
|
||||
```
|
||||
|
||||
## __教程__
|
||||
|
@ -171,15 +172,16 @@ var f=func(x,y,z,deft=1){
|
|||
}
|
||||
var f = func(args...) {
|
||||
var sum = 0;
|
||||
foreach(var i;args)
|
||||
foreach(var i; args) {
|
||||
sum += i;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
```
|
||||
|
||||
__`upval`__ 是存储闭包数据的特殊类型, 在 __`vm`__ 中使用,以确保闭包功能正常。
|
||||
|
||||
__`obj`__ 是用来存储`C/C++`的一些复杂数据结构。这种类型的数据由内置函数生成。如果想为nasal添加新的数据结构, 可以看下文如何通过修改本项目来添加内置函数。
|
||||
__`ghost`__ 是用来存储`C/C++`的一些复杂数据结构。这种类型的数据由内置函数生成。如果想为nasal添加新的数据结构, 可以看下文如何通过修改本项目来添加内置函数。
|
||||
|
||||
</details>
|
||||
|
||||
|
@ -308,10 +310,12 @@ if(1){
|
|||
while循环和for循环大体上与C/C++是一致的。
|
||||
|
||||
```javascript
|
||||
while(condition)
|
||||
while(condition) {
|
||||
continue;
|
||||
for(var i=0;i<10;i+=1)
|
||||
}
|
||||
for(var i = 0; i<10; i += 1) {
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
同时,nasal还有另外两种直接遍历列表的循环方式:
|
||||
|
@ -319,15 +323,17 @@ for(var i=0;i<10;i+=1)
|
|||
`forindex` 会获取列表的下标,依次递增. 下标会从`0`递增到`size(elem)-1`结束。
|
||||
|
||||
```javascript
|
||||
forindex(var i;elem)
|
||||
forindex(var i; elem) {
|
||||
print(elem[i]);
|
||||
}
|
||||
```
|
||||
|
||||
`foreach`会依次直接获取列表中的数据. 这些数据会从`elem[0]`依次获取到`elem[size(elem)-1]`.
|
||||
|
||||
```javascript
|
||||
foreach(var i;elem)
|
||||
foreach(var i; elem) {
|
||||
print(i);
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
@ -506,42 +512,27 @@ println(d());
|
|||
|
||||
__警告:__ 如果你 __不想__ 通过直接修改解释器源码来添加你自定义的函数,那么你应该看下一个节 __`模块`__ 的内容。
|
||||
|
||||
如果你确实是想修改源码来搞一个自己私人订制的解释器,那么你可以说:“我他妈就是想自己私人订制,你们他妈的管得着吗”,
|
||||
然后看看源码中关于内置函数的部分,以及`lib.nas`中是如何包装这些函数的,还有下面的样例:
|
||||
如果你确实是想修改源码来搞一个自己私人订制的解释器 ———— “我他妈就是想自己私人订制,你们他妈的管得着吗?”,
|
||||
参考源码中关于内置函数的部分,以及`lib.nas`中是如何包装这些函数的,下面是其中一个样例:
|
||||
|
||||
定义新的内置函数:
|
||||
|
||||
```C++
|
||||
// 你可以使用这个宏来直接定义一个新的内置函数
|
||||
nas_native(builtin_print);
|
||||
var builtin_print(context*, gc*);
|
||||
```
|
||||
|
||||
然后用C++完成这个函数的函数体:
|
||||
|
||||
```C++
|
||||
var builtin_print(var* local,gc& ngc)
|
||||
{
|
||||
var builtin_print(context* ctx, gc* ngc) {
|
||||
// 局部变量的下标其实是从 1 开始的
|
||||
// 因为 local[0] 是保留给 'me' 的空间
|
||||
var vec=local[1];
|
||||
// 主要部分
|
||||
// 一些必要的类型检查和输入合法性检测也要在这里写出
|
||||
// 如果检测到问题,用builtin_err函数来返回vm_null
|
||||
// 并且狠狠地骂那些不好好写代码的混蛋(玩笑)
|
||||
for(auto& i:vec.vec().elems)
|
||||
switch(i.type)
|
||||
{
|
||||
case vm_none: std::cout<<"undefined"; break;
|
||||
case vm_nil: std::cout<<"nil"; break;
|
||||
case vm_num: std::cout<<i.num(); break;
|
||||
case vm_str: std::cout<<i.str(); break;
|
||||
case vm_vec: std::cout<<i.vec(); break;
|
||||
case vm_hash: std::cout<<i.hash(); break;
|
||||
case vm_func: std::cout<<"func(..){..}";break;
|
||||
case vm_obj: std::cout<<"<object>"; break;
|
||||
for(auto& i : ctx->localr[1].vec().elems) {
|
||||
std::cout << i;
|
||||
}
|
||||
std::cout << std::flush;
|
||||
// 最后一定要记得生成返回值,返回值必须是一个内置的类型,
|
||||
// 最后生成返回值,返回值必须是一个内置的类型,
|
||||
// 可以使用ngc::alloc(type)来申请一个需要内存管理的复杂数据结构
|
||||
// 或者用我们已经定义好的nil/one/zero,这些可以直接使用
|
||||
return nil;
|
||||
|
@ -554,17 +545,24 @@ var builtin_print(var* local,gc& ngc)
|
|||
可以使用`gc::temp`来暂时存储一个会被返回的需要gc管理的变量,这样可以防止内部所有的申请错误触发垃圾回收。如下所示:
|
||||
|
||||
```C++
|
||||
var builtin_keys(var* local,gc& ngc)
|
||||
{
|
||||
var hash=local[1];
|
||||
if(hash.type!=vm_hash)
|
||||
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管理的变量,防止错误的回收
|
||||
var res=ngc.temp=ngc.alloc(vm_vec);
|
||||
auto res = ngc->temp = ngc->alloc(vm_vec);
|
||||
auto& vec = res.vec().elems;
|
||||
for(auto& iter:hash.hash().elems)
|
||||
vec.push_back(ngc.newstr(iter.first));
|
||||
ngc.temp=nil;
|
||||
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;
|
||||
}
|
||||
```
|
||||
|
@ -572,12 +570,7 @@ var builtin_keys(var* local,gc& ngc)
|
|||
这些工作都完成之后,在内置函数注册表中填写它在nasal中的别名,并且在表中填对这个函数的函数指针:
|
||||
|
||||
```C++
|
||||
struct func
|
||||
{
|
||||
const char* name;
|
||||
var (*func)(var*,gc&);
|
||||
} builtin[]=
|
||||
{
|
||||
nasal_builtin_table builtin[] = {
|
||||
{"__print", builtin_print},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
@ -605,7 +598,7 @@ var print=func(elems...){
|
|||
当然也有另外一种办法来导入这些nasal文件,下面两种导入方式的效果是一样的:
|
||||
|
||||
```javascript
|
||||
import.dirname.dirname.filename;
|
||||
use dirname.dirname.filename;
|
||||
import("./dirname/dirname/filename.nas");
|
||||
```
|
||||
|
||||
|
@ -702,7 +695,7 @@ Windows(`.dll`):
|
|||
下面例子中`os.platform()`是用来检测当前运行的系统环境的,这样可以实现跨平台:
|
||||
|
||||
```javascript
|
||||
import.std.dylib;
|
||||
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)
|
||||
|
@ -719,7 +712,7 @@ dylib.dlclose(dlhandle.lib);
|
|||
`dylib.limitcall`用于获取使用固定长度传参的 `dlcall` 函数,这种函数可以提高你的程序运行效率,因为它不需要用 `vm_vec` 来存储传入参数,而是使用局部作用域来直接存储,从而避免了频繁调用可能导致的频繁垃圾收集。所以上面展示的代码同样可以这样写:
|
||||
|
||||
```javascript
|
||||
import.std.dylib;
|
||||
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
|
||||
|
@ -767,7 +760,7 @@ dylib.dlclose(dlhandle.lib);
|
|||
|
||||
<details><summary> 自定义类型(开发者教程) </summary>
|
||||
|
||||
创建一个自定义类型现在不是很困难。下面是使用示例:
|
||||
创建一个自定义类型很容易。下面是使用示例:
|
||||
|
||||
```c++
|
||||
const auto ghost_for_test = "ghost_for_test";
|
||||
|
@ -785,19 +778,31 @@ void ghost_for_test_destructor(void* ptr) {
|
|||
var create_new_ghost(var* args, usize size, gc* ngc) {
|
||||
var res = ngc->alloc(vm_obj);
|
||||
// 创建自定义类型
|
||||
res.obj().set(ghost_for_test, ghost_for_test_destructor, new u32);
|
||||
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.objchk(ghost_for_test)) {
|
||||
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.obj() << " result = "
|
||||
<< *((u32*)res.obj().ptr) << "\n";
|
||||
std::cout << "print_new_ghost: " << res.ghost() << " result = "
|
||||
<< *((u32*)res.ghost().pointer) << "\n";
|
||||
return nil;
|
||||
}
|
||||
```
|
||||
|
@ -814,7 +819,7 @@ var print_new_ghost(var* args, usize size, gc* ngc) {
|
|||
|
||||
我们使用下面的这个函数检测是否是正确的自定义类型:
|
||||
|
||||
`bool var::objchk(const std::string&);`
|
||||
`bool var::object_check(const std::string&);`
|
||||
|
||||
参数是自定义类型的类型名。
|
||||
|
||||
|
@ -866,8 +871,7 @@ code: undefined symbol "i"
|
|||
`die`函数用于直接抛出错误并终止执行。
|
||||
|
||||
```javascript
|
||||
func()
|
||||
{
|
||||
func() {
|
||||
println("hello");
|
||||
die("error occurred this line");
|
||||
return;
|
||||
|
@ -877,17 +881,27 @@ func()
|
|||
```javascript
|
||||
hello
|
||||
[vm] error: error occurred this line
|
||||
[vm] native function error.
|
||||
trace back:
|
||||
0x000000ac 40 00 00 00 25 callb 0x25 <__die@0x41afc0> (lib.nas:131)
|
||||
0x000004f6 3e 00 00 00 01 callfv 0x1 (a.nas:4)
|
||||
0x000004fa 3e 00 00 00 00 callfv 0x0 (a.nas:6)
|
||||
vm stack (0x7fffcd21bc68 <sp+80>, limit 10, total 12):
|
||||
0x0000005b | null |
|
||||
...
|
||||
0x00000057 | str | <0x138ff60> error occurred t...
|
||||
...
|
||||
0x00000052 | nil |
|
||||
[vm] error: error occurred in native function
|
||||
|
||||
call trace (main)
|
||||
call func@0x557513935710() {entry: 0x850}
|
||||
|
||||
trace back (main)
|
||||
0x000547 4c 00 00 16 callb 0x16 <__die@0x557512441780>(std/lib.nas:150)
|
||||
0x000856 4a 00 00 01 callfv 0x1(a.nas:3)
|
||||
0x00085a 4a 00 00 00 callfv 0x0(a.nas:5)
|
||||
|
||||
stack (0x5575138e8c40, limit 10, total 14)
|
||||
0x00000d | null |
|
||||
0x00000c | pc | 0x856
|
||||
0x00000b | addr | 0x5575138e8c50
|
||||
0x00000a | nil |
|
||||
0x000009 | nil |
|
||||
0x000008 | str | <0x5575138d9190> error occurred t...
|
||||
0x000007 | nil |
|
||||
0x000006 | func | <0x5575139356f0> entry:0x850
|
||||
0x000005 | pc | 0x85a
|
||||
0x000004 | addr | 0x0
|
||||
```
|
||||
|
||||
</details>
|
||||
|
@ -907,18 +921,31 @@ func(f){
|
|||
```
|
||||
|
||||
```javascript
|
||||
[vm] stack overflow
|
||||
trace back:
|
||||
0x000004fb 3e 00 00 00 01 callfv 0x1 (a.nas:5)
|
||||
0x000004fb 1349 same call(s)
|
||||
0x000004f3 3e 00 00 00 01 callfv 0x1 (a.nas:2)
|
||||
0x000004ff 3e 00 00 00 01 callfv 0x1 (a.nas:3)
|
||||
vm stack (0x7fffd3781d58 <sp+80>, limit 10, total 8108):
|
||||
0x00001ffb | func | <0x15f8d90> entry:0x4f9
|
||||
0x00001ffa | func | <0x15f8d90> entry:0x4f9
|
||||
0x00001ff9 | pc | 0x4fb
|
||||
...
|
||||
0x00001ff2 | addr | 0x7fffd37a16e8
|
||||
[vm] error: stack overflow
|
||||
|
||||
call trace (main)
|
||||
call func@0x564106058620(f) {entry: 0x859}
|
||||
--> 583 same call(s)
|
||||
call func@0x5641060586c0(f) {entry: 0x851}
|
||||
|
||||
trace back (main)
|
||||
0x000859 45 00 00 01 calll 0x1(a.nas:5)
|
||||
0x00085b 4a 00 00 01 callfv 0x1(a.nas:5)
|
||||
0x00085b 582 same call(s)
|
||||
0x000853 4a 00 00 01 callfv 0x1(a.nas:2)
|
||||
0x00085f 4a 00 00 01 callfv 0x1(a.nas:3)
|
||||
|
||||
stack (0x56410600be00, limit 10, total 4096)
|
||||
0x000fff | func | <0x564106058600> entry:0x859
|
||||
0x000ffe | pc | 0x85b
|
||||
0x000ffd | addr | 0x56410601bd20
|
||||
0x000ffc | nil |
|
||||
0x000ffb | nil |
|
||||
0x000ffa | func | <0x564106058600> entry:0x859
|
||||
0x000ff9 | nil |
|
||||
0x000ff8 | func | <0x564106058600> entry:0x859
|
||||
0x000ff7 | pc | 0x85b
|
||||
0x000ff6 | addr | 0x56410601bcb0
|
||||
```
|
||||
|
||||
</details>
|
||||
|
@ -934,11 +961,13 @@ func(){
|
|||
```
|
||||
|
||||
```javascript
|
||||
[vm] callv: must call a vector/hash/string
|
||||
trace back:
|
||||
0x000004f4 3b 00 00 00 00 callv 0x0 (a.nas:3)
|
||||
vm stack (0x7fffff539c28 <sp+80>, limit 10, total 1):
|
||||
0x00000050 | num | 0
|
||||
[vm] error: must call a vector/hash/string but get number
|
||||
|
||||
trace back (main)
|
||||
0x000854 47 00 00 00 callv 0x0(a.nas:3)
|
||||
|
||||
stack (0x564993f462b0, limit 10, total 1)
|
||||
0x000000 | num | 0
|
||||
```
|
||||
|
||||
</details>
|
||||
|
@ -950,35 +979,48 @@ vm stack (0x7fffff539c28 <sp+80>, limit 10, total 1):
|
|||
```javascript
|
||||
hello
|
||||
[vm] error: error occurred this line
|
||||
[vm] error: native function error
|
||||
[vm] error: error occurred in native function
|
||||
|
||||
call trace (main)
|
||||
call func@0x55dcb5b8fbf0() {entry: 0x850}
|
||||
|
||||
trace back (main)
|
||||
0x000000b0 40 00 00 00 2b callb 0x2b <__die@0x41c380> (lib.nas:131)
|
||||
0x00000553 3e 00 00 00 01 callfv 0x1 (test.nas:4)
|
||||
0x00000557 3e 00 00 00 00 callfv 0x0 (test.nas:6)
|
||||
vm stack (0x7fffe0ffed90 <sp+63>, limit 10, total 12)
|
||||
0x0000004a | null |
|
||||
0x00000049 | pc | 0x553
|
||||
0x00000048 | addr | 0x7fffe0ffeda0
|
||||
...
|
||||
0x00000041 | nil |
|
||||
0x000547 4c 00 00 16 callb 0x16 <__die@0x55dcb3c41780>(std/lib.nas:150)
|
||||
0x000856 4a 00 00 01 callfv 0x1(a.nas:3)
|
||||
0x00085a 4a 00 00 00 callfv 0x0(a.nas:5)
|
||||
|
||||
stack (0x55dcb5b43120, limit 10, total 14)
|
||||
0x00000d | null |
|
||||
0x00000c | pc | 0x856
|
||||
0x00000b | addr | 0x55dcb5b43130
|
||||
0x00000a | nil |
|
||||
0x000009 | nil |
|
||||
0x000008 | str | <0x55dcb5b33670> error occurred t...
|
||||
0x000007 | nil |
|
||||
0x000006 | func | <0x55dcb5b8fbd0> entry:0x850
|
||||
0x000005 | pc | 0x85a
|
||||
0x000004 | addr | 0x0
|
||||
|
||||
registers (main)
|
||||
[ pc ] | pc | 0xb0
|
||||
[ global ] | addr | 0x7fffe0ffe9a0
|
||||
[ localr ] | addr | 0x7fffe0ffedf0
|
||||
[pc ] | pc | 0x547
|
||||
[global] | addr | 0x55dcb5b53130
|
||||
[local ] | addr | 0x55dcb5b43190
|
||||
[memr ] | addr | 0x0
|
||||
[ canary ] | addr | 0x7fffe1002990
|
||||
[ top ] | addr | 0x7fffe0ffee40
|
||||
[ funcr ] | func | <0x677cd0> entry:0xb0
|
||||
[ upvalr ] | nil |
|
||||
global (0x7fffe0ffe9a0 <sp+0>)
|
||||
0x00000000 | func | <0x65fb00> entry:0x5
|
||||
0x00000001 | func | <0x65fb20> entry:0xd
|
||||
[canary] | addr | 0x55dcb5b53110
|
||||
[top ] | addr | 0x55dcb5b431f0
|
||||
[funcr ] | func | <0x55dcb5b65620> entry:0x547
|
||||
[upval ] | nil |
|
||||
|
||||
global (0x55dcb5b53130)
|
||||
0x000000 | nmspc| <0x55dcb5b33780> namespace [95 val]
|
||||
0x000001 | vec | <0x55dcb5b64c20> [0 val]
|
||||
...
|
||||
0x0000003d | func | <0x66bf00> entry:0x51f
|
||||
0x0000003e | hash | <0x65ffa0> {5 val}
|
||||
local (0x7fffe0ffedf0 <sp+45>)
|
||||
0x00000000 | nil |
|
||||
0x00000001 | str | <0x6cb630> error occurred t...
|
||||
0x00005e | func | <0x55dcb5b8fc70> entry:0x846
|
||||
|
||||
local (0x55dcb5b43190 <+7>)
|
||||
0x000000 | nil |
|
||||
0x000001 | str | <0x55dcb5b33670> error occurred t...
|
||||
0x000002 | nil |
|
||||
```
|
||||
|
||||
</details>
|
||||
|
@ -1002,16 +1044,18 @@ source code:
|
|||
for(var i=0;i<31;i+=1)
|
||||
print(fib(i),'\n');
|
||||
|
||||
|
||||
next bytecode:
|
||||
--> 0x00000000 01 00 00 00 41 intg 0x41 (test/fib.nas:0)
|
||||
0x00000001 0b 00 00 00 05 newf 0x5 (lib.nas:6)
|
||||
0x00000002 02 00 00 00 02 intl 0x2 (lib.nas:6)
|
||||
0x00000003 0f 00 00 00 00 dyn 0x0 ("elems") (lib.nas:6)
|
||||
0x00000004 32 00 00 00 07 jmp 0x7 (lib.nas:6)
|
||||
0x00000005 40 00 00 00 00 callb 0x0 <__print@0x419c80> (lib.nas:7)
|
||||
0x00000006 4a 00 00 00 00 ret 0x0 (lib.nas:7)
|
||||
0x00000007 03 00 00 00 00 loadg 0x0 (lib.nas:6)
|
||||
vm stack (0x7fffd0259138 <sp+65>, limit 10, total 0)
|
||||
0x000848 4a 00 00 01 callfv 0x1(std/lib.nas:427)
|
||||
0x000849 3d 00 00 00 pop 0x0(std/lib.nas:427)
|
||||
0x00084a 07 00 00 00 pnil 0x0(std/lib.nas:423)
|
||||
0x00084b 56 00 00 00 ret 0x0(std/lib.nas:423)
|
||||
0x00084c 03 00 00 5e loadg 0x5e(std/lib.nas:423)
|
||||
--> 0x00084d 0b 00 08 51 newf 0x851(test/fib.nas:1)
|
||||
0x00084e 02 00 00 03 intl 0x3(test/fib.nas:1)
|
||||
0x00084f 0d 00 00 08 para 0x8 (x)(test/fib.nas:1)
|
||||
|
||||
stack (0x55ccd0a1b9d0, limit 10, total 0)
|
||||
>>
|
||||
```
|
||||
|
||||
|
@ -1034,23 +1078,26 @@ source code:
|
|||
for(var i=0;i<31;i+=1)
|
||||
print(fib(i),'\n');
|
||||
|
||||
|
||||
next bytecode:
|
||||
0x00000548 0c 00 00 00 aa happ 0xaa ("running") (lib.nas:503)
|
||||
0x00000549 03 00 00 00 3e loadg 0x3e (lib.nas:498)
|
||||
0x0000054a 0b 00 00 05 4e newf 0x54e (test/fib.nas:1)
|
||||
0x0000054b 02 00 00 00 02 intl 0x2 (test/fib.nas:1)
|
||||
0x0000054c 0d 00 00 00 1b para 0x1b ("x") (test/fib.nas:1)
|
||||
0x0000054d 32 00 00 05 5d jmp 0x55d (test/fib.nas:1)
|
||||
--> 0x0000054e 39 00 00 00 01 calll 0x1 (test/fib.nas:3)
|
||||
0x0000054f 2d 00 00 00 03 lessc 0x3 (2) (test/fib.nas:3)
|
||||
vm stack (0x7fffd0259138 <sp+65>, limit 10, total 7)
|
||||
0x00000047 | pc | 0x566
|
||||
0x00000046 | addr | 0x0
|
||||
0x00000045 | nil |
|
||||
0x00000044 | num | 0
|
||||
0x00000043 | nil |
|
||||
0x00000042 | nil |
|
||||
0x00000041 | func | <0x88d2f0> entry:0x5
|
||||
0x000850 3e 00 08 60 jmp 0x860(test/fib.nas:1)
|
||||
--> 0x000851 45 00 00 01 calll 0x1(test/fib.nas:3)
|
||||
0x000852 39 00 00 07 lessc 0x7 (2)(test/fib.nas:3)
|
||||
0x000853 40 00 08 56 jf 0x856(test/fib.nas:3)
|
||||
0x000854 45 00 00 01 calll 0x1(test/fib.nas:3)
|
||||
0x000855 56 00 00 00 ret 0x0(test/fib.nas:3)
|
||||
0x000856 44 00 00 5f callg 0x5f(test/fib.nas:4)
|
||||
0x000857 45 00 00 01 calll 0x1(test/fib.nas:4)
|
||||
|
||||
stack (0x55ccd0a1b9d0, limit 10, total 8)
|
||||
0x000007 | pc | 0x869
|
||||
0x000006 | addr | 0x0
|
||||
0x000005 | nil |
|
||||
0x000004 | nil |
|
||||
0x000003 | num | 0
|
||||
0x000002 | nil |
|
||||
0x000001 | nil |
|
||||
0x000000 | func | <0x55ccd0a58fa0> entry:0x487
|
||||
>>
|
||||
```
|
||||
|
||||
|
@ -1077,3 +1124,22 @@ Nasal REPL interpreter version 11.0 (Oct 7 2023 17:28:31)
|
|||
|
||||
>>>
|
||||
```
|
||||
|
||||
试试引入 `std/json.nas` 模块 ~
|
||||
|
||||
```bash
|
||||
[nasal-repl] Initializating enviroment...
|
||||
[nasal-repl] Initialization complete.
|
||||
|
||||
Nasal REPL interpreter version 11.1 (Nov 1 2023 23:37:30)
|
||||
.h, .help | show help
|
||||
.e, .exit | quit the REPL
|
||||
.q, .quit | quit the REPL
|
||||
.c, .clear | clear the screen
|
||||
.s, .source | show source code
|
||||
|
||||
>>> use std.json;
|
||||
{stringify:func(..) {..},parse:func(..) {..}}
|
||||
|
||||
>>>
|
||||
```
|
||||
|
|
11
doc/dev.md
11
doc/dev.md
|
@ -1,5 +1,7 @@
|
|||
# __Development History__
|
||||
|
||||

|
||||
|
||||
## __Contents__
|
||||
|
||||
* [__Parser__](#parser)
|
||||
|
@ -22,6 +24,7 @@
|
|||
* [__Release Notes__](#release-notes)
|
||||
* [v8.0](#version-80-release)
|
||||
* [v11.0](#version-110-release)
|
||||
* [v11.1](#version-111-release)
|
||||
|
||||
## __Parser__
|
||||
|
||||
|
@ -697,3 +700,11 @@ This bug is fixed in `v9.0`. So we suggest that do not use `v8.0`.
|
|||
9. Add `CMakeLists.txt` for cmake user(including `Visual Studio`).
|
||||
|
||||
10. New ghost type register process.
|
||||
|
||||
### __version 11.1 release__
|
||||
|
||||
1. Bug fix: debugger in v11.0 is malfunctional.
|
||||
|
||||
2. Bug fix: symbol_finder does not check definition in foreach/forindex loop.
|
||||
|
||||
3. Change extension syntax `import.xx.xx` to `use xx.xx`.
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# __开发历史记录__
|
||||
|
||||

|
||||
|
||||
## __目录__
|
||||
|
||||
* [__语法分析__](#语法分析)
|
||||
|
@ -22,6 +24,7 @@
|
|||
* [__发行日志__](#发行日志)
|
||||
* [v8.0](#version-80-release)
|
||||
* [v11.0](#version-110-release)
|
||||
* [v11.1](#version-111-release)
|
||||
|
||||
## __语法分析__
|
||||
|
||||
|
@ -630,3 +633,11 @@ in __`nasal_dbg.h:215`__: `auto canary=gc.stack+STACK_MAX_DEPTH-1;`
|
|||
9. 添加`CMakeLists.txt` (可在`Visual Studio`中使用)。
|
||||
|
||||
10. 全新的自定义类型注册流程。
|
||||
|
||||
### __version 11.1 release__
|
||||
|
||||
1. Bug 修复: 修复 v11.0 的 debugger 无法启动的问题。
|
||||
|
||||
2. Bug 修复: symbol_finder 不检查 foreach/forindex 中的迭代变量声明的问题。
|
||||
|
||||
3. 扩展语法 `import.xx.xx` 改为 `use xx.xx`。
|
||||
|
|
|
@ -62,3 +62,27 @@ var example_module = func {
|
|||
};
|
||||
}();
|
||||
```
|
||||
|
||||
## Import a module
|
||||
|
||||
Here is a module named `std/example_module.nas`:
|
||||
|
||||
```nasal
|
||||
var a = 1;
|
||||
```
|
||||
|
||||
Then there's a script file named `test.nas`, import module in this file using this way:
|
||||
|
||||
```nasal
|
||||
use std.example_module;
|
||||
|
||||
println(example_module.a); # 1
|
||||
```
|
||||
|
||||
Or this way:
|
||||
|
||||
```nasal
|
||||
import("std/example_module.nas");
|
||||
|
||||
println(example_module.a); # 1
|
||||
```
|
||||
|
|
|
@ -33,10 +33,11 @@
|
|||
</head>
|
||||
<body>
|
||||
<h1> Nasal | Not another scripting language!</h1>
|
||||
<img src="/doc/pic/social.png" width="900" height="400" style="margin-left: 15px;"><br /></img>
|
||||
<div class="badges">
|
||||
<a href="https://github.com/ValKmjolnir/Nasal-Interpreter"><img src="https://img.shields.io/github/languages/code-size/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github"></img></a>
|
||||
<a href="https://github.com/ValKmjolnir/Nasal-Interpreter"><img src="https://img.shields.io/github/v/release/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github"></img></a>
|
||||
<a href="https://github.com/ValKmjolnir/Nasal-Interpreter"><img src="https://img.shields.io/badge/dev-v10.0-blue?style=flat-square&logo=github"></img></a>
|
||||
<a href="https://github.com/ValKmjolnir/Nasal-Interpreter"><img src="https://img.shields.io/badge/dev-v11.2-blue?style=flat-square&logo=github"></img></a>
|
||||
<a href="https://github.com/ValKmjolnir/Nasal-Interpreter"><img src="https://img.shields.io/badge/license-GPLv2-green?style=flat-square&logo=github"><br/></img></a>
|
||||
</div>
|
||||
<h2> Introduction | 介绍</h2>
|
||||
|
@ -79,13 +80,14 @@
|
|||
在8.0版本中这个解释器需要跑超过2200秒来绘制这张图。
|
||||
</p>
|
||||
<p>
|
||||
The figure below is the feigenbaum-figure generated by ppm script written in nasal.
|
||||
The figure below is the feigenbaum-figure and burningship-figure generated by ppm script written in nasal.
|
||||
</p>
|
||||
<p>
|
||||
下方是使用 nasal 的 ppm 生成脚本生成的 feigenbaum 图形。
|
||||
下方是使用 nasal 的 ppm 生成脚本生成的 feigenbaum 和 burningship 图形。
|
||||
</p>
|
||||
</text>
|
||||
<img src="/doc/pic/feigenbaum.png" width="900" height="550" style="margin-left: 15px;"><br /></img>
|
||||
<img src="/doc/pic/burningship.png" width="900" height="550" style="margin-left: 15px;"><br /></img>
|
||||
<h2> Example | 样例代码</h2>
|
||||
<form method="get">
|
||||
<text style="margin-left: 15px;"> </text>
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 161 KiB |
|
@ -64,7 +64,7 @@ var set_new_ghost(var* args, usize size, gc* ngc) {
|
|||
return nil;
|
||||
}
|
||||
f64 num = args[1].num();
|
||||
*((u32*)res.ghost().pointer) = static_cast<u32>(num);
|
||||
*(reinterpret_cast<u32*>(res.ghost().pointer)) = static_cast<u32>(num);
|
||||
std::cout << "set_new_ghost: successfully set ghost = " << num << "\n";
|
||||
return nil;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import.std.dylib;
|
||||
use std.dylib;
|
||||
|
||||
var _dl = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import.std.dylib;
|
||||
use std.dylib;
|
||||
|
||||
var (
|
||||
kbhit,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import.std.dylib;
|
||||
use std.dylib;
|
||||
|
||||
var _dl = dylib.dlopen("libmat."~(os.platform()=="windows"?"dll":"so"));
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import.std.dylib;
|
||||
use std.dylib;
|
||||
|
||||
var socket=func(){
|
||||
var lib=dylib.dlopen("libnasock"~(os.platform()=="windows"?".dll":".so"));
|
||||
|
|
|
@ -71,7 +71,7 @@ var nas_bind(var* args, usize size, gc* ngc) {
|
|||
server.sin_port = htons(args[2].num());
|
||||
return var::num(static_cast<double>(bind(
|
||||
args[0].num(),
|
||||
(sockaddr*)&server,
|
||||
reinterpret_cast<sockaddr*>(&server),
|
||||
sizeof(server)
|
||||
)));
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ var nas_connect(var* args, usize size, gc* ngc) {
|
|||
memcpy(&addr.sin_addr, entry->h_addr, entry->h_length);
|
||||
return var::num(static_cast<double>(connect(
|
||||
args[0].num(),
|
||||
(sockaddr*)&addr,
|
||||
reinterpret_cast<sockaddr*>(&addr),
|
||||
sizeof(sockaddr_in)
|
||||
)));
|
||||
}
|
||||
|
@ -110,9 +110,17 @@ var nas_accept(var* args, usize size, gc* ngc) {
|
|||
sockaddr_in client;
|
||||
int socklen = sizeof(sockaddr_in);
|
||||
#ifdef _WIN32
|
||||
int client_sd = accept(args[0].num(), (sockaddr*)&client, &socklen);
|
||||
int client_sd = accept(
|
||||
args[0].num(),
|
||||
reinterpret_cast<sockaddr*>(&client),
|
||||
&socklen
|
||||
);
|
||||
#else
|
||||
int client_sd = accept(args[0].num(), (sockaddr*)&client, (socklen_t*)&socklen);
|
||||
int client_sd = accept(
|
||||
args[0].num(),
|
||||
reinterpret_cast<sockaddr*>(&client),
|
||||
reinterpret_cast<socklen_t*>(&socklen)
|
||||
);
|
||||
#endif
|
||||
var res = ngc->temp = ngc->alloc(vm_hash);
|
||||
auto& hash = res.hash().elems;
|
||||
|
@ -159,7 +167,7 @@ var nas_sendto(var* args, usize size, gc* ngc) {
|
|||
args[3].str().c_str(),
|
||||
args[3].str().length(),
|
||||
args[4].num(),
|
||||
(sockaddr*)&addr,
|
||||
reinterpret_cast<sockaddr*>(&addr),
|
||||
sizeof(sockaddr_in)
|
||||
)));
|
||||
}
|
||||
|
@ -205,7 +213,7 @@ var nas_recvfrom(var* args, usize size, gc* ngc) {
|
|||
buf,
|
||||
args[1].num(),
|
||||
args[2].num(),
|
||||
(sockaddr*)&addr,
|
||||
reinterpret_cast<sockaddr*>(&addr),
|
||||
&socklen
|
||||
);
|
||||
#else
|
||||
|
@ -214,8 +222,8 @@ var nas_recvfrom(var* args, usize size, gc* ngc) {
|
|||
buf,
|
||||
args[1].num(),
|
||||
args[2].num(),
|
||||
(sockaddr*)&addr,
|
||||
(socklen_t*)&socklen
|
||||
reinterpret_cast<sockaddr*>(&addr),
|
||||
reinterpret_cast<socklen_t*>(&socklen)
|
||||
);
|
||||
#endif
|
||||
hash["size"] = var::num(static_cast<double>(recvsize));
|
||||
|
|
|
@ -4,6 +4,20 @@
|
|||
|
||||
namespace nasal {
|
||||
|
||||
bool ast_dumper::visit_use_stmt(use_stmt* node) {
|
||||
dump_indent();
|
||||
std::cout << "use" << format_location(node->get_location());
|
||||
push_indent();
|
||||
for(auto i : node->get_path()) {
|
||||
if (i==node->get_path().back()) {
|
||||
set_last();
|
||||
}
|
||||
i->accept(this);
|
||||
}
|
||||
pop_indent();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ast_dumper::visit_null_expr(null_expr* node) {
|
||||
dump_indent();
|
||||
std::cout << "null" << format_location(node->get_location());
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace nasal {
|
||||
|
||||
|
@ -41,6 +42,7 @@ private:
|
|||
}
|
||||
|
||||
public:
|
||||
bool visit_use_stmt(use_stmt*) override;
|
||||
bool visit_null_expr(null_expr*) override;
|
||||
bool visit_nil_expr(nil_expr*) override;
|
||||
bool visit_number_literal(number_literal*) override;
|
||||
|
|
|
@ -7,6 +7,13 @@ bool ast_visitor::visit_expr(expr* node) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ast_visitor::visit_use_stmt(use_stmt* node) {
|
||||
for(auto i : node->get_path()) {
|
||||
i->accept(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ast_visitor::visit_call(call* node) {
|
||||
node->accept(this);
|
||||
return true;
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace nasal {
|
|||
class ast_visitor {
|
||||
public:
|
||||
virtual bool visit_expr(expr*);
|
||||
virtual bool visit_use_stmt(use_stmt*);
|
||||
virtual bool visit_call(call*);
|
||||
virtual bool visit_null_expr(null_expr*);
|
||||
virtual bool visit_nil_expr(nil_expr*);
|
||||
|
|
|
@ -45,7 +45,7 @@ var builtin_cocreate(context* ctx, gc* ngc) {
|
|||
coroutine.ctx.top++;
|
||||
|
||||
// store old localr on stack
|
||||
coroutine.ctx.top[0] = var::addr((var*)nullptr);
|
||||
coroutine.ctx.top[0] = var::addr(nullptr);
|
||||
coroutine.ctx.top++;
|
||||
|
||||
// store old pc on stack
|
||||
|
|
|
@ -53,9 +53,9 @@ var builtin_dlopen(context* ctx, gc* ngc) {
|
|||
|
||||
// get "get" function, to get the register table
|
||||
#ifdef _WIN32
|
||||
void* register_table_get_function = (void*)GetProcAddress(
|
||||
void* register_table_get_function = reinterpret_cast<void*>(GetProcAddress(
|
||||
static_cast<HMODULE>(library_object.ghost().pointer), "get"
|
||||
);
|
||||
));
|
||||
#else
|
||||
void* register_table_get_function = dlsym(
|
||||
library_object.ghost().pointer, "get"
|
||||
|
|
|
@ -5,9 +5,6 @@ namespace nasal {
|
|||
const auto file_type_name = "file";
|
||||
|
||||
void filehandle_destructor(void* ptr) {
|
||||
if (static_cast<FILE*>(ptr)==stdin) {
|
||||
return;
|
||||
}
|
||||
fclose(static_cast<FILE*>(ptr));
|
||||
}
|
||||
|
||||
|
@ -207,6 +204,25 @@ var builtin_eof(context* ctx, gc* ngc) {
|
|||
));
|
||||
}
|
||||
|
||||
var builtin_stdin(context* ctx, gc* ngc) {
|
||||
auto file_descriptor = ngc->alloc(vm_obj);
|
||||
file_descriptor.ghost().set(file_type_name, nullptr, stdin);
|
||||
return file_descriptor;
|
||||
}
|
||||
|
||||
var builtin_stdout(context* ctx, gc* ngc) {
|
||||
auto file_descriptor = ngc->alloc(vm_obj);
|
||||
file_descriptor.ghost().set(file_type_name, nullptr, stdout);
|
||||
return file_descriptor;
|
||||
}
|
||||
|
||||
var builtin_stderr(context* ctx, gc* ngc) {
|
||||
auto file_descriptor = ngc->alloc(vm_obj);
|
||||
file_descriptor.ghost().set(file_type_name, nullptr, stderr);
|
||||
return file_descriptor;
|
||||
}
|
||||
|
||||
|
||||
nasal_builtin_table io_lib_native[] = {
|
||||
{"__readfile", builtin_readfile},
|
||||
{"__fout", builtin_fout},
|
||||
|
@ -220,6 +236,9 @@ nasal_builtin_table io_lib_native[] = {
|
|||
{"__readln", builtin_readln},
|
||||
{"__stat", builtin_stat},
|
||||
{"__eof", builtin_eof},
|
||||
{"__stdin", builtin_stdin},
|
||||
{"__stdout", builtin_stdout},
|
||||
{"__stderr", builtin_stderr},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
|
|
|
@ -32,6 +32,9 @@ var builtin_tell(context*, gc*);
|
|||
var builtin_readln(context*, gc*);
|
||||
var builtin_stat(context*, gc*);
|
||||
var builtin_eof(context*, gc*);
|
||||
var builtin_stdin(context*, gc*);
|
||||
var builtin_stdout(context*, gc*);
|
||||
var builtin_stderr(context*, gc*);
|
||||
|
||||
extern nasal_builtin_table io_lib_native[];
|
||||
|
||||
|
|
|
@ -7,6 +7,16 @@ void expr::accept(ast_visitor* visitor) {
|
|||
visitor->visit_expr(this);
|
||||
}
|
||||
|
||||
use_stmt::~use_stmt() {
|
||||
for(auto i : path) {
|
||||
delete i;
|
||||
}
|
||||
}
|
||||
|
||||
void use_stmt::accept(ast_visitor* visitor) {
|
||||
visitor->visit_use_stmt(this);
|
||||
}
|
||||
|
||||
void call::accept(ast_visitor* visitor) {
|
||||
visitor->visit_call(this);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace nasal {
|
|||
|
||||
enum class expr_type:u32 {
|
||||
ast_null = 0, // null node
|
||||
ast_use, // use statement
|
||||
ast_block, // code block
|
||||
ast_nil, // nil keyword
|
||||
ast_num, // number, basic value type
|
||||
|
@ -46,6 +47,7 @@ enum class expr_type:u32 {
|
|||
};
|
||||
|
||||
class ast_visitor;
|
||||
class identifier;
|
||||
class hash_pair;
|
||||
class parameter;
|
||||
class slice_vector;
|
||||
|
@ -77,6 +79,19 @@ public:
|
|||
virtual void accept(ast_visitor*);
|
||||
};
|
||||
|
||||
class use_stmt: public expr {
|
||||
private:
|
||||
std::vector<identifier*> path;
|
||||
|
||||
public:
|
||||
use_stmt(const span& location):
|
||||
expr(location, expr_type::ast_use) {}
|
||||
~use_stmt() override;
|
||||
void accept(ast_visitor*) override;
|
||||
void add_path(identifier* node) {path.push_back(node);}
|
||||
const auto& get_path() const {return path;}
|
||||
};
|
||||
|
||||
class call: public expr {
|
||||
public:
|
||||
call(const span& location, expr_type node_type):
|
||||
|
@ -121,7 +136,7 @@ public:
|
|||
string_literal(const span& location, const std::string& str):
|
||||
expr(location, expr_type::ast_str), content(str) {}
|
||||
~string_literal() override = default;
|
||||
const std::string get_content() const {return content;}
|
||||
const std::string& get_content() const {return content;}
|
||||
void accept(ast_visitor*) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -309,8 +309,8 @@ var builtin_substr(context* ctx, gc* ngc) {
|
|||
if (len.type!=vm_num || len.num()<0) {
|
||||
return nas_err("substr", "\"length\" should be number >= 0");
|
||||
}
|
||||
usize begin = (usize)beg.num();
|
||||
usize length = (usize)len.num();
|
||||
auto begin = static_cast<usize>(beg.num());
|
||||
auto length = static_cast<usize>(len.num());
|
||||
if (begin>=str.str().length()) {
|
||||
return nas_err("susbtr", "begin index out of range: "+std::to_string(begin));
|
||||
}
|
||||
|
@ -397,7 +397,7 @@ var builtin_chr(context* ctx, gc* ngc) {
|
|||
};
|
||||
auto num = static_cast<i32>(ctx->localr[1].num());
|
||||
if (0<=num && num<128) {
|
||||
return ngc->newstr((char)num);
|
||||
return ngc->newstr(static_cast<char>(num));
|
||||
} else if (128<=num && num<256) {
|
||||
return ngc->newstr(extend[num-128]);
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ void codegen::check_id_exist(identifier* node) {
|
|||
);
|
||||
}
|
||||
|
||||
void codegen::regist_num(const f64 num) {
|
||||
void codegen::regist_number(const f64 num) {
|
||||
if (const_number_map.count(num)) {
|
||||
return;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ void codegen::regist_num(const f64 num) {
|
|||
const_number_table.push_back(num);
|
||||
}
|
||||
|
||||
void codegen::regist_str(const std::string& str) {
|
||||
void codegen::regist_string(const std::string& str) {
|
||||
if (const_string_map.count(str)) {
|
||||
return;
|
||||
}
|
||||
|
@ -94,11 +94,11 @@ void codegen::find_symbol(code_block* node) {
|
|||
scope.insert(i.name);
|
||||
}
|
||||
// add symbol for codegen symbol check
|
||||
add_symbol(i.name);
|
||||
regist_symbol(i.name);
|
||||
}
|
||||
}
|
||||
|
||||
void codegen::add_symbol(const std::string& name) {
|
||||
void codegen::regist_symbol(const std::string& name) {
|
||||
if (local.empty()) {
|
||||
if (global.count(name)) {
|
||||
return;
|
||||
|
@ -150,25 +150,25 @@ void codegen::emit(u8 operation_code, u32 immediate_num, const span& location) {
|
|||
});
|
||||
}
|
||||
|
||||
void codegen::num_gen(number_literal* node) {
|
||||
void codegen::number_gen(number_literal* node) {
|
||||
f64 num = node->get_number();
|
||||
regist_num(num);
|
||||
regist_number(num);
|
||||
emit(op_pnum, const_number_map.at(num), node->get_location());
|
||||
}
|
||||
|
||||
void codegen::str_gen(string_literal* node) {
|
||||
void codegen::string_gen(string_literal* node) {
|
||||
const auto& str = node->get_content();
|
||||
regist_str(str);
|
||||
regist_string(str);
|
||||
emit(op_pstr, const_string_map.at(str), node->get_location());
|
||||
}
|
||||
|
||||
void codegen::bool_gen(bool_literal* node) {
|
||||
f64 num = node->get_flag()? 1:0;
|
||||
regist_num(num);
|
||||
regist_number(num);
|
||||
emit(op_pnum, const_number_map.at(num), node->get_location());
|
||||
}
|
||||
|
||||
void codegen::vec_gen(vector_expr* node) {
|
||||
void codegen::vector_gen(vector_expr* node) {
|
||||
for(auto child : node->get_elements()) {
|
||||
calc_gen(child);
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ void codegen::hash_gen(hash_expr* node) {
|
|||
for(auto child : node->get_members()) {
|
||||
calc_gen(child->get_value());
|
||||
const auto& field_name = child->get_name();
|
||||
regist_str(field_name);
|
||||
regist_string(field_name);
|
||||
emit(op_happ, const_string_map.at(field_name), child->get_location());
|
||||
}
|
||||
}
|
||||
|
@ -243,7 +243,7 @@ void codegen::func_gen(function* node) {
|
|||
tmp->get_location()
|
||||
);
|
||||
}
|
||||
regist_str(name);
|
||||
regist_string(name);
|
||||
switch(tmp->get_parameter_type()) {
|
||||
case parameter::param_type::normal_parameter:
|
||||
emit(op_para, const_string_map.at(name), tmp->get_location());
|
||||
|
@ -256,7 +256,7 @@ void codegen::func_gen(function* node) {
|
|||
emit(op_dyn, const_string_map.at(name), tmp->get_location());
|
||||
break;
|
||||
}
|
||||
add_symbol(name);
|
||||
regist_symbol(name);
|
||||
}
|
||||
|
||||
code[newf].num = code.size()+1; // entry
|
||||
|
@ -282,7 +282,7 @@ void codegen::func_gen(function* node) {
|
|||
while(local_symbol_find(arg)>=0) {
|
||||
arg = "0" + arg;
|
||||
}
|
||||
add_symbol(arg);
|
||||
regist_symbol(arg);
|
||||
|
||||
// generate code block
|
||||
in_foreach_loop_level.push_back(0);
|
||||
|
@ -307,20 +307,23 @@ void codegen::func_gen(function* node) {
|
|||
|
||||
void codegen::call_gen(call_expr* node) {
|
||||
calc_gen(node->get_first());
|
||||
if (code.back().op==op_callb) {
|
||||
if (code.size() && code.back().op==op_callb) {
|
||||
return;
|
||||
}
|
||||
for(auto i : node->get_calls()) {
|
||||
switch(i->get_type()) {
|
||||
case expr_type::ast_callh: call_hash_gen((call_hash*)i); break;
|
||||
case expr_type::ast_callv: call_vector_gen((call_vector*)i); break;
|
||||
case expr_type::ast_callf: call_func_gen((call_function*)i); break;
|
||||
case expr_type::ast_callh:
|
||||
call_hash_gen(reinterpret_cast<call_hash*>(i)); break;
|
||||
case expr_type::ast_callv:
|
||||
call_vector_gen(reinterpret_cast<call_vector*>(i)); break;
|
||||
case expr_type::ast_callf:
|
||||
call_func_gen(reinterpret_cast<call_function*>(i)); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void codegen::call_id(identifier* node) {
|
||||
void codegen::call_identifier(identifier* node) {
|
||||
const auto& name = node->get_name();
|
||||
if (native_function_mapper.count(name)) {
|
||||
emit(op_callb,
|
||||
|
@ -349,10 +352,12 @@ void codegen::call_id(identifier* node) {
|
|||
return;
|
||||
}
|
||||
die("undefined symbol \"" + name + "\"", node->get_location());
|
||||
// generation failed, put a push nil operand here to fill the space
|
||||
emit(op_pnil, index, node->get_location());
|
||||
}
|
||||
|
||||
void codegen::call_hash_gen(call_hash* node) {
|
||||
regist_str(node->get_field());
|
||||
regist_string(node->get_field());
|
||||
emit(op_callh, const_string_map.at(node->get_field()), node->get_location());
|
||||
}
|
||||
|
||||
|
@ -383,9 +388,10 @@ void codegen::call_func_gen(call_function* node) {
|
|||
node->get_argument()[0]->get_type()==expr_type::ast_pair) {
|
||||
emit(op_newh, 0, node->get_location());
|
||||
for(auto child : node->get_argument()) {
|
||||
calc_gen(((hash_pair*)child)->get_value());
|
||||
const auto& field_name = ((hash_pair*)child)->get_name();
|
||||
regist_str(field_name);
|
||||
auto pair_node = reinterpret_cast<hash_pair*>(child);
|
||||
calc_gen(pair_node->get_value());
|
||||
const auto& field_name = pair_node->get_name();
|
||||
regist_string(field_name);
|
||||
emit(op_happ, const_string_map.at(field_name), child->get_location());
|
||||
}
|
||||
emit(op_callfh, 0, node->get_location());
|
||||
|
@ -413,7 +419,7 @@ void codegen::mcall(expr* node) {
|
|||
}
|
||||
// generate symbol call if node is just ast_id and return
|
||||
if (node->get_type()==expr_type::ast_id) {
|
||||
mcall_id((identifier*)node);
|
||||
mcall_identifier(reinterpret_cast<identifier*>(node));
|
||||
return;
|
||||
}
|
||||
// generate call expression until the last sub-node
|
||||
|
@ -422,17 +428,22 @@ void codegen::mcall(expr* node) {
|
|||
for(usize i = 0; i<call_node->get_calls().size()-1; ++i) {
|
||||
auto tmp = call_node->get_calls()[i];
|
||||
switch(tmp->get_type()) {
|
||||
case expr_type::ast_callh: call_hash_gen((call_hash*)tmp); break;
|
||||
case expr_type::ast_callv: call_vector_gen((call_vector*)tmp); break;
|
||||
case expr_type::ast_callf: call_func_gen((call_function*)tmp); break;
|
||||
case expr_type::ast_callh:
|
||||
call_hash_gen(reinterpret_cast<call_hash*>(tmp)); break;
|
||||
case expr_type::ast_callv:
|
||||
call_vector_gen(reinterpret_cast<call_vector*>(tmp)); break;
|
||||
case expr_type::ast_callf:
|
||||
call_func_gen(reinterpret_cast<call_function*>(tmp)); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
// the last sub-node will be used to generate memory call expression
|
||||
auto tmp = call_node->get_calls().back();
|
||||
switch(tmp->get_type()) {
|
||||
case expr_type::ast_callh: mcall_hash((call_hash*)tmp); break;
|
||||
case expr_type::ast_callv: mcall_vec((call_vector*)tmp); break;
|
||||
case expr_type::ast_callh:
|
||||
mcall_hash(reinterpret_cast<call_hash*>(tmp)); break;
|
||||
case expr_type::ast_callv:
|
||||
mcall_vec(reinterpret_cast<call_vector*>(tmp)); break;
|
||||
case expr_type::ast_callf:
|
||||
die("bad left-value: function call", tmp->get_location()); break;
|
||||
default:
|
||||
|
@ -440,7 +451,7 @@ void codegen::mcall(expr* node) {
|
|||
}
|
||||
}
|
||||
|
||||
void codegen::mcall_id(identifier* node) {
|
||||
void codegen::mcall_identifier(identifier* node) {
|
||||
const auto& name = node->get_name();
|
||||
if (native_function_mapper.count(name)) {
|
||||
die("cannot modify native function", node->get_location());
|
||||
|
@ -478,7 +489,7 @@ void codegen::mcall_vec(call_vector* node) {
|
|||
}
|
||||
|
||||
void codegen::mcall_hash(call_hash* node) {
|
||||
regist_str(node->get_field());
|
||||
regist_string(node->get_field());
|
||||
emit(op_mcallh, const_string_map.at(node->get_field()), node->get_location());
|
||||
}
|
||||
|
||||
|
@ -502,14 +513,20 @@ void codegen::multi_def(definition_expr* node) {
|
|||
// (var a,b,c) = (c,b,a);
|
||||
if (node->get_tuple()) {
|
||||
auto& vals = node->get_tuple()->get_elements();
|
||||
if (identifiers.size()<vals.size()) {
|
||||
die("lack values in multi-definition",
|
||||
if (identifiers.size()>vals.size()) {
|
||||
die("lack values in multi-definition, expect " +
|
||||
std::to_string(identifiers.size()) + " but get " +
|
||||
std::to_string(vals.size()),
|
||||
node->get_tuple()->get_location()
|
||||
);
|
||||
} else if (identifiers.size()>vals.size()) {
|
||||
die("too many values in multi-definition",
|
||||
return;
|
||||
} else if (identifiers.size()<vals.size()) {
|
||||
die("too many values in multi-definition, expect " +
|
||||
std::to_string(identifiers.size()) + " but get " +
|
||||
std::to_string(vals.size()),
|
||||
node->get_tuple()->get_location()
|
||||
);
|
||||
return;
|
||||
}
|
||||
for(usize i = 0; i<size; ++i) {
|
||||
calc_gen(vals[i]);
|
||||
|
@ -532,7 +549,7 @@ void codegen::multi_def(definition_expr* node) {
|
|||
emit(op_pop, 0, node->get_location());
|
||||
}
|
||||
|
||||
void codegen::def_gen(definition_expr* node) {
|
||||
void codegen::definition_gen(definition_expr* node) {
|
||||
if (node->get_variable_name() && node->get_tuple()) {
|
||||
die("cannot accept too many values", node->get_value()->get_location());
|
||||
}
|
||||
|
@ -554,8 +571,9 @@ void codegen::assignment_expression(assignment_expr* node) {
|
|||
if (node->get_right()->get_type()!=expr_type::ast_num) {
|
||||
emit(op_addeq, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
auto num = reinterpret_cast<number_literal*>(node->get_right())
|
||||
->get_number();
|
||||
regist_number(num);
|
||||
emit(op_addeqc, const_number_map[num], node->get_location());
|
||||
}
|
||||
break;
|
||||
|
@ -567,8 +585,9 @@ void codegen::assignment_expression(assignment_expr* node) {
|
|||
if (node->get_right()->get_type()!=expr_type::ast_num) {
|
||||
emit(op_subeq, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
auto num = reinterpret_cast<number_literal*>(node->get_right())
|
||||
->get_number();
|
||||
regist_number(num);
|
||||
emit(op_subeqc, const_number_map[num], node->get_location());
|
||||
}
|
||||
break;
|
||||
|
@ -580,8 +599,9 @@ void codegen::assignment_expression(assignment_expr* node) {
|
|||
if (node->get_right()->get_type()!=expr_type::ast_num) {
|
||||
emit(op_muleq, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
auto num = reinterpret_cast<number_literal*>(node->get_right())
|
||||
->get_number();
|
||||
regist_number(num);
|
||||
emit(op_muleqc, const_number_map[num], node->get_location());
|
||||
}
|
||||
break;
|
||||
|
@ -593,8 +613,9 @@ void codegen::assignment_expression(assignment_expr* node) {
|
|||
if (node->get_right()->get_type()!=expr_type::ast_num) {
|
||||
emit(op_diveq, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
auto num = reinterpret_cast<number_literal*>(node->get_right())
|
||||
->get_number();
|
||||
regist_number(num);
|
||||
emit(op_diveqc, const_number_map[num], node->get_location());
|
||||
}
|
||||
break;
|
||||
|
@ -606,8 +627,9 @@ void codegen::assignment_expression(assignment_expr* node) {
|
|||
if (node->get_right()->get_type()!=expr_type::ast_str) {
|
||||
emit(op_lnkeq, 0, node->get_location());
|
||||
} else {
|
||||
const auto& str = ((string_literal*)node->get_right())->get_content();
|
||||
regist_str(str);
|
||||
const auto& str = reinterpret_cast<string_literal*>(
|
||||
node->get_right())->get_content();
|
||||
regist_string(str);
|
||||
emit(op_lnkeqc, const_string_map[str], node->get_location());
|
||||
}
|
||||
break;
|
||||
|
@ -647,7 +669,7 @@ void codegen::gen_assignment_equal_statement(assignment_expr* node) {
|
|||
// generate symbol load
|
||||
calc_gen(node->get_right());
|
||||
// get memory space of left identifier
|
||||
mcall_id((identifier*)node->get_left());
|
||||
mcall_identifier(reinterpret_cast<identifier*>(node->get_left()));
|
||||
// check memory get operand type and replace it with load operand
|
||||
switch(code.back().op) {
|
||||
case op_mcallg: code.back().op = op_loadg; break;
|
||||
|
@ -697,21 +719,40 @@ void codegen::assignment_statement(assignment_expr* node) {
|
|||
}
|
||||
|
||||
void codegen::multi_assign_gen(multi_assign* node) {
|
||||
if (node->get_value()->get_type()==expr_type::ast_tuple &&
|
||||
node->get_tuple()->get_elements().size()<((tuple_expr*)node->get_value())->get_elements().size()) {
|
||||
die("lack values in multi-assignment", node->get_value()->get_location());
|
||||
} else if (node->get_value()->get_type()==expr_type::ast_tuple &&
|
||||
node->get_tuple()->get_elements().size()>((tuple_expr*)node->get_value())->get_elements().size()) {
|
||||
die("too many values in multi-assignment", node->get_value()->get_location());
|
||||
auto tuple_node = node->get_tuple();
|
||||
auto value_node = node->get_value();
|
||||
if (value_node->get_type()==expr_type::ast_tuple) {
|
||||
auto tuple_size = tuple_node->get_elements().size();
|
||||
auto value_size = reinterpret_cast<tuple_expr*>(value_node)
|
||||
->get_elements().size();
|
||||
if (tuple_size>value_size) {
|
||||
die(
|
||||
"lack value(s) in multi-assignment, expect " +
|
||||
std::to_string(tuple_size) + " but get " +
|
||||
std::to_string(value_size),
|
||||
value_node->get_location()
|
||||
);
|
||||
return;
|
||||
} else if (tuple_size<value_size) {
|
||||
die(
|
||||
"too many values in multi-assignment, expect " +
|
||||
std::to_string(tuple_size) + " but get " +
|
||||
std::to_string(value_size),
|
||||
value_node->get_location()
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
i32 size = node->get_tuple()->get_elements().size();
|
||||
i32 size = tuple_node->get_elements().size();
|
||||
// generate multiple assignment: (a, b, c) = (1, 2, 3);
|
||||
if (node->get_value()->get_type()==expr_type::ast_tuple) {
|
||||
if (value_node->get_type()==expr_type::ast_tuple) {
|
||||
const auto& value_tuple = reinterpret_cast<tuple_expr*>(value_node)
|
||||
->get_elements();
|
||||
for(i32 i = size-1; i>=0; --i) {
|
||||
calc_gen(((tuple_expr*)node->get_value())->get_elements()[i]);
|
||||
calc_gen(value_tuple[i]);
|
||||
}
|
||||
auto& tuple = node->get_tuple()->get_elements();
|
||||
auto& tuple = tuple_node->get_elements();
|
||||
for(i32 i = 0; i<size; ++i) {
|
||||
mcall(tuple[i]);
|
||||
// use load operands to avoid meq's pop operand
|
||||
|
@ -722,10 +763,10 @@ void codegen::multi_assign_gen(multi_assign* node) {
|
|||
}
|
||||
|
||||
// generate multiple assignment: (a, b, c) = [1, 2, 3];
|
||||
calc_gen(node->get_value());
|
||||
auto& tuple = node->get_tuple()->get_elements();
|
||||
calc_gen(value_node);
|
||||
auto& tuple = tuple_node->get_elements();
|
||||
for(i32 i = 0; i<size; ++i) {
|
||||
emit(op_callvi, i, node->get_value()->get_location());
|
||||
emit(op_callvi, i, value_node->get_location());
|
||||
mcall(tuple[i]);
|
||||
// use load operands to avoid meq's pop operand
|
||||
// and this operation changes local and global value directly
|
||||
|
@ -775,9 +816,12 @@ void codegen::loop_gen(expr* node) {
|
|||
break_ptr.push_front({});
|
||||
|
||||
switch(node->get_type()) {
|
||||
case expr_type::ast_while: while_gen((while_expr*)node); break;
|
||||
case expr_type::ast_for: for_gen((for_expr*)node); break;
|
||||
case expr_type::ast_forei: forei_gen((forei_expr*)node); break;
|
||||
case expr_type::ast_while:
|
||||
while_gen(reinterpret_cast<while_expr*>(node)); break;
|
||||
case expr_type::ast_for:
|
||||
for_gen(reinterpret_cast<for_expr*>(node)); break;
|
||||
case expr_type::ast_forei:
|
||||
forei_gen(reinterpret_cast<forei_expr*>(node)); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
@ -809,7 +853,7 @@ void codegen::for_gen(for_expr* node) {
|
|||
statement_generation(node->get_initial());
|
||||
usize jmp_place = code.size();
|
||||
if (node->get_condition()->get_type()==expr_type::ast_null) {
|
||||
regist_num(1);
|
||||
regist_number(1);
|
||||
emit(op_pnum, const_number_map.at(1), node->get_condition()->get_location());
|
||||
} else {
|
||||
calc_gen(node->get_condition());
|
||||
|
@ -873,11 +917,11 @@ void codegen::statement_generation(expr* node) {
|
|||
switch(node->get_type()) {
|
||||
case expr_type::ast_null: break;
|
||||
case expr_type::ast_def:
|
||||
def_gen((definition_expr*)node); break;
|
||||
definition_gen(reinterpret_cast<definition_expr*>(node)); break;
|
||||
case expr_type::ast_multi_assign:
|
||||
multi_assign_gen((multi_assign*)node); break;
|
||||
multi_assign_gen(reinterpret_cast<multi_assign*>(node)); break;
|
||||
case expr_type::ast_assign:
|
||||
assignment_statement((assignment_expr*)node); break;
|
||||
assignment_statement(reinterpret_cast<assignment_expr*>(node)); break;
|
||||
case expr_type::ast_nil:
|
||||
case expr_type::ast_num:
|
||||
case expr_type::ast_str:
|
||||
|
@ -936,7 +980,7 @@ void codegen::and_gen(binary_operator* node) {
|
|||
void codegen::unary_gen(unary_operator* node) {
|
||||
// generate optimized result
|
||||
if (node->get_optimized_number()) {
|
||||
num_gen(node->get_optimized_number());
|
||||
number_gen(node->get_optimized_number());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -954,11 +998,11 @@ void codegen::unary_gen(unary_operator* node) {
|
|||
void codegen::binary_gen(binary_operator* node) {
|
||||
// generate optimized result
|
||||
if (node->get_optimized_number()) {
|
||||
num_gen(node->get_optimized_number());
|
||||
number_gen(node->get_optimized_number());
|
||||
return;
|
||||
}
|
||||
if (node->get_optimized_string()) {
|
||||
str_gen(node->get_optimized_string());
|
||||
string_gen(node->get_optimized_string());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1002,8 +1046,9 @@ void codegen::binary_gen(binary_operator* node) {
|
|||
calc_gen(node->get_right());
|
||||
emit(op_add, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
auto num = reinterpret_cast<number_literal*>(node->get_right())
|
||||
->get_number();
|
||||
regist_number(num);
|
||||
emit(op_addc, const_number_map.at(num), node->get_location());
|
||||
}
|
||||
return;
|
||||
|
@ -1013,8 +1058,9 @@ void codegen::binary_gen(binary_operator* node) {
|
|||
calc_gen(node->get_right());
|
||||
emit(op_sub, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
auto num = reinterpret_cast<number_literal*>(node->get_right())
|
||||
->get_number();
|
||||
regist_number(num);
|
||||
emit(op_subc, const_number_map.at(num), node->get_location());
|
||||
}
|
||||
return;
|
||||
|
@ -1024,8 +1070,9 @@ void codegen::binary_gen(binary_operator* node) {
|
|||
calc_gen(node->get_right());
|
||||
emit(op_mul, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
auto num = reinterpret_cast<number_literal*>(node->get_right())
|
||||
->get_number();
|
||||
regist_number(num);
|
||||
emit(op_mulc, const_number_map.at(num), node->get_location());
|
||||
}
|
||||
return;
|
||||
|
@ -1035,8 +1082,9 @@ void codegen::binary_gen(binary_operator* node) {
|
|||
calc_gen(node->get_right());
|
||||
emit(op_div, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
auto num = reinterpret_cast<number_literal*>(node->get_right())
|
||||
->get_number();
|
||||
regist_number(num);
|
||||
emit(op_divc, const_number_map.at(num), node->get_location());
|
||||
}
|
||||
return;
|
||||
|
@ -1046,8 +1094,9 @@ void codegen::binary_gen(binary_operator* node) {
|
|||
calc_gen(node->get_right());
|
||||
emit(op_lnk, 0, node->get_location());
|
||||
} else {
|
||||
const auto& str = ((string_literal*)node->get_right())->get_content();
|
||||
regist_str(str);
|
||||
const auto& str = reinterpret_cast<string_literal*>(
|
||||
node->get_right())->get_content();
|
||||
regist_string(str);
|
||||
emit(op_lnkc, const_string_map.at(str), node->get_location());
|
||||
}
|
||||
break;
|
||||
|
@ -1057,8 +1106,9 @@ void codegen::binary_gen(binary_operator* node) {
|
|||
calc_gen(node->get_right());
|
||||
emit(op_less, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
auto num = reinterpret_cast<number_literal*>(node->get_right())
|
||||
->get_number();
|
||||
regist_number(num);
|
||||
emit(op_lessc, const_number_map.at(num), node->get_location());
|
||||
}
|
||||
return;
|
||||
|
@ -1068,8 +1118,9 @@ void codegen::binary_gen(binary_operator* node) {
|
|||
calc_gen(node->get_right());
|
||||
emit(op_leq, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
auto num = reinterpret_cast<number_literal*>(node->get_right())
|
||||
->get_number();
|
||||
regist_number(num);
|
||||
emit(op_leqc, const_number_map.at(num), node->get_location());
|
||||
}
|
||||
return;
|
||||
|
@ -1079,8 +1130,9 @@ void codegen::binary_gen(binary_operator* node) {
|
|||
calc_gen(node->get_right());
|
||||
emit(op_grt, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
auto num = reinterpret_cast<number_literal*>(node->get_right())
|
||||
->get_number();
|
||||
regist_number(num);
|
||||
emit(op_grtc, const_number_map.at(num), node->get_location());
|
||||
}
|
||||
return;
|
||||
|
@ -1090,8 +1142,9 @@ void codegen::binary_gen(binary_operator* node) {
|
|||
calc_gen(node->get_right());
|
||||
emit(op_geq, 0, node->get_location());
|
||||
} else {
|
||||
auto num = ((number_literal*)node->get_right())->get_number();
|
||||
regist_num(num);
|
||||
auto num = reinterpret_cast<number_literal*>(node->get_right())
|
||||
->get_number();
|
||||
regist_number(num);
|
||||
emit(op_geqc, const_number_map.at(num), node->get_location());
|
||||
}
|
||||
return;
|
||||
|
@ -1116,33 +1169,38 @@ void codegen::calc_gen(expr* node) {
|
|||
case expr_type::ast_nil:
|
||||
emit(op_pnil, 0, node->get_location()); break;
|
||||
case expr_type::ast_num:
|
||||
num_gen((number_literal*)node); break;
|
||||
number_gen(reinterpret_cast<number_literal*>(node)); break;
|
||||
case expr_type::ast_str:
|
||||
str_gen((string_literal*)node); break;
|
||||
string_gen(reinterpret_cast<string_literal*>(node)); break;
|
||||
case expr_type::ast_id:
|
||||
call_id((identifier*)node); break;
|
||||
call_identifier(reinterpret_cast<identifier*>(node)); break;
|
||||
case expr_type::ast_bool:
|
||||
bool_gen((bool_literal*)node); break;
|
||||
bool_gen(reinterpret_cast<bool_literal*>(node)); break;
|
||||
case expr_type::ast_vec:
|
||||
vec_gen((vector_expr*)node); break;
|
||||
vector_gen(reinterpret_cast<vector_expr*>(node)); break;
|
||||
case expr_type::ast_hash:
|
||||
hash_gen((hash_expr*)node); break;
|
||||
hash_gen(reinterpret_cast<hash_expr*>(node)); break;
|
||||
case expr_type::ast_func:
|
||||
func_gen((function*)node); break;
|
||||
func_gen(reinterpret_cast<function*>(node)); break;
|
||||
case expr_type::ast_call:
|
||||
call_gen((call_expr*)node); break;
|
||||
call_gen(reinterpret_cast<call_expr*>(node)); break;
|
||||
case expr_type::ast_assign:
|
||||
assignment_expression((assignment_expr*)node); break;
|
||||
assignment_expression(
|
||||
reinterpret_cast<assignment_expr*>(node)
|
||||
);
|
||||
break;
|
||||
case expr_type::ast_ternary:
|
||||
trino_gen((ternary_operator*)node); break;
|
||||
trino_gen(reinterpret_cast<ternary_operator*>(node)); break;
|
||||
case expr_type::ast_unary:
|
||||
unary_gen((unary_operator*)node); break;
|
||||
unary_gen(reinterpret_cast<unary_operator*>(node)); break;
|
||||
case expr_type::ast_binary:
|
||||
binary_gen((binary_operator*)node); break;
|
||||
binary_gen(reinterpret_cast<binary_operator*>(node)); break;
|
||||
case expr_type::ast_def:
|
||||
// definition in calculation only should be single def
|
||||
single_def((definition_expr*)node);
|
||||
call_id(((definition_expr*)node)->get_variable_name());
|
||||
single_def(reinterpret_cast<definition_expr*>(node));
|
||||
call_identifier(
|
||||
(reinterpret_cast<definition_expr*>(node))->get_variable_name()
|
||||
);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
@ -1150,11 +1208,16 @@ void codegen::calc_gen(expr* node) {
|
|||
|
||||
void codegen::repl_mode_info_output_gen(expr* node) {
|
||||
switch(node->get_type()) {
|
||||
case expr_type::ast_id: call_id((identifier*)node); break;
|
||||
case expr_type::ast_nil: emit(op_pnil, 0, node->get_location()); break;
|
||||
case expr_type::ast_num: num_gen((number_literal*)node); break;
|
||||
case expr_type::ast_str: str_gen((string_literal*)node); break;
|
||||
case expr_type::ast_bool: bool_gen((bool_literal*)node); break;
|
||||
case expr_type::ast_id:
|
||||
call_identifier(reinterpret_cast<identifier*>(node)); break;
|
||||
case expr_type::ast_nil:
|
||||
emit(op_pnil, 0, node->get_location()); break;
|
||||
case expr_type::ast_num:
|
||||
number_gen(reinterpret_cast<number_literal*>(node)); break;
|
||||
case expr_type::ast_str:
|
||||
string_gen(reinterpret_cast<string_literal*>(node)); break;
|
||||
case expr_type::ast_bool:
|
||||
bool_gen(reinterpret_cast<bool_literal*>(node)); break;
|
||||
default: return;
|
||||
}
|
||||
// generate repl output operand
|
||||
|
@ -1164,26 +1227,41 @@ void codegen::repl_mode_info_output_gen(expr* node) {
|
|||
}
|
||||
|
||||
void codegen::block_gen(code_block* node) {
|
||||
bool is_use_statement = true;
|
||||
for(auto tmp : node->get_expressions()) {
|
||||
if (tmp->get_type()!=expr_type::ast_use) {
|
||||
is_use_statement = false;
|
||||
}
|
||||
switch(tmp->get_type()) {
|
||||
case expr_type::ast_use:
|
||||
if (!local.empty()) {
|
||||
die("module import is not allowed here.",
|
||||
tmp->get_location()
|
||||
);
|
||||
} else if (!is_use_statement) {
|
||||
die("module import should be used at the top of the file.",
|
||||
tmp->get_location()
|
||||
);
|
||||
}
|
||||
break;
|
||||
case expr_type::ast_null: break;
|
||||
case expr_type::ast_id:
|
||||
if (need_repl_output) {
|
||||
if (need_repl_output && local.empty()) {
|
||||
repl_mode_info_output_gen(tmp);
|
||||
} else {
|
||||
check_id_exist((identifier*)tmp);
|
||||
check_id_exist(reinterpret_cast<identifier*>(tmp));
|
||||
}
|
||||
break;
|
||||
case expr_type::ast_nil:
|
||||
case expr_type::ast_num:
|
||||
case expr_type::ast_str:
|
||||
case expr_type::ast_bool:
|
||||
if (need_repl_output) {
|
||||
if (need_repl_output && local.empty()) {
|
||||
repl_mode_info_output_gen(tmp);
|
||||
}
|
||||
break;
|
||||
case expr_type::ast_cond:
|
||||
cond_gen((condition_expr*)tmp); break;
|
||||
cond_gen(reinterpret_cast<condition_expr*>(tmp)); break;
|
||||
case expr_type::ast_continue:
|
||||
continue_ptr.front().push_back(code.size());
|
||||
emit(op_jmp, 0, tmp->get_location());
|
||||
|
@ -1208,7 +1286,7 @@ void codegen::block_gen(code_block* node) {
|
|||
case expr_type::ast_multi_assign:
|
||||
statement_generation(tmp); break;
|
||||
case expr_type::ast_ret:
|
||||
ret_gen((return_expr*)tmp); break;
|
||||
ret_gen(reinterpret_cast<return_expr*>(tmp)); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
@ -1231,9 +1309,9 @@ const error& codegen::compile(parse& parse, linker& import, bool repl_flag) {
|
|||
in_foreach_loop_level.push_back(0);
|
||||
|
||||
// add special symbol globals, which is a hash stores all global variables
|
||||
add_symbol("globals");
|
||||
regist_symbol("globals");
|
||||
// add special symbol arg here, which is used to store command line args
|
||||
add_symbol("arg");
|
||||
regist_symbol("arg");
|
||||
|
||||
// search global symbols first
|
||||
find_symbol(parse.tree());
|
||||
|
|
|
@ -78,34 +78,34 @@ private:
|
|||
err.err("code", loc, info);
|
||||
}
|
||||
|
||||
void regist_num(const f64);
|
||||
void regist_str(const std::string&);
|
||||
void regist_number(const f64);
|
||||
void regist_string(const std::string&);
|
||||
void find_symbol(code_block*);
|
||||
void add_symbol(const std::string&);
|
||||
void regist_symbol(const std::string&);
|
||||
i32 local_symbol_find(const std::string&);
|
||||
i32 global_symbol_find(const std::string&);
|
||||
i32 upvalue_symbol_find(const std::string&);
|
||||
|
||||
void emit(u8, u32, const span&);
|
||||
|
||||
void num_gen(number_literal*);
|
||||
void str_gen(string_literal*);
|
||||
void number_gen(number_literal*);
|
||||
void string_gen(string_literal*);
|
||||
void bool_gen(bool_literal*);
|
||||
void vec_gen(vector_expr*);
|
||||
void vector_gen(vector_expr*);
|
||||
void hash_gen(hash_expr*);
|
||||
void func_gen(function*);
|
||||
void call_gen(call_expr*);
|
||||
void call_id(identifier*);
|
||||
void call_identifier(identifier*);
|
||||
void call_hash_gen(call_hash*);
|
||||
void call_vector_gen(call_vector*);
|
||||
void call_func_gen(call_function*);
|
||||
void mcall(expr*);
|
||||
void mcall_id(identifier*);
|
||||
void mcall_identifier(identifier*);
|
||||
void mcall_vec(call_vector*);
|
||||
void mcall_hash(call_hash*);
|
||||
void multi_def(definition_expr*);
|
||||
void single_def(definition_expr*);
|
||||
void def_gen(definition_expr*);
|
||||
void definition_gen(definition_expr*);
|
||||
void assignment_expression(assignment_expr*);
|
||||
void gen_assignment_equal_statement(assignment_expr*);
|
||||
void replace_left_assignment_with_load(const span&);
|
||||
|
|
|
@ -2,123 +2,122 @@
|
|||
#include "symbol_finder.h"
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace nasal {
|
||||
|
||||
linker::linker():
|
||||
show_path(false), lib_loaded(false),
|
||||
this_file(""), lib_path("") {
|
||||
char sep = is_windows()? ';':':';
|
||||
std::string PATH = getenv("PATH");
|
||||
usize last = 0, pos = PATH.find(sep, 0);
|
||||
while(pos!=std::string::npos) {
|
||||
std::string dirpath = PATH.substr(last, pos-last);
|
||||
linker::linker(): show_path_flag(false), library_loaded(false), this_file("") {
|
||||
const auto seperator= is_windows()? ';':':';
|
||||
const auto PATH = std::string(getenv("PATH"));
|
||||
usize last = 0, position = PATH.find(seperator, 0);
|
||||
while(position!=std::string::npos) {
|
||||
std::string dirpath = PATH.substr(last, position-last);
|
||||
if (dirpath.length()) {
|
||||
envpath.push_back(dirpath);
|
||||
}
|
||||
last = pos+1;
|
||||
pos = PATH.find(sep, last);
|
||||
last = position+1;
|
||||
position = PATH.find(seperator, last);
|
||||
}
|
||||
if (last!=PATH.length()) {
|
||||
envpath.push_back(PATH.substr(last));
|
||||
}
|
||||
}
|
||||
|
||||
std::string linker::get_path(call_expr* node) {
|
||||
if (node->get_calls()[0]->get_type()==expr_type::ast_callf) {
|
||||
auto tmp = (call_function*)node->get_calls()[0];
|
||||
return ((string_literal*)tmp->get_argument()[0])->get_content();
|
||||
std::string linker::get_path(expr* node) {
|
||||
if (node->get_type()==expr_type::ast_use) {
|
||||
auto file_relative_path = std::string("");
|
||||
const auto& path = reinterpret_cast<use_stmt*>(node)->get_path();
|
||||
for(auto i : path) {
|
||||
file_relative_path += i->get_name();
|
||||
if (i!=path.back()) {
|
||||
file_relative_path += (is_windows()? "\\":"/");
|
||||
}
|
||||
auto fpath = std::string(".");
|
||||
for(auto i : node->get_calls()) {
|
||||
fpath += (is_windows()? "\\":"/") + ((call_hash*)i)->get_field();
|
||||
}
|
||||
return fpath + ".nas";
|
||||
return file_relative_path + ".nas";
|
||||
}
|
||||
auto call_node = reinterpret_cast<call_expr*>(node);
|
||||
auto arguments = reinterpret_cast<call_function*>(call_node->get_calls()[0]);
|
||||
auto content = reinterpret_cast<string_literal*>(arguments->get_argument()[0]);
|
||||
return content->get_content();
|
||||
}
|
||||
|
||||
std::string linker::find_file(
|
||||
std::string linker::find_real_file_path(
|
||||
const std::string& filename, const span& location) {
|
||||
// first add file name itself into the file path
|
||||
std::vector<std::string> fpath = {filename};
|
||||
std::vector<std::string> path_list = {filename};
|
||||
|
||||
// generate search path from environ path
|
||||
for(const auto& p : envpath) {
|
||||
fpath.push_back(p + (is_windows()? "\\":"/") + filename);
|
||||
path_list.push_back(p + (is_windows()? "\\":"/") + filename);
|
||||
}
|
||||
|
||||
// search file
|
||||
for(const auto& i : fpath) {
|
||||
if (access(i.c_str(), F_OK)!=-1) {
|
||||
return i;
|
||||
for(const auto& path : path_list) {
|
||||
if (access(path.c_str(), F_OK)!=-1) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
// we will find lib.nas in nasal std directory
|
||||
if (filename=="lib.nas") {
|
||||
return is_windows()?
|
||||
find_file("std\\lib.nas", location):
|
||||
find_file("std/lib.nas", location);
|
||||
find_real_file_path("std\\lib.nas", location):
|
||||
find_real_file_path("std/lib.nas", location);
|
||||
}
|
||||
if (!show_path) {
|
||||
if (!show_path_flag) {
|
||||
err.err("link",
|
||||
"in <" + location.file + ">: " +
|
||||
"cannot find file <" + filename + ">, " +
|
||||
"use <-d> to get detail search path");
|
||||
"use <-d> to get detail search path"
|
||||
);
|
||||
return "";
|
||||
}
|
||||
std::string paths = "";
|
||||
for(const auto& i : fpath) {
|
||||
paths += " -> " + i + "\n";
|
||||
auto path_list_info = std::string("");
|
||||
for(const auto& path : path_list) {
|
||||
path_list_info += " -> " + path + "\n";
|
||||
}
|
||||
err.err("link",
|
||||
"in <" + location.file + ">: " +
|
||||
"cannot find file <" + filename + "> in these paths:\n" + paths);
|
||||
"cannot find file <" + filename +
|
||||
"> in these paths:\n" + path_list_info
|
||||
);
|
||||
return "";
|
||||
}
|
||||
|
||||
bool linker::import_check(expr* node) {
|
||||
/*
|
||||
call
|
||||
|_id:import
|
||||
|_callh:std
|
||||
|_callh:file
|
||||
*/
|
||||
if (node->get_type()!=expr_type::ast_call) {
|
||||
return false;
|
||||
}
|
||||
auto tmp = (call_expr*)node;
|
||||
if (tmp->get_first()->get_type()!=expr_type::ast_id) {
|
||||
return false;
|
||||
}
|
||||
if (((identifier*)tmp->get_first())->get_name()!="import") {
|
||||
return false;
|
||||
}
|
||||
if (!tmp->get_calls().size()) {
|
||||
return false;
|
||||
}
|
||||
// import.xxx.xxx;
|
||||
if (tmp->get_calls()[0]->get_type()==expr_type::ast_callh) {
|
||||
for(auto i : tmp->get_calls()) {
|
||||
if (i->get_type()!=expr_type::ast_callh) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (node->get_type()==expr_type::ast_use) {
|
||||
return true;
|
||||
}
|
||||
// import("xxx");
|
||||
if (tmp->get_calls().size()!=1) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
call
|
||||
|_id:import
|
||||
|_call_func
|
||||
|_string:'filename'
|
||||
*/
|
||||
if (tmp->get_calls()[0]->get_type()!=expr_type::ast_callf) {
|
||||
if (node->get_type()!=expr_type::ast_call) {
|
||||
return false;
|
||||
}
|
||||
auto func_call = (call_function*)tmp->get_calls()[0];
|
||||
auto call_node = reinterpret_cast<call_expr*>(node);
|
||||
auto first_expr = call_node->get_first();
|
||||
if (first_expr->get_type()!=expr_type::ast_id) {
|
||||
return false;
|
||||
}
|
||||
if (reinterpret_cast<identifier*>(first_expr)->get_name()!="import") {
|
||||
return false;
|
||||
}
|
||||
if (!call_node->get_calls().size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// import("xxx");
|
||||
if (call_node->get_calls().size()!=1) {
|
||||
return false;
|
||||
}
|
||||
auto maybe_func_call = call_node->get_calls()[0];
|
||||
if (maybe_func_call->get_type()!=expr_type::ast_callf) {
|
||||
return false;
|
||||
}
|
||||
auto func_call = reinterpret_cast<call_function*>(maybe_func_call);
|
||||
if (func_call->get_argument().size()!=1) {
|
||||
return false;
|
||||
}
|
||||
|
@ -128,31 +127,20 @@ bool linker::import_check(expr* node) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool linker::exist(const std::string& file) {
|
||||
bool linker::check_exist_or_record_file(const std::string& file) {
|
||||
// avoid importing the same file
|
||||
for(const auto& fname : files) {
|
||||
if (file==fname) {
|
||||
for(const auto& name : imported_files) {
|
||||
if (file==name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
files.push_back(file);
|
||||
imported_files.push_back(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
u16 linker::find(const std::string& file) {
|
||||
for(usize i = 0; i<files.size(); ++i) {
|
||||
if (files[i]==file) {
|
||||
return static_cast<u16>(i);
|
||||
}
|
||||
}
|
||||
std::cerr << "unreachable: using this method incorrectly\n";
|
||||
std::exit(-1);
|
||||
return UINT16_MAX;
|
||||
}
|
||||
|
||||
bool linker::check_self_import(const std::string& file) {
|
||||
for(const auto& i : module_load_stack) {
|
||||
if (file==i) {
|
||||
for(const auto& name : module_load_stack) {
|
||||
if (file==name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -176,27 +164,19 @@ void linker::link(code_block* new_tree_root, code_block* old_tree_root) {
|
|||
old_tree_root->get_expressions().clear();
|
||||
}
|
||||
|
||||
code_block* linker::import_regular_file(call_expr* node) {
|
||||
lexer lex;
|
||||
parse par;
|
||||
code_block* linker::import_regular_file(
|
||||
expr* node, std::unordered_set<std::string>& used_modules) {
|
||||
// get filename
|
||||
auto filename = get_path(node);
|
||||
// clear this node
|
||||
for(auto i : node->get_calls()) {
|
||||
delete i;
|
||||
}
|
||||
node->get_calls().clear();
|
||||
auto location = node->get_first()->get_location();
|
||||
delete node->get_first();
|
||||
node->set_first(new nil_expr(location));
|
||||
// this will make node to call_expr(nil),
|
||||
// will not be optimized when generating bytecodes
|
||||
|
||||
// avoid infinite loading loop
|
||||
filename = find_file(filename, node->get_location());
|
||||
if (!filename.length()) {
|
||||
filename = find_real_file_path(filename, node->get_location());
|
||||
// if get empty string(error) or this file is used before, do not parse
|
||||
if (!filename.length() || used_modules.count(filename)) {
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
}
|
||||
|
||||
// check self import, avoid infinite loading loop
|
||||
if (check_self_import(filename)) {
|
||||
err.err("link",
|
||||
"self-referenced module <" + filename + ">:\n" +
|
||||
|
@ -204,58 +184,61 @@ code_block* linker::import_regular_file(call_expr* node) {
|
|||
);
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
}
|
||||
exist(filename);
|
||||
check_exist_or_record_file(filename);
|
||||
|
||||
module_load_stack.push_back(filename);
|
||||
// start importing...
|
||||
if (lex.scan(filename).geterr()) {
|
||||
lexer nasal_lexer;
|
||||
parse nasal_parser;
|
||||
if (nasal_lexer.scan(filename).geterr()) {
|
||||
err.err("link", "error occurred when analysing <" + filename + ">");
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
}
|
||||
if (par.compile(lex).geterr()) {
|
||||
if (nasal_parser.compile(nasal_lexer).geterr()) {
|
||||
err.err("link", "error occurred when analysing <" + filename + ">");
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
}
|
||||
|
||||
auto parse_result = par.swap(nullptr);
|
||||
// swap result out
|
||||
auto parse_result = nasal_parser.swap(nullptr);
|
||||
|
||||
// check if parse result has 'import'
|
||||
auto result = load(parse_result, find(filename));
|
||||
auto result = load(parse_result, filename);
|
||||
module_load_stack.pop_back();
|
||||
return result;
|
||||
}
|
||||
|
||||
code_block* linker::import_nasal_lib() {
|
||||
lexer lex;
|
||||
parse par;
|
||||
auto filename = find_file("lib.nas", {0, 0, 0, 0, files[0]});
|
||||
if (!filename.length()) {
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
auto path = find_real_file_path(
|
||||
"lib.nas", {0, 0, 0, 0, this_file}
|
||||
);
|
||||
if (!path.length()) {
|
||||
return new code_block({0, 0, 0, 0, path});
|
||||
}
|
||||
lib_path = filename;
|
||||
|
||||
// avoid infinite loading library
|
||||
if (exist(filename)) {
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
if (check_exist_or_record_file(path)) {
|
||||
return new code_block({0, 0, 0, 0, path});
|
||||
}
|
||||
|
||||
// start importing...
|
||||
if (lex.scan(filename).geterr()) {
|
||||
lexer nasal_lexer;
|
||||
parse nasal_parser;
|
||||
if (nasal_lexer.scan(path).geterr()) {
|
||||
err.err("link",
|
||||
"error occurred when analysing library <" + filename + ">"
|
||||
"error occurred when analysing library <" + path + ">"
|
||||
);
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
return new code_block({0, 0, 0, 0, path});
|
||||
}
|
||||
if (par.compile(lex).geterr()) {
|
||||
if (nasal_parser.compile(nasal_lexer).geterr()) {
|
||||
err.err("link",
|
||||
"error occurred when analysing library <" + filename + ">"
|
||||
"error occurred when analysing library <" + path + ">"
|
||||
);
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
return new code_block({0, 0, 0, 0, path});
|
||||
}
|
||||
|
||||
auto parse_result = par.swap(nullptr);
|
||||
// swap result out
|
||||
auto parse_result = nasal_parser.swap(nullptr);
|
||||
// check if library has 'import' (in fact it should not)
|
||||
return load(parse_result, find(filename));
|
||||
return load(parse_result, path);
|
||||
}
|
||||
|
||||
std::string linker::generate_module_name(const std::string& file_path) {
|
||||
|
@ -301,14 +284,11 @@ std::string linker::generate_module_name(const std::string& file_path) {
|
|||
"get empty module name from <" + file_path + ">, " +
|
||||
"will not be easily accessed."
|
||||
);
|
||||
return module_name;
|
||||
}
|
||||
if (module_name.length() && '0' <= module_name[0] && module_name[0] <= '9') {
|
||||
err.warn("link",
|
||||
"get module <" + module_name + "> from <" + file_path + ">, " +
|
||||
"will not be easily accessed."
|
||||
);
|
||||
}
|
||||
if (module_name.length() && module_name.find(".")!=std::string::npos) {
|
||||
if (std::isdigit(module_name[0]) ||
|
||||
module_name.find(".")!=std::string::npos ||
|
||||
module_name.find("-")!=std::string::npos) {
|
||||
err.warn("link",
|
||||
"get module <" + module_name + "> from <" + file_path + ">, " +
|
||||
"will not be easily accessed."
|
||||
|
@ -353,32 +333,43 @@ definition_expr* linker::generate_module_definition(code_block* block) {
|
|||
return def;
|
||||
}
|
||||
|
||||
code_block* linker::load(code_block* program_root, u16 fileindex) {
|
||||
auto tree = new code_block({0, 0, 0, 0, files[fileindex]});
|
||||
code_block* linker::load(code_block* program_root, const std::string& filename) {
|
||||
auto tree = new code_block({0, 0, 0, 0, filename});
|
||||
// load library, this ast will be linked with root directly
|
||||
// so no extra namespace is generated
|
||||
if (!lib_loaded) {
|
||||
if (!library_loaded) {
|
||||
auto nasal_lib_code_block = import_nasal_lib();
|
||||
// insert nasal lib code to the back of tree
|
||||
link(tree, nasal_lib_code_block);
|
||||
delete nasal_lib_code_block;
|
||||
lib_loaded = true;
|
||||
library_loaded = true;
|
||||
}
|
||||
|
||||
// load imported modules
|
||||
for(auto& import_ast_node : program_root->get_expressions()) {
|
||||
if (!import_check(import_ast_node)) {
|
||||
std::unordered_set<std::string> used_modules = {};
|
||||
for(auto& import_node : program_root->get_expressions()) {
|
||||
if (!import_check(import_node)) {
|
||||
break;
|
||||
}
|
||||
auto module_code_block = import_regular_file((call_expr*)import_ast_node);
|
||||
// parse file and get ast
|
||||
auto module_code_block = import_regular_file(import_node, used_modules);
|
||||
auto replace_node = new null_expr(import_node->get_location());
|
||||
// after importing the regular file as module, delete this node
|
||||
const auto loc = import_ast_node->get_location();
|
||||
delete import_ast_node;
|
||||
delete import_node;
|
||||
// and replace the node with null_expr node
|
||||
import_ast_node = new null_expr(loc);
|
||||
import_node = replace_node;
|
||||
|
||||
// avoid repeatedly importing the same module
|
||||
const auto& module_path = module_code_block->get_location().file;
|
||||
if (used_modules.count(module_path)) {
|
||||
delete module_code_block;
|
||||
continue;
|
||||
}
|
||||
|
||||
// then we generate a function warping the code block,
|
||||
// and export the necessary global symbols in this code block
|
||||
// by generate a return statement, with a hashmap return value
|
||||
used_modules.insert(module_path);
|
||||
tree->add_expression(generate_module_definition(module_code_block));
|
||||
}
|
||||
|
||||
|
@ -389,15 +380,17 @@ code_block* linker::load(code_block* program_root, u16 fileindex) {
|
|||
|
||||
const error& linker::link(
|
||||
parse& parse, const std::string& self, bool spath = false) {
|
||||
show_path = spath;
|
||||
// switch for showing path when errors occur
|
||||
show_path_flag = spath;
|
||||
|
||||
// initializing file map
|
||||
this_file = self;
|
||||
files = {self};
|
||||
imported_files = {self};
|
||||
module_load_stack = {self};
|
||||
|
||||
// scan root and import files
|
||||
// then generate a new ast and return to import_ast
|
||||
// the main file's index is 0
|
||||
auto new_tree_root = load(parse.tree(), 0);
|
||||
auto new_tree_root = load(parse.tree(), self);
|
||||
auto old_tree_root = parse.swap(new_tree_root);
|
||||
delete old_tree_root;
|
||||
return err;
|
||||
|
|
|
@ -18,43 +18,42 @@
|
|||
#include "nasal_parse.h"
|
||||
#include "symbol_finder.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace nasal {
|
||||
|
||||
class linker {
|
||||
private:
|
||||
bool show_path;
|
||||
bool lib_loaded;
|
||||
bool show_path_flag;
|
||||
bool library_loaded;
|
||||
std::string this_file;
|
||||
std::string lib_path;
|
||||
error err;
|
||||
std::vector<std::string> files;
|
||||
std::vector<std::string> imported_files;
|
||||
std::vector<std::string> module_load_stack;
|
||||
std::vector<std::string> envpath;
|
||||
|
||||
private:
|
||||
bool import_check(expr*);
|
||||
bool exist(const std::string&);
|
||||
u16 find(const std::string&);
|
||||
bool check_exist_or_record_file(const std::string&);
|
||||
bool check_self_import(const std::string&);
|
||||
std::string generate_self_import_path(const std::string&);
|
||||
void link(code_block*, code_block*);
|
||||
std::string get_path(call_expr*);
|
||||
std::string find_file(const std::string&, const span&);
|
||||
code_block* import_regular_file(call_expr*);
|
||||
std::string get_path(expr*);
|
||||
std::string find_real_file_path(const std::string&, const span&);
|
||||
code_block* import_regular_file(expr*, std::unordered_set<std::string>&);
|
||||
code_block* import_nasal_lib();
|
||||
std::string generate_module_name(const std::string&);
|
||||
return_expr* generate_module_return(code_block*);
|
||||
definition_expr* generate_module_definition(code_block*);
|
||||
code_block* load(code_block*, u16);
|
||||
code_block* load(code_block*, const std::string&);
|
||||
|
||||
public:
|
||||
linker();
|
||||
const error& link(parse&, const std::string&, bool);
|
||||
const auto& get_file_list() const {return files;}
|
||||
const auto& get_this_file() const {return this_file;}
|
||||
const auto& get_lib_path() const {return lib_path;}
|
||||
const auto& get_file_list() const {return imported_files;}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ enum class tok:u32 {
|
|||
id, // identifier
|
||||
tktrue, // keyword true
|
||||
tkfalse, // keyword false
|
||||
use, // keyword use
|
||||
rfor, // loop keyword for
|
||||
forindex, // loop keyword forindex
|
||||
foreach, // loop keyword foreach
|
||||
|
@ -103,6 +104,7 @@ private:
|
|||
std::vector<token> toks;
|
||||
|
||||
const std::unordered_map<std::string, tok> typetbl {
|
||||
{"use" ,tok::use },
|
||||
{"true" ,tok::tktrue },
|
||||
{"false" ,tok::tkfalse },
|
||||
{"for" ,tok::rfor },
|
||||
|
|
|
@ -132,9 +132,13 @@ bool parse::check_func_end(expr* node) {
|
|||
if (type==expr_type::ast_func) {
|
||||
return true;
|
||||
} else if (type==expr_type::ast_def) {
|
||||
return check_func_end(((definition_expr*)node)->get_value());
|
||||
return check_func_end(
|
||||
reinterpret_cast<definition_expr*>(node)->get_value()
|
||||
);
|
||||
} else if (type==expr_type::ast_assign) {
|
||||
return check_func_end(((assignment_expr*)node)->get_right());
|
||||
return check_func_end(
|
||||
reinterpret_cast<assignment_expr*>(node)->get_right()
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -197,6 +201,18 @@ void parse::update_location(expr* node) {
|
|||
node->update_location(toks[ptr-1].loc);
|
||||
}
|
||||
|
||||
use_stmt* parse::use_stmt_gen() {
|
||||
auto node = new use_stmt(toks[ptr].loc);
|
||||
match(tok::use);
|
||||
node->add_path(id());
|
||||
while(lookahead(tok::dot)) {
|
||||
match(tok::dot);
|
||||
node->add_path(id());
|
||||
}
|
||||
update_location(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
null_expr* parse::null() {
|
||||
return new null_expr(toks[ptr].loc);
|
||||
}
|
||||
|
@ -355,6 +371,7 @@ expr* parse::expression() {
|
|||
die(thisspan, "must use return in functions");
|
||||
}
|
||||
switch(type) {
|
||||
case tok::use: return use_stmt_gen();
|
||||
case tok::tknil:
|
||||
case tok::num:
|
||||
case tok::str:
|
||||
|
|
|
@ -24,6 +24,7 @@ private:
|
|||
|
||||
private:
|
||||
const std::unordered_map<tok, std::string> tokname {
|
||||
{tok::use ,"use" },
|
||||
{tok::rfor ,"for" },
|
||||
{tok::forindex,"forindex"},
|
||||
{tok::foreach ,"foreach" },
|
||||
|
@ -92,6 +93,7 @@ private:
|
|||
void update_location(expr*);
|
||||
|
||||
private:
|
||||
use_stmt* use_stmt_gen();
|
||||
null_expr* null();
|
||||
nil_expr* nil();
|
||||
number_literal* num();
|
||||
|
|
|
@ -12,7 +12,8 @@ void optimizer::const_string(
|
|||
const auto& left = left_node->get_content();
|
||||
const auto& right = right_node->get_content();
|
||||
node->set_optimized_string(
|
||||
new string_literal(node->get_location(), left+right));
|
||||
new string_literal(node->get_location(), left+right)
|
||||
);
|
||||
}
|
||||
|
||||
void optimizer::const_number(
|
||||
|
@ -43,7 +44,8 @@ void optimizer::const_number(
|
|||
return;
|
||||
}
|
||||
node->set_optimized_number(
|
||||
new number_literal(node->get_location(), res));
|
||||
new number_literal(node->get_location(), res)
|
||||
);
|
||||
}
|
||||
|
||||
void optimizer::const_number(
|
||||
|
@ -62,46 +64,56 @@ void optimizer::const_number(
|
|||
return;
|
||||
}
|
||||
node->set_optimized_number(
|
||||
new number_literal(node->get_location(), res));
|
||||
new number_literal(node->get_location(), res)
|
||||
);
|
||||
}
|
||||
|
||||
bool optimizer::visit_binary_operator(binary_operator* node) {
|
||||
node->get_left()->accept(this);
|
||||
node->get_right()->accept(this);
|
||||
auto left_node = node->get_left();
|
||||
auto right_node = node->get_right();
|
||||
left_node->accept(this);
|
||||
right_node->accept(this);
|
||||
|
||||
number_literal* left_num_node = nullptr;
|
||||
number_literal* right_num_node = nullptr;
|
||||
string_literal* left_str_node = nullptr;
|
||||
string_literal* right_str_node = nullptr;
|
||||
if (node->get_left()->get_type()==expr_type::ast_num) {
|
||||
left_num_node = (number_literal*)node->get_left();
|
||||
} else if (node->get_left()->get_type()==expr_type::ast_binary &&
|
||||
((binary_operator*)node->get_left())->get_optimized_number()) {
|
||||
left_num_node = ((binary_operator*)node->get_left())->get_optimized_number();
|
||||
} else if (node->get_left()->get_type()==expr_type::ast_unary &&
|
||||
((unary_operator*)node->get_left())->get_optimized_number()) {
|
||||
left_num_node = ((unary_operator*)node->get_left())->get_optimized_number();
|
||||
if (left_node->get_type()==expr_type::ast_num) {
|
||||
left_num_node = reinterpret_cast<number_literal*>(left_node);
|
||||
} else if (left_node->get_type()==expr_type::ast_binary &&
|
||||
reinterpret_cast<binary_operator*>(left_node)->get_optimized_number()) {
|
||||
auto optimized = reinterpret_cast<binary_operator*>(left_node);
|
||||
left_num_node = optimized->get_optimized_number();
|
||||
} else if (left_node->get_type()==expr_type::ast_unary &&
|
||||
reinterpret_cast<unary_operator*>(left_node)->get_optimized_number()) {
|
||||
auto optimized = reinterpret_cast<unary_operator*>(left_node);
|
||||
left_num_node = optimized->get_optimized_number();
|
||||
}
|
||||
if (node->get_right()->get_type()==expr_type::ast_num) {
|
||||
right_num_node = (number_literal*)node->get_right();
|
||||
} else if (node->get_right()->get_type()==expr_type::ast_binary &&
|
||||
((binary_operator*)node->get_right())->get_optimized_number()) {
|
||||
right_num_node = ((binary_operator*)node->get_right())->get_optimized_number();
|
||||
} else if (node->get_right()->get_type()==expr_type::ast_unary &&
|
||||
((unary_operator*)node->get_right())->get_optimized_number()) {
|
||||
right_num_node = ((unary_operator*)node->get_right())->get_optimized_number();
|
||||
if (right_node->get_type()==expr_type::ast_num) {
|
||||
right_num_node = reinterpret_cast<number_literal*>(right_node);
|
||||
} else if (right_node->get_type()==expr_type::ast_binary &&
|
||||
reinterpret_cast<binary_operator*>(right_node)->get_optimized_number()) {
|
||||
auto optimized = reinterpret_cast<binary_operator*>(right_node);
|
||||
right_num_node = optimized->get_optimized_number();
|
||||
} else if (right_node->get_type()==expr_type::ast_unary &&
|
||||
reinterpret_cast<unary_operator*>(right_node)->get_optimized_number()) {
|
||||
auto optimized = reinterpret_cast<unary_operator*>(right_node);
|
||||
right_num_node = optimized->get_optimized_number();
|
||||
}
|
||||
|
||||
if (node->get_left()->get_type()==expr_type::ast_str) {
|
||||
left_str_node = (string_literal*)node->get_left();
|
||||
} else if (node->get_left()->get_type()==expr_type::ast_binary &&
|
||||
((binary_operator*)node->get_left())->get_optimized_string()) {
|
||||
left_str_node = ((binary_operator*)node->get_left())->get_optimized_string();
|
||||
if (left_node->get_type()==expr_type::ast_str) {
|
||||
left_str_node = reinterpret_cast<string_literal*>(left_node);
|
||||
} else if (left_node->get_type()==expr_type::ast_binary &&
|
||||
reinterpret_cast<binary_operator*>(left_node)->get_optimized_string()) {
|
||||
auto optimized = reinterpret_cast<binary_operator*>(left_node);
|
||||
left_str_node = optimized->get_optimized_string();
|
||||
}
|
||||
if (node->get_right()->get_type()==expr_type::ast_str) {
|
||||
right_str_node = (string_literal*)node->get_right();
|
||||
} else if (node->get_right()->get_type()==expr_type::ast_binary &&
|
||||
((binary_operator*)node->get_right())->get_optimized_string()) {
|
||||
right_str_node = ((binary_operator*)node->get_right())->get_optimized_string();
|
||||
if (right_node->get_type()==expr_type::ast_str) {
|
||||
right_str_node = reinterpret_cast<string_literal*>(right_node);
|
||||
} else if (right_node->get_type()==expr_type::ast_binary &&
|
||||
reinterpret_cast<binary_operator*>(right_node)->get_optimized_string()) {
|
||||
auto optimized = reinterpret_cast<binary_operator*>(right_node);
|
||||
right_str_node = optimized->get_optimized_string();
|
||||
}
|
||||
if (left_num_node && right_num_node) {
|
||||
const_number(node, left_num_node, right_num_node);
|
||||
|
@ -115,19 +127,23 @@ bool optimizer::visit_binary_operator(binary_operator* node) {
|
|||
}
|
||||
|
||||
bool optimizer::visit_unary_operator(unary_operator* node) {
|
||||
node->get_value()->accept(this);
|
||||
number_literal* value_node = nullptr;
|
||||
if (node->get_value()->get_type()==expr_type::ast_num) {
|
||||
value_node = (number_literal*)node->get_value();
|
||||
} else if (node->get_value()->get_type()==expr_type::ast_binary &&
|
||||
((binary_operator*)node->get_value())->get_optimized_number()) {
|
||||
value_node = ((binary_operator*)node->get_value())->get_optimized_number();
|
||||
} else if (node->get_value()->get_type()==expr_type::ast_unary &&
|
||||
((unary_operator*)node->get_value())->get_optimized_number()) {
|
||||
value_node = ((unary_operator*)node->get_value())->get_optimized_number();
|
||||
auto value = node->get_value();
|
||||
value->accept(this);
|
||||
|
||||
number_literal* num_node = nullptr;
|
||||
if (value->get_type()==expr_type::ast_num) {
|
||||
num_node = reinterpret_cast<number_literal*>(value);
|
||||
} else if (value->get_type()==expr_type::ast_binary &&
|
||||
reinterpret_cast<binary_operator*>(value)->get_optimized_number()) {
|
||||
auto optimized = reinterpret_cast<binary_operator*>(value);
|
||||
num_node = optimized->get_optimized_number();
|
||||
} else if (value->get_type()==expr_type::ast_unary &&
|
||||
reinterpret_cast<unary_operator*>(value)->get_optimized_number()) {
|
||||
auto optimized = reinterpret_cast<unary_operator*>(value);
|
||||
num_node = optimized->get_optimized_number();
|
||||
}
|
||||
if (value_node) {
|
||||
const_number(node, value_node);
|
||||
if (num_node) {
|
||||
const_number(node, num_node);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# flightgear developer environments simulator (beta)
|
||||
# ValKmjolnir 2022
|
||||
import.std.runtime;
|
||||
use std.runtime;
|
||||
|
||||
println("-------------------------------------------------------------");
|
||||
println(" FlightGear simulated-env for developers project, since 2019");
|
||||
|
|
|
@ -66,3 +66,9 @@ var stat = func(filename) {
|
|||
var eof = func(filehandle) {
|
||||
return __eof(filehandle);
|
||||
}
|
||||
|
||||
var stdin = func() { return __stdin; }();
|
||||
|
||||
var stdout = func() { return __stdout;}();
|
||||
|
||||
var stderr = func() { return __stderr; }();
|
||||
|
|
14
std/lib.nas
14
std/lib.nas
|
@ -1,13 +1,13 @@
|
|||
# lib.nas
|
||||
# 2019 ValKmjolnir
|
||||
|
||||
import.std.coroutine;
|
||||
import.std.math;
|
||||
import.std.string;
|
||||
import.std.io;
|
||||
import.std.os;
|
||||
import.std.bits;
|
||||
import.std.unix;
|
||||
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.
|
||||
# this function uses std::cout to output logs.
|
||||
|
|
|
@ -379,7 +379,7 @@ var dump = func {
|
|||
# Don't recurse into aliases, lest we get stuck in a loop
|
||||
if(type != "ALIAS") {
|
||||
var children = node.getChildren();
|
||||
foreach(c; children) { dump(name ~ "/", c); }
|
||||
foreach(var c; children) { dump(name ~ "/", c); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -498,7 +498,7 @@ var createNodeObjectsFromHash = func (property_list, namespace = nil) {
|
|||
logprint(LOG_WARN, "createNodeObjectsFromHash: Error, property_list argument is not a hash.");
|
||||
return nil;
|
||||
}
|
||||
foreach (key; keys(property_list)) {
|
||||
foreach (var key; keys(property_list)) {
|
||||
namespace[key] = props.getNode(property_list[key],1);
|
||||
}
|
||||
}
|
||||
|
@ -743,7 +743,7 @@ var UpdateManager =
|
|||
obj.needs_update = 0;
|
||||
obj.property = {};
|
||||
obj.is_numeric = {};
|
||||
foreach (hashkey; obj.hashkeylist) {
|
||||
foreach (var hashkey; obj.hashkeylist) {
|
||||
obj.property[hashkey] = props.globals.getNode(hashkey);
|
||||
obj.lastval[hashkey] = nil;
|
||||
# var ty = obj.property[hashkey].getType();
|
||||
|
@ -833,7 +833,7 @@ var UpdateManager =
|
|||
me.needs_update = 0;
|
||||
|
||||
if (obj != nil or me.lastval == nil) {
|
||||
foreach (hashkey; me.hashkeylist) {
|
||||
foreach (var hashkey; me.hashkeylist) {
|
||||
if (me.isnum) {
|
||||
if (me.lastval[hashkey] == nil or math.abs(me.lastval[hashkey] - obj[hashkey]) >= me.delta) {
|
||||
me.needs_update = 1;
|
||||
|
@ -847,7 +847,7 @@ var UpdateManager =
|
|||
}
|
||||
if (me.needs_update) {
|
||||
me.changed(obj);
|
||||
foreach (hashkey; me.hashkeylist) {
|
||||
foreach (var hashkey; me.hashkeylist) {
|
||||
me.lastval[hashkey] = obj[hashkey];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,9 @@ var stack=func(){
|
|||
return pop(vec);
|
||||
},
|
||||
top: func() {
|
||||
if(size(vec)!=0)
|
||||
if (size(vec)!=0) {
|
||||
return vec[-1];
|
||||
}
|
||||
},
|
||||
clear: func() {
|
||||
vec = [];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import.std.padding;
|
||||
import.std.process_bar;
|
||||
use std.padding;
|
||||
use std.process_bar;
|
||||
|
||||
var char_ttf=[
|
||||
[" "," "," "," "," "," "],
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Road check and auto pilot by ValKmjolnir
|
||||
import.std.fg_env;
|
||||
use std.fg_env;
|
||||
|
||||
var props = fg_env.props;
|
||||
var geodinfo = fg_env.geodinfo;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import.std.queue;
|
||||
use std.queue;
|
||||
|
||||
rand(time(0));
|
||||
var pixel=[' ','#','.','*'];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import.std.mat;
|
||||
use std.mat;
|
||||
|
||||
rand(time(0));
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
use std.process_bar;
|
||||
|
||||
var ppm = func(filename, width, height, RGB) {
|
||||
# P3 use ASCII number
|
||||
# P6 use binary character
|
||||
var fd = io.open(filename, "wb");
|
||||
io.write(fd, "P6\n"~width~" "~height~"\n255\n");
|
||||
for(var i = 0; i<height; i += 1) {
|
||||
for(var j = 0; j<width; j += 1) {
|
||||
io.write(fd,RGB(i,j));
|
||||
}
|
||||
}
|
||||
io.close(fd);
|
||||
}
|
||||
|
||||
var width = 1920;
|
||||
var height = 1080;
|
||||
var bar = (os.platform()=="windows")?
|
||||
process_bar.bar(front:"sharp", back:"point", sep:"line", length:50):
|
||||
process_bar.high_resolution_bar(50);
|
||||
|
||||
var f = func(i, j) {
|
||||
var (yMin, yMax, xMin, xMax) = (-2, 1.1, -3.2, 2);
|
||||
var (yDel, xDel) = (yMax-yMin, xMax-xMin);
|
||||
var (y, x) = ((i/height)*yDel+yMin, (j/width)*xDel+xMin);
|
||||
var (x0, y0) = (x, y);
|
||||
for(var iter = 0; iter<64; iter += 1) {
|
||||
(x0, y0) = (math.abs(x0), math.abs(y0));
|
||||
var (x1, y1) = ((x0*x0)-(y0*y0)+x, 2*x0*y0+y);
|
||||
(x0, y0) = (x1, y1);
|
||||
if ((x0*x0)+(y0*y0)>8) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
var progress = (i*width+j+1)/(width*height);
|
||||
if (progress*100-int(progress*100)==0) {
|
||||
print(bar.bar(progress), " ", progress*100, "% \r");
|
||||
}
|
||||
iter = iter>=25? 255:int(iter/25*255);
|
||||
var c = char(iter);
|
||||
return c~c~c;
|
||||
}
|
||||
|
||||
ppm("burningship.ppm", width, height, f);
|
||||
println();
|
|
@ -1,5 +1,5 @@
|
|||
import.std.padding;
|
||||
import.std.file;
|
||||
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});
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
import.module.libmat;
|
||||
import.std.runtime;
|
||||
use module.libmat;
|
||||
use std.runtime;
|
||||
|
||||
func(){
|
||||
# allocate more spaces
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# coroutine.nas by ValKmjolnir
|
||||
# 2022/5/19
|
||||
import.std.process_bar;
|
||||
import.std.padding;
|
||||
use std.process_bar;
|
||||
use std.padding;
|
||||
|
||||
if(os.platform()=="windows"){
|
||||
system("chcp 65001");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import.std.padding;
|
||||
import.std.process_bar;
|
||||
use std.padding;
|
||||
use std.process_bar;
|
||||
|
||||
var mess=func(vec) {
|
||||
srand();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import.std.runtime;
|
||||
use std.runtime;
|
||||
|
||||
var mod = math.mod;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import.std.process_bar;
|
||||
use std.process_bar;
|
||||
|
||||
var ppm = func(filename, width, height, RGB) {
|
||||
# P3 use ASCII number
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import.module.libkey;
|
||||
use module.libkey;
|
||||
|
||||
srand();
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import.std.runtime;
|
||||
use std.runtime;
|
||||
|
||||
var test_func = func(test_processes...) {
|
||||
var test_process_total = maketimestamp();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# hexdump.nas by ValKmjolnir
|
||||
# 2021/8/13
|
||||
import.std.file;
|
||||
import.std.runtime;
|
||||
use std.file;
|
||||
use std.runtime;
|
||||
|
||||
# init
|
||||
var hex=func(){
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import.module.libsock;
|
||||
use module.libsock;
|
||||
|
||||
var socket = libsock.socket;
|
||||
|
||||
|
@ -320,9 +320,11 @@ while(1){
|
|||
elsif(path=="/license")
|
||||
http.send(client,respond.ok(io.readfile("./LICENSE")));
|
||||
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")
|
||||
path=="/doc/pic/feigenbaum.png" or
|
||||
path=="/doc/pic/burningship.png")
|
||||
http.send(client,respond.ok(io.readfile("."~path)));
|
||||
else{
|
||||
var filename=substr(path,1,size(path)-1);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import.std.json;
|
||||
import.std.process_bar;
|
||||
use std.json;
|
||||
use std.process_bar;
|
||||
|
||||
var ss = json.stringify({
|
||||
vec:[0,1,2],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import.module.libsock;
|
||||
import.std.json;
|
||||
import.std.runtime;
|
||||
use module.libsock;
|
||||
use std.json;
|
||||
use std.runtime;
|
||||
|
||||
var socket = libsock.socket;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import.std.process_bar;
|
||||
import.std.runtime;
|
||||
use std.process_bar;
|
||||
use std.runtime;
|
||||
|
||||
var new_map=func(width,height){
|
||||
var tmp=[];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import.test.md5_self;
|
||||
import.std.process_bar;
|
||||
import.std.file;
|
||||
use test.md5_self;
|
||||
use std.process_bar;
|
||||
use std.file;
|
||||
|
||||
srand();
|
||||
|
||||
|
@ -65,13 +65,18 @@ var filechecksum=func(){
|
|||
append(files, "./doc/"~p);
|
||||
}
|
||||
|
||||
var source = [];
|
||||
foreach(var f; files) {
|
||||
append(source, io.readfile(f));
|
||||
}
|
||||
|
||||
var byte = 0;
|
||||
var total = size(files);
|
||||
var timestamp = maketimestamp();
|
||||
timestamp.stamp();
|
||||
var bar = process_bar.high_resolution_bar(40);
|
||||
forindex(var i; files) {
|
||||
var f=io.readfile(files[i]);
|
||||
var f = source[i];
|
||||
var res = md5(f);
|
||||
byte += size(f);
|
||||
if(cmp(res, md5_self.md5(f))){
|
||||
|
@ -88,11 +93,13 @@ var filechecksum=func(){
|
|||
}
|
||||
|
||||
var randomchecksum = func() {
|
||||
for(var i=0;i<2048;i+=256)
|
||||
for(var i = 0; i<2048; i += 256) {
|
||||
compare(i, i+256);
|
||||
}
|
||||
}
|
||||
|
||||
if(os.platform()=="windows")
|
||||
if(os.platform()=="windows") {
|
||||
system("chcp 65001");
|
||||
}
|
||||
filechecksum();
|
||||
randomchecksum();
|
|
@ -1,5 +1,5 @@
|
|||
import.std.dylib;
|
||||
import.module.libfib;
|
||||
use std.dylib;
|
||||
use module.libfib;
|
||||
|
||||
println(keys(libfib));
|
||||
libfib.test_ghost();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import.std.process_bar;
|
||||
import.module.libkey;
|
||||
import.std.runtime;
|
||||
use std.process_bar;
|
||||
use module.libkey;
|
||||
use std.runtime;
|
||||
|
||||
var is_windows_platform=os.platform()=="windows";
|
||||
var is_macos_platform=os.platform()=="macOS";
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import.std.process_bar;
|
||||
use std.process_bar;
|
||||
|
||||
var ppm = func(filename, width, height, RGB) {
|
||||
# P3 use ASCII number
|
||||
# P6 use binary character
|
||||
var fd = io.open(filename, "wb");
|
||||
io.write(fd,"P3\n"~width~" "~height~"\n255\n");
|
||||
io.write(fd, "P6\n"~width~" "~height~"\n255\n");
|
||||
for(var i = 0; i<height; i += 1) {
|
||||
for(var j=0;j<width;j+=1)
|
||||
for(var j = 0; j<width; j += 1) {
|
||||
io.write(fd,RGB(i,j));
|
||||
io.write(fd,"\n");
|
||||
}
|
||||
}
|
||||
io.close(fd);
|
||||
}
|
||||
|
@ -34,8 +34,10 @@ var f=func(i,j){
|
|||
if (progress*100-int(progress*100)==0) {
|
||||
print(bar.bar(progress), " ", progress*100, "% \r");
|
||||
}
|
||||
iter=iter==25?255:int(iter/25*255);
|
||||
return iter~" "~iter~" "~iter~" ";
|
||||
iter = iter>=25? 255:int(iter/25*255);
|
||||
var c = char(iter);
|
||||
return c~c~c;
|
||||
}
|
||||
ppm("a.ppm",width,height,f);
|
||||
|
||||
ppm("mandelbrotset.ppm", width, height, f);
|
||||
println();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import.std.runtime;
|
||||
use std.runtime;
|
||||
|
||||
# basic type
|
||||
nil;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# this will cause error
|
||||
# import.b;
|
||||
# use b;
|
||||
|
||||
println("init a");
|
||||
var a = "hello";
|
|
@ -1,3 +1,3 @@
|
|||
import.a;
|
||||
use a;
|
||||
|
||||
println("init b");
|
|
@ -1,3 +1,3 @@
|
|||
import.b;
|
||||
use b;
|
||||
|
||||
println("init c");
|
|
@ -1,6 +1,6 @@
|
|||
import.c;
|
||||
import.a;
|
||||
import.b;
|
||||
use c;
|
||||
use a;
|
||||
use b;
|
||||
|
||||
println(a);
|
||||
println(b);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import.module.libkey;
|
||||
import.std.list;
|
||||
import.std.runtime;
|
||||
use module.libkey;
|
||||
use std.list;
|
||||
use std.runtime;
|
||||
|
||||
var game=func(x,y){
|
||||
rand(time(0));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import.module.libkey;
|
||||
import.std.runtime;
|
||||
use module.libkey;
|
||||
use std.runtime;
|
||||
|
||||
var color=[
|
||||
"\e[31m","\e[32m","\e[33m","\e[34m","\e[35m","\e[36m",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import.std.runtime;
|
||||
use std.runtime;
|
||||
|
||||
var os_time=func(){
|
||||
return "[\e[33;1m"~os.time()~"\e[0m] ";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import.std.runtime;
|
||||
use std.runtime;
|
||||
|
||||
var to_lower=func(s){
|
||||
var tmp="";
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
|
||||
println("[",os.time(),"] auto push, please wait...");
|
||||
println("[",os.time(),"] (=.=) auto push, please wait...");
|
||||
|
||||
while(system("git push")!=0) {
|
||||
println("[",os.time(),"] failed to push, retrying...");
|
||||
println("[",os.time(),"] (ToT) failed to push, retrying...");
|
||||
unix.sleep(0.5);
|
||||
}
|
||||
|
||||
println("[",os.time(),"] (^o^) auto push complete.");
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
import.std.file;
|
||||
use std.file;
|
||||
use std.padding;
|
||||
use std.process_bar;
|
||||
|
||||
if (size(arg)!=1) {
|
||||
var tips = func() {
|
||||
println("usage:");
|
||||
println(" nasal search_file.nas [key]");
|
||||
}
|
||||
|
||||
if (size(arg)<1) {
|
||||
println("need a key string to search files.");
|
||||
tips();
|
||||
exit(-1);
|
||||
} else if (size(arg)>1) {
|
||||
println("too many arguments.");
|
||||
tips();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
@ -10,7 +22,7 @@ var needle = arg[0];
|
|||
var do_flat = func(vec) {
|
||||
var flat = [];
|
||||
var bfs = [vec];
|
||||
while(size(bfs)) {
|
||||
while(size(bfs)!=0) {
|
||||
var d = pop(bfs);
|
||||
foreach(var f; d.files) {
|
||||
if (ishash(f)) {
|
||||
|
@ -24,16 +36,44 @@ var do_flat = func(vec) {
|
|||
return flat;
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
foreach(var f;do_flat(file.recursive_find_files("."))) {
|
||||
var result = [];
|
||||
var all_files = file.recursive_find_files(".");
|
||||
foreach(var f; do_flat(all_files)) {
|
||||
var pos = find(needle, f);
|
||||
if (pos == -1) {
|
||||
continue;
|
||||
}
|
||||
count += 1;
|
||||
var begin = substr(f, 0, pos);
|
||||
var end = pos+size(needle)>=size(f)? "":substr(f, pos+size(needle), size(f));
|
||||
println(begin, "\e[95;1m", needle, "\e[0m", end);
|
||||
var file_size = fstat(f).st_size;
|
||||
var unit = " b";
|
||||
if (file_size>1024) {
|
||||
file_size/=1024;
|
||||
unit = "kb";
|
||||
}
|
||||
if (file_size>1024) {
|
||||
file_size/=1024;
|
||||
unit = "mb";
|
||||
}
|
||||
if (file_size>1024) {
|
||||
file_size/=1024;
|
||||
unit = "gb";
|
||||
}
|
||||
file_size = int(file_size);
|
||||
append(result, {
|
||||
info: begin~"\e[95;1m"~needle~"\e[0m"~end,
|
||||
size: file_size,
|
||||
unit: unit
|
||||
});
|
||||
}
|
||||
|
||||
println("\n", count, " result(s).");
|
||||
var max_len = 0;
|
||||
foreach(var elem; result) {
|
||||
var temp = size(str(elem.size)~" "~elem.unit);
|
||||
max_len = math.max(max_len, temp);
|
||||
}
|
||||
foreach(var elem; result) {
|
||||
var temp = padding.leftpad(str(elem.size)~" "~elem.unit, max_len);
|
||||
println(temp, " | ", elem.info);
|
||||
}
|
||||
println("\n", size(result), " result(s).");
|
Loading…
Reference in New Issue