Merge pull request #26 from ValKmjolnir/develop

 simpler ghost type check mechanism & split lib
This commit is contained in:
Li Haokun 2023-08-12 11:54:13 +08:00 committed by GitHub
commit afaef55c68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 729 additions and 652 deletions

View File

@ -23,7 +23,10 @@ set(NASAL_OBJECT_SOURCE_FILE
${CMAKE_SOURCE_DIR}/src/coroutine.cpp
${CMAKE_SOURCE_DIR}/src/fg_props.cpp
${CMAKE_SOURCE_DIR}/src/bits_lib.cpp
${CMAKE_SOURCE_DIR}/src/io_lib.cpp
${CMAKE_SOURCE_DIR}/src/math_lib.cpp
${CMAKE_SOURCE_DIR}/src/dylib_lib.cpp
${CMAKE_SOURCE_DIR}/src/unix_lib.cpp
${CMAKE_SOURCE_DIR}/src/nasal_codegen.cpp
${CMAKE_SOURCE_DIR}/src/nasal_dbg.cpp
${CMAKE_SOURCE_DIR}/src/nasal_err.cpp

View File

@ -19,7 +19,10 @@ NASAL_HEADER=\
src/symbol_finder.h\
src/fg_props.h\
src/bits_lib.h\
src/io_lib.h\
src/math_lib.h\
src/dylib_lib.h\
src/unix_lib.h\
src/coroutine.h
NASAL_OBJECT=\
@ -39,7 +42,10 @@ NASAL_OBJECT=\
build/nasal_gc.o\
build/nasal_builtin.o\
build/fg_props.o\
build/io_lib.o\
build/math_lib.o\
build/unix_lib.o\
build/dylib_lib.o\
build/coroutine.o\
build/nasal_vm.o\
build/nasal_dbg.o\
@ -111,6 +117,24 @@ build/math_lib.o: \
src/math_lib.h src/math_lib.cpp | build
$(CXX) -std=$(STD) -c -O3 src/math_lib.cpp -fno-exceptions -fPIC -o build/math_lib.o -I .
build/io_lib.o: \
src/nasal.h\
src/nasal_gc.h\
src/io_lib.h src/io_lib.cpp | build
$(CXX) -std=$(STD) -c -O3 src/io_lib.cpp -fno-exceptions -fPIC -o build/io_lib.o -I .
build/dylib_lib.o: \
src/nasal.h\
src/nasal_gc.h\
src/dylib_lib.h src/dylib_lib.cpp | build
$(CXX) -std=$(STD) -c -O3 src/dylib_lib.cpp -fno-exceptions -fPIC -o build/dylib_lib.o -I .
build/unix_lib.o: \
src/nasal.h\
src/nasal_gc.h\
src/unix_lib.h src/unix_lib.cpp | build
$(CXX) -std=$(STD) -c -O3 src/unix_lib.cpp -fno-exceptions -fPIC -o build/unix_lib.o -I .
build/fg_props.o: \
src/nasal.h\
src/nasal_gc.h\

View File

@ -37,7 +37,7 @@ var quick_fib(var* args, usize size, gc* ngc) {
return var::num(res);
}
u32 ghost_for_test;
const auto ghost_for_test = "ghost_for_test";
void ghost_for_test_destructor(void* ptr) {
std::cout << "ghost_for_test::destructor (0x";
@ -49,7 +49,7 @@ 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, new u32, &ngc->global_ghost_type_table);
res.obj().set(ghost_for_test, ghost_for_test_destructor, new u32);
return res;
}
@ -87,14 +87,6 @@ module_func_info func_tbl[] = {
}
extern "C" module_func_info* get(ghost_register_table* table) {
if (table->exists("fib_for_test")) {
nasal_fib_module::ghost_for_test = table->get_ghost_type_index("fib_for_test");
return nasal_fib_module::func_tbl;
}
nasal_fib_module::ghost_for_test = table->register_ghost_type(
"fib_for_test",
nasal_fib_module::ghost_for_test_destructor
);
extern "C" module_func_info* get() {
return nasal_fib_module::func_tbl;
}

View File

@ -99,6 +99,6 @@ module_func_info func_tbl[]={
{nullptr,nullptr}
};
extern "C" module_func_info* get(ghost_register_table* table) {
extern "C" module_func_info* get() {
return func_tbl;
}

View File

@ -1,31 +1,54 @@
import.std.dylib;
var libfib=func(){
var dl=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib=dl.fib;
var qfib=dl.quick_fib;
var create_ghost=dl.create_ghost;
var set_ghost=dl.set_ghost;
var print_ghost=dl.print_ghost;
var zero_call=dylib.limitcall(0);
var call=dylib.limitcall(1);
var test_call=dylib.limitcall(2);
var res={
fib: func(x) {return call(fib,x)},
qfib: func(x) {return call(qfib,x)},
create_ghost: func() {return zero_call(create_ghost)},
set_ghost: func(object, x) {return test_call(set_ghost, object, x)},
print_ghost: func(object) {return call(print_ghost, object)}
};
var _dl = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
res.test_ghost=func() {
var ghost=res.create_ghost();
res.print_ghost(nil); # err
res.print_ghost(ghost); # random
res.set_ghost(nil, 114); # err
res.set_ghost(ghost, 114); # success
res.print_ghost(ghost); # 114
}
var _fib = _dl.fib;
return res;
}();
var _qfib = _dl.quick_fib;
var _create_ghost = _dl.create_ghost;
var _set_ghost = _dl.set_ghost;
var _print_ghost = _dl.print_ghost;
var _zero_call = dylib.limitcall(0);
var _call = dylib.limitcall(1);
var _test_call = dylib.limitcall(2);
var fib = func(x) {
return _call(_fib, x)
}
var qfib = func(x) {
return _call(_qfib, x)
}
var create_ghost = func() {
return _zero_call(_create_ghost)
}
var set_ghost = func(object, x) {
return _test_call(_set_ghost, object, x)
}
var print_ghost = func(object) {
return _call(_print_ghost, object)
}
var test_ghost=func() {
var ghost = create_ghost();
print_ghost(nil); # err
print_ghost(ghost); # random
set_ghost(nil, 114); # err
set_ghost(ghost, 114); # success
print_ghost(ghost); # 114
}

View File

@ -1,62 +1,66 @@
import.std.dylib;
var dl=dylib.dlopen("libmat."~(os.platform()=="windows"?"dll":"so"));
var vec2=dl.nas_vec2;
var vec3=dl.nas_vec3;
var (vec2add,vec2sub,vec2mul,vec2div,vec2neg,vec2norm,vec2len,vec2dot)=(
dl.nas_vec2_add,
dl.nas_vec2_sub,
dl.nas_vec2_mult,
dl.nas_vec2_div,
dl.nas_vec2_neg,
dl.nas_vec2_norm,
dl.nas_vec2_len,
dl.nas_vec2_dot
var _dl = dylib.dlopen("libmat."~(os.platform()=="windows"?"dll":"so"));
var _vec2 = _dl.nas_vec2;
var _vec3 = _dl.nas_vec3;
var (_vec2add, _vec2sub, _vec2mul, _vec2div, _vec2neg, _vec2norm, _vec2len, _vec2dot)=(
_dl.nas_vec2_add,
_dl.nas_vec2_sub,
_dl.nas_vec2_mult,
_dl.nas_vec2_div,
_dl.nas_vec2_neg,
_dl.nas_vec2_norm,
_dl.nas_vec2_len,
_dl.nas_vec2_dot
);
var (vec3add,vec3sub,vec3mul,vec3div,vec3neg,vec3norm,vec3len,vec3dot)=(
dl.nas_vec3_add,
dl.nas_vec3_sub,
dl.nas_vec3_mult,
dl.nas_vec3_div,
dl.nas_vec3_neg,
dl.nas_vec3_norm,
dl.nas_vec3_len,
dl.nas_vec3_dot
var (_vec3add, _vec3sub, _vec3mul, _vec3div, _vec3neg, _vec3norm, _vec3len, _vec3dot)=(
_dl.nas_vec3_add,
_dl.nas_vec3_sub,
_dl.nas_vec3_mult,
_dl.nas_vec3_div,
_dl.nas_vec3_neg,
_dl.nas_vec3_norm,
_dl.nas_vec3_len,
_dl.nas_vec3_dot
);
var (rotate_x,rotate_y,rotate_z)=(
dl.nas_rotate_x,
dl.nas_rotate_y,
dl.nas_rotate_z
var (_rotate_x, _rotate_y, _rotate_z)=(
_dl.nas_rotate_x,
_dl.nas_rotate_y,
_dl.nas_rotate_z
);
var (invoke_i,invoke_ii,invoke_iii)=(
var (_invoke_i, _invoke_ii, _invoke_iii)=(
dylib.limitcall(1),
dylib.limitcall(2),
dylib.limitcall(3)
);
var vec2={
new: func(x,y){return invoke_ii(vec2,x,y);},
add: func(v0,v1){return invoke_ii(vec2add,v0,v1);},
sub: func(v0,v1){return invoke_ii(vec2sub,v0,v1);},
mul: func(v0,v1){return invoke_ii(vec2mul,v0,v1);},
div: func(v0,v1){return invoke_ii(vec2div,v0,v1);},
neg: func(v0){return invoke_i(vec2neg,v0);},
norm: func(v0){return invoke_i(vec2norm,v0);},
len: func(v0){return invoke_i(vec2len,v0);},
dot: func(v0,v1){return invoke_ii(vec2dot,v0,v1);}
};
var vec3={
new: func(x,y,z){return invoke_iii(vec3,x,y,z);},
add: func(v0,v1){return invoke_ii(vec3add,v0,v1);},
sub: func(v0,v1){return invoke_ii(vec3sub,v0,v1);},
mul: func(v0,v1){return invoke_ii(vec3mul,v0,v1);},
div: func(v0,v1){return invoke_ii(vec3div,v0,v1);},
neg: func(v0){return invoke_i(vec3neg,v0);},
norm: func(v0){return invoke_i(vec3norm,v0);},
len: func(v0){return invoke_i(vec3len,v0);},
rx: func(v0,angle){return invoke_ii(rotate_x,v0,angle);},
ry: func(v0,angle){return invoke_ii(rotate_y,v0,angle);},
rz: func(v0,angle){return invoke_ii(rotate_z,v0,angle);},
dot: func(v0,v1){return invoke_ii(vec3dot,v0,v1);}
var vec2 = {
new: func(x, y) {return _invoke_ii(_vec2, x, y);},
add: func(v0, v1) {return _invoke_ii(_vec2add, v0, v1);},
sub: func(v0, v1) {return _invoke_ii(_vec2sub, v0, v1);},
mul: func(v0, v1) {return _invoke_ii(_vec2mul, v0, v1);},
div: func(v0, v1) {return _invoke_ii(_vec2div, v0, v1);},
neg: func(v0) {return _invoke_i(_vec2neg, v0);},
norm: func(v0) {return _invoke_i(_vec2norm, v0);},
len: func(v0) {return _invoke_i(_vec2len, v0);},
dot: func(v0, v1) {return _invoke_ii(_vec2dot, v0, v1);}
};
var vec3 = {
new: func(x, y, z) {return _invoke_iii(_vec3, x, y, z);},
add: func(v0, v1) {return _invoke_ii(_vec3add, v0, v1);},
sub: func(v0, v1) {return _invoke_ii(_vec3sub, v0, v1);},
mul: func(v0, v1) {return _invoke_ii(_vec3mul, v0, v1);},
div: func(v0, v1) {return _invoke_ii(_vec3div, v0, v1);},
neg: func(v0) {return _invoke_i(_vec3neg, v0);},
norm: func(v0) {return _invoke_i(_vec3norm, v0);},
len: func(v0) {return _invoke_i(_vec3len, v0);},
rx: func(v0, angle) {return _invoke_ii(_rotate_x, v0, angle);},
ry: func(v0, angle) {return _invoke_ii(_rotate_y, v0, angle);},
rz: func(v0, angle) {return _invoke_ii(_rotate_z, v0, angle);},
dot: func(v0, v1) {return _invoke_ii(_vec3dot, v0, v1);}
};

View File

@ -291,6 +291,6 @@ module_func_info func_tbl[]={
{nullptr,nullptr}
};
extern "C" module_func_info* get(ghost_register_table* table) {
extern "C" module_func_info* get() {
return func_tbl;
}

View File

@ -209,6 +209,6 @@ module_func_info func_tbl[]={
{nullptr,nullptr}
};
extern "C" module_func_info* get(ghost_register_table* table) {
extern "C" module_func_info* get() {
return func_tbl;
}

105
src/dylib_lib.cpp Normal file
View File

@ -0,0 +1,105 @@
#include "dylib_lib.h"
const auto dylib_type_name = "dylib";
const auto func_addr_type_name = "faddr";
void dylib_destructor(void* ptr) {
#ifdef _WIN32
FreeLibrary((HMODULE)ptr);
#else
dlclose(ptr);
#endif
}
void func_addr_destructor(void* ptr) {}
var builtin_dlopen(var* local, gc& ngc) {
var dlname = local[1];
if (dlname.type!=vm_str) {
return nas_err("dlopen", "\"libname\" must be string");
}
#ifdef _WIN32
wchar_t* str = new wchar_t[dlname.str().size()+1];
if (!str) {
return nas_err("dlopen", "malloc failed");
}
memset(str, 0, sizeof(wchar_t)*dlname.str().size()+1);
mbstowcs(str, dlname.str().c_str(),dlname.str().size()+1);
void* ptr = LoadLibraryA(dlname.str().c_str());
delete []str;
#else
void* ptr = dlopen(dlname.str().c_str(), RTLD_LOCAL|RTLD_LAZY);
#endif
if (!ptr) {
return nas_err("dlopen", "cannot open dynamic lib <"+dlname.str()+">");
}
var ret = ngc.temp = ngc.alloc(vm_hash);
var lib = ngc.alloc(vm_obj);
lib.obj().set(dylib_type_name, dylib_destructor, ptr);
ret.hash().elems["lib"] = lib;
#ifdef _WIN32
void* func = (void*)GetProcAddress((HMODULE)lib.obj().ptr, "get");
#else
void* func = dlsym(lib.obj().ptr, "get");
#endif
if (!func) {
return nas_err("dlopen", "cannot find <get> function");
}
// get function pointer by name
module_func_info* tbl = ((get_func_ptr)func)();
if (!tbl) {
return nas_err("dlopen", "failed to get module functions");
}
for(u32 i = 0; tbl[i].name; ++i) {
void* p = (void*)tbl[i].fd;
var tmp = ngc.alloc(vm_obj);
tmp.obj().set(func_addr_type_name, func_addr_destructor, p);
ret.hash().elems[tbl[i].name] = tmp;
}
ngc.temp = nil;
return ret;
}
var builtin_dlclose(var* local, gc& ngc) {
var libptr = local[1];
if (!libptr.objchk(dylib_type_name)) {
return nas_err("dlclose", "\"lib\" is not a valid dynamic lib");
}
libptr.obj().clear();
return nil;
}
var builtin_dlcallv(var* local, gc& ngc) {
var fp = local[1];
var args = local[2];
if (!fp.objchk(func_addr_type_name)) {
return nas_err("dlcall", "\"ptr\" is not a valid function pointer");
}
auto& vec = args.vec().elems;
return ((module_func)fp.obj().ptr)(vec.data(), vec.size(), &ngc);
}
var builtin_dlcall(var* local, gc& ngc) {
var fp = local[1];
if (!fp.objchk(func_addr_type_name)) {
return nas_err("dlcall", "\"ptr\" is not a valid function pointer");
}
var* local_frame_start = local+2;
usize local_frame_size = ngc.rctx->top-local_frame_start;
// arguments' stored place begins at local +2
return ((module_func)fp.obj().ptr)(
local_frame_start,
local_frame_size,
&ngc);
}
nasal_builtin_table dylib_lib_native[] = {
{"__dlopen", builtin_dlopen},
{"__dlclose", builtin_dlclose},
{"__dlcallv", builtin_dlcallv},
{"__dlcall", builtin_dlcall},
{nullptr, nullptr}
};

22
src/dylib_lib.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "nasal.h"
#include "nasal_gc.h"
#include "nasal_builtin.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#include <sys/wait.h>
#endif
void dylib_destructor(void*);
void func_addr_destructor(void*);
var builtin_dlopen(var*, gc&);
var builtin_dlclose(var*, gc&);
var builtin_dlcallv(var*, gc&);
var builtin_dlcall(var*, gc&);
extern nasal_builtin_table dylib_lib_native[];

200
src/io_lib.cpp Normal file
View File

@ -0,0 +1,200 @@
#include "io_lib.h"
const auto file_type_name = "file";
void filehandle_destructor(void* ptr) {
if ((FILE*)ptr==stdin) {
return;
}
fclose((FILE*)ptr);
}
var builtin_readfile(var* local, gc& ngc) {
var val = local[1];
if (val.type!=vm_str) {
return nas_err("io::readfile", "\"filename\" must be string");
}
std::ifstream in(val.str(), std::ios::binary);
std::stringstream rd;
if (!in.fail()) {
rd << in.rdbuf();
}
return ngc.newstr(rd.str());
}
var builtin_fout(var* local, gc& ngc) {
var val = local[1];
var str = local[2];
if (val.type!=vm_str) {
return nas_err("io::fout", "\"filename\" must be string");
}
std::ofstream out(val.str());
if (out.fail()) {
return nas_err("io::fout", "cannot open <"+val.str()+">");
}
out << str;
return nil;
}
var builtin_exists(var* local, gc& ngc) {
if (local[1].type!=vm_str) {
return zero;
}
return access(local[1].str().c_str(), F_OK)!=-1?one:zero;
}
var builtin_open(var* local, gc& ngc) {
var name = local[1];
var mode = local[2];
if (name.type!=vm_str) {
return nas_err("open", "\"filename\" must be string");
}
if (mode.type!=vm_str) {
return nas_err("open", "\"mode\" must be string");
}
FILE* res = fopen(name.str().c_str(), mode.str().c_str());
if (!res) {
return nas_err("open", "failed to open file <"+name.str()+">");
}
var ret = ngc.alloc(vm_obj);
ret.obj().set(file_type_name, filehandle_destructor, res);
return ret;
}
var builtin_close(var* local, gc& ngc) {
var fd = local[1];
if (!fd.objchk(file_type_name)) {
return nas_err("close", "not a valid filehandle");
}
fd.obj().clear();
return nil;
}
var builtin_read(var* local, gc& ngc) {
var fd = local[1];
var buf = local[2];
var len = local[3];
if (!fd.objchk(file_type_name)) {
return nas_err("read", "not a valid filehandle");
}
if (buf.type!=vm_str || buf.val.gcobj->unmut) {
return nas_err("read", "\"buf\" must be mutable string");
}
if (len.type!=vm_num) {
return nas_err("read", "\"len\" must be number");
}
if (len.num()<=0 || len.num()>=(1<<30)) {
return nas_err("read", "\"len\" less than 1 or too large");
}
char* buff = new char[(usize)len.num()+1];
if (!buff) {
return nas_err("read", "malloc failed");
}
f64 res = fread(buff,1,len.num(), (FILE*)fd.obj().ptr);
buf.str() = buff;
buf.val.gcobj->unmut = true;
delete []buff;
return var::num(res);
}
var builtin_write(var* local, gc& ngc) {
var fd = local[1];
var str = local[2];
if (!fd.objchk(file_type_name)) {
return nas_err("write", "not a valid filehandle");
}
if (str.type!=vm_str) {
return nas_err("write", "\"str\" must be string");
}
return var::num((f64)fwrite(str.str().c_str(), 1, str.str().length(), (FILE*)fd.obj().ptr));
}
var builtin_seek(var* local, gc& ngc) {
var fd = local[1];
var pos = local[2];
var whence = local[3];
if (!fd.objchk(file_type_name)) {
return nas_err("seek", "not a valid filehandle");
}
return var::num((f64)fseek((FILE*)fd.obj().ptr, pos.num(), whence.num()));
}
var builtin_tell(var* local, gc& ngc) {
var fd = local[1];
if (!fd.objchk(file_type_name)) {
return nas_err("tell", "not a valid filehandle");
}
return var::num((f64)ftell((FILE*)fd.obj().ptr));
}
var builtin_readln(var* local, gc& ngc) {
var fd = local[1];
if (!fd.objchk(file_type_name)) {
return nas_err("readln", "not a valid filehandle");
}
var str = ngc.alloc(vm_str);
char c;
while((c = fgetc((FILE*)fd.obj().ptr))!=EOF) {
if (c=='\r') {
continue;
}
if (c=='\n') {
return str;
}
str.str() += c;
}
if (str.str().length()) {
return str;
}
return nil;
}
var builtin_stat(var* local, gc& ngc) {
var name = local[1];
if (name.type!=vm_str) {
return nas_err("stat", "\"filename\" must be string");
}
struct stat buf;
if (stat(name.str().c_str(),&buf)<0) {
return nas_err("stat", "failed to open file <"+name.str()+">");
}
var ret = ngc.alloc(vm_vec);
ret.vec().elems = {
var::num((f64)buf.st_dev),
var::num((f64)buf.st_ino),
var::num((f64)buf.st_mode),
var::num((f64)buf.st_nlink),
var::num((f64)buf.st_uid),
var::num((f64)buf.st_gid),
var::num((f64)buf.st_rdev),
var::num((f64)buf.st_size),
var::num((f64)buf.st_atime),
var::num((f64)buf.st_mtime),
var::num((f64)buf.st_ctime)
};
return ret;
}
var builtin_eof(var* local, gc& ngc) {
var fd = local[1];
if (!fd.objchk(file_type_name)) {
return nas_err("readln", "not a valid filehandle");
}
return var::num((f64)feof((FILE*)fd.obj().ptr));
}
nasal_builtin_table io_lib_native[] = {
{"__readfile", builtin_readfile},
{"__fout", builtin_fout},
{"__exists", builtin_exists},
{"__open", builtin_open},
{"__close", builtin_close},
{"__read", builtin_read},
{"__write", builtin_write},
{"__seek", builtin_seek},
{"__tell", builtin_tell},
{"__readln", builtin_readln},
{"__stat", builtin_stat},
{"__eof", builtin_eof},
{nullptr, nullptr}
};

28
src/io_lib.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include "nasal.h"
#include "nasal_gc.h"
#include "nasal_builtin.h"
#include <sys/stat.h>
#ifdef _MSC_VER
#define F_OK 0 // fuck msc
#endif
void filehandle_destructor(void*);
var builtin_readfile(var*, gc&);
var builtin_fout(var*, gc&);
var builtin_exists(var*, gc&);
var builtin_open(var*, gc&);
var builtin_close(var*, gc&);
var builtin_read(var*, gc&);
var builtin_write(var*, gc&);
var builtin_seek(var*, gc&);
var builtin_tell(var*, gc&);
var builtin_readln(var*, gc&);
var builtin_stat(var*, gc&);
var builtin_eof(var*, gc&);
extern nasal_builtin_table io_lib_native[];

View File

@ -72,33 +72,6 @@ var builtin_input(var* local, gc& ngc) {
return ret;
}
var builtin_readfile(var* local, gc& ngc) {
var val = local[1];
if (val.type!=vm_str) {
return nas_err("io::readfile", "\"filename\" must be string");
}
std::ifstream in(val.str(), std::ios::binary);
std::stringstream rd;
if (!in.fail()) {
rd << in.rdbuf();
}
return ngc.newstr(rd.str());
}
var builtin_fout(var* local, gc& ngc) {
var val = local[1];
var str = local[2];
if (val.type!=vm_str) {
return nas_err("io::fout", "\"filename\" must be string");
}
std::ofstream out(val.str());
if (out.fail()) {
return nas_err("io::fout", "cannot open <"+val.str()+">");
}
out << str;
return nil;
}
var builtin_split(var* local, gc& ngc) {
var delimeter = local[1];
var str = local[2];
@ -423,153 +396,6 @@ var builtin_values(var* local, gc& ngc) {
return vec;
}
var builtin_exists(var* local, gc& ngc) {
if (local[1].type!=vm_str) {
return zero;
}
return access(local[1].str().c_str(), F_OK)!=-1?one:zero;
}
var builtin_open(var* local, gc& ngc) {
var name = local[1];
var mode = local[2];
if (name.type!=vm_str) {
return nas_err("open", "\"filename\" must be string");
}
if (mode.type!=vm_str) {
return nas_err("open", "\"mode\" must be string");
}
FILE* res = fopen(name.str().c_str(), mode.str().c_str());
if (!res) {
return nas_err("open", "failed to open file <"+name.str()+">");
}
var ret = ngc.alloc(vm_obj);
ret.obj().set(ngc.global_ghost_type_table.ghost_file, res, &ngc.global_ghost_type_table);
return ret;
}
var builtin_close(var* local, gc& ngc) {
var fd = local[1];
if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) {
return nas_err("close", "not a valid filehandle");
}
fd.obj().clear();
return nil;
}
var builtin_read(var* local, gc& ngc) {
var fd = local[1];
var buf = local[2];
var len = local[3];
if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) {
return nas_err("read", "not a valid filehandle");
}
if (buf.type!=vm_str || buf.val.gcobj->unmut) {
return nas_err("read", "\"buf\" must be mutable string");
}
if (len.type!=vm_num) {
return nas_err("read", "\"len\" must be number");
}
if (len.num()<=0 || len.num()>=(1<<30)) {
return nas_err("read", "\"len\" less than 1 or too large");
}
char* buff = new char[(usize)len.num()+1];
if (!buff) {
return nas_err("read", "malloc failed");
}
f64 res = fread(buff,1,len.num(), (FILE*)fd.obj().ptr);
buf.str() = buff;
buf.val.gcobj->unmut = true;
delete []buff;
return var::num(res);
}
var builtin_write(var* local, gc& ngc) {
var fd = local[1];
var str = local[2];
if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) {
return nas_err("write", "not a valid filehandle");
}
if (str.type!=vm_str) {
return nas_err("write", "\"str\" must be string");
}
return var::num((f64)fwrite(str.str().c_str(), 1, str.str().length(), (FILE*)fd.obj().ptr));
}
var builtin_seek(var* local, gc& ngc) {
var fd = local[1];
var pos = local[2];
var whence = local[3];
if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) {
return nas_err("seek", "not a valid filehandle");
}
return var::num((f64)fseek((FILE*)fd.obj().ptr, pos.num(), whence.num()));
}
var builtin_tell(var* local, gc& ngc) {
var fd = local[1];
if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) {
return nas_err("tell", "not a valid filehandle");
}
return var::num((f64)ftell((FILE*)fd.obj().ptr));
}
var builtin_readln(var* local, gc& ngc) {
var fd = local[1];
if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) {
return nas_err("readln", "not a valid filehandle");
}
var str = ngc.alloc(vm_str);
char c;
while((c = fgetc((FILE*)fd.obj().ptr))!=EOF) {
if (c=='\r') {
continue;
}
if (c=='\n') {
return str;
}
str.str() += c;
}
if (str.str().length()) {
return str;
}
return nil;
}
var builtin_stat(var* local, gc& ngc) {
var name = local[1];
if (name.type!=vm_str) {
return nas_err("stat", "\"filename\" must be string");
}
struct stat buf;
if (stat(name.str().c_str(),&buf)<0) {
return nas_err("stat", "failed to open file <"+name.str()+">");
}
var ret = ngc.alloc(vm_vec);
ret.vec().elems = {
var::num((f64)buf.st_dev),
var::num((f64)buf.st_ino),
var::num((f64)buf.st_mode),
var::num((f64)buf.st_nlink),
var::num((f64)buf.st_uid),
var::num((f64)buf.st_gid),
var::num((f64)buf.st_rdev),
var::num((f64)buf.st_size),
var::num((f64)buf.st_atime),
var::num((f64)buf.st_mtime),
var::num((f64)buf.st_ctime)
};
return ret;
}
var builtin_eof(var* local, gc& ngc) {
var fd = local[1];
if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) {
return nas_err("readln", "not a valid filehandle");
}
return var::num((f64)feof((FILE*)fd.obj().ptr));
}
var builtin_sleep(var* local, gc& ngc) {
var val = local[1];
if (val.type!=vm_num) {
@ -585,215 +411,6 @@ var builtin_sleep(var* local, gc& ngc) {
return nil;
}
var builtin_pipe(var* local, gc& ngc) {
#ifndef _WIN32
i32 fd[2];
var res = ngc.alloc(vm_vec);
if (pipe(fd)==-1) {
return nas_err("pipe", "failed to create pipe");
}
res.vec().elems.push_back(var::num((f64)fd[0]));
res.vec().elems.push_back(var::num((f64)fd[1]));
return res;
#endif
return nas_err("pipe", "not supported");
}
var builtin_fork(var* local, gc& ngc) {
#ifndef _WIN32
f64 res=fork();
if (res<0) {
return nas_err("fork", "failed to fork a process");
}
return var::num((f64)res);
#endif
return nas_err("fork", "not supported");
}
var builtin_waitpid(var* local, gc& ngc) {
var pid = local[1];
var nohang = local[2];
if (pid.type!=vm_num || nohang.type!=vm_num) {
return nas_err("waitpid", "pid and nohang must be number");
}
#ifndef _WIN32
i32 ret_pid,status;
ret_pid = waitpid(pid.num(),&status,nohang.num()==0? 0:WNOHANG);
var vec = ngc.alloc(vm_vec);
vec.vec().elems.push_back(var::num((f64)ret_pid));
vec.vec().elems.push_back(var::num((f64)status));
return vec;
#endif
return nas_err("waitpid", "not supported");
}
var builtin_opendir(var* local, gc& ngc) {
var path = local[1];
if (path.type!=vm_str) {
return nas_err("opendir", "\"path\" must be string");
}
#ifdef _MSC_VER
WIN32_FIND_DATAA data;
HANDLE p;
p = FindFirstFileA((path.str()+"\\*.*").c_str(),&data);
if (p==INVALID_HANDLE_VALUE) {
return nas_err("opendir", "cannot open dir <"+path.str()+">");
}
#else
DIR* p = opendir(path.str().c_str());
if (!p) {
return nas_err("opendir", "cannot open dir <"+path.str()+">");
}
#endif
var ret = ngc.alloc(vm_obj);
ret.obj().set(ngc.global_ghost_type_table.ghost_dir, p, &ngc.global_ghost_type_table);
return ret;
}
var builtin_readdir(var* local, gc& ngc) {
var handle = local[1];
if (!handle.objchk(ngc.global_ghost_type_table.ghost_dir)) {
return nas_err("readdir", "not a valid dir handle");
}
#ifdef _MSC_VER
WIN32_FIND_DATAA data;
if (!FindNextFileA(handle.obj().ptr,&data)) {
return nil;
}
return ngc.newstr(data.cFileName);
#else
dirent* p = readdir((DIR*)handle.obj().ptr);
return p? ngc.newstr(p->d_name):nil;
#endif
}
var builtin_closedir(var* local, gc& ngc) {
var handle = local[1];
if (!handle.objchk(ngc.global_ghost_type_table.ghost_dir)) {
return nas_err("closedir", "not a valid dir handle");
}
handle.obj().clear();
return nil;
}
var builtin_chdir(var* local, gc& ngc) {
var path = local[1];
if (path.type!=vm_str) {
return var::num((f64)-1);
}
return var::num((f64)chdir(path.str().c_str()));
}
var builtin_environ(var* local, gc& ngc) {
var res = ngc.temp = ngc.alloc(vm_vec);
auto& vec = res.vec().elems;
for(char** env = environ; *env; ++env) {
vec.push_back(ngc.newstr(*env));
}
ngc.temp = nil;
return res;
}
var builtin_getcwd(var* local, gc& ngc) {
char buf[1024];
if (!getcwd(buf, sizeof(buf))) {
return nil;
}
return ngc.newstr(buf);
}
var builtin_getenv(var* local, gc& ngc) {
var envvar = local[1];
if (envvar.type!=vm_str) {
return nas_err("getenv", "\"envvar\" must be string");
}
char* res = getenv(envvar.str().c_str());
return res? ngc.newstr(res):nil;
}
var builtin_dlopen(var* local, gc& ngc) {
var dlname = local[1];
if (dlname.type!=vm_str) {
return nas_err("dlopen", "\"libname\" must be string");
}
#ifdef _WIN32
wchar_t* str = new wchar_t[dlname.str().size()+1];
if (!str) {
return nas_err("dlopen", "malloc failed");
}
memset(str, 0, sizeof(wchar_t)*dlname.str().size()+1);
mbstowcs(str, dlname.str().c_str(),dlname.str().size()+1);
void* ptr = LoadLibraryA(dlname.str().c_str());
delete []str;
#else
void* ptr = dlopen(dlname.str().c_str(), RTLD_LOCAL|RTLD_LAZY);
#endif
if (!ptr) {
return nas_err("dlopen", "cannot open dynamic lib <"+dlname.str()+">");
}
var ret = ngc.temp = ngc.alloc(vm_hash);
var lib = ngc.alloc(vm_obj);
lib.obj().set(ngc.global_ghost_type_table.ghost_dylib, ptr, &ngc.global_ghost_type_table);
ret.hash().elems["lib"] = lib;
#ifdef _WIN32
void* func = (void*)GetProcAddress((HMODULE)lib.obj().ptr, "get");
#else
void* func = dlsym(lib.obj().ptr, "get");
#endif
if (!func) {
return nas_err("dlopen", "cannot find <get> function");
}
// get function pointer by name
module_func_info* tbl = ((get_func_ptr)func)(&ngc.global_ghost_type_table);
if (!tbl) {
return nas_err("dlopen", "failed to get module functions");
}
for(u32 i = 0; tbl[i].name; ++i) {
void* p = (void*)tbl[i].fd;
var tmp = ngc.alloc(vm_obj);
tmp.obj().set(ngc.global_ghost_type_table.ghost_faddr, p, &ngc.global_ghost_type_table);
ret.hash().elems[tbl[i].name] = tmp;
}
ngc.temp = nil;
return ret;
}
var builtin_dlclose(var* local, gc& ngc) {
var libptr = local[1];
if (!libptr.objchk(ngc.global_ghost_type_table.ghost_dylib)) {
return nas_err("dlclose", "\"lib\" is not a valid dynamic lib");
}
libptr.obj().clear();
return nil;
}
var builtin_dlcallv(var* local, gc& ngc) {
var fp = local[1];
var args = local[2];
if (!fp.objchk(ngc.global_ghost_type_table.ghost_faddr)) {
return nas_err("dlcall", "\"ptr\" is not a valid function pointer");
}
auto& vec = args.vec().elems;
return ((module_func)fp.obj().ptr)(vec.data(), vec.size(), &ngc);
}
var builtin_dlcall(var* local, gc& ngc) {
var fp = local[1];
if (!fp.objchk(ngc.global_ghost_type_table.ghost_faddr)) {
return nas_err("dlcall", "\"ptr\" is not a valid function pointer");
}
var* local_frame_start = local+2;
usize local_frame_size = ngc.rctx->top-local_frame_start;
// arguments' stored place begins at local +2
return ((module_func)fp.obj().ptr)(
local_frame_start,
local_frame_size,
&ngc);
}
var builtin_platform(var* local, gc& ngc) {
if (is_windows()) {
return ngc.newstr("windows");
@ -1003,8 +620,6 @@ nasal_builtin_table builtin[] = {
{"__setsize", builtin_setsize},
{"__system", builtin_system},
{"__input", builtin_input},
{"__readfile", builtin_readfile},
{"__fout", builtin_fout},
{"__split", builtin_split},
{"__rand", builtin_rand},
{"__id", builtin_id},
@ -1029,31 +644,7 @@ nasal_builtin_table builtin[] = {
{"__chr", builtin_chr},
{"__char", builtin_char},
{"__values", builtin_values},
{"__exists", builtin_exists},
{"__open", builtin_open},
{"__close", builtin_close},
{"__read", builtin_read},
{"__write", builtin_write},
{"__seek", builtin_seek},
{"__tell", builtin_tell},
{"__readln", builtin_readln},
{"__stat", builtin_stat},
{"__eof", builtin_eof},
{"__sleep", builtin_sleep},
{"__pipe", builtin_pipe},
{"__fork", builtin_fork},
{"__waitpid", builtin_waitpid},
{"__opendir", builtin_opendir},
{"__readdir", builtin_readdir},
{"__closedir", builtin_closedir},
{"__chdir", builtin_chdir},
{"__environ", builtin_environ},
{"__getcwd", builtin_getcwd},
{"__getenv", builtin_getenv},
{"__dlopen", builtin_dlopen},
{"__dlclose", builtin_dlclose},
{"__dlcallv", builtin_dlcallv},
{"__dlcall", builtin_dlcall},
{"__platform", builtin_platform},
{"__arch", builtin_arch},
{"__md5", builtin_md5},

View File

@ -3,33 +3,20 @@
#include "nasal.h"
#include "nasal_gc.h"
#ifndef _MSC_VER
#include <unistd.h>
#include <dirent.h>
#else
#define F_OK 0 // fuck msc
#ifdef _MSC_VER
#pragma warning (disable:4566) // i know i'm using utf-8, fuck you
#pragma warning (disable:4244)
#pragma warning (disable:4267)
#pragma warning (disable:4996)
#define _CRT_SECURE_NO_DEPRECATE 1
#define _CRT_NONSTDC_NO_DEPRECATE 1
#include <io.h>
#include <direct.h>
#endif
#include <sstream>
#include <cmath>
#include <thread>
#include <sys/stat.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#include <sys/wait.h>
#endif
// for environ
#if defined __APPLE__
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
@ -43,8 +30,6 @@ var builtin_append(var*, gc&);
var builtin_setsize(var*, gc&);
var builtin_system(var*, gc&);
var builtin_input(var*, gc&);
var builtin_readfile(var*, gc&);
var builtin_fout(var*, gc&);
var builtin_split(var*, gc&);
var builtin_rand(var*, gc&);
var builtin_id(var*, gc&);
@ -69,31 +54,7 @@ var builtin_cmp(var*, gc&);
var builtin_chr(var*, gc&);
var builtin_char(var*, gc&);
var builtin_values(var*, gc&);
var builtin_exists(var*, gc&);
var builtin_open(var*, gc&);
var builtin_close(var*, gc&);
var builtin_read(var*, gc&);
var builtin_write(var*, gc&);
var builtin_seek(var*, gc&);
var builtin_tell(var*, gc&);
var builtin_readln(var*, gc&);
var builtin_stat(var*, gc&);
var builtin_eof(var*, gc&);
var builtin_sleep(var*, gc&);
var builtin_pipe(var*, gc&);
var builtin_fork(var*, gc&);
var builtin_waitpid(var*, gc&);
var builtin_opendir(var*, gc&);
var builtin_readdir(var*, gc&);
var builtin_closedir(var*, gc&);
var builtin_chdir(var*, gc&);
var builtin_environ(var*, gc&);
var builtin_getcwd(var*, gc&);
var builtin_getenv(var*, gc&);
var builtin_dlopen(var*, gc&);
var builtin_dlclose(var*, gc&);
var builtin_dlcallv(var*, gc&);
var builtin_dlcall(var*, gc&);
var builtin_platform(var*, gc&);
var builtin_arch(var*, gc&);
// md5 related functions

View File

@ -21,10 +21,13 @@ void codegen::load_native_function_table(nasal_builtin_table* table) {
void codegen::init_native_function() {
load_native_function_table(builtin);
load_native_function_table(io_lib_native);
load_native_function_table(math_lib_native);
load_native_function_table(bits_native);
load_native_function_table(coroutine_native);
load_native_function_table(flight_gear_native);
load_native_function_table(dylib_lib_native);
load_native_function_table(unix_lib_native);
}
void codegen::check_id_exist(identifier* node) {

View File

@ -13,6 +13,9 @@
#include "bits_lib.h"
#include "math_lib.h"
#include "fg_props.h"
#include "io_lib.h"
#include "dylib_lib.h"
#include "unix_lib.h"
#include <iomanip>
#include <list>

View File

@ -141,9 +141,11 @@ private:
u32 bk_line;
error src;
private:
debug_prof_data data;
bool do_profiling;
private:
std::vector<std::string> parse(const std::string&);
u16 file_index(const std::string&) const;
void err();

View File

@ -1,30 +1,5 @@
#include "nasal_gc.h"
void filehandle_destructor(void* ptr) {
if ((FILE*)ptr==stdin) {
return;
}
fclose((FILE*)ptr);
}
void dir_entry_destructor(void* ptr) {
#ifndef _MSC_VER
closedir((DIR*)ptr);
#else
FindClose(ptr);
#endif
}
void dylib_destructor(void* ptr) {
#ifdef _WIN32
FreeLibrary((HMODULE)ptr);
#else
dlclose(ptr);
#endif
}
void func_addr_destructor(void* ptr) {}
var nas_vec::get_val(const i32 n) {
i32 size = elems.size();
if (n<-size || n>=size) {
@ -123,18 +98,22 @@ void nas_func::clear() {
}
void nas_ghost::set(
usize ghost_type, void* ghost_pointer, ghost_register_table* table) {
type = ghost_type;
const std::string& ghost_type_name,
destructor destructor_pointer,
void* ghost_pointer) {
type_name = ghost_type_name;
dtor_ptr = destructor_pointer;
ptr = ghost_pointer;
ghost_type_table = table;
}
void nas_ghost::clear() {
if (!ptr) {
if (!ptr || !dtor_ptr) {
return;
}
ghost_type_table->destructor(type)(ptr);
dtor_ptr(ptr);
type_name = "";
ptr = nullptr;
dtor_ptr = nullptr;
}
std::ostream& operator<<(std::ostream& out, const nas_ghost& ghost) {
@ -268,8 +247,8 @@ std::ostream& operator<<(std::ostream& out, var& ref) {
return out;
}
bool var::objchk(usize obj_type) {
return type==vm_obj && obj().type==obj_type && obj().ptr;
bool var::objchk(const std::string& name) {
return type==vm_obj && obj().type_name==name && obj().ptr;
}
var var::none() {

View File

@ -93,7 +93,7 @@ public:
// number and string can be translated to each other
f64 tonum();
std::string tostr();
bool objchk(usize);
bool objchk(const std::string&);
// create new var object
static var none();
@ -180,82 +180,24 @@ public:
}
};
void filehandle_destructor(void*);
void dir_entry_destructor(void*);
void dylib_destructor(void*);
void func_addr_destructor(void*);
struct ghost_register_table {
private:
using dtor=void (*)(void*);
private:
std::unordered_map<std::string, usize> mapper;
std::vector<std::string> ghost_name;
std::vector<dtor> destructors;
public:
// reserved ghost type only for native functions
usize ghost_file;
usize ghost_dir;
usize ghost_dylib;
usize ghost_faddr;
public:
ghost_register_table() {
ghost_file = register_ghost_type("file", filehandle_destructor);
ghost_dir = register_ghost_type("dir", dir_entry_destructor);
ghost_dylib = register_ghost_type("dylib", dylib_destructor);
ghost_faddr = register_ghost_type("faddr", func_addr_destructor);
}
bool exists(const std::string& name) const {
return mapper.count(name);
}
usize get_ghost_type_index(const std::string& name) const {
return mapper.at(name);
}
const std::string& get_ghost_name(usize index) const {
return ghost_name.at(index);
}
usize register_ghost_type(const std::string& name, dtor ptr) {
if (mapper.count(name)) {
std::cerr << "nasal_gc.h: ghost_register_table::register_ghost_type: ";
std::cerr << "ghost type \"" << name << "\" already exists.\n";
std::exit(1);
}
auto res = destructors.size();
mapper[name] = res;
ghost_name.push_back(name);
destructors.push_back(ptr);
return res;
}
dtor destructor(usize index) {
return destructors.at(index);
}
};
struct nas_ghost {
private:
using destructor=void (*)(void*);
public:
usize type;
std::string type_name;
destructor dtor_ptr;
void* ptr;
private:
ghost_register_table* ghost_type_table;
public:
nas_ghost(): type(0), ptr(nullptr), ghost_type_table(nullptr) {}
nas_ghost(): type_name(""), dtor_ptr(nullptr), ptr(nullptr) {}
~nas_ghost() {clear();}
void set(usize, void*, ghost_register_table*);
void set(const std::string&, destructor, void*);
void clear();
public:
const std::string& get_ghost_name() const {
return ghost_type_table->get_ghost_name(type);
return type_name;
}
};
@ -336,7 +278,6 @@ const var one = var::num(1);
const var nil = var::nil();
struct gc {
ghost_register_table global_ghost_type_table;
/* main context temporary storage */
context mctx;
@ -433,4 +374,4 @@ struct module_func_info {
};
// module function "get" type
typedef module_func_info* (*get_func_ptr)(ghost_register_table*);
typedef module_func_info* (*get_func_ptr)();

View File

@ -23,6 +23,7 @@ protected:
const f64* cnum = nullptr; // constant numbers
const std::string* cstr = nullptr; // constant symbols and strings
std::vector<u32> imm; // immediate number table
std::vector<nasal_builtin_table> native;
/* garbage collector */
gc ngc;
@ -33,7 +34,6 @@ protected:
/* values used for debugger */
const std::string* files = nullptr; // file name list
const opcode* bytecode = nullptr; // bytecode buffer address
std::vector<nasal_builtin_table> native;
/* vm initializing function */
void init(

151
src/unix_lib.cpp Normal file
View File

@ -0,0 +1,151 @@
#include "unix_lib.h"
const auto dir_type_name = "dir";
void dir_entry_destructor(void* ptr) {
#ifndef _MSC_VER
closedir((DIR*)ptr);
#else
FindClose(ptr);
#endif
}
var builtin_pipe(var* local, gc& ngc) {
#ifndef _WIN32
i32 fd[2];
var res = ngc.alloc(vm_vec);
if (pipe(fd)==-1) {
return nas_err("pipe", "failed to create pipe");
}
res.vec().elems.push_back(var::num((f64)fd[0]));
res.vec().elems.push_back(var::num((f64)fd[1]));
return res;
#endif
return nas_err("pipe", "not supported");
}
var builtin_fork(var* local, gc& ngc) {
#ifndef _WIN32
f64 res=fork();
if (res<0) {
return nas_err("fork", "failed to fork a process");
}
return var::num((f64)res);
#endif
return nas_err("fork", "not supported");
}
var builtin_waitpid(var* local, gc& ngc) {
var pid = local[1];
var nohang = local[2];
if (pid.type!=vm_num || nohang.type!=vm_num) {
return nas_err("waitpid", "pid and nohang must be number");
}
#ifndef _WIN32
i32 ret_pid,status;
ret_pid = waitpid(pid.num(),&status,nohang.num()==0? 0:WNOHANG);
var vec = ngc.alloc(vm_vec);
vec.vec().elems.push_back(var::num((f64)ret_pid));
vec.vec().elems.push_back(var::num((f64)status));
return vec;
#endif
return nas_err("waitpid", "not supported");
}
var builtin_opendir(var* local, gc& ngc) {
var path = local[1];
if (path.type!=vm_str) {
return nas_err("opendir", "\"path\" must be string");
}
#ifdef _MSC_VER
WIN32_FIND_DATAA data;
HANDLE p;
p = FindFirstFileA((path.str()+"\\*.*").c_str(),&data);
if (p==INVALID_HANDLE_VALUE) {
return nas_err("opendir", "cannot open dir <"+path.str()+">");
}
#else
DIR* p = opendir(path.str().c_str());
if (!p) {
return nas_err("opendir", "cannot open dir <"+path.str()+">");
}
#endif
var ret = ngc.alloc(vm_obj);
ret.obj().set(dir_type_name, dir_entry_destructor, p);
return ret;
}
var builtin_readdir(var* local, gc& ngc) {
var handle = local[1];
if (!handle.objchk(dir_type_name)) {
return nas_err("readdir", "not a valid dir handle");
}
#ifdef _MSC_VER
WIN32_FIND_DATAA data;
if (!FindNextFileA(handle.obj().ptr,&data)) {
return nil;
}
return ngc.newstr(data.cFileName);
#else
dirent* p = readdir((DIR*)handle.obj().ptr);
return p? ngc.newstr(p->d_name):nil;
#endif
}
var builtin_closedir(var* local, gc& ngc) {
var handle = local[1];
if (!handle.objchk(dir_type_name)) {
return nas_err("closedir", "not a valid dir handle");
}
handle.obj().clear();
return nil;
}
var builtin_chdir(var* local, gc& ngc) {
var path = local[1];
if (path.type!=vm_str) {
return var::num((f64)-1);
}
return var::num((f64)chdir(path.str().c_str()));
}
var builtin_environ(var* local, gc& ngc) {
var res = ngc.temp = ngc.alloc(vm_vec);
auto& vec = res.vec().elems;
for(char** env = environ; *env; ++env) {
vec.push_back(ngc.newstr(*env));
}
ngc.temp = nil;
return res;
}
var builtin_getcwd(var* local, gc& ngc) {
char buf[1024];
if (!getcwd(buf, sizeof(buf))) {
return nil;
}
return ngc.newstr(buf);
}
var builtin_getenv(var* local, gc& ngc) {
var envvar = local[1];
if (envvar.type!=vm_str) {
return nas_err("getenv", "\"envvar\" must be string");
}
char* res = getenv(envvar.str().c_str());
return res? ngc.newstr(res):nil;
}
nasal_builtin_table unix_lib_native[] = {
{"__pipe", builtin_pipe},
{"__fork", builtin_fork},
{"__waitpid", builtin_waitpid},
{"__opendir", builtin_opendir},
{"__readdir", builtin_readdir},
{"__closedir", builtin_closedir},
{"__chdir", builtin_chdir},
{"__environ", builtin_environ},
{"__getcwd", builtin_getcwd},
{"__getenv", builtin_getenv},
{nullptr, nullptr}
};

36
src/unix_lib.h Normal file
View File

@ -0,0 +1,36 @@
#pragma once
#include "nasal.h"
#include "nasal_gc.h"
#include "nasal_builtin.h"
#ifndef _MSC_VER
#include <unistd.h>
#include <dirent.h>
#else
#define _CRT_SECURE_NO_DEPRECATE 1
#define _CRT_NONSTDC_NO_DEPRECATE 1
#include <io.h>
#include <direct.h>
#endif
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/wait.h>
#endif
void dir_entry_destructor(void*);
var builtin_pipe(var*, gc&);
var builtin_fork(var*, gc&);
var builtin_waitpid(var*, gc&);
var builtin_opendir(var*, gc&);
var builtin_readdir(var*, gc&);
var builtin_closedir(var*, gc&);
var builtin_chdir(var*, gc&);
var builtin_environ(var*, gc&);
var builtin_getcwd(var*, gc&);
var builtin_getenv(var*, gc&);
extern nasal_builtin_table unix_lib_native[];

View File

@ -59,12 +59,16 @@ var buf = func(len) {
return __buf;
}
var bit = [var __ = 1];
for(var i = 1; i<32; i += 1) {
func(vec, arg...){
var bit = func() {
var res = [var __ = 1];
var append = func(vec, arg...) {
return __append;
}(bit, __ += __);
}
}
for(var i = 1; i<32; i += 1) {
append(res, __ += __);
}
return res;
}();
var test = func(n, b) {
n /= bit[b];

View File

@ -1,6 +1,9 @@
# unix.nas
# 2023 by ValKmjolnir
var _S_IFDIR = 0x4000;
var _S_IFREG = 0x8000;
var pipe = func() {
return __pipe;
}
@ -22,13 +25,11 @@ var waitpid = func(pid, nohang = 0) {
}
var isdir = func(path) {
# S_IFDIR 0x4000
return !!bits.u32_and(io.stat(path)[2],0x4000);
return !!bits.u32_and(io.stat(path)[2], _S_IFDIR);
}
var isfile = func(path) {
# S_IFREG 0x8000
return !!bits.u32_and(io.stat(path)[2],0x8000);
return !!bits.u32_and(io.stat(path)[2], _S_IFREG);
}
var opendir = func(path) {

View File

@ -1,4 +1,8 @@
import.std.dylib;
import.module.libfib;
println(keys(libfib));
libfib.test_ghost();
var libfib=func(){
var (dd,fib,qfib)=(nil,nil,nil);