Merge pull request #49 from ValKmjolnir/develop

👍 add test file for subprocess
This commit is contained in:
ValK 2024-06-14 00:41:54 +08:00 committed by GitHub
commit 7c175a2883
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 90 additions and 58 deletions

View File

@ -330,6 +330,7 @@ test:nasal
@ ./nasal -t -d test/quick_sort.nas
@ ./nasal -t -d test/regex_test.nas
@ ./nasal -e test/scalar.nas hello world
@ ./nasal test/subprocess_test.nas
@ ./nasal -e test/trait.nas
@ ./nasal -t -d test/turingmachine.nas
@ ./nasal -d test/wavecollapse.nas

View File

@ -91,10 +91,10 @@ var set_new_ghost(var* args, usize size, gc* ngc) {
}
f64 num = args[1].num();
reinterpret_cast<ghost_obj*>(res.ghost().pointer)->number = static_cast<u32>(num);
res.ghost().get<ghost_obj>()->number = static_cast<u32>(num);
std::cout << "set_new_ghost: successfully set ghost.number = " << num << "\n";
reinterpret_cast<ghost_obj*>(res.ghost().pointer)->test_string = ngc->newstr("just for test");
res.ghost().get<ghost_obj>()->test_string = ngc->newstr("just for test");
std::cout << "set_new_ghost: successfully set ghost.test_string = just for test\n";
return nil;
}
@ -106,9 +106,9 @@ var print_new_ghost(var* args, usize size, gc* ngc) {
return nil;
}
std::cout << "print_new_ghost: " << res.ghost() << " number = "
<< reinterpret_cast<ghost_obj*>(res.ghost().pointer)->number
<< res.ghost().get<ghost_obj>()->number
<< " test_string = "
<< reinterpret_cast<ghost_obj*>(res.ghost().pointer)->test_string
<< res.ghost().get<ghost_obj>()->test_string
<< "\n";
return nil;
}

View File

