Merge pull request #19 from ValKmjolnir/develop

 add ghost_type_table for type registration & add cmake for VS to build
This commit is contained in:
Li Haokun 2023-05-11 20:59:49 +08:00 committed by GitHub
commit 36f6dd6c96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 959 additions and 788 deletions

2
.gitignore vendored
View File

@ -38,6 +38,7 @@
*.vcxproj.user *.vcxproj.user
.vs .vs
x64 x64
CMakePresents.json
# nasal executable # nasal executable
nasal nasal
@ -49,6 +50,7 @@ dump
# build dir # build dir
build build
out
# macOS special cache directory # macOS special cache directory
.DS_Store .DS_Store

View File

@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.10)
project(nasal VERSION 10.1) project(nasal VERSION 10.1)
message("CMAKE_HOST_SYSTEM_NAME: ${CMAKE_HOST_SYSTEM_NAME}")
# -std=c++14 -Wshadow -Wall # -std=c++14 -Wshadow -Wall
set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_CXX_STANDARD_REQUIRED True)
@ -9,6 +11,7 @@ set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Wshadow -Wall")
# generate release executables # generate release executables
set(CMAKE_BUILD_TYPE "Release") set(CMAKE_BUILD_TYPE "Release")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/module)
add_library(fib SHARED ${CMAKE_SOURCE_DIR}/module/fib.cpp) add_library(fib SHARED ${CMAKE_SOURCE_DIR}/module/fib.cpp)
target_include_directories(fib PRIVATE ${CMAKE_SOURCE_DIR}) target_include_directories(fib PRIVATE ${CMAKE_SOURCE_DIR})
@ -23,5 +26,20 @@ add_library(nasock SHARED ${CMAKE_SOURCE_DIR}/module/nasocket.cpp)
target_include_directories(nasock PRIVATE ${CMAKE_SOURCE_DIR}) target_include_directories(nasock PRIVATE ${CMAKE_SOURCE_DIR})
add_executable(nasal main.cpp) add_executable(nasal main.cpp)
target_link_libraries(nasal dl)
if(CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
message("Ignore linking dl lib")
else()
target_link_libraries(nasal dl)
endif()
target_include_directories(nasal PRIVATE ${CMAKE_SOURCE_DIR}) target_include_directories(nasal PRIVATE ${CMAKE_SOURCE_DIR})
if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
add_custom_command(
TARGET nasal POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/build/nasal
${CMAKE_SOURCE_DIR}/nasal
)
endif()

View File

@ -2,12 +2,22 @@
## First | 首先 ## First | 首先
Make sure you are using VS 2022. We give a __CMakeLists.txt__ for you to create new VS project from it.
确保你使用的是 VS 2022。 我们为你提供了 __CMakeLists.txt__ 用于创建新的 VS 工程。
If you are using this way, you will __not need__ to continue reading.
如果你使用的是这种方式,下面的内容你就 __不需要__ 再读了。
Creating VS project from a CMake file is the __simplest__ way.
从 CMake 文件创建 VS 工程是 __最简单__ 的方式。
## How to Create VS project ## How to Create VS project
Make sure you are using VS 2022. You may not get the dynamic libraries by using this way to compile.
1. Get code from this repo using `git`. 1. Get code from this repo using `git`.
2. In Visual Studio, click `File`->`New`->`Project From Existing Code...`. 2. In Visual Studio, click `File`->`New`->`Project From Existing Code...`.
@ -20,12 +30,14 @@ Make sure you are using VS 2022.
## 如何创建VS工程 ## 如何创建VS工程
1. 用`git`从这个仓库获取代码。 确保你使用的是 VS 2022。这个方式可能无法生成一些动态库。
1. 用 `git` 从这个仓库获取代码。
2. 在VS的界面点击文件(F)->新建(N)->从现有代码创建项目(E)。 2. 在VS的界面点击文件(F)->新建(N)->从现有代码创建项目(E)。
3. 选择创建`Visual C++`项目->下一步->项目文件位置选择你下载的代码存放的文件夹->填项目名称,随便写->完成。 3. 选择创建 `Visual C++` 项目->下一步->项目文件位置选择你下载的代码存放的文件夹->填项目名称,随便写->完成。
4. 从项目中去掉 `module` 里的cpp文件以防止编译错误。(那些本应该编译到动态库) 4. 从项目中去掉 `module` 里的cpp文件以防止编译错误。(那些本应该编译到动态库)
5. 点开左侧解决方案资源管理器中的`Source Files`,右键点击`main.cpp`,编译。 5. 点开左侧解决方案资源管理器中的 `Source Files`,右键点击 `main.cpp`,编译。

View File

@ -1,6 +1,10 @@
// module for test
#include <iostream> #include <iostream>
#include "../nasal.h" #include "../nasal.h"
namespace nasal_fib_module {
double fibonaci(double x) { double fibonaci(double x) {
if (x<=2) { if (x<=2) {
return x; return x;
@ -33,12 +37,63 @@ var quick_fib(var* args, usize size, gc* ngc) {
return var::num(res); return var::num(res);
} }
mod_func func_tbl[]={ u32 ghost_for_test;
{"fib",fib},
{"quick_fib",quick_fib}, void ghost_for_test_destructor(void* ptr) {
{nullptr, nullptr}, std::cout<<"ghost_for_test::destructor (0x";
std::cout<<std::hex<<(u64)ptr<<std::dec<<") {\n";
delete (u32*)ptr;
std::cout<<" delete 0x"<<std::hex<<(u64)ptr<<std::dec<<";\n";
std::cout<<"}\n";
}
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);
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;
}
f64 num=args[1].num();
*((u32*)res.obj().ptr)=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)) {
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";
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() { }
return 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
);
return nasal_fib_module::func_tbl;
} }

