diff --git a/CMakeLists.txt b/CMakeLists.txt index 706880d..39e57cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Wshadow -Wall") # generate release executables set(CMAKE_BUILD_TYPE "Release") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/module) add_library(fib SHARED ${CMAKE_SOURCE_DIR}/module/fib.cpp) target_include_directories(fib PRIVATE ${CMAKE_SOURCE_DIR}) @@ -24,4 +25,11 @@ target_include_directories(nasock PRIVATE ${CMAKE_SOURCE_DIR}) add_executable(nasal main.cpp) target_link_libraries(nasal dl) -target_include_directories(nasal PRIVATE ${CMAKE_SOURCE_DIR}) \ No newline at end of file +target_include_directories(nasal PRIVATE ${CMAKE_SOURCE_DIR}) + +add_custom_command( + TARGET nasal POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_SOURCE_DIR}/build/nasal + ${CMAKE_SOURCE_DIR}/nasal +) \ No newline at end of file diff --git a/module/fib.cpp b/module/fib.cpp index b58ab8e..70c2219 100644 --- a/module/fib.cpp +++ b/module/fib.cpp @@ -1,6 +1,10 @@ +// module for test + #include #include "../nasal.h" +namespace nasal_fib_module { + double fibonaci(double x) { if (x<=2) { return x; @@ -33,12 +37,56 @@ var quick_fib(var* args, usize size, gc* ngc) { return var::num(res); } -mod_func func_tbl[]={ - {"fib",fib}, - {"quick_fib",quick_fib}, - {nullptr, nullptr}, +u32 ghost_for_test; + +void ghost_for_test_destructor(void* ptr) { + std::cout<<"delete "<alloc(vm_obj); + res.obj().set(ghost_for_test, new u32); + return res; +} + +var set_new_ghost(var* args, usize size, gc* ngc) { + var res=args[0]; + if (!res.objchk(ghost_for_test)) { + std::cout<<"set_new_ghost: not ghost for test type.\n"; + return nil; + } + std::cout<<"set_new_ghost: successfully set ghost.\n"; + f64 num=args[1].num(); + *((u32*)res.obj().ptr)=static_cast(num); + return nil; +} + +var print_new_ghost(var* args, usize size, gc* ngc) { + var res=args[0]; + if (!res.objchk(ghost_for_test)) { + std::cout<<"print_new_ghost: not ghost for test type.\n"; + return nil; + } + std::cout<<"print_new_ghost: result = "<<*((u32*)res.obj().ptr)<<"\n"; + return nil; +} + +module_func_info func_tbl[]={ + {"fib", fib}, + {"quick_fib", quick_fib}, + {"create_ghost", create_new_ghost}, + {"set_ghost", set_new_ghost}, + {"print_ghost", print_new_ghost}, + {nullptr, nullptr} }; -extern "C" mod_func* get(ghost_register_table* table) { - return func_tbl; +} + +extern "C" module_func_info* get(ghost_register_table* table) { + nasal_fib_module::ghost_for_test=table->register_ghost_type( + "fib_for_test", + nasal_fib_module::ghost_for_test_destructor + ); + return nasal_fib_module::func_tbl; } \ No newline at end of file diff --git a/module/keyboard.cpp b/module/keyboard.cpp index 6736385..f4b798d 100644 --- a/module/keyboard.cpp +++ b/module/keyboard.cpp @@ -88,13 +88,13 @@ var nas_noblock(var* args, usize size, gc* ngc) { return nil; } -mod_func func_tbl[]={ +module_func_info func_tbl[]={ {"nas_getch",nas_getch}, {"nas_kbhit",nas_kbhit}, {"nas_noblock",nas_noblock}, {nullptr,nullptr} }; -extern "C" mod_func* get(ghost_register_table* table) { +extern "C" module_func_info* get(ghost_register_table* table) { return func_tbl; } \ No newline at end of file diff --git a/module/libfib.nas b/module/libfib.nas index b852ec0..7fe2a1c 100644 --- a/module/libfib.nas +++ b/module/libfib.nas @@ -2,9 +2,28 @@ 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); - return { - fib: func(x){return call(fib,x)}, - qfib:func(x){return call(qfib,x)} + 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)} }; + + 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 + } + + return res; }(); \ No newline at end of file diff --git a/module/matrix.cpp b/module/matrix.cpp index d74431c..05e8454 100644 --- a/module/matrix.cpp +++ b/module/matrix.cpp @@ -266,7 +266,7 @@ var nas_vec3_dot(var* args, usize size, gc* ngc) { return var::num(v0[0].num()*v1[0].num()+v0[1].num()*v1[1].num()+v0[2].num()*v1[2].num()); } -mod_func func_tbl[]={ +module_func_info func_tbl[]={ {"nas_vec2",nas_vec2}, {"nas_vec2_add",nas_vec2_add}, {"nas_vec2_sub",nas_vec2_sub}, @@ -291,6 +291,6 @@ mod_func func_tbl[]={ {nullptr,nullptr} }; -extern "C" mod_func* get(ghost_register_table* table) { +extern "C" module_func_info* get(ghost_register_table* table) { return func_tbl; } \ No newline at end of file diff --git a/module/nasocket.cpp b/module/nasocket.cpp index 3935567..4234b11 100644 --- a/module/nasocket.cpp +++ b/module/nasocket.cpp @@ -190,7 +190,7 @@ var nas_errno(var* args, usize size, gc* ngc) { return ngc->newstr(strerror(errno)); } -mod_func func_tbl[]={ +module_func_info func_tbl[]={ {"nas_socket",nas_socket}, {"nas_closesocket",nas_closesocket}, {"nas_shutdown",nas_shutdown}, @@ -206,6 +206,6 @@ mod_func func_tbl[]={ {nullptr,nullptr} }; -extern "C" mod_func* get(ghost_register_table* table) { +extern "C" module_func_info* get(ghost_register_table* table) { return func_tbl; } \ No newline at end of file diff --git a/nasal_builtin.h b/nasal_builtin.h index a1c6c55..10b3071 100644 --- a/nasal_builtin.h +++ b/nasal_builtin.h @@ -544,13 +544,13 @@ var builtin_open(var* local, gc& ngc) { return nas_err("open", "failed to open file <"+name.str()+">"); } var ret=ngc.alloc(vm_obj); - ret.obj().set(ghost_file, res); + ret.obj().set(global_ghost_type_table.ghost_file, res); return ret; } var builtin_close(var* local, gc& ngc) { var fd=local[1]; - if (!fd.objchk(ghost_file)) { + if (!fd.objchk(global_ghost_type_table.ghost_file)) { return nas_err("close", "not a valid filehandle"); } fd.obj().clear(); @@ -561,7 +561,7 @@ var builtin_read(var* local, gc& ngc) { var fd=local[1]; var buf=local[2]; var len=local[3]; - if (!fd.objchk(ghost_file)) { + if (!fd.objchk(global_ghost_type_table.ghost_file)) { return nas_err("read", "not a valid filehandle"); } if (buf.type!=vm_str || buf.val.gcobj->unmut) { @@ -587,7 +587,7 @@ var builtin_read(var* local, gc& ngc) { var builtin_write(var* local, gc& ngc) { var fd=local[1]; var str=local[2]; - if (!fd.objchk(ghost_file)) { + if (!fd.objchk(global_ghost_type_table.ghost_file)) { return nas_err("write", "not a valid filehandle"); } if (str.type!=vm_str) { @@ -600,7 +600,7 @@ var builtin_seek(var* local, gc& ngc) { var fd=local[1]; var pos=local[2]; var whence=local[3]; - if (!fd.objchk(ghost_file)) { + if (!fd.objchk(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())); @@ -608,7 +608,7 @@ var builtin_seek(var* local, gc& ngc) { var builtin_tell(var* local, gc& ngc) { var fd=local[1]; - if (!fd.objchk(ghost_file)) { + if (!fd.objchk(global_ghost_type_table.ghost_file)) { return nas_err("tell", "not a valid filehandle"); } return var::num((f64)ftell((FILE*)fd.obj().ptr)); @@ -616,7 +616,7 @@ var builtin_tell(var* local, gc& ngc) { var builtin_readln(var* local, gc& ngc) { var fd=local[1]; - if (!fd.objchk(ghost_file)) { + if (!fd.objchk(global_ghost_type_table.ghost_file)) { return nas_err("readln", "not a valid filehandle"); } var str=ngc.alloc(vm_str); @@ -664,7 +664,7 @@ var builtin_stat(var* local, gc& ngc) { var builtin_eof(var* local, gc& ngc) { var fd=local[1]; - if (!fd.objchk(ghost_file)) { + if (!fd.objchk(global_ghost_type_table.ghost_file)) { return nas_err("readln", "not a valid filehandle"); } return var::num((f64)feof((FILE*)fd.obj().ptr)); @@ -849,13 +849,13 @@ var builtin_opendir(var* local, gc& ngc) { } #endif var ret=ngc.alloc(vm_obj); - ret.obj().set(ghost_dir,p); + ret.obj().set(global_ghost_type_table.ghost_dir,p); return ret; } var builtin_readdir(var* local, gc& ngc) { var handle=local[1]; - if (!handle.objchk(ghost_dir)) { + if (!handle.objchk(global_ghost_type_table.ghost_dir)) { return nas_err("readdir", "not a valid dir handle"); } #ifdef _MSC_VER @@ -872,7 +872,7 @@ var builtin_readdir(var* local, gc& ngc) { var builtin_closedir(var* local, gc& ngc) { var handle=local[1]; - if (!handle.objchk(ghost_dir)) { + if (!handle.objchk(global_ghost_type_table.ghost_dir)) { return nas_err("closedir", "not a valid dir handle"); } handle.obj().clear(); @@ -936,7 +936,7 @@ var builtin_dlopen(var* local, gc& ngc) { } var ret=ngc.temp=ngc.alloc(vm_hash); var lib=ngc.alloc(vm_obj); - lib.obj().set(ghost_dylib, ptr); + lib.obj().set(global_ghost_type_table.ghost_dylib, ptr); ret.hash().elems["lib"]=lib; #ifdef _WIN32 @@ -948,14 +948,14 @@ var builtin_dlopen(var* local, gc& ngc) { return nas_err("dlopen", "cannot find function"); } // get function pointer by name - mod_func* tbl=(mod_func*)((getptr)func)(&global_ghost_type_table); + module_func_info* tbl=((get_func_ptr)func)(&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(ghost_faddr, p); + tmp.obj().set(global_ghost_type_table.ghost_faddr, p); ret.hash().elems[tbl[i].name]=tmp; } @@ -965,7 +965,7 @@ var builtin_dlopen(var* local, gc& ngc) { var builtin_dlclose(var* local, gc& ngc) { var libptr=local[1]; - if (!libptr.objchk(ghost_dylib)) { + if (!libptr.objchk(global_ghost_type_table.ghost_dylib)) { return nas_err("dlclose", "\"lib\" is not a valid dynamic lib"); } libptr.obj().clear(); @@ -975,23 +975,27 @@ var builtin_dlclose(var* local, gc& ngc) { var builtin_dlcallv(var* local, gc& ngc) { var fp=local[1]; var args=local[2]; - if (!fp.objchk(ghost_faddr)) { + if (!fp.objchk(global_ghost_type_table.ghost_faddr)) { return nas_err("dlcall", "\"ptr\" is not a valid function pointer"); } auto& vec=args.vec().elems; - return ((mod)fp.obj().ptr)(vec.data(), vec.size(), &ngc); + 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(ghost_faddr)) { + if (!fp.objchk(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 ((mod)fp.obj().ptr)( + return ((module_func)fp.obj().ptr)( local_frame_start, local_frame_size, &ngc diff --git a/nasal_gc.h b/nasal_gc.h index 63f37db..65c8414 100644 --- a/nasal_gc.h +++ b/nasal_gc.h @@ -55,13 +55,13 @@ enum class gc_status:u8 { found }; -struct nas_vec; // vector -struct nas_hash; // hashmap(dict) -struct nas_func; // function(lambda) -struct nas_upval;// upvalue -struct nas_obj; // special objects -struct nas_co; // coroutine -struct nas_val; // nas_val includes gc-managed types +struct nas_vec; // vector +struct nas_hash; // hashmap(dict) +struct nas_func; // function(lambda) +struct nas_upval; // upvalue +struct nas_obj; // special objects +struct nas_co; // coroutine +struct nas_val; // nas_val includes gc-managed types struct var { public: @@ -154,6 +154,7 @@ struct nas_func { }; struct nas_upval { +public: /* on stack, use these variables */ bool onstk; u32 size; @@ -162,19 +163,28 @@ struct nas_upval { /* not on stack, use this */ std::vector elems; - nas_upval() {onstk=true;stk=nullptr;size=0;} - var& operator[](usize n) {return onstk? stk[n]:elems[n];} - void clear() {onstk=true;elems.clear();size=0;} +public: + nas_upval(): onstk(true), size(0), stk(nullptr) {} + + var& operator[](usize n) { + return onstk? stk[n]:elems[n]; + } + + void clear() { + onstk=true; + elems.clear(); + size=0; + } }; -void file_dtor(void* ptr) { +void filehandle_destructor(void* ptr) { if ((FILE*)ptr==stdin) { return; } fclose((FILE*)ptr); } -void dir_dtor(void* ptr) { +void dir_entry_destructor(void* ptr) { #ifndef _MSC_VER closedir((DIR*)ptr); #else @@ -182,7 +192,7 @@ void dir_dtor(void* ptr) { #endif } -void dylib_dtor(void* ptr) { +void dylib_destructor(void* ptr) { #ifdef _WIN32 FreeLibrary((HMODULE)ptr); #else @@ -190,9 +200,7 @@ void dylib_dtor(void* ptr) { #endif } -void faddr_dtor(void* ptr) {} - -usize ghost_file, ghost_dir, ghost_dylib, ghost_faddr; +void func_addr_destructor(void* ptr) {} struct ghost_register_table { private: @@ -202,17 +210,25 @@ private: std::unordered_map mapper; std::vector 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", file_dtor); - ghost_dir=register_ghost_type("dir", dir_dtor); - ghost_dylib=register_ghost_type("dylib", dylib_dtor); - ghost_faddr=register_ghost_type("faddr", faddr_dtor); + 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); } usize register_ghost_type(const std::string& name, dtor ptr) { if (mapper.count(name)) { - std::cerr<<"ghost type \""<