@ -100,9 +100,8 @@ void codestream::dump(std::ostream& out) const {
case op_loadl:
out << hex << "0x" << num << dec; break;
case op_callb:
out << hex << "0x" << num << " <" << natives[num].name
<< "@0x" << reinterpret_cast<u64>(natives[num].func)
<< dec << ">"; break;
out << hex << "0x" << num << dec << " ["
<< natives[num].name << "]"; break;
case op_upval:
case op_mupval:
case op_loadu:

View File

@ -164,7 +164,7 @@ void nas_ghost::clear() {
std::ostream& operator<<(std::ostream& out, const nas_ghost& ghost) {
out << "<object " << ghost.get_ghost_name();
out << " at 0x" << std::hex;
out << reinterpret_cast<u64>(ghost.pointer) << std::dec << ">";
out << ghost.convert<u64>() << std::dec << ">";
return out;
}

View File

@ -213,6 +213,12 @@ public:
public:
const auto& get_ghost_name() const { return type_name; }
public:
template<typename T>
T* get() { return static_cast<T*>(pointer); }
template<typename T>
T convert() const { return reinterpret_cast<T>(pointer); }
};
struct context {

View File

@ -98,34 +98,30 @@ void vm::value_info(var& val) {
case vm_type::vm_nil: std::clog << "| nil |"; break;
case vm_type::vm_num: std::clog << "| num | " << val.num(); break;
case vm_type::vm_str:
std::clog << "| str | <0x" << std::hex << p << "> " << std::dec;
std::clog << "\"" << util::rawstr(val.str(), 16) << "\"";
std::clog << "| str | \"" << util::rawstr(val.str(), 16) << "\"";
break;
case vm_type::vm_func:
std::clog << "| func | <0x" << std::hex << p << std::dec << "> ";
std::clog << val.func();
std::clog << "| func | " << val.func();
break;
case vm_type::vm_upval:
std::clog << "| upval| <0x" << std::hex << p << std::dec;
std::clog << "> [" << val.upval().size << " val]"; break;
case vm_type::vm_vec:
std::clog << "| vec | <0x" << std::hex << p << std::dec;
std::clog << "> [" << val.vec().size() << " val]"; break;
std::clog << "| vec | [" << val.vec().size() << " val]"; break;
case vm_type::vm_hash:
std::clog << "| hash | <0x" << std::hex << p << std::dec << "> ";
std::clog << "| hash | ";
hash_value_info(val);
break;
case vm_type::vm_ghost:
std::clog << "| obj | <0x" << std::hex << p << "> " << std::dec;
std::clog << "obj:" << val.ghost().type_name;
std::clog << "object:" << val.ghost().type_name;
break;
case vm_type::vm_co:
std::clog << "| co | <0x" << std::hex << p << std::dec;
std::clog << "> coroutine";
std::clog << "| co | coroutine@0x" << std::hex << p << std::dec;
break;
case vm_type::vm_map:
std::clog << "| nmspc| <0x" << std::hex << p << std::dec;
std::clog << "> namespace [" << val.map().mapper.size() << " val]";
std::clog << "| nmspc| [";
std::clog << val.map().mapper.size() << " val]";
break;
default:
std::clog << "| err | <0x" << std::hex << p << std::dec;
@ -136,8 +132,7 @@ void vm::value_info(var& val) {
}
void vm::function_detail_info(const nas_func& func) {
std::clog << "func@0x";
std::clog << std::hex << reinterpret_cast<u64>(&func) << std::dec;
std::clog << "func";
std::vector<std::string> argument_list = {};
argument_list.resize(func.keys.size());
@ -212,7 +207,7 @@ void vm::trace_back() {
}
ret.push(ctx.pc); // store the position program crashed
std::clog << "\ntrace back " << (ngc.cort? "(coroutine)":"(main)") << "\n";
std::clog << "\nback trace " << (ngc.cort? "(coroutine)":"(main)") << "\n";
codestream::set(const_number, const_string, native_function.data(), files);
for(u32 p = 0, same = 0, prev = 0xffffffff; !ret.empty(); prev = p, ret.pop()) {
if ((p = ret.top())==prev) {
@ -236,7 +231,7 @@ void vm::stack_info(const u64 limit = 16) {
var* bottom = ctx.stack;
const auto stack_address = reinterpret_cast<u64>(bottom);
std::clog << "\nvm stack (0x" << std::hex << stack_address << std::dec;
std::clog << "\nstack (0x" << std::hex << stack_address << std::dec;
std::clog << ", limit " << limit << ", total ";
std::clog << (top<bottom? 0:static_cast<i64>(top-bottom+1)) << ")\n";
@ -250,7 +245,7 @@ void vm::stack_info(const u64 limit = 16) {
}
void vm::register_info() {
std::clog << "\nregisters (" << (ngc.cort? "coroutine":"main") << ")\n";
std::clog << "\nregister (" << (ngc.cort? "coroutine":"main") << ")\n";
std::clog << std::hex
<< " [ pc ] | pc | 0x" << ctx.pc << "\n"
<< " [ global ] | addr | 0x"

View File

@ -615,7 +615,7 @@ var builtin_time_stamp(context* ctx, gc* ngc) {
if (!object.object_check("nasal-time-stamp")) {
return nil;
}
auto stamp = static_cast<time_stamp*>(object.ghost().pointer);
auto stamp = object.ghost().get<time_stamp>();
stamp->make_stamp();
return nil;
}
@ -625,7 +625,7 @@ var builtin_elapsed_millisecond(context* ctx, gc* ngc) {
if (!object.object_check("nasal-time-stamp")) {
return var::num(-1);
}
auto stamp = static_cast<time_stamp*>(object.ghost().pointer);
auto stamp = object.ghost().get<time_stamp>();
return var::num(static_cast<f64>(stamp->elapsed_milliseconds()));
}
@ -634,7 +634,7 @@ var builtin_elapsed_microsecond(context* ctx, gc* ngc) {
if (!object.object_check("nasal-time-stamp")) {
return var::num(-1);
}
auto stamp = static_cast<time_stamp*>(object.ghost().pointer);
auto stamp = object.ghost().get<time_stamp>();
return var::num(static_cast<f64>(stamp->elapsed_microseconds()));
}
@ -717,7 +717,7 @@ var builtin_ghosttype(context* ctx, gc* ngc) {
if (!name.length()) {
std::stringstream ss;
ss << "0x" << std::hex;
ss << reinterpret_cast<u64>(arg.ghost().pointer) << std::dec;
ss << arg.ghost().convert<u64>() << std::dec;
return ngc->newstr(ss.str());
}
return ngc->newstr(name);

View File

@ -55,7 +55,7 @@ var builtin_dlopen(context* ctx, gc* ngc) {
// get "get" function, to get the register table
#ifdef _WIN32
void* register_table_get_function = reinterpret_cast<void*>(GetProcAddress(
static_cast<HMODULE>(library_object.ghost().pointer), "get"
library_object.ghost().convert<HMODULE>(), "get"
));
#else
void* register_table_get_function = dlsym(
@ -105,7 +105,7 @@ var builtin_dlcallv(context* ctx, gc* ngc) {
);
}
auto& vec = arguments.vec().elems;
return reinterpret_cast<module_func>(function_object.ghost().pointer)(
return function_object.ghost().convert<module_func>()(
vec.data(),
vec.size(),
ngc
@ -124,7 +124,7 @@ var builtin_dlcall(context* ctx, gc* ngc) {
// so arguments starts from ctx->localr[2]
var* local_frame_start = ctx->localr + 2;
usize local_frame_size = ngc->running_context->top - local_frame_start;
return reinterpret_cast<module_func>(function_object.ghost().pointer)(
return function_object.ghost().convert<module_func>()(
local_frame_start,
local_frame_size,
ngc

View File

@ -101,7 +101,7 @@ var builtin_read(context* ctx, gc* ngc) {
}
auto read_size = fread(
temp_buffer, 1, length.num(),
static_cast<FILE*>(file_descriptor.ghost().pointer)
file_descriptor.ghost().get<FILE>()
);
buffer.str() = temp_buffer;
buffer.val.gcobj->immutable = true;
@ -121,7 +121,7 @@ var builtin_write(context* ctx, gc* ngc) {
}
return var::num(static_cast<f64>(fwrite(
source.str().c_str(), 1, source.str().length(),
static_cast<FILE*>(file_descriptor.ghost().pointer)
file_descriptor.ghost().get<FILE>()
)));
}
@ -134,7 +134,7 @@ var builtin_seek(context* ctx, gc* ngc) {
return nas_err("io::seek", "not a valid filehandle");
}
return var::num(static_cast<f64>(fseek(
static_cast<FILE*>(file_descriptor.ghost().pointer),
file_descriptor.ghost().get<FILE>(),
position.num(),
whence.num()
)));
@ -146,7 +146,7 @@ var builtin_tell(context* ctx, gc* ngc) {
return nas_err("io::tell", "not a valid filehandle");
}
return var::num(static_cast<f64>(
ftell(static_cast<FILE*>(file_descriptor.ghost().pointer))
ftell(file_descriptor.ghost().get<FILE>())
));
}
@ -157,7 +157,7 @@ var builtin_readln(context* ctx, gc* ngc) {
}
auto result = ngc->alloc(vm_type::vm_str);
char c;
while((c = fgetc(static_cast<FILE*>(file_descriptor.ghost().pointer)))!=EOF) {
while((c = fgetc(file_descriptor.ghost().get<FILE>()))!=EOF) {
if (c=='\r') {
continue;
}
@ -204,7 +204,7 @@ var builtin_eof(context* ctx, gc* ngc) {
return nas_err("io::readln", "not a valid filehandle");
}
return var::num(static_cast<f64>(
feof(static_cast<FILE*>(file_descriptor.ghost().pointer))
feof(file_descriptor.ghost().get<FILE>())
));
}

View File

@ -369,7 +369,7 @@ var builtin_json_stringify(context* ctx, gc* ngc) {
if (!json_object.object_check("nasal::json")) {
return nas_err("json::stringify", "expect a json object.");
}
auto json_ptr = static_cast<json*>(json_object.ghost().pointer);
auto json_ptr = json_object.ghost().get<json>();
return ngc->newstr(json_ptr->stringify(object));
}
@ -382,7 +382,7 @@ var builtin_json_parse(context* ctx, gc* ngc) {
if (!input_string.is_str()) {
return nas_err("json::parse", "require string as the input.");
}
auto json_ptr = static_cast<json*>(json_object.ghost().pointer);
auto json_ptr = json_object.ghost().get<json>();
return json_ptr->parse(input_string.str(), ngc);
}
@ -391,7 +391,7 @@ var builtin_json_get_error(context* ctx, gc* ngc) {
if (!json_object.object_check("nasal::json")) {
return nas_err("json::get_error", "expect a json object.");
}
auto json_ptr = static_cast<json*>(json_object.ghost().pointer);
auto json_ptr = json_object.ghost().get<json>();
return ngc->newstr(json_ptr->get_error());
}

View File

@ -24,18 +24,16 @@
namespace nasal {
const auto subproc_desc_name = "subprocess_descriptor";
void subprocess_desc_dtor(void* ptr) {
#ifdef WIN32
auto pi = &static_cast<subprocess_descriptor*>(ptr)->pi;
auto pi = &static_cast<subprocess*>(ptr)->pi;
WaitForSingleObject(pi->hProcess, 0);
TerminateProcess(pi->hProcess, 0);
CloseHandle(pi->hProcess);
CloseHandle(pi->hThread);
#else
auto pid = static_cast<subprocess_descriptor*>(ptr)->pid;
auto pid = static_cast<subprocess*>(ptr)->pid;
int status;
pid_t result = waitpid(pid, &status, WNOHANG);
@ -50,26 +48,30 @@ void subprocess_desc_dtor(void* ptr) {
var builtin_subprocess_create(context* ctx, gc* ngc) {
auto cmd = ctx->localr[1];
if (!cmd.is_vec()) {
return nas_err("subprocess::create", "expect a string as the command");
return nas_err("subprocess::create",
"expect string vector as the command"
);
}
for(const auto& v : cmd.vec().elems) {
if (!v.is_str()) {
return nas_err("subprocess::create", "non-string arguments");
return nas_err("subprocess::create",
"non-string argument found"
);
}
}
auto obj = ngc->alloc(vm_type::vm_ghost);
obj.ghost().set(
subproc_desc_name,
subprocess::name(),
subprocess_desc_dtor,
nullptr,
new subprocess_descriptor
new subprocess
);
#ifdef WIN32
auto si = &static_cast<subprocess_descriptor*>(obj.ghost().pointer)->si;
auto pi = &static_cast<subprocess_descriptor*>(obj.ghost().pointer)->pi;
auto si = &obj.ghost().get<subprocess>()->si;
auto pi = &obj.ghost().get<subprocess>()->pi;
// init STARTUPINFO
ZeroMemory(si, sizeof(STARTUPINFOW));
@ -135,7 +137,7 @@ var builtin_subprocess_create(context* ctx, gc* ngc) {
}
// parent process
static_cast<subprocess_descriptor*>(obj.ghost().pointer)->pid = pid;
obj.ghost().get<subprocess>()->pid = pid;
for(usize i = 0; argv[i]; ++i) {
delete argv[i];
}
@ -148,14 +150,14 @@ var builtin_subprocess_create(context* ctx, gc* ngc) {
var builtin_subprocess_terminate(context* ctx, gc* ngc) {
auto obj = ctx->localr[1];
if (!obj.object_check(subproc_desc_name)) {
if (!obj.object_check(subprocess::name())) {
return nas_err("subprocess::terminate",
"need correct subprocess descriptor"
"need correct subprocess object"
);
}
#ifdef WIN32
auto pi = &static_cast<subprocess_descriptor*>(obj.ghost().pointer)->pi;
auto pi = &obj.ghost().get<subprocess>()->pi;
WaitForSingleObject(pi->hProcess, 0);
TerminateProcess(pi->hProcess, -1);
@ -166,7 +168,7 @@ var builtin_subprocess_terminate(context* ctx, gc* ngc) {
CloseHandle(pi->hProcess);
CloseHandle(pi->hThread);
#else
auto pid = static_cast<subprocess_descriptor*>(obj.ghost().pointer)->pid;
auto pid = obj.ghost().get<subprocess>()->pid;
int status;
pid_t result = waitpid(pid, &status, WNOHANG);

View File

@ -14,13 +14,18 @@
namespace nasal {
struct subprocess_descriptor {
struct subprocess {
#ifndef WIN32
pid_t pid;
#else
STARTUPINFOW si;
PROCESS_INFORMATION pi;
#endif
public:
static const char* name() {
return "nasal::subprocess";
}
};
void subprocess_desc_dtor(void*);

View File

@ -89,7 +89,7 @@ var builtin_readdir(context* ctx, gc* ngc) {
}
return ngc->newstr(data.cFileName);
#else
dirent* p = readdir(static_cast<DIR*>(handle.ghost().pointer));
dirent* p = readdir(handle.ghost().get<DIR>());
return p? ngc->newstr(p->d_name):nil;
#endif
}

View File

@ -0,0 +1,11 @@
use std.unix;
var count = 0;
while(1) {
unix.sleep(0.1);
count += 0.1;
println("process running time: ", count);
if (count > 2) {
die("test failed");
}
}

13
test/subprocess_test.nas Normal file
View File

@ -0,0 +1,13 @@
use std.subprocess;
use std.unix;
var process = subprocess.create([
"./nasal",
"test/for_subprocess_test/infinite_loop.nas"
]);
unix.sleep(1);
println("kill subprocess...");
var res = subprocess.terminate(process);
println("subprocess killed, code ", res);