View File

@ -1,6 +1,10 @@
#include "../nasal.h" #include "../nasal.h"
#include <unistd.h>
#include <iostream> #include <iostream>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#ifdef _WIN32 #ifdef _WIN32
#include <conio.h> #include <conio.h>
#else #else
@ -88,13 +92,13 @@ var nas_noblock(var* args, usize size, gc* ngc) {
return nil; return nil;
} }
mod_func func_tbl[]={ module_func_info func_tbl[]={
{"nas_getch",nas_getch}, {"nas_getch",nas_getch},
{"nas_kbhit",nas_kbhit}, {"nas_kbhit",nas_kbhit},
{"nas_noblock",nas_noblock}, {"nas_noblock",nas_noblock},
{nullptr,nullptr} {nullptr,nullptr}
}; };
extern "C" mod_func* get() { extern "C" module_func_info* get(ghost_register_table* table) {
return func_tbl; return func_tbl;
} }

View File

@ -2,9 +2,28 @@ var libfib=func(){
var dl=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so")); var dl=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib=dl.fib; var fib=dl.fib;
var qfib=dl.quick_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 call=dylib.limitcall(1);
return { var test_call=dylib.limitcall(2);
fib: func(x){return call(fib,x)}, var res={
qfib:func(x){return call(qfib,x)} 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;
}(); }();

View File

@ -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()); 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",nas_vec2},
{"nas_vec2_add",nas_vec2_add}, {"nas_vec2_add",nas_vec2_add},
{"nas_vec2_sub",nas_vec2_sub}, {"nas_vec2_sub",nas_vec2_sub},
@ -291,6 +291,6 @@ mod_func func_tbl[]={
{nullptr,nullptr} {nullptr,nullptr}
}; };
extern "C" mod_func* get() { extern "C" module_func_info* get(ghost_register_table* table) {
return func_tbl; return func_tbl;
} }

View File

