add unix.opendir unix.readdir unix.closedir

This commit is contained in:
ValKmjolnir 2021-10-31 23:11:04 +08:00
parent e4ea34db51
commit f8e2918561
7 changed files with 101 additions and 11 deletions

1
.gitignore vendored
View File

@ -33,3 +33,4 @@
nasal
.vscode
dump

View File

@ -43,7 +43,7 @@ It's quite easy to build this 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
@ -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.
`vm_nil` is a null type. It means nothing.
```javascript
var spc=nil;
```
`vm_num` has 3 formats. Dec, hex and oct. Using IEEE754 double to store.
```javascript
var n=1;
var n=2.71828;
@ -605,13 +608,17 @@ var n=0x7fffffff;
var n=0xAA55;
var n=0o170001;
```
`vm_str` has 3 formats. But the third one is often used to declare a character.
```javascript
var s='str';
var s="another string";
var s=`c`;
```
`vm_vec` has unlimited length and can store all types of values.
```javascript
var vec=[];
var vec=[
@ -623,7 +630,9 @@ var vec=[
];
append(vec,0,1,2);
```
`vm_hash` is a hashmap that stores values with strings/identifiers as the key.
```javascript
var hash={
member1:nil,
@ -636,7 +645,9 @@ var hash={
}
};
```
`vm_func` is a function type (in fact it is lambda).
```javascript
var f=func(x,y,z){
return nil;
@ -654,11 +665,13 @@ var f=func(args...){
return sum;
}
```
`vm_obj` is a special type that stores user data.
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,
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.
```javascript
var my_new_obj=func(){
return __builtin_my_obj();
@ -675,20 +688,26 @@ Nasal has basic math operators `+` `-` `*` `/` and a special operator `~` that l
'str1'~'str2';
(1+2)*(3+4)
```
For conditional expressions, operators `==` `!=` `<` `>` `<=` `>=` are used to compare two values.
`and` `or` have the same function as C/C++ `&&` `||`, link comparations together.
```javascript
1+1 and 0;
1<0 or 1>0;
1<=0 and 1>=0;
1==0 or 1!=0;
```
Unary operators `-` `!` have the same function as C/C++.
```javascript
-1;
!0;
```
Operators `=` `+=` `-=` `*=` `/=` `~=` are used in assignment expressions.
```javascript
a=b=c=d=1;
a+=1;
@ -736,6 +755,7 @@ if(1){
### __Loop__
While loop and for loop is simalar to C/C++.
```javascript
while(condition)
continue;
@ -743,14 +763,18 @@ while(condition)
for(var i=0;i<10;i+=1)
break;
```
Nasal has another two kinds of loops that iterates through a vector:
`forindex` will get the index of a vector.
```javascript
forindex(var i;elem)
print(elem[i]);
```
`foreach` will get the element of a vector.
```javascript
foreach(var i;elem)
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',
try it for fun:
```javascript
var fib=func(f){
return f(f);
@ -800,8 +825,10 @@ var fib=func(f){
```
### __Closure__
Closure means you could get the variable that is not in the local scope of a function that you called.
Here is an example, result is `1`:
```javascript
var f=func(){
var a=1;
@ -809,7 +836,9 @@ var f=func(){
}
print(f()());
```
Using closure makes it easier to OOP.
```javascript
var student=func(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.
Using this mechanism, we could OOP like this, the result is `114514`:
```javascript
var trait={
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`.
variable `me` points to hash `a`, so we change the `a.val`.
And `get` has the same process.
```javascript
var a=class.new();
a.set(114514);
@ -874,7 +906,9 @@ Definition:
```C++
nasal_ref builtin_chr(std::vector<nasal_ref>&,nasal_gc&);
```
Then complete this function using C++:
```C++
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;
}
```
After that, register the built-in function's name(in nasal) and the function's pointer in this table:
```C++
struct func
{
@ -922,6 +958,7 @@ var print=func(elems...){
return __builtin_print(elems);
};
```
In fact the arguments that `__builtin_print` uses is not necessary.
So writting it like this is also right:
@ -1080,6 +1117,7 @@ vm stack(limit 10):
```
Here is an example of stack overflow:
```javascript
func(f){
return f(f);
@ -1091,6 +1129,7 @@ func(f){
```
And the trace back info:
```javascript
[vm] stack overflow
trace back:
@ -1104,6 +1143,7 @@ vm stack(limit 10):
```
Error will be thrown if there's a fatal error when executing:
```javascript
func(){
return 0;
@ -1111,6 +1151,7 @@ func(){
```
And the trace back info:
```javascript
[vm] error at 0x00000008: callv: must call a vector/hash/string
trace back:
@ -1120,6 +1161,7 @@ vm stack(limit 10):
```
Use command `-d` or `--detail` the trace back info will be this:
```javascript
hello world
[vm] error: exception test

View File

@ -100,9 +100,9 @@ var unix=
dup2: func(fd0,fd1){die("not supported yet");},
exec: func(filename,argv,envp){die("not supported yet");},
waitpid: func(pid,nohang=0){die("not supported yet");},
opendir: func(path){die("not supported yet");},
readdir: func(handle){die("not supported yet");},
closedir: func(handle){die("not supported yet");},
opendir: func(path){return __builtin_opendir;},
readdir: func(handle){return __builtin_readdir;},
closedir: func(handle){return __builtin_closedir;},
time: func(){return time(0);},
sleep: func(secs){return __builtin_sleep(secs);},
chdir: func(path){return __builtin_chdir(path);},

View File

@ -63,6 +63,7 @@ void err()
void execute(const std::string& file,const uint32_t cmd)
{
// 33kb space on stack
nasal_lexer lexer;
nasal_parse parse;
nasal_import linker;
@ -107,6 +108,11 @@ void execute(const std::string& file,const uint32_t cmd)
int main(int argc,const char* argv[])
{
if(argc==1)
{
help();
return 0;
}
if(argc==2)
{
std::string s(argv[1]);

View File

@ -21,6 +21,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
inline double hex_to_double(const char* str)
{

View File

@ -9,7 +9,8 @@
*/
enum obj_type
{
obj_file,
obj_file=1,
obj_dir,
};
// declaration of builtin functions
// 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_buf);
nas_native(builtin_sleep);
nas_native(builtin_opendir);
nas_native(builtin_readdir);
nas_native(builtin_closedir);
nas_native(builtin_chdir);
nas_native(builtin_getcwd);
nas_native(builtin_getenv);
@ -142,6 +146,9 @@ struct
{"__builtin_setfld", builtin_setfld },
{"__builtin_buf", builtin_buf },
{"__builtin_sleep", builtin_sleep },
{"__builtin_opendir", builtin_opendir },
{"__builtin_readdir", builtin_readdir },
{"__builtin_closedir",builtin_closedir},
{"__builtin_chdir", builtin_chdir },
{"__builtin_getcwd", builtin_getcwd },
{"__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));
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 path=local[1];

View File

@ -100,9 +100,9 @@ var unix=
dup2: func(fd0,fd1){die("not supported yet");},
exec: func(filename,argv,envp){die("not supported yet");},
waitpid: func(pid,nohang=0){die("not supported yet");},
opendir: func(path){die("not supported yet");},
readdir: func(handle){die("not supported yet");},
closedir: func(handle){die("not supported yet");},
opendir: func(path){return __builtin_opendir;},
readdir: func(handle){return __builtin_readdir;},
closedir: func(handle){return __builtin_closedir;},
time: func(){return time(0);},
sleep: func(secs){return __builtin_sleep(secs);},
chdir: func(path){return __builtin_chdir(path);},