add unix.opendir unix.readdir unix.closedir
This commit is contained in:
parent
e4ea34db51
commit
f8e2918561
|
@ -32,4 +32,5 @@
|
||||||
*.app
|
*.app
|
||||||
|
|
||||||
nasal
|
nasal
|
||||||
.vscode
|
.vscode
|
||||||
|
dump
|
48
README.md
48
README.md
|
@ -24,7 +24,7 @@ especially when checking syntax errors.
|
||||||
So i tried to write a new interpreter to help them checking syntax error and even, runtime error.
|
So i tried to write a new interpreter to help them checking syntax error and even, runtime error.
|
||||||
|
|
||||||
I wrote the lexer,
|
I wrote the lexer,
|
||||||
parser and
|
parser and
|
||||||
bytecode virtual machine(there was an ast-interpreter,
|
bytecode virtual machine(there was an ast-interpreter,
|
||||||
but i deleted it after version4.0) to help checking errors.
|
but i deleted it after version4.0) to help checking errors.
|
||||||
We found it much easier to check syntax and runtime
|
We found it much easier to check syntax and runtime
|
||||||
|
@ -43,7 +43,7 @@ It's quite easy to build this interpreter.
|
||||||
|
|
||||||
MUST USE `-O2/-O3` if want to optimize the interpreter!
|
MUST USE `-O2/-O3` if want to optimize the interpreter!
|
||||||
|
|
||||||
Also remember to use g++ or clang++.
|
Also remember to use g++ or clang++.(mingw-w64 in Windows)
|
||||||
|
|
||||||
> [cpp compiler] -std=c++11 -O3 main.cpp -o nasal.exe -fno-exceptions
|
> [cpp compiler] -std=c++11 -O3 main.cpp -o nasal.exe -fno-exceptions
|
||||||
|
|
||||||
|
@ -592,10 +592,13 @@ You could totally use it after reading this simple tutorial:
|
||||||
This type is used to interrupt the execution of virtual machine and will not be created by user program.
|
This type is used to interrupt the execution of virtual machine and will not be created by user program.
|
||||||
|
|
||||||
`vm_nil` is a null type. It means nothing.
|
`vm_nil` is a null type. It means nothing.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var spc=nil;
|
var spc=nil;
|
||||||
```
|
```
|
||||||
|
|
||||||
`vm_num` has 3 formats. Dec, hex and oct. Using IEEE754 double to store.
|
`vm_num` has 3 formats. Dec, hex and oct. Using IEEE754 double to store.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var n=1;
|
var n=1;
|
||||||
var n=2.71828;
|
var n=2.71828;
|
||||||
|
@ -605,13 +608,17 @@ var n=0x7fffffff;
|
||||||
var n=0xAA55;
|
var n=0xAA55;
|
||||||
var n=0o170001;
|
var n=0o170001;
|
||||||
```
|
```
|
||||||
|
|
||||||
`vm_str` has 3 formats. But the third one is often used to declare a character.
|
`vm_str` has 3 formats. But the third one is often used to declare a character.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var s='str';
|
var s='str';
|
||||||
var s="another string";
|
var s="another string";
|
||||||
var s=`c`;
|
var s=`c`;
|
||||||
```
|
```
|
||||||
|
|
||||||
`vm_vec` has unlimited length and can store all types of values.
|
`vm_vec` has unlimited length and can store all types of values.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var vec=[];
|
var vec=[];
|
||||||
var vec=[
|
var vec=[
|
||||||
|
@ -623,7 +630,9 @@ var vec=[
|
||||||
];
|
];
|
||||||
append(vec,0,1,2);
|
append(vec,0,1,2);
|
||||||
```
|
```
|
||||||
|
|
||||||
`vm_hash` is a hashmap that stores values with strings/identifiers as the key.
|
`vm_hash` is a hashmap that stores values with strings/identifiers as the key.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var hash={
|
var hash={
|
||||||
member1:nil,
|
member1:nil,
|
||||||
|
@ -636,7 +645,9 @@ var hash={
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
`vm_func` is a function type (in fact it is lambda).
|
`vm_func` is a function type (in fact it is lambda).
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var f=func(x,y,z){
|
var f=func(x,y,z){
|
||||||
return nil;
|
return nil;
|
||||||
|
@ -654,11 +665,13 @@ var f=func(args...){
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`vm_obj` is a special type that stores user data.
|
`vm_obj` is a special type that stores user data.
|
||||||
This means you could use other complex C/C++ data types in nasal.
|
This means you could use other complex C/C++ data types in nasal.
|
||||||
This type is used when you are trying to add a new data structure into nasal,
|
This type is used when you are trying to add a new data structure into nasal,
|
||||||
so this type is often created by native-function that programmed in C/C++ by library developers.
|
so this type is often created by native-function that programmed in C/C++ by library developers.
|
||||||
You could see how to write your own native-functions below.
|
You could see how to write your own native-functions below.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var my_new_obj=func(){
|
var my_new_obj=func(){
|
||||||
return __builtin_my_obj();
|
return __builtin_my_obj();
|
||||||
|
@ -675,20 +688,26 @@ Nasal has basic math operators `+` `-` `*` `/` and a special operator `~` that l
|
||||||
'str1'~'str2';
|
'str1'~'str2';
|
||||||
(1+2)*(3+4)
|
(1+2)*(3+4)
|
||||||
```
|
```
|
||||||
|
|
||||||
For conditional expressions, operators `==` `!=` `<` `>` `<=` `>=` are used to compare two values.
|
For conditional expressions, operators `==` `!=` `<` `>` `<=` `>=` are used to compare two values.
|
||||||
`and` `or` have the same function as C/C++ `&&` `||`, link comparations together.
|
`and` `or` have the same function as C/C++ `&&` `||`, link comparations together.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
1+1 and 0;
|
1+1 and 0;
|
||||||
1<0 or 1>0;
|
1<0 or 1>0;
|
||||||
1<=0 and 1>=0;
|
1<=0 and 1>=0;
|
||||||
1==0 or 1!=0;
|
1==0 or 1!=0;
|
||||||
```
|
```
|
||||||
|
|
||||||
Unary operators `-` `!` have the same function as C/C++.
|
Unary operators `-` `!` have the same function as C/C++.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
-1;
|
-1;
|
||||||
!0;
|
!0;
|
||||||
```
|
```
|
||||||
|
|
||||||
Operators `=` `+=` `-=` `*=` `/=` `~=` are used in assignment expressions.
|
Operators `=` `+=` `-=` `*=` `/=` `~=` are used in assignment expressions.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
a=b=c=d=1;
|
a=b=c=d=1;
|
||||||
a+=1;
|
a+=1;
|
||||||
|
@ -736,6 +755,7 @@ if(1){
|
||||||
### __Loop__
|
### __Loop__
|
||||||
|
|
||||||
While loop and for loop is simalar to C/C++.
|
While loop and for loop is simalar to C/C++.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
while(condition)
|
while(condition)
|
||||||
continue;
|
continue;
|
||||||
|
@ -743,14 +763,18 @@ while(condition)
|
||||||
for(var i=0;i<10;i+=1)
|
for(var i=0;i<10;i+=1)
|
||||||
break;
|
break;
|
||||||
```
|
```
|
||||||
|
|
||||||
Nasal has another two kinds of loops that iterates through a vector:
|
Nasal has another two kinds of loops that iterates through a vector:
|
||||||
|
|
||||||
`forindex` will get the index of a vector.
|
`forindex` will get the index of a vector.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
forindex(var i;elem)
|
forindex(var i;elem)
|
||||||
print(elem[i]);
|
print(elem[i]);
|
||||||
```
|
```
|
||||||
|
|
||||||
`foreach` will get the element of a vector.
|
`foreach` will get the element of a vector.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
foreach(var i;elem)
|
foreach(var i;elem)
|
||||||
print(i);
|
print(i);
|
||||||
|
@ -786,6 +810,7 @@ func(x){return 1/(1+math.exp(-x));}(0.5);
|
||||||
|
|
||||||
There's an interesting test file 'y-combinator.nas',
|
There's an interesting test file 'y-combinator.nas',
|
||||||
try it for fun:
|
try it for fun:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var fib=func(f){
|
var fib=func(f){
|
||||||
return f(f);
|
return f(f);
|
||||||
|
@ -800,8 +825,10 @@ var fib=func(f){
|
||||||
```
|
```
|
||||||
|
|
||||||
### __Closure__
|
### __Closure__
|
||||||
|
|
||||||
Closure means you could get the variable that is not in the local scope of a function that you called.
|
Closure means you could get the variable that is not in the local scope of a function that you called.
|
||||||
Here is an example, result is `1`:
|
Here is an example, result is `1`:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var f=func(){
|
var f=func(){
|
||||||
var a=1;
|
var a=1;
|
||||||
|
@ -809,7 +836,9 @@ var f=func(){
|
||||||
}
|
}
|
||||||
print(f()());
|
print(f()());
|
||||||
```
|
```
|
||||||
|
|
||||||
Using closure makes it easier to OOP.
|
Using closure makes it easier to OOP.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var student=func(n,a){
|
var student=func(n,a){
|
||||||
var (name,age)=(n,a);
|
var (name,age)=(n,a);
|
||||||
|
@ -833,6 +862,7 @@ virtual machine will search the member is parents.
|
||||||
If there is a hash that has the member, you will get the member's value.
|
If there is a hash that has the member, you will get the member's value.
|
||||||
|
|
||||||
Using this mechanism, we could OOP like this, the result is `114514`:
|
Using this mechanism, we could OOP like this, the result is `114514`:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var trait={
|
var trait={
|
||||||
get:func{return me.val;},
|
get:func{return me.val;},
|
||||||
|
@ -848,9 +878,11 @@ var class={
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
First virtual machine cannot find member `set` in hash `a`, but in `a.parents` there's a hash `trait` has the member `set`, so we get the `set`.
|
First virtual machine cannot find member `set` in hash `a`, but in `a.parents` there's a hash `trait` has the member `set`, so we get the `set`.
|
||||||
variable `me` points to hash `a`, so we change the `a.val`.
|
variable `me` points to hash `a`, so we change the `a.val`.
|
||||||
And `get` has the same process.
|
And `get` has the same process.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var a=class.new();
|
var a=class.new();
|
||||||
a.set(114514);
|
a.set(114514);
|
||||||
|
@ -874,7 +906,9 @@ Definition:
|
||||||
```C++
|
```C++
|
||||||
nasal_ref builtin_chr(std::vector<nasal_ref>&,nasal_gc&);
|
nasal_ref builtin_chr(std::vector<nasal_ref>&,nasal_gc&);
|
||||||
```
|
```
|
||||||
|
|
||||||
Then complete this function using C++:
|
Then complete this function using C++:
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
nasal_ref builtin_print(std::vector<nasal_ref>& local,nasal_gc& gc)
|
nasal_ref builtin_print(std::vector<nasal_ref>& local,nasal_gc& gc)
|
||||||
{
|
{
|
||||||
|
@ -902,7 +936,9 @@ nasal_ref builtin_print(std::vector<nasal_ref>& local,nasal_gc& gc)
|
||||||
return gc.nil;
|
return gc.nil;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
After that, register the built-in function's name(in nasal) and the function's pointer in this table:
|
After that, register the built-in function's name(in nasal) and the function's pointer in this table:
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
struct func
|
struct func
|
||||||
{
|
{
|
||||||
|
@ -922,6 +958,7 @@ var print=func(elems...){
|
||||||
return __builtin_print(elems);
|
return __builtin_print(elems);
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
In fact the arguments that `__builtin_print` uses is not necessary.
|
In fact the arguments that `__builtin_print` uses is not necessary.
|
||||||
So writting it like this is also right:
|
So writting it like this is also right:
|
||||||
|
|
||||||
|
@ -1080,6 +1117,7 @@ vm stack(limit 10):
|
||||||
```
|
```
|
||||||
|
|
||||||
Here is an example of stack overflow:
|
Here is an example of stack overflow:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
func(f){
|
func(f){
|
||||||
return f(f);
|
return f(f);
|
||||||
|
@ -1091,6 +1129,7 @@ func(f){
|
||||||
```
|
```
|
||||||
|
|
||||||
And the trace back info:
|
And the trace back info:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
[vm] stack overflow
|
[vm] stack overflow
|
||||||
trace back:
|
trace back:
|
||||||
|
@ -1104,6 +1143,7 @@ vm stack(limit 10):
|
||||||
```
|
```
|
||||||
|
|
||||||
Error will be thrown if there's a fatal error when executing:
|
Error will be thrown if there's a fatal error when executing:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
func(){
|
func(){
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1111,6 +1151,7 @@ func(){
|
||||||
```
|
```
|
||||||
|
|
||||||
And the trace back info:
|
And the trace back info:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
[vm] error at 0x00000008: callv: must call a vector/hash/string
|
[vm] error at 0x00000008: callv: must call a vector/hash/string
|
||||||
trace back:
|
trace back:
|
||||||
|
@ -1120,6 +1161,7 @@ vm stack(limit 10):
|
||||||
```
|
```
|
||||||
|
|
||||||
Use command `-d` or `--detail` the trace back info will be this:
|
Use command `-d` or `--detail` the trace back info will be this:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
hello world
|
hello world
|
||||||
[vm] error: exception test
|
[vm] error: exception test
|
||||||
|
@ -1188,4 +1230,4 @@ global:
|
||||||
local:
|
local:
|
||||||
[0] nil |
|
[0] nil |
|
||||||
[1] str | <0x249abd0> exception test
|
[1] str | <0x249abd0> exception test
|
||||||
```
|
```
|
||||||
|
|
6
lib.nas
6
lib.nas
|
@ -100,9 +100,9 @@ var unix=
|
||||||
dup2: func(fd0,fd1){die("not supported yet");},
|
dup2: func(fd0,fd1){die("not supported yet");},
|
||||||
exec: func(filename,argv,envp){die("not supported yet");},
|
exec: func(filename,argv,envp){die("not supported yet");},
|
||||||
waitpid: func(pid,nohang=0){die("not supported yet");},
|
waitpid: func(pid,nohang=0){die("not supported yet");},
|
||||||
opendir: func(path){die("not supported yet");},
|
opendir: func(path){return __builtin_opendir;},
|
||||||
readdir: func(handle){die("not supported yet");},
|
readdir: func(handle){return __builtin_readdir;},
|
||||||
closedir: func(handle){die("not supported yet");},
|
closedir: func(handle){return __builtin_closedir;},
|
||||||
time: func(){return time(0);},
|
time: func(){return time(0);},
|
||||||
sleep: func(secs){return __builtin_sleep(secs);},
|
sleep: func(secs){return __builtin_sleep(secs);},
|
||||||
chdir: func(path){return __builtin_chdir(path);},
|
chdir: func(path){return __builtin_chdir(path);},
|
||||||
|
|
6
main.cpp
6
main.cpp
|
@ -63,6 +63,7 @@ void err()
|
||||||
|
|
||||||
void execute(const std::string& file,const uint32_t cmd)
|
void execute(const std::string& file,const uint32_t cmd)
|
||||||
{
|
{
|
||||||
|
// 33kb space on stack
|
||||||
nasal_lexer lexer;
|
nasal_lexer lexer;
|
||||||
nasal_parse parse;
|
nasal_parse parse;
|
||||||
nasal_import linker;
|
nasal_import linker;
|
||||||
|
@ -107,6 +108,11 @@ void execute(const std::string& file,const uint32_t cmd)
|
||||||
|
|
||||||
int main(int argc,const char* argv[])
|
int main(int argc,const char* argv[])
|
||||||
{
|
{
|
||||||
|
if(argc==1)
|
||||||
|
{
|
||||||
|
help();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if(argc==2)
|
if(argc==2)
|
||||||
{
|
{
|
||||||
std::string s(argv[1]);
|
std::string s(argv[1]);
|
||||||
|
|
1
nasal.h
1
nasal.h
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
inline double hex_to_double(const char* str)
|
inline double hex_to_double(const char* str)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
*/
|
*/
|
||||||
enum obj_type
|
enum obj_type
|
||||||
{
|
{
|
||||||
obj_file,
|
obj_file=1,
|
||||||
|
obj_dir,
|
||||||
};
|
};
|
||||||
// declaration of builtin functions
|
// declaration of builtin functions
|
||||||
// to add new builtin function, declare it here and write the definition below
|
// to add new builtin function, declare it here and write the definition below
|
||||||
|
@ -69,6 +70,9 @@ nas_native(builtin_sfld);
|
||||||
nas_native(builtin_setfld);
|
nas_native(builtin_setfld);
|
||||||
nas_native(builtin_buf);
|
nas_native(builtin_buf);
|
||||||
nas_native(builtin_sleep);
|
nas_native(builtin_sleep);
|
||||||
|
nas_native(builtin_opendir);
|
||||||
|
nas_native(builtin_readdir);
|
||||||
|
nas_native(builtin_closedir);
|
||||||
nas_native(builtin_chdir);
|
nas_native(builtin_chdir);
|
||||||
nas_native(builtin_getcwd);
|
nas_native(builtin_getcwd);
|
||||||
nas_native(builtin_getenv);
|
nas_native(builtin_getenv);
|
||||||
|
@ -142,6 +146,9 @@ struct
|
||||||
{"__builtin_setfld", builtin_setfld },
|
{"__builtin_setfld", builtin_setfld },
|
||||||
{"__builtin_buf", builtin_buf },
|
{"__builtin_buf", builtin_buf },
|
||||||
{"__builtin_sleep", builtin_sleep },
|
{"__builtin_sleep", builtin_sleep },
|
||||||
|
{"__builtin_opendir", builtin_opendir },
|
||||||
|
{"__builtin_readdir", builtin_readdir },
|
||||||
|
{"__builtin_closedir",builtin_closedir},
|
||||||
{"__builtin_chdir", builtin_chdir },
|
{"__builtin_chdir", builtin_chdir },
|
||||||
{"__builtin_getcwd", builtin_getcwd },
|
{"__builtin_getcwd", builtin_getcwd },
|
||||||
{"__builtin_getenv", builtin_getenv },
|
{"__builtin_getenv", builtin_getenv },
|
||||||
|
@ -895,6 +902,39 @@ nasal_ref builtin_sleep(std::vector<nasal_ref>& local,nasal_gc& gc)
|
||||||
usleep((useconds_t)(val.num()*1e6));
|
usleep((useconds_t)(val.num()*1e6));
|
||||||
return gc.nil;
|
return gc.nil;
|
||||||
}
|
}
|
||||||
|
nasal_ref builtin_opendir(std::vector<nasal_ref>& local,nasal_gc& gc)
|
||||||
|
{
|
||||||
|
nasal_ref path=local[1];
|
||||||
|
if(path.type!=vm_str)
|
||||||
|
return builtin_err("opendir","\"path\" must be string");
|
||||||
|
DIR* p=opendir(path.str()->c_str());
|
||||||
|
if(!p)
|
||||||
|
return builtin_err("opendir","cannot open dir <"+*path.str()+">");
|
||||||
|
nasal_ref ret=gc.alloc(vm_obj);
|
||||||
|
ret.obj()->type=obj_dir;
|
||||||
|
ret.obj()->ptr=(void*)p;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
nasal_ref builtin_readdir(std::vector<nasal_ref>& local,nasal_gc& gc)
|
||||||
|
{
|
||||||
|
nasal_ref handle=local[1];
|
||||||
|
if(handle.type!=vm_obj || handle.obj()->type!=obj_dir)
|
||||||
|
return builtin_err("readdir","not a correct dir handle");
|
||||||
|
dirent* p=readdir((DIR*)handle.obj()->ptr);
|
||||||
|
if(!p)
|
||||||
|
return gc.nil;
|
||||||
|
nasal_ref ret=gc.alloc(vm_str);
|
||||||
|
*ret.str()=p->d_name;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
nasal_ref builtin_closedir(std::vector<nasal_ref>& local,nasal_gc& gc)
|
||||||
|
{
|
||||||
|
nasal_ref handle=local[1];
|
||||||
|
if(handle.type!=vm_obj || handle.obj()->type!=obj_dir)
|
||||||
|
return builtin_err("closedir","not a correct dir handle");
|
||||||
|
closedir((DIR*)handle.obj()->ptr);
|
||||||
|
return gc.nil;
|
||||||
|
}
|
||||||
nasal_ref builtin_chdir(std::vector<nasal_ref>& local,nasal_gc& gc)
|
nasal_ref builtin_chdir(std::vector<nasal_ref>& local,nasal_gc& gc)
|
||||||
{
|
{
|
||||||
nasal_ref path=local[1];
|
nasal_ref path=local[1];
|
||||||
|
|
|
@ -100,9 +100,9 @@ var unix=
|
||||||
dup2: func(fd0,fd1){die("not supported yet");},
|
dup2: func(fd0,fd1){die("not supported yet");},
|
||||||
exec: func(filename,argv,envp){die("not supported yet");},
|
exec: func(filename,argv,envp){die("not supported yet");},
|
||||||
waitpid: func(pid,nohang=0){die("not supported yet");},
|
waitpid: func(pid,nohang=0){die("not supported yet");},
|
||||||
opendir: func(path){die("not supported yet");},
|
opendir: func(path){return __builtin_opendir;},
|
||||||
readdir: func(handle){die("not supported yet");},
|
readdir: func(handle){return __builtin_readdir;},
|
||||||
closedir: func(handle){die("not supported yet");},
|
closedir: func(handle){return __builtin_closedir;},
|
||||||
time: func(){return time(0);},
|
time: func(){return time(0);},
|
||||||
sleep: func(secs){return __builtin_sleep(secs);},
|
sleep: func(secs){return __builtin_sleep(secs);},
|
||||||
chdir: func(path){return __builtin_chdir(path);},
|
chdir: func(path){return __builtin_chdir(path);},
|
||||||
|
|
Loading…
Reference in New Issue