@ -1,5 +1,8 @@
#include "../nasal.h" #include "../nasal.h"
#ifndef _MSC_VER
#include <unistd.h> #include <unistd.h>
#endif
#ifdef _WIN32 #ifdef _WIN32
#include <winsock.h> #include <winsock.h>
@ -190,7 +193,7 @@ var nas_errno(var* args, usize size, gc* ngc) {
return ngc->newstr(strerror(errno)); return ngc->newstr(strerror(errno));
} }
mod_func func_tbl[]={ module_func_info func_tbl[]={
{"nas_socket",nas_socket}, {"nas_socket",nas_socket},
{"nas_closesocket",nas_closesocket}, {"nas_closesocket",nas_closesocket},
{"nas_shutdown",nas_shutdown}, {"nas_shutdown",nas_shutdown},
@ -206,6 +209,6 @@ mod_func func_tbl[]={
{nullptr,nullptr} {nullptr,nullptr}
}; };
extern "C" mod_func* get() { extern "C" module_func_info* get(ghost_register_table* table) {
return func_tbl; return func_tbl;
} }

View File

@ -8,6 +8,9 @@
#include <dirent.h> #include <dirent.h>
#else #else
#pragma warning (disable:4566) // i know i'm using utf-8, fuck you #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_SECURE_NO_DEPRECATE 1
#define _CRT_NONSTDC_NO_DEPRECATE 1 #define _CRT_NONSTDC_NO_DEPRECATE 1
#include <io.h> #include <io.h>
@ -544,13 +547,13 @@ var builtin_open(var* local, gc& ngc) {
return nas_err("open", "failed to open file <"+name.str()+">"); return nas_err("open", "failed to open file <"+name.str()+">");
} }
var ret=ngc.alloc(vm_obj); var ret=ngc.alloc(vm_obj);
ret.obj().set(obj_type::file, res); ret.obj().set(ngc.global_ghost_type_table.ghost_file, res, &ngc.global_ghost_type_table);
return ret; return ret;
} }
var builtin_close(var* local, gc& ngc) { var builtin_close(var* local, gc& ngc) {
var fd=local[1]; var fd=local[1];
if (!fd.objchk(obj_type::file)) { if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) {
return nas_err("close", "not a valid filehandle"); return nas_err("close", "not a valid filehandle");
} }
fd.obj().clear(); fd.obj().clear();
@ -561,7 +564,7 @@ var builtin_read(var* local, gc& ngc) {
var fd=local[1]; var fd=local[1];
var buf=local[2]; var buf=local[2];
var len=local[3]; var len=local[3];
if (!fd.objchk(obj_type::file)) { if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) {
return nas_err("read", "not a valid filehandle"); return nas_err("read", "not a valid filehandle");
} }
if (buf.type!=vm_str || buf.val.gcobj->unmut) { if (buf.type!=vm_str || buf.val.gcobj->unmut) {
@ -587,7 +590,7 @@ var builtin_read(var* local, gc& ngc) {
var builtin_write(var* local, gc& ngc) { var builtin_write(var* local, gc& ngc) {
var fd=local[1]; var fd=local[1];
var str=local[2]; var str=local[2];
if (!fd.objchk(obj_type::file)) { if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) {
return nas_err("write", "not a valid filehandle"); return nas_err("write", "not a valid filehandle");
} }
if (str.type!=vm_str) { if (str.type!=vm_str) {
@ -600,7 +603,7 @@ var builtin_seek(var* local, gc& ngc) {
var fd=local[1]; var fd=local[1];
var pos=local[2]; var pos=local[2];
var whence=local[3]; var whence=local[3];
if (!fd.objchk(obj_type::file)) { if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) {
return nas_err("seek", "not a valid filehandle"); return nas_err("seek", "not a valid filehandle");
} }
return var::num((f64)fseek((FILE*)fd.obj().ptr, pos.num(), whence.num())); return var::num((f64)fseek((FILE*)fd.obj().ptr, pos.num(), whence.num()));
@ -608,7 +611,7 @@ var builtin_seek(var* local, gc& ngc) {
var builtin_tell(var* local, gc& ngc) { var builtin_tell(var* local, gc& ngc) {
var fd=local[1]; var fd=local[1];
if (!fd.objchk(obj_type::file)) { if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) {
return nas_err("tell", "not a valid filehandle"); return nas_err("tell", "not a valid filehandle");
} }
return var::num((f64)ftell((FILE*)fd.obj().ptr)); return var::num((f64)ftell((FILE*)fd.obj().ptr));
@ -616,7 +619,7 @@ var builtin_tell(var* local, gc& ngc) {
var builtin_readln(var* local, gc& ngc) { var builtin_readln(var* local, gc& ngc) {
var fd=local[1]; var fd=local[1];
if (!fd.objchk(obj_type::file)) { if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) {
return nas_err("readln", "not a valid filehandle"); return nas_err("readln", "not a valid filehandle");
} }
var str=ngc.alloc(vm_str); var str=ngc.alloc(vm_str);
@ -664,7 +667,7 @@ var builtin_stat(var* local, gc& ngc) {
var builtin_eof(var* local, gc& ngc) { var builtin_eof(var* local, gc& ngc) {
var fd=local[1]; var fd=local[1];
if (!fd.objchk(obj_type::file)) { if (!fd.objchk(ngc.global_ghost_type_table.ghost_file)) {
return nas_err("readln", "not a valid filehandle"); return nas_err("readln", "not a valid filehandle");
} }
return var::num((f64)feof((FILE*)fd.obj().ptr)); return var::num((f64)feof((FILE*)fd.obj().ptr));
@ -849,13 +852,13 @@ var builtin_opendir(var* local, gc& ngc) {
} }
#endif #endif
var ret=ngc.alloc(vm_obj); var ret=ngc.alloc(vm_obj);
ret.obj().set(obj_type::dir,p); ret.obj().set(ngc.global_ghost_type_table.ghost_dir, p, &ngc.global_ghost_type_table);
return ret; return ret;
} }
var builtin_readdir(var* local, gc& ngc) { var builtin_readdir(var* local, gc& ngc) {
var handle=local[1]; var handle=local[1];
if (!handle.objchk(obj_type::dir)) { if (!handle.objchk(ngc.global_ghost_type_table.ghost_dir)) {
return nas_err("readdir", "not a valid dir handle"); return nas_err("readdir", "not a valid dir handle");
} }
#ifdef _MSC_VER #ifdef _MSC_VER
@ -872,7 +875,7 @@ var builtin_readdir(var* local, gc& ngc) {
var builtin_closedir(var* local, gc& ngc) { var builtin_closedir(var* local, gc& ngc) {
var handle=local[1]; var handle=local[1];
if (!handle.objchk(obj_type::dir)) { if (!handle.objchk(ngc.global_ghost_type_table.ghost_dir)) {
return nas_err("closedir", "not a valid dir handle"); return nas_err("closedir", "not a valid dir handle");
} }
handle.obj().clear(); handle.obj().clear();
@ -936,7 +939,7 @@ var builtin_dlopen(var* local, gc& ngc) {
} }
var ret=ngc.temp=ngc.alloc(vm_hash); var ret=ngc.temp=ngc.alloc(vm_hash);
var lib=ngc.alloc(vm_obj); var lib=ngc.alloc(vm_obj);
lib.obj().set(obj_type::dylib, ptr); lib.obj().set(ngc.global_ghost_type_table.ghost_dylib, ptr, &ngc.global_ghost_type_table);
ret.hash().elems["lib"]=lib; ret.hash().elems["lib"]=lib;
#ifdef _WIN32 #ifdef _WIN32
@ -948,14 +951,14 @@ var builtin_dlopen(var* local, gc& ngc) {
return nas_err("dlopen", "cannot find <get> function"); return nas_err("dlopen", "cannot find <get> function");
} }
// get function pointer by name // get function pointer by name
mod_func* tbl=(mod_func*)((getptr)func)(); module_func_info* tbl=((get_func_ptr)func)(&ngc.global_ghost_type_table);
if (!tbl) { if (!tbl) {
return nas_err("dlopen", "failed to get module functions"); return nas_err("dlopen", "failed to get module functions");
} }
for(u32 i=0;tbl[i].name;++i) { for(u32 i=0;tbl[i].name;++i) {
void* p=(void*)tbl[i].fd; void* p=(void*)tbl[i].fd;
var tmp=ngc.alloc(vm_obj); var tmp=ngc.alloc(vm_obj);
tmp.obj().set(obj_type::faddr, p); tmp.obj().set(ngc.global_ghost_type_table.ghost_faddr, p, &ngc.global_ghost_type_table);
ret.hash().elems[tbl[i].name]=tmp; ret.hash().elems[tbl[i].name]=tmp;
} }
@ -965,7 +968,7 @@ var builtin_dlopen(var* local, gc& ngc) {
var builtin_dlclose(var* local, gc& ngc) { var builtin_dlclose(var* local, gc& ngc) {
var libptr=local[1]; var libptr=local[1];
if (!libptr.objchk(obj_type::dylib)) { if (!libptr.objchk(ngc.global_ghost_type_table.ghost_dylib)) {
return nas_err("dlclose", "\"lib\" is not a valid dynamic lib"); return nas_err("dlclose", "\"lib\" is not a valid dynamic lib");
} }
libptr.obj().clear(); libptr.obj().clear();
@ -975,23 +978,27 @@ var builtin_dlclose(var* local, gc& ngc) {
var builtin_dlcallv(var* local, gc& ngc) { var builtin_dlcallv(var* local, gc& ngc) {
var fp=local[1]; var fp=local[1];
var args=local[2]; var args=local[2];
if (!fp.objchk(obj_type::faddr)) { if (!fp.objchk(ngc.global_ghost_type_table.ghost_faddr)) {
return nas_err("dlcall", "\"ptr\" is not a valid function pointer"); return nas_err("dlcall", "\"ptr\" is not a valid function pointer");
} }
auto& vec=args.vec().elems; 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 builtin_dlcall(var* local, gc& ngc) {
var fp=local[1]; var fp=local[1];
if (!fp.objchk(obj_type::faddr)) { if (!fp.objchk(ngc.global_ghost_type_table.ghost_faddr)) {
return nas_err("dlcall", "\"ptr\" is not a valid function pointer"); return nas_err("dlcall", "\"ptr\" is not a valid function pointer");
} }
var* local_frame_start=local+2; var* local_frame_start=local+2;
usize local_frame_size=ngc.rctx->top-local_frame_start; usize local_frame_size=ngc.rctx->top-local_frame_start;
// arguments' stored place begins at local +2 // arguments' stored place begins at local +2
return ((mod)fp.obj().ptr)( return ((module_func)fp.obj().ptr)(
local_frame_start, local_frame_start,
local_frame_size, local_frame_size,
&ngc &ngc

View File

@ -9,6 +9,11 @@
#include <stack> #include <stack>
#include <unordered_map> #include <unordered_map>
#ifdef _MSC_VER
#pragma warning (disable:4244)
#pragma warning (disable:4267)
#endif
class codegen { class codegen {
private: private:
u16 fileindex; u16 fileindex;

View File

@ -1,4 +1,9 @@
#pragma once #pragma once
#ifdef _MSC_VER
#pragma warning (disable:4244)
#pragma warning (disable:4267)
#pragma warning (disable:4102)
#endif
#ifndef _MSC_VER #ifndef _MSC_VER
#include <unistd.h> #include <unistd.h>
@ -43,14 +48,6 @@ enum vm_type:u8 {
const u32 gc_type_size=vm_co-vm_str+1; const u32 gc_type_size=vm_co-vm_str+1;
enum class obj_type:u32 {
null=0,
file=1,
dir,
dylib,
faddr
};
enum class coroutine_status:u32 { enum class coroutine_status:u32 {
suspended, suspended,
running, running,
@ -63,13 +60,13 @@ enum class gc_status:u8 {
found found
}; };
struct nas_vec; // vector struct nas_vec; // vector
struct nas_hash; // hashmap(dict) struct nas_hash; // hashmap(dict)
struct nas_func; // function(lambda) struct nas_func; // function(lambda)
struct nas_upval;// upvalue struct nas_upval; // upvalue
struct nas_obj; // special objects struct nas_obj; // special objects
struct nas_co; // coroutine struct nas_co; // coroutine
struct nas_val; // nas_val includes gc-managed types struct nas_val; // nas_val includes gc-managed types
struct var { struct var {
public: public:
@ -99,7 +96,7 @@ public:
// number and string can be translated to each other // number and string can be translated to each other
f64 tonum(); f64 tonum();
string tostr(); string tostr();
bool objchk(obj_type); bool objchk(usize);
// create new var object // create new var object
static var none(); static var none();
@ -162,6 +159,7 @@ struct nas_func {
}; };
struct nas_upval { struct nas_upval {
public:
/* on stack, use these variables */ /* on stack, use these variables */
bool onstk; bool onstk;
u32 size; u32 size;
@ -170,55 +168,119 @@ struct nas_upval {
/* not on stack, use this */ /* not on stack, use this */
std::vector<var> elems; std::vector<var> 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;}
};
struct ghost_info {
string name;
void (*destructor)(void*);
};
struct nas_ghost {
private:
static std::vector<ghost_info> ghost_register_table;
usize type;
void* ptr;
public: public:
nas_ghost(): type(0), ptr(nullptr) {} nas_upval(): onstk(true), size(0), stk(nullptr) {}
~nas_ghost() {
if (!ptr) { return; } var& operator[](usize n) {
ghost_register_table[type].destructor(ptr); return onstk? stk[n]:elems[n];
} }
static usize regist_ghost_type(ghost_info i) { void clear() {
auto res=ghost_register_table.size(); onstk=true;
ghost_register_table.push_back(i); elems.clear();
size=0;
}
};
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) {}
struct ghost_register_table {
private:
using dtor=void (*)(void*);
private:
std::unordered_map<string,usize> mapper;
std::vector<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 string& name) const {
return mapper.count(name);
}
usize get_ghost_type_index(const string& name) const {
return mapper.at(name);
}
const 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; return res;
} }
const std::string& name() { dtor destructor(usize index) {
return ghost_register_table[type].name; return destructors.at(index);
} }
}; };
struct nas_obj { struct nas_obj {
obj_type type; public:
usize type;
void* ptr; void* ptr;
private: private:
/* RAII constructor, new object is initialized when creating */ ghost_register_table* ghost_type_table;
void file_dtor();
void dir_dtor();
void dylib_dtor();
public: public:
nas_obj(): type(obj_type::null), ptr(nullptr) {} nas_obj(): type(0), ptr(nullptr), ghost_type_table(nullptr) {}
~nas_obj() {clear();} ~nas_obj() {clear();}
void set(obj_type, void*); void set(usize, void*, ghost_register_table*);
void clear(); void clear();
public:
friend std::ostream& operator<<(std::ostream& out, nas_obj& ghost) {
out<<"<object "<<ghost.ghost_type_table->get_ghost_name(ghost.type);
out<<" at 0x"<<std::hex<<(u64)ghost.ptr<<std::dec<<">";
return out;
}
}; };
struct context { struct context {
@ -357,47 +419,20 @@ void nas_func::clear() {
keys.clear(); keys.clear();
} }
void nas_obj::set(obj_type t, void* p) { void nas_obj::set(usize t, void* p, ghost_register_table* table) {
type=t; type=t;
ptr=p; ptr=p;
ghost_type_table=table;
} }
void nas_obj::clear() { void nas_obj::clear() {
if (!ptr) { if (!ptr) {
return; return;
} }
switch(type) { ghost_type_table->destructor(type)(ptr);
case obj_type::file: file_dtor(); break;
case obj_type::dir: dir_dtor(); break;
case obj_type::dylib: dylib_dtor();break;
default: break;
}
ptr=nullptr; ptr=nullptr;
} }
void nas_obj::file_dtor() {
if ((FILE*)ptr==stdin) {
return;
}
fclose((FILE*)ptr);
}
void nas_obj::dir_dtor() {
#ifndef _MSC_VER
closedir((DIR*)ptr);
#else
FindClose(ptr);
#endif
}
void nas_obj::dylib_dtor() {
#ifdef _WIN32
FreeLibrary((HMODULE)ptr);
#else
dlclose(ptr);
#endif
}
void nas_co::clear() { void nas_co::clear() {
for(u32 i=0;i<STACK_DEPTH;++i) { for(u32 i=0;i<STACK_DEPTH;++i) {
stack[i]=var::nil(); stack[i]=var::nil();
@ -479,14 +514,14 @@ std::ostream& operator<<(std::ostream& out, var& ref) {
case vm_vec: out<<ref.vec(); break; case vm_vec: out<<ref.vec(); break;
case vm_hash: out<<ref.hash(); break; case vm_hash: out<<ref.hash(); break;
case vm_func: out<<"func(..) {..}";break; case vm_func: out<<"func(..) {..}";break;
case vm_obj: out<<"<object>"; break; case vm_obj: out<<ref.obj(); break;
case vm_co: out<<"<coroutine>"; break; case vm_co: out<<"<coroutine>"; break;
} }
return out; return out;
} }
bool var::objchk(obj_type objtype) { bool var::objchk(usize obj_type) {
return type==vm_obj && obj().type==objtype && obj().ptr; return type==vm_obj && obj().type==obj_type && obj().ptr;
} }
var var::none() { var var::none() {
@ -534,6 +569,7 @@ const var one =var::num(1);
const var nil =var::nil(); const var nil =var::nil();
struct gc { struct gc {
ghost_register_table global_ghost_type_table;
/* main context temporary storage */ /* main context temporary storage */
context mctx; context mctx;
@ -587,11 +623,27 @@ public:
void clear(); void clear();
void info(); void info();
var alloc(const u8); var alloc(const u8);
var newstr(char);
var newstr(const char*);
var newstr(const string&);
void ctxchg(nas_co&); void ctxchg(nas_co&);
void ctxreserve(); void ctxreserve();
public:
var newstr(char c) {
var s=alloc(vm_str);
s.str()=c;
return s;
}
var newstr(const char* buff) {
var s=alloc(vm_str);
s.str()=buff;
return s;
}
var newstr(const string& buff) {
var s=alloc(vm_str);
s.str()=buff;
return s;
}
}; };
void gc::mark() { void gc::mark() {
@ -691,14 +743,15 @@ void gc::sweep() {
} }
void gc::extend(u8 type) { void gc::extend(u8 type) {
u8 index=type-vm_str; const u8 index=type-vm_str;
size[index]+=incr[index]; size[index]+=incr[index];
for(u32 i=0;i<incr[index];++i) { for(u32 i=0;i<incr[index];++i) {
nas_val* tmp=new nas_val(type); nas_val* tmp=new nas_val(type);
if (!tmp) { if (!tmp) {
std::cerr<<"failed to allocate new memory\n"; std::cerr<<"nasal_gc.h: gc::extend: ";
std::cerr<<"failed to allocate memory\n";
std::exit(-1); std::exit(-1);
} }
@ -720,7 +773,7 @@ void gc::init(const std::vector<string>& s, const std::vector<string>& argv) {
size[i]=gcnt[i]=acnt[i]=0; size[i]=gcnt[i]=acnt[i]=0;
} }
// coroutine pointer set to nullpre // coroutine pointer set to nullptr
cort=nullptr; cort=nullptr;
// init constant strings // init constant strings
@ -820,24 +873,6 @@ var gc::alloc(u8 type) {
return ret; return ret;
} }
var gc::newstr(char c) {
var s=alloc(vm_str);
s.str()=c;
return s;
}
var gc::newstr(const char* buff) {
var s=alloc(vm_str);
s.str()=buff;
return s;
}
var gc::newstr(const string& buff) {
var s=alloc(vm_str);
s.str()=buff;
return s;
}
void gc::ctxchg(nas_co& co) { void gc::ctxchg(nas_co& co) {
// store running state to main context // store running state to main context
mctx=*rctx; mctx=*rctx;
@ -869,19 +904,19 @@ void gc::ctxreserve() {
} }
// use to print error log and return error value // use to print error log and return error value
var nas_err(const string& err_f, const string& info) { var nas_err(const string& error_function_name, const string& info) {
std::cerr<<"[vm] "<<err_f<<": "<<info<<"\n"; std::cerr<<"[vm] "<<error_function_name<<": "<<info<<"\n";
return var::none(); return var::none();
} }
// module function type // module function type
typedef var (*mod)(var*, usize, gc*); typedef var (*module_func)(var*, usize, gc*);
// module function stores in tables with this type, end with {nullptr,nullptr} // module function stores in tables with this type, end with {nullptr,nullptr}
struct mod_func { struct module_func_info {
const char* name; const char* name;
mod fd; module_func fd;
}; };
// module function "get" type // module function "get" type
typedef mod_func* (*getptr)(); typedef module_func_info* (*get_func_ptr)(ghost_register_table*);

View File

@ -1,4 +1,9 @@
#pragma once #pragma once
#ifdef _MSC_VER
#pragma warning (disable:4244)
#pragma warning (disable:4267)
#pragma warning (disable:4102)
#endif
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>

View File

@ -7,6 +7,12 @@
#include "nasal_gc.h" #include "nasal_gc.h"
#include "nasal_codegen.h" #include "nasal_codegen.h"
#ifdef _MSC_VER
#pragma warning (disable:4244)
#pragma warning (disable:4267)
#pragma warning (disable:4102)
#endif
class vm { class vm {
protected: protected:

View File

@ -11,7 +11,7 @@ var new_map=func(width,height){
} }
var prt=func(map){ var prt=func(map){
var s='\e[1;1H'; var s='\ec\e[1;1H';
foreach(var line;map){ foreach(var line;map){
foreach(var elem;line) foreach(var elem;line)
s~=elem~' '; s~=elem~' ';