Merge pull request #49 from ValKmjolnir/develop
👍 add test file for subprocess
This commit is contained in:
commit
7c175a2883
1
makefile
1
makefile
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>())
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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);
|
Loading…
Reference in New Issue