Merge pull request #51 from ValKmjolnir/develop
🐛 fix bug in subprocess and dylib
This commit is contained in:
commit
1c537f0398
|
@ -639,11 +639,11 @@ Windows(`.dll`):
|
||||||
|
|
||||||
`g++ -shared -o libfib.dll fib.o`
|
`g++ -shared -o libfib.dll fib.o`
|
||||||
|
|
||||||
Then we write a test nasal file to run this fib function, using `os.platform()` we could write a cross-platform program:
|
Then we write a test nasal file to run this fib function:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
use std.dylib;
|
use std.dylib;
|
||||||
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
var dlhandle = dylib.dlopen("libfib");
|
||||||
var fib = dlhandle.fib;
|
var fib = dlhandle.fib;
|
||||||
for(var i = 1; i<30; i += 1)
|
for(var i = 1; i<30; i += 1)
|
||||||
println(dylib.dlcall(fib, i));
|
println(dylib.dlcall(fib, i));
|
||||||
|
@ -660,7 +660,7 @@ dylib.dlclose(dlhandle.lib);
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
use std.dylib;
|
use std.dylib;
|
||||||
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
var dlhandle = dylib.dlopen("libfib");
|
||||||
var fib = dlhandle.fib;
|
var fib = dlhandle.fib;
|
||||||
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
|
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
|
||||||
for(var i = 1; i<30; i += 1)
|
for(var i = 1; i<30; i += 1)
|
||||||
|
|
|
@ -618,12 +618,11 @@ Windows(`.dll`):
|
||||||
|
|
||||||
`g++ -shared -o libfib.dll fib.o`
|
`g++ -shared -o libfib.dll fib.o`
|
||||||
|
|
||||||
好了,那么我们可以写一个测试用的nasal代码来运行这个斐波那契函数了。
|
好了,那么我们可以写一个测试用的nasal代码来运行这个斐波那契函数了:
|
||||||
下面例子中`os.platform()`是用来检测当前运行的系统环境的,这样可以实现跨平台:
|
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
use std.dylib;
|
use std.dylib;
|
||||||
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
var dlhandle = dylib.dlopen("libfib");
|
||||||
var fib = dlhandle.fib;
|
var fib = dlhandle.fib;
|
||||||
for(var i = 1; i<30; i += 1)
|
for(var i = 1; i<30; i += 1)
|
||||||
println(dylib.dlcall(fib, i));
|
println(dylib.dlcall(fib, i));
|
||||||
|
@ -640,7 +639,7 @@ dylib.dlclose(dlhandle.lib);
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
use std.dylib;
|
use std.dylib;
|
||||||
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
var dlhandle = dylib.dlopen("libfib");
|
||||||
var fib = dlhandle.fib;
|
var fib = dlhandle.fib;
|
||||||
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
|
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
|
||||||
for(var i = 1; i<30; i += 1)
|
for(var i = 1; i<30; i += 1)
|
||||||
|
|
2
makefile
2
makefile
|
@ -189,6 +189,8 @@ build/dylib_lib.o: \
|
||||||
src/nasal.h\
|
src/nasal.h\
|
||||||
src/nasal_type.h\
|
src/nasal_type.h\
|
||||||
src/nasal_gc.h\
|
src/nasal_gc.h\
|
||||||
|
src/util/util.h\
|
||||||
|
src/util/fs.h\
|
||||||
src/natives/dylib_lib.h src/natives/dylib_lib.cpp | build
|
src/natives/dylib_lib.h src/natives/dylib_lib.cpp | build
|
||||||
$(CXX) $(CXXFLAGS) src/natives/dylib_lib.cpp -o build/dylib_lib.o
|
$(CXX) $(CXXFLAGS) src/natives/dylib_lib.cpp -o build/dylib_lib.o
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std.dylib;
|
use std.dylib;
|
||||||
use std.os;
|
use std.os;
|
||||||
|
|
||||||
var _dl = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
var _dl = dylib.dlopen("libfib");
|
||||||
|
|
||||||
var _fib = _dl.fib;
|
var _fib = _dl.fib;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ var (
|
||||||
getch,
|
getch,
|
||||||
nonblock
|
nonblock
|
||||||
) = func {
|
) = func {
|
||||||
var lib = dylib.dlopen("libkey"~(os.platform()=="windows"? ".dll":".so"));
|
var lib = dylib.dlopen("libkey");
|
||||||
var kb = lib.nas_kbhit;
|
var kb = lib.nas_kbhit;
|
||||||
var gt = lib.nas_getch;
|
var gt = lib.nas_getch;
|
||||||
var nb = lib.nas_noblock;
|
var nb = lib.nas_noblock;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std.dylib;
|
use std.dylib;
|
||||||
use std.os;
|
use std.os;
|
||||||
|
|
||||||
var _dl = dylib.dlopen("libmat."~(os.platform()=="windows"?"dll":"so"));
|
var _dl = dylib.dlopen("libmat");
|
||||||
|
|
||||||
var _vec2 = _dl.nas_vec2;
|
var _vec2 = _dl.nas_vec2;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std.dylib;
|
||||||
use std.os;
|
use std.os;
|
||||||
|
|
||||||
var socket = func() {
|
var socket = func() {
|
||||||
var lib = dylib.dlopen("libnasock"~(os.platform()=="windows"? ".dll":".so"));
|
var lib = dylib.dlopen("libnasock");
|
||||||
|
|
||||||
var sock = lib.nas_socket;
|
var sock = lib.nas_socket;
|
||||||
var closesocket = lib.nas_closesocket;
|
var closesocket = lib.nas_closesocket;
|
||||||
|
|
|
@ -60,6 +60,7 @@ private:
|
||||||
"__chdir", "__environ", "__getcwd", "__getenv",
|
"__chdir", "__environ", "__getcwd", "__getenv",
|
||||||
// subprocess
|
// subprocess
|
||||||
"__subprocess_create",
|
"__subprocess_create",
|
||||||
|
"__subprocess_active",
|
||||||
"__subprocess_terminate"
|
"__subprocess_terminate"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ void operand_line_counter::dump_operand_count() const {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::clog << " ";
|
std::clog << " ";
|
||||||
std::clog << operand_name_table.at(static_cast<op_code_type>(i.first));
|
std::clog << operand_name_table.at(static_cast<opcode_type>(i.first));
|
||||||
std::clog << " : " << i.second << " (" << rate << "%)\n";
|
std::clog << " : " << i.second << " (" << rate << "%)\n";
|
||||||
}
|
}
|
||||||
std::clog << " total : " << total << '\n';
|
std::clog << " total : " << total << '\n';
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace nasal {
|
||||||
// and show them before each line of the source file
|
// and show them before each line of the source file
|
||||||
class operand_line_counter {
|
class operand_line_counter {
|
||||||
private:
|
private:
|
||||||
static const usize operand_size = op_code_type::op_ret + 1;
|
static const usize operand_size = opcode_type::op_ret + 1;
|
||||||
u64 operand_counter[operand_size];
|
u64 operand_counter[operand_size];
|
||||||
std::vector<std::string> file_name_list;
|
std::vector<std::string> file_name_list;
|
||||||
std::vector<std::vector<u64>> file_line_counter;
|
std::vector<std::vector<u64>> file_line_counter;
|
||||||
|
|
|
@ -315,16 +315,20 @@ void gc::info() const {
|
||||||
indent_string += "─";
|
indent_string += "─";
|
||||||
}
|
}
|
||||||
const auto first_line = "╭" + indent_string + "┬" +
|
const auto first_line = "╭" + indent_string + "┬" +
|
||||||
indent_string + "─" +
|
indent_string + "┬" +
|
||||||
indent_string + "─" +
|
indent_string + "┬" +
|
||||||
indent_string + "╮";
|
indent_string + "╮";
|
||||||
|
const auto second_line = "├" + indent_string + "┼" +
|
||||||
|
indent_string + "┼" +
|
||||||
|
indent_string + "┼" +
|
||||||
|
indent_string + "┤";
|
||||||
const auto mid_line = "├" + indent_string + "┼" +
|
const auto mid_line = "├" + indent_string + "┼" +
|
||||||
indent_string + "┼" +
|
indent_string + "┴" +
|
||||||
indent_string + "┼" +
|
indent_string + "┴" +
|
||||||
indent_string + "┤";
|
indent_string + "┤";
|
||||||
const auto another_mid_line = "├" + indent_string + "┼" +
|
const auto another_mid_line = "├" + indent_string + "┼" +
|
||||||
indent_string + "┴" +
|
indent_string + "─" +
|
||||||
indent_string + "┴" +
|
indent_string + "─" +
|
||||||
indent_string + "┤";
|
indent_string + "┤";
|
||||||
const auto last_line = "╰" + indent_string + "┴" +
|
const auto last_line = "╰" + indent_string + "┴" +
|
||||||
indent_string + "─" +
|
indent_string + "─" +
|
||||||
|
@ -336,7 +340,7 @@ void gc::info() const {
|
||||||
std::clog << " │ " << left << setw(indent) << setfill(' ') << "gc count";
|
std::clog << " │ " << left << setw(indent) << setfill(' ') << "gc count";
|
||||||
std::clog << " │ " << left << setw(indent) << setfill(' ') << "alloc count";
|
std::clog << " │ " << left << setw(indent) << setfill(' ') << "alloc count";
|
||||||
std::clog << " │ " << left << setw(indent) << setfill(' ') << "memory size";
|
std::clog << " │ " << left << setw(indent) << setfill(' ') << "memory size";
|
||||||
std::clog << " │\n" << mid_line << "\n";
|
std::clog << " │\n" << second_line << "\n";
|
||||||
|
|
||||||
double total = 0;
|
double total = 0;
|
||||||
for(u8 i = 0; i<gc_type_size; ++i) {
|
for(u8 i = 0; i<gc_type_size; ++i) {
|
||||||
|
@ -355,8 +359,8 @@ void gc::info() const {
|
||||||
const auto den = std::chrono::high_resolution_clock::duration::period::den;
|
const auto den = std::chrono::high_resolution_clock::duration::period::den;
|
||||||
std::clog << "│ " << left << setw(indent) << setfill(' ') << "detail";
|
std::clog << "│ " << left << setw(indent) << setfill(' ') << "detail";
|
||||||
std::clog << " │ " << left << setw(indent) << setfill(' ') << "time spend";
|
std::clog << " │ " << left << setw(indent) << setfill(' ') << "time spend";
|
||||||
std::clog << " │ " << left << setw(indent) << setfill('x') << "x";
|
std::clog << " " << left << setw(indent) << setfill(' ') << " ";
|
||||||
std::clog << " │ " << left << setw(indent) << setfill('x') << "x";
|
std::clog << " " << left << setw(indent) << setfill(' ') << " ";
|
||||||
std::clog << " │\n" << another_mid_line << "\n";
|
std::clog << " │\n" << another_mid_line << "\n";
|
||||||
|
|
||||||
const auto gc_time = worktime*1.0/den*1000;
|
const auto gc_time = worktime*1.0/den*1000;
|
||||||
|
|
|
@ -29,11 +29,12 @@ void codestream::dump(std::ostream& out) const {
|
||||||
|
|
||||||
// dump immediate number(hex format)
|
// dump immediate number(hex format)
|
||||||
for(i32 i = 64-8; i>=0; i -= 8) {
|
for(i32 i = 64-8; i>=0; i -= 8) {
|
||||||
out << hex << setw(2) << setfill('0') << ((num>>i)&0xff) << dec << " ";
|
auto this_byte = ((num>>i)&0xff);
|
||||||
|
out << hex << setw(2) << setfill('0') << this_byte << dec << " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
// dump operand name
|
// dump operand name
|
||||||
out << " " << operand_name_table.at(static_cast<op_code_type>(op)) << " ";
|
out << " " << operand_name_table.at(static_cast<opcode_type>(op)) << " ";
|
||||||
|
|
||||||
switch(op) {
|
switch(op) {
|
||||||
case op_addeq:
|
case op_addeq:
|
||||||
|
@ -56,7 +57,7 @@ void codestream::dump(std::ostream& out) const {
|
||||||
break;
|
break;
|
||||||
case op_lnkeqc:
|
case op_lnkeqc:
|
||||||
out << hex << "0x" << num << dec;
|
out << hex << "0x" << num << dec;
|
||||||
out << " (" << util::rawstr(const_string[num], 16) << ")";
|
out << " (\"" << util::rawstr(const_string[num], 32) << "\")";
|
||||||
break;
|
break;
|
||||||
case op_addecp:
|
case op_addecp:
|
||||||
case op_subecp:
|
case op_subecp:
|
||||||
|
@ -67,7 +68,7 @@ void codestream::dump(std::ostream& out) const {
|
||||||
break;
|
break;
|
||||||
case op_lnkecp:
|
case op_lnkecp:
|
||||||
out << hex << "0x" << num << dec;
|
out << hex << "0x" << num << dec;
|
||||||
out << " (" << util::rawstr(const_string[num], 16) << ") sp-1";
|
out << " (\"" << util::rawstr(const_string[num], 32) << "\") sp-1";
|
||||||
break;
|
break;
|
||||||
case op_addc:
|
case op_addc:
|
||||||
case op_subc:
|
case op_subc:
|
||||||
|
@ -100,8 +101,11 @@ void codestream::dump(std::ostream& out) const {
|
||||||
case op_loadl:
|
case op_loadl:
|
||||||
out << hex << "0x" << num << dec; break;
|
out << hex << "0x" << num << dec; break;
|
||||||
case op_callb:
|
case op_callb:
|
||||||
out << hex << "0x" << num << dec << " ["
|
out << hex << "0x" << num << dec;
|
||||||
<< natives[num].name << "]"; break;
|
out << " <" << natives[num].name << "@0x";
|
||||||
|
out << hex << reinterpret_cast<u64>(natives[num].func) << dec;
|
||||||
|
out << ">";
|
||||||
|
break;
|
||||||
case op_upval:
|
case op_upval:
|
||||||
case op_mupval:
|
case op_mupval:
|
||||||
case op_loadu:
|
case op_loadu:
|
||||||
|
@ -116,7 +120,7 @@ void codestream::dump(std::ostream& out) const {
|
||||||
case op_deft:
|
case op_deft:
|
||||||
case op_dyn:
|
case op_dyn:
|
||||||
out << hex << "0x" << num << dec;
|
out << hex << "0x" << num << dec;
|
||||||
out << " (" << util::rawstr(const_string[num], 16) << ")";
|
out << " (\"" << util::rawstr(const_string[num], 32) << "\")";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (files) {
|
if (files) {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
namespace nasal {
|
namespace nasal {
|
||||||
|
|
||||||
enum op_code_type: u8 {
|
enum opcode_type: u8 {
|
||||||
op_exit, // stop the virtual machine
|
op_exit, // stop the virtual machine
|
||||||
op_repl, // in repl mode: print value on stack top
|
op_repl, // in repl mode: print value on stack top
|
||||||
op_intl, // local scope size
|
op_intl, // local scope size
|
||||||
|
@ -98,95 +98,95 @@ enum op_code_type: u8 {
|
||||||
op_ret // return
|
op_ret // return
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::unordered_map<op_code_type, std::string> operand_name_table = {
|
static std::unordered_map<opcode_type, std::string> operand_name_table = {
|
||||||
{op_code_type::op_exit, "exit "},
|
{opcode_type::op_exit, "exit "},
|
||||||
{op_code_type::op_repl, "repl "},
|
{opcode_type::op_repl, "repl "},
|
||||||
{op_code_type::op_intl, "intl "},
|
{opcode_type::op_intl, "intl "},
|
||||||
{op_code_type::op_loadg, "loadg "},
|
{opcode_type::op_loadg, "loadg "},
|
||||||
{op_code_type::op_loadl, "loadl "},
|
{opcode_type::op_loadl, "loadl "},
|
||||||
{op_code_type::op_loadu, "loadu "},
|
{opcode_type::op_loadu, "loadu "},
|
||||||
{op_code_type::op_dup, "dup "},
|
{opcode_type::op_dup, "dup "},
|
||||||
{op_code_type::op_pnum, "pnum "},
|
{opcode_type::op_pnum, "pnum "},
|
||||||
{op_code_type::op_pnil, "pnil "},
|
{opcode_type::op_pnil, "pnil "},
|
||||||
{op_code_type::op_pstr, "pstr "},
|
{opcode_type::op_pstr, "pstr "},
|
||||||
{op_code_type::op_newv, "newv "},
|
{opcode_type::op_newv, "newv "},
|
||||||
{op_code_type::op_newh, "newh "},
|
{opcode_type::op_newh, "newh "},
|
||||||
{op_code_type::op_newf, "newf "},
|
{opcode_type::op_newf, "newf "},
|
||||||
{op_code_type::op_happ, "happ "},
|
{opcode_type::op_happ, "happ "},
|
||||||
{op_code_type::op_para, "para "},
|
{opcode_type::op_para, "para "},
|
||||||
{op_code_type::op_deft, "def "},
|
{opcode_type::op_deft, "def "},
|
||||||
{op_code_type::op_dyn, "dyn "},
|
{opcode_type::op_dyn, "dyn "},
|
||||||
{op_code_type::op_lnot, "lnot "},
|
{opcode_type::op_lnot, "lnot "},
|
||||||
{op_code_type::op_usub, "usub "},
|
{opcode_type::op_usub, "usub "},
|
||||||
{op_code_type::op_bnot, "bitnot"},
|
{opcode_type::op_bnot, "bitnot"},
|
||||||
{op_code_type::op_btor, "bitor "},
|
{opcode_type::op_btor, "bitor "},
|
||||||
{op_code_type::op_btxor, "bitxor"},
|
{opcode_type::op_btxor, "bitxor"},
|
||||||
{op_code_type::op_btand, "bitand"},
|
{opcode_type::op_btand, "bitand"},
|
||||||
{op_code_type::op_add, "add "},
|
{opcode_type::op_add, "add "},
|
||||||
{op_code_type::op_sub, "sub "},
|
{opcode_type::op_sub, "sub "},
|
||||||
{op_code_type::op_mul, "mult "},
|
{opcode_type::op_mul, "mult "},
|
||||||
{op_code_type::op_div, "div "},
|
{opcode_type::op_div, "div "},
|
||||||
{op_code_type::op_lnk, "lnk "},
|
{opcode_type::op_lnk, "lnk "},
|
||||||
{op_code_type::op_addc, "addc "},
|
{opcode_type::op_addc, "addc "},
|
||||||
{op_code_type::op_subc, "subc "},
|
{opcode_type::op_subc, "subc "},
|
||||||
{op_code_type::op_mulc, "multc "},
|
{opcode_type::op_mulc, "multc "},
|
||||||
{op_code_type::op_divc, "divc "},
|
{opcode_type::op_divc, "divc "},
|
||||||
{op_code_type::op_lnkc, "lnkc "},
|
{opcode_type::op_lnkc, "lnkc "},
|
||||||
{op_code_type::op_addeq, "addeq "},
|
{opcode_type::op_addeq, "addeq "},
|
||||||
{op_code_type::op_subeq, "subeq "},
|
{opcode_type::op_subeq, "subeq "},
|
||||||
{op_code_type::op_muleq, "muleq "},
|
{opcode_type::op_muleq, "muleq "},
|
||||||
{op_code_type::op_diveq, "diveq "},
|
{opcode_type::op_diveq, "diveq "},
|
||||||
{op_code_type::op_lnkeq, "lnkeq "},
|
{opcode_type::op_lnkeq, "lnkeq "},
|
||||||
{op_code_type::op_btandeq, "bandeq"},
|
{opcode_type::op_btandeq, "bandeq"},
|
||||||
{op_code_type::op_btoreq, "boreq "},
|
{opcode_type::op_btoreq, "boreq "},
|
||||||
{op_code_type::op_btxoreq, "bxoreq"},
|
{opcode_type::op_btxoreq, "bxoreq"},
|
||||||
{op_code_type::op_addeqc, "addeqc"},
|
{opcode_type::op_addeqc, "addeqc"},
|
||||||
{op_code_type::op_subeqc, "subeqc"},
|
{opcode_type::op_subeqc, "subeqc"},
|
||||||
{op_code_type::op_muleqc, "muleqc"},
|
{opcode_type::op_muleqc, "muleqc"},
|
||||||
{op_code_type::op_diveqc, "diveqc"},
|
{opcode_type::op_diveqc, "diveqc"},
|
||||||
{op_code_type::op_lnkeqc, "lnkeqc"},
|
{opcode_type::op_lnkeqc, "lnkeqc"},
|
||||||
{op_code_type::op_addecp, "addecp"},
|
{opcode_type::op_addecp, "addecp"},
|
||||||
{op_code_type::op_subecp, "subecp"},
|
{opcode_type::op_subecp, "subecp"},
|
||||||
{op_code_type::op_mulecp, "mulecp"},
|
{opcode_type::op_mulecp, "mulecp"},
|
||||||
{op_code_type::op_divecp, "divecp"},
|
{opcode_type::op_divecp, "divecp"},
|
||||||
{op_code_type::op_lnkecp, "lnkecp"},
|
{opcode_type::op_lnkecp, "lnkecp"},
|
||||||
{op_code_type::op_meq, "meq "},
|
{opcode_type::op_meq, "meq "},
|
||||||
{op_code_type::op_eq, "eq "},
|
{opcode_type::op_eq, "eq "},
|
||||||
{op_code_type::op_neq, "neq "},
|
{opcode_type::op_neq, "neq "},
|
||||||
{op_code_type::op_less, "less "},
|
{opcode_type::op_less, "less "},
|
||||||
{op_code_type::op_leq, "leq "},
|
{opcode_type::op_leq, "leq "},
|
||||||
{op_code_type::op_grt, "grt "},
|
{opcode_type::op_grt, "grt "},
|
||||||
{op_code_type::op_geq, "geq "},
|
{opcode_type::op_geq, "geq "},
|
||||||
{op_code_type::op_lessc, "lessc "},
|
{opcode_type::op_lessc, "lessc "},
|
||||||
{op_code_type::op_leqc, "leqc "},
|
{opcode_type::op_leqc, "leqc "},
|
||||||
{op_code_type::op_grtc, "grtc "},
|
{opcode_type::op_grtc, "grtc "},
|
||||||
{op_code_type::op_geqc, "geqc "},
|
{opcode_type::op_geqc, "geqc "},
|
||||||
{op_code_type::op_pop, "pop "},
|
{opcode_type::op_pop, "pop "},
|
||||||
{op_code_type::op_jmp, "jmp "},
|
{opcode_type::op_jmp, "jmp "},
|
||||||
{op_code_type::op_jt, "jt "},
|
{opcode_type::op_jt, "jt "},
|
||||||
{op_code_type::op_jf, "jf "},
|
{opcode_type::op_jf, "jf "},
|
||||||
{op_code_type::op_cnt, "cnt "},
|
{opcode_type::op_cnt, "cnt "},
|
||||||
{op_code_type::op_findex, "findx "},
|
{opcode_type::op_findex, "findx "},
|
||||||
{op_code_type::op_feach, "feach "},
|
{opcode_type::op_feach, "feach "},
|
||||||
{op_code_type::op_callg, "callg "},
|
{opcode_type::op_callg, "callg "},
|
||||||
{op_code_type::op_calll, "calll "},
|
{opcode_type::op_calll, "calll "},
|
||||||
{op_code_type::op_upval, "upval "},
|
{opcode_type::op_upval, "upval "},
|
||||||
{op_code_type::op_callv, "callv "},
|
{opcode_type::op_callv, "callv "},
|
||||||
{op_code_type::op_callvi, "callvi"},
|
{opcode_type::op_callvi, "callvi"},
|
||||||
{op_code_type::op_callh, "callh "},
|
{opcode_type::op_callh, "callh "},
|
||||||
{op_code_type::op_callfv, "callfv"},
|
{opcode_type::op_callfv, "callfv"},
|
||||||
{op_code_type::op_callfh, "callfh"},
|
{opcode_type::op_callfh, "callfh"},
|
||||||
{op_code_type::op_callb, "callb "},
|
{opcode_type::op_callb, "callb "},
|
||||||
{op_code_type::op_slcbeg, "slcbeg"},
|
{opcode_type::op_slcbeg, "slcbeg"},
|
||||||
{op_code_type::op_slcend, "slcend"},
|
{opcode_type::op_slcend, "slcend"},
|
||||||
{op_code_type::op_slc, "slice "},
|
{opcode_type::op_slc, "slice "},
|
||||||
{op_code_type::op_slc2, "slice2"},
|
{opcode_type::op_slc2, "slice2"},
|
||||||
{op_code_type::op_mcallg, "mcallg"},
|
{opcode_type::op_mcallg, "mcallg"},
|
||||||
{op_code_type::op_mcalll, "mcalll"},
|
{opcode_type::op_mcalll, "mcalll"},
|
||||||
{op_code_type::op_mupval, "mupval"},
|
{opcode_type::op_mupval, "mupval"},
|
||||||
{op_code_type::op_mcallv, "mcallv"},
|
{opcode_type::op_mcallv, "mcallv"},
|
||||||
{op_code_type::op_mcallh, "mcallh"},
|
{opcode_type::op_mcallh, "mcallh"},
|
||||||
{op_code_type::op_ret, "ret "}
|
{opcode_type::op_ret, "ret "}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct opcode {
|
struct opcode {
|
||||||
|
|
|
@ -89,12 +89,18 @@ std::ostream& operator<<(std::ostream& out, nas_hash& hash) {
|
||||||
out << (hash.elems.size()? "{..}":"{}");
|
out << (hash.elems.size()? "{..}":"{}");
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mark print, to avoid infinite recursion
|
||||||
hash.printed = true;
|
hash.printed = true;
|
||||||
|
|
||||||
|
static const char* sep[] = {", ", "}"};
|
||||||
usize iter = 0, size = hash.elems.size();
|
usize iter = 0, size = hash.elems.size();
|
||||||
out << "{";
|
out << "{";
|
||||||
for(auto& i : hash.elems) {
|
for(auto& i : hash.elems) {
|
||||||
out << i.first << ":" << i.second << ",}"[(++iter)==size];
|
out << i.first << ": " << i.second << sep[(++iter)==size];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore flag
|
||||||
hash.printed = false;
|
hash.printed = false;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -212,12 +218,18 @@ std::ostream& operator<<(std::ostream& out, nas_map& mp) {
|
||||||
out << (mp.mapper.size()? "{..}":"{}");
|
out << (mp.mapper.size()? "{..}":"{}");
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mark print, to avoid infinite recursion
|
||||||
mp.printed = true;
|
mp.printed = true;
|
||||||
|
|
||||||
|
static const char* sep[] = {", ", "}"};
|
||||||
usize iter = 0, size = mp.mapper.size();
|
usize iter = 0, size = mp.mapper.size();
|
||||||
out << "{";
|
out << "{";
|
||||||
for(auto& i : mp.mapper) {
|
for(auto& i : mp.mapper) {
|
||||||
out << i.first << ":" << *i.second << ",}"[(++iter)==size];
|
out << i.first << ": " << *i.second << sep[(++iter)==size];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore flag
|
||||||
mp.printed = false;
|
mp.printed = false;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -336,7 +348,7 @@ var var::addr(var* p) {
|
||||||
return {vm_type::vm_addr, p};
|
return {vm_type::vm_addr, p};
|
||||||
}
|
}
|
||||||
|
|
||||||
var* var::addr() {
|
var* var::addr() const {
|
||||||
return val.addr;
|
return val.addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// get value
|
// get value
|
||||||
var* addr();
|
var* addr() const;
|
||||||
u64 ret() const;
|
u64 ret() const;
|
||||||
i64& cnt();
|
i64& cnt();
|
||||||
f64 num() const;
|
f64 num() const;
|
||||||
|
@ -131,7 +131,7 @@ struct nas_vec {
|
||||||
// mark if this is printed, avoid stack overflow
|
// mark if this is printed, avoid stack overflow
|
||||||
bool printed = false;
|
bool printed = false;
|
||||||
|
|
||||||
usize size() const {return elems.size();}
|
auto size() const { return elems.size(); }
|
||||||
var get_value(const i32);
|
var get_value(const i32);
|
||||||
var* get_memory(const i32);
|
var* get_memory(const i32);
|
||||||
};
|
};
|
||||||
|
@ -142,7 +142,7 @@ struct nas_hash {
|
||||||
// mark if this is printed, avoid stack overflow
|
// mark if this is printed, avoid stack overflow
|
||||||
bool printed = false;
|
bool printed = false;
|
||||||
|
|
||||||
usize size() const {return elems.size();}
|
auto size() const { return elems.size(); }
|
||||||
var get_value(const std::string&);
|
var get_value(const std::string&);
|
||||||
var* get_memory(const std::string&);
|
var* get_memory(const std::string&);
|
||||||
};
|
};
|
||||||
|
@ -256,9 +256,11 @@ struct nas_map {
|
||||||
bool printed = false;
|
bool printed = false;
|
||||||
std::unordered_map<std::string, var*> mapper;
|
std::unordered_map<std::string, var*> mapper;
|
||||||
|
|
||||||
|
public:
|
||||||
void clear() {
|
void clear() {
|
||||||
mapper.clear();
|
mapper.clear();
|
||||||
}
|
}
|
||||||
|
auto size() const { return mapper.size(); }
|
||||||
|
|
||||||
var get_value(const std::string&);
|
var get_value(const std::string&);
|
||||||
var* get_memory(const std::string&);
|
var* get_memory(const std::string&);
|
||||||
|
|
270
src/nasal_vm.cpp
270
src/nasal_vm.cpp
|
@ -63,12 +63,39 @@ void vm::context_and_global_init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm::hash_value_info(var& val) {
|
void vm::return_address_info(const var& val) {
|
||||||
|
std::clog << "0x";
|
||||||
|
std::clog << std::hex << val.ret() << std::dec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm::memory_address_info(const var& val) {
|
||||||
|
std::clog << "0x";
|
||||||
|
std::clog << std::hex << reinterpret_cast<u64>(val.addr()) << std::dec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm::raw_string_info(var& val) {
|
||||||
|
std::clog << "\"" << util::rawstr(val.str(), 24) << "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm::upvalue_info(var& val) {
|
||||||
|
std::clog << "[" << val.upval().size << " val] ";
|
||||||
|
if (val.upval().on_stack) {
|
||||||
|
std::clog << "offset:0x" << std::hex;
|
||||||
|
std::clog << reinterpret_cast<u64>(val.upval().stack_frame_offset);
|
||||||
|
std::clog << std::dec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm::vector_value_info(var& val) {
|
||||||
|
std::clog << "[" << val.vec().size() << " val]";
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm::hash_value_info(var& val, const usize max_show_elems) {
|
||||||
std::clog << "{";
|
std::clog << "{";
|
||||||
usize count = 0;
|
usize count = 0;
|
||||||
for(const auto& i : val.hash().elems) {
|
for(const auto& i : val.hash().elems) {
|
||||||
++count;
|
++count;
|
||||||
if (count>3) {
|
if (count>max_show_elems) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,62 +104,96 @@ void vm::hash_value_info(var& val) {
|
||||||
std::clog << ", ";
|
std::clog << ", ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (val.hash().size()>3) {
|
if (val.hash().size()>max_show_elems) {
|
||||||
std::clog << "...";
|
std::clog << "...";
|
||||||
}
|
}
|
||||||
std::clog << "}";
|
std::clog << "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm::value_info(var& val) {
|
void vm::ghost_type_info(var& val) {
|
||||||
const auto p = reinterpret_cast<u64>(val.val.gcobj);
|
std::clog << "<object:" << val.ghost().type_name;
|
||||||
|
std::clog << "@0x" << std::hex << val.ghost().pointer << ">" << std::dec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm::coroutine_value_info(var& val) {
|
||||||
|
std::clog << "[ ";
|
||||||
|
switch(val.co().status) {
|
||||||
|
case nas_co::status::dead: std::clog << "dead"; break;
|
||||||
|
case nas_co::status::running: std::clog << "running"; break;
|
||||||
|
case nas_co::status::suspended: std::clog << "suspended"; break;
|
||||||
|
}
|
||||||
|
std::clog << " ] @0x";
|
||||||
|
std::clog << std::hex << reinterpret_cast<u64>(val.val.gcobj) << std::dec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm::namespace_value_info(var& val, const usize max_show_elems) {
|
||||||
|
std::clog << "{";
|
||||||
|
usize count = 0;
|
||||||
|
for(const auto& i : val.map().mapper) {
|
||||||
|
++count;
|
||||||
|
if (count>max_show_elems) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::clog << i.first;
|
||||||
|
if (count!=val.map().size()) {
|
||||||
|
std::clog << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (val.map().size()>max_show_elems) {
|
||||||
|
std::clog << "...";
|
||||||
|
}
|
||||||
|
std::clog << "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm::value_name_form(const var& val) {
|
||||||
|
std::clog << "| ";
|
||||||
switch(val.type) {
|
switch(val.type) {
|
||||||
case vm_type::vm_none: std::clog << "| null |"; break;
|
case vm_type::vm_none: std::clog << "null "; break;
|
||||||
case vm_type::vm_ret:
|
case vm_type::vm_ret: std::clog << "ret "; break;
|
||||||
std::clog << "| pc | 0x" << std::hex << val.ret() << std::dec;
|
case vm_type::vm_addr: std::clog << "addr "; break;
|
||||||
break;
|
case vm_type::vm_cnt: std::clog << "cnt "; break;
|
||||||
case vm_type::vm_addr:
|
case vm_type::vm_nil: std::clog << "nil "; break;
|
||||||
std::clog << "| addr | 0x";
|
case vm_type::vm_num: std::clog << "num "; break;
|
||||||
std::clog << std::hex << reinterpret_cast<u64>(val.addr()) << std::dec;
|
case vm_type::vm_str: std::clog << "str "; break;
|
||||||
break;
|
case vm_type::vm_func: std::clog << "func "; break;
|
||||||
case vm_type::vm_cnt: std::clog << "| cnt | " << val.cnt(); break;
|
case vm_type::vm_upval: std::clog << "upval "; break;
|
||||||
case vm_type::vm_nil: std::clog << "| nil |"; break;
|
case vm_type::vm_vec: std::clog << "vec "; break;
|
||||||
case vm_type::vm_num: std::clog << "| num | " << val.num(); break;
|
case vm_type::vm_hash: std::clog << "hash "; break;
|
||||||
case vm_type::vm_str:
|
case vm_type::vm_ghost: std::clog << "ghost "; break;
|
||||||
std::clog << "| str | \"" << util::rawstr(val.str(), 16) << "\"";
|
case vm_type::vm_co: std::clog << "co "; break;
|
||||||
break;
|
case vm_type::vm_map: std::clog << "map "; break;
|
||||||
case vm_type::vm_func:
|
default: std::clog << "err "; break;
|
||||||
std::clog << "| func | " << val.func();
|
}
|
||||||
break;
|
std::clog << " | ";
|
||||||
case vm_type::vm_upval:
|
}
|
||||||
std::clog << "| upval| <0x" << std::hex << p << std::dec;
|
|
||||||
std::clog << "> [" << val.upval().size << " val]"; break;
|
void vm::value_info(var& val) {
|
||||||
case vm_type::vm_vec:
|
value_name_form(val);
|
||||||
std::clog << "| vec | [" << val.vec().size() << " val]"; break;
|
|
||||||
case vm_type::vm_hash:
|
switch(val.type) {
|
||||||
std::clog << "| hash | ";
|
case vm_type::vm_none: break;
|
||||||
hash_value_info(val);
|
case vm_type::vm_ret: return_address_info(val); break;
|
||||||
break;
|
case vm_type::vm_addr: memory_address_info(val); break;
|
||||||
case vm_type::vm_ghost:
|
case vm_type::vm_cnt: std::clog << val.cnt(); break;
|
||||||
std::clog << "| obj | <0x" << std::hex << p << "> " << std::dec;
|
case vm_type::vm_nil: break;
|
||||||
std::clog << "object:" << val.ghost().type_name;
|
case vm_type::vm_num: std::clog << val.num(); break;
|
||||||
break;
|
case vm_type::vm_str: raw_string_info(val); break;
|
||||||
case vm_type::vm_co:
|
case vm_type::vm_func: std::clog << val.func(); break;
|
||||||
std::clog << "| co | coroutine@0x" << std::hex << p << std::dec;
|
case vm_type::vm_upval: upvalue_info(val); break;
|
||||||
break;
|
case vm_type::vm_vec: vector_value_info(val); break;
|
||||||
case vm_type::vm_map:
|
case vm_type::vm_hash: hash_value_info(val, 4); break;
|
||||||
std::clog << "| nmspc| [";
|
case vm_type::vm_ghost: ghost_type_info(val); break;
|
||||||
std::clog << val.map().mapper.size() << " val]";
|
case vm_type::vm_co: coroutine_value_info(val); break;
|
||||||
break;
|
case vm_type::vm_map: namespace_value_info(val, 4); break;
|
||||||
default:
|
default: std::clog << "unknown"; break;
|
||||||
std::clog << "| err | <0x" << std::hex << p << std::dec;
|
|
||||||
std::clog << "> unknown object";
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
std::clog << "\n";
|
std::clog << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm::function_detail_info(const nas_func& func) {
|
void vm::function_detail_info(const nas_func& func) {
|
||||||
std::clog << "func";
|
std::clog << "func@";
|
||||||
|
std::clog << std::hex << reinterpret_cast<u64>(&func) << std::dec;
|
||||||
|
|
||||||
std::vector<std::string> argument_list = {};
|
std::vector<std::string> argument_list = {};
|
||||||
argument_list.resize(func.keys.size());
|
argument_list.resize(func.keys.size());
|
||||||
|
@ -157,64 +218,105 @@ void vm::function_detail_info(const nas_func& func) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm::function_call_trace() {
|
void vm::function_call_trace() {
|
||||||
|
util::windows_code_page_manager cp;
|
||||||
|
cp.set_utf8_output();
|
||||||
|
|
||||||
var* bottom = ctx.stack;
|
var* bottom = ctx.stack;
|
||||||
var* top = ctx.top;
|
var* top = ctx.top;
|
||||||
|
|
||||||
// generate trace back
|
// generate trace back
|
||||||
std::stack<const nas_func*> functions;
|
std::stack<const nas_func*> functions;
|
||||||
|
std::stack<u64> callsite;
|
||||||
|
|
||||||
|
// load call trace
|
||||||
for(var* i = bottom; i<=top; ++i) {
|
for(var* i = bottom; i<=top; ++i) {
|
||||||
if (i->is_func() && i-1>=bottom && (i-1)->is_ret()) {
|
// i-1 is the callsite program counter of this function
|
||||||
functions.push(&i->func());
|
if (i->is_addr() && i+2<=top &&
|
||||||
|
(i+1)->is_ret() && (i+1)->ret()>0 &&
|
||||||
|
(i+2)->is_func()) {
|
||||||
|
functions.push(&(i+2)->func());
|
||||||
|
callsite.push((i+1)->ret());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (functions.empty()) {
|
|
||||||
|
// another condition may exist
|
||||||
|
// have ret pc on stack, but no function at the top of the ret pc
|
||||||
|
for(var * i = top; i>=bottom; --i) {
|
||||||
|
if ((i->is_addr() && i+2<=top && (i+1)->is_ret() && !(i+2)->is_func()) ||
|
||||||
|
(i->is_addr() && i+1<=top && i+2>top && (i+1)->is_ret())) {
|
||||||
|
functions.push(&ctx.funcr.func());
|
||||||
|
callsite.push((i+1)->ret());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// function register stores the latest-called function
|
||||||
|
if (functions.empty() && !ctx.funcr.is_func()) {
|
||||||
|
cp.restore_code_page();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::clog << "\ncall trace " << (ngc.cort? "(coroutine)":"(main)") << "\n";
|
std::clog << "\ncall trace ";
|
||||||
const nas_func* last = nullptr;
|
std::clog << (ngc.cort? "(coroutine)":"(main)") << "\n";
|
||||||
u32 same = 0;
|
std::clog << " crash occurred in\n ";
|
||||||
for(auto func = last; !functions.empty(); functions.pop()) {
|
function_detail_info(ctx.funcr.func());
|
||||||
func = functions.top();
|
std::clog << " at " << files[bytecode[ctx.pc].fidx] << ":";
|
||||||
if (last==func) {
|
std::clog << bytecode[ctx.pc].line << "\n";
|
||||||
++same;
|
|
||||||
continue;
|
|
||||||
} else if (same) {
|
|
||||||
std::clog << " --> " << same << " same call(s)\n";
|
|
||||||
same = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const nas_func* last = nullptr;
|
||||||
|
u64 last_callsite = SIZE_MAX;
|
||||||
|
u64 same_count = 0;
|
||||||
|
for(; !functions.empty() && !callsite.empty(); functions.pop(), callsite.pop()) {
|
||||||
|
auto func = functions.top();
|
||||||
|
auto place = callsite.top();
|
||||||
|
|
||||||
|
if (last==func && last_callsite==place) {
|
||||||
|
++same_count;
|
||||||
|
continue;
|
||||||
|
} else if (same_count) {
|
||||||
|
std::clog << " `--> " << same_count << " same call(s)\n";
|
||||||
|
same_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
last = func;
|
last = func;
|
||||||
|
last_callsite = place;
|
||||||
|
|
||||||
|
// output called function
|
||||||
std::clog << " call ";
|
std::clog << " call ";
|
||||||
function_detail_info(*func);
|
function_detail_info(*func);
|
||||||
std::clog << "\n";
|
|
||||||
|
// output callsite
|
||||||
|
std::clog << " from ";
|
||||||
|
std::clog << files[bytecode[place].fidx] << ":";
|
||||||
|
std::clog << bytecode[place].line << "\n";
|
||||||
}
|
}
|
||||||
if (same) {
|
if (same_count) {
|
||||||
std::clog << " --> " << same << " same call(s)\n";
|
std::clog << " `--> " << same_count << " same call(s)\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cp.restore_code_page();
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm::trace_back() {
|
void vm::trace_back() {
|
||||||
// var* bottom = ctx.stack;
|
|
||||||
// var* top = ctx.top;
|
|
||||||
|
|
||||||
// generate trace back
|
// generate trace back
|
||||||
std::stack<u32> ret;
|
std::stack<u64> ret;
|
||||||
for(var* i = ctx.stack; i<=ctx.top; ++i) {
|
for(var* i = ctx.stack; i<=ctx.top; ++i) {
|
||||||
if (i->is_ret() && i->ret()!=0) {
|
if (i->is_ret() && i->ret()!=0) {
|
||||||
ret.push(i->ret());
|
ret.push(i->ret());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret.push(ctx.pc); // store the position program crashed
|
|
||||||
|
|
||||||
std::clog << "\nback trace " << (ngc.cort? "(coroutine)":"(main)") << "\n";
|
// store the position program crashed
|
||||||
|
ret.push(ctx.pc);
|
||||||
|
|
||||||
|
std::clog << "\nback trace ";
|
||||||
|
std::clog << (ngc.cort? "(coroutine)":"(main)") << "\n";
|
||||||
codestream::set(const_number, const_string, native_function.data(), files);
|
codestream::set(const_number, const_string, native_function.data(), files);
|
||||||
for(u32 p = 0, same = 0, prev = 0xffffffff; !ret.empty(); prev = p, ret.pop()) {
|
|
||||||
|
for(u64 p = 0, same = 0, prev = 0xffffffff; !ret.empty(); prev = p, ret.pop()) {
|
||||||
if ((p = ret.top())==prev) {
|
if ((p = ret.top())==prev) {
|
||||||
++same;
|
++same;
|
||||||
continue;
|
continue;
|
||||||
}
|
} else if (same) {
|
||||||
if (same) {
|
|
||||||
std::clog << " 0x" << std::hex
|
std::clog << " 0x" << std::hex
|
||||||
<< std::setw(8) << std::setfill('0')
|
<< std::setw(8) << std::setfill('0')
|
||||||
<< prev << std::dec << " "
|
<< prev << std::dec << " "
|
||||||
|
@ -247,16 +349,16 @@ void vm::stack_info(const u64 limit = 16) {
|
||||||
void vm::register_info() {
|
void vm::register_info() {
|
||||||
std::clog << "\nregister (" << (ngc.cort? "coroutine":"main") << ")\n";
|
std::clog << "\nregister (" << (ngc.cort? "coroutine":"main") << ")\n";
|
||||||
std::clog << std::hex
|
std::clog << std::hex
|
||||||
<< " [ pc ] | pc | 0x" << ctx.pc << "\n"
|
<< " [ pc ] | pc | 0x" << ctx.pc << "\n"
|
||||||
<< " [ global ] | addr | 0x"
|
<< " [ global ] | addr | 0x"
|
||||||
<< reinterpret_cast<u64>(global) << "\n"
|
<< reinterpret_cast<u64>(global) << "\n"
|
||||||
<< " [ local ] | addr | 0x"
|
<< " [ local ] | addr | 0x"
|
||||||
<< reinterpret_cast<u64>(ctx.localr) << "\n"
|
<< reinterpret_cast<u64>(ctx.localr) << "\n"
|
||||||
<< " [ memr ] | addr | 0x"
|
<< " [ memr ] | addr | 0x"
|
||||||
<< reinterpret_cast<u64>(ctx.memr) << "\n"
|
<< reinterpret_cast<u64>(ctx.memr) << "\n"
|
||||||
<< " [ canary ] | addr | 0x"
|
<< " [ canary ] | addr | 0x"
|
||||||
<< reinterpret_cast<u64>(ctx.canary) << "\n"
|
<< reinterpret_cast<u64>(ctx.canary) << "\n"
|
||||||
<< " [ top ] | addr | 0x"
|
<< " [ top ] | addr | 0x"
|
||||||
<< reinterpret_cast<u64>(ctx.top) << "\n"
|
<< reinterpret_cast<u64>(ctx.top) << "\n"
|
||||||
<< std::dec;
|
<< std::dec;
|
||||||
std::clog << " [ funcr ] "; value_info(ctx.funcr);
|
std::clog << " [ funcr ] "; value_info(ctx.funcr);
|
||||||
|
@ -346,8 +448,8 @@ std::string vm::report_lack_arguments(u32 argc, const nas_func& func) const {
|
||||||
return result + out.str();
|
return result + out.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string vm::report_special_call_lack_arguments(
|
std::string vm::report_special_call_lack_arguments(var* local,
|
||||||
var* local, const nas_func& func) const {
|
const nas_func& func) const {
|
||||||
auto result = std::string("lack argument(s) when calling function:\n func(");
|
auto result = std::string("lack argument(s) when calling function:\n func(");
|
||||||
std::vector<std::string> argument_list = {};
|
std::vector<std::string> argument_list = {};
|
||||||
argument_list.resize(func.keys.size());
|
argument_list.resize(func.keys.size());
|
||||||
|
@ -370,8 +472,8 @@ std::string vm::report_special_call_lack_arguments(
|
||||||
return result + out.str();
|
return result + out.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string vm::report_key_not_found(
|
std::string vm::report_key_not_found(const std::string& not_found,
|
||||||
const std::string& not_found, const nas_hash& hash) const {
|
const nas_hash& hash) const {
|
||||||
auto result = "member \"" + not_found + "\" doesn't exist in hash {";
|
auto result = "member \"" + not_found + "\" doesn't exist in hash {";
|
||||||
for(const auto& i : hash.elems) {
|
for(const auto& i : hash.elems) {
|
||||||
result += i.first + ", ";
|
result += i.first + ", ";
|
||||||
|
|
|
@ -65,7 +65,16 @@ protected:
|
||||||
protected:
|
protected:
|
||||||
/* debug functions */
|
/* debug functions */
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
void hash_value_info(var&);
|
void return_address_info(const var&);
|
||||||
|
void memory_address_info(const var&);
|
||||||
|
void raw_string_info(var&);
|
||||||
|
void upvalue_info(var&);
|
||||||
|
void vector_value_info(var&);
|
||||||
|
void hash_value_info(var&, const usize);
|
||||||
|
void ghost_type_info(var&);
|
||||||
|
void coroutine_value_info(var&);
|
||||||
|
void namespace_value_info(var&, const usize);
|
||||||
|
void value_name_form(const var&);
|
||||||
void value_info(var&);
|
void value_info(var&);
|
||||||
void function_detail_info(const nas_func&);
|
void function_detail_info(const nas_func&);
|
||||||
void function_call_trace();
|
void function_call_trace();
|
||||||
|
@ -76,6 +85,8 @@ protected:
|
||||||
void local_state();
|
void local_state();
|
||||||
void upvalue_state();
|
void upvalue_state();
|
||||||
void all_state_detail();
|
void all_state_detail();
|
||||||
|
|
||||||
|
protected:
|
||||||
std::string report_lack_arguments(u32, const nas_func&) const;
|
std::string report_lack_arguments(u32, const nas_func&) const;
|
||||||
std::string report_special_call_lack_arguments(var*, const nas_func&) const;
|
std::string report_special_call_lack_arguments(var*, const nas_func&) const;
|
||||||
std::string report_key_not_found(const std::string&, const nas_hash&) const;
|
std::string report_key_not_found(const std::string&, const nas_hash&) const;
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
#include "natives/dylib_lib.h"
|
#include "natives/dylib_lib.h"
|
||||||
|
#include "util/util.h"
|
||||||
|
#include "util/fs.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace nasal {
|
namespace nasal {
|
||||||
|
|
||||||
const auto dynamic_library_type_name = "dylib";
|
const auto dynamic_library_type_name = "nasal::dynamic_library";
|
||||||
const auto function_address_type_name = "faddr";
|
const auto function_address_type_name = "nasal::function_address";
|
||||||
|
|
||||||
void dynamic_library_destructor(void* pointer) {
|
void dynamic_library_destructor(void* pointer) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -13,33 +18,74 @@ void dynamic_library_destructor(void* pointer) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string search_dynamic_library_path(const std::string& dlname) {
|
||||||
|
const auto ext = (util::is_windows()? ".dll":".so");
|
||||||
|
const auto lib_path = (util::is_windows()? ".\\":"./") + dlname + ext;
|
||||||
|
if (fs::exists(lib_path)) {
|
||||||
|
return lib_path;
|
||||||
|
}
|
||||||
|
const auto env_path = std::string(getenv("PATH"));
|
||||||
|
const auto sep = (util::is_windows()? ";":":");
|
||||||
|
|
||||||
|
// do split string
|
||||||
|
std::vector<std::string> env_path_vec = {"."};
|
||||||
|
usize last = 0;
|
||||||
|
usize pos = env_path.find(sep, 0);
|
||||||
|
while(pos!=std::string::npos) {
|
||||||
|
if (pos>last) {
|
||||||
|
env_path_vec.push_back(env_path.substr(last, pos-last));
|
||||||
|
}
|
||||||
|
last = pos + 1;
|
||||||
|
pos = env_path.find(sep, last);
|
||||||
|
}
|
||||||
|
if (last!=env_path.length()) {
|
||||||
|
env_path_vec.push_back(env_path.substr(last));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto path_front = util::is_windows()? "\\module\\":"/module/";
|
||||||
|
for(auto& p : env_path_vec) {
|
||||||
|
p += path_front + lib_path;
|
||||||
|
if (fs::exists(p)) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
var builtin_dlopen(context* ctx, gc* ngc) {
|
var builtin_dlopen(context* ctx, gc* ngc) {
|
||||||
auto dlname = ctx->localr[1];
|
auto dl = ctx->localr[1];
|
||||||
if (!dlname.is_str()) {
|
if (!dl.is_str()) {
|
||||||
return nas_err("dylib::dlopen", "\"libname\" must be string");
|
return nas_err("dylib::dlopen", "\"libname\" must be string");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto dlname = search_dynamic_library_path(dl.str());
|
||||||
|
if (dlname.empty()) {
|
||||||
|
return nas_err("dylib::dlopen",
|
||||||
|
"cannot find dynamic lib <" + dl.str() + ">"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// get library pointer
|
// get library pointer
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
wchar_t* wide_string = new wchar_t[dlname.str().size()+1];
|
wchar_t* wide_string = new wchar_t[dlname.size()+1];
|
||||||
if (!wide_string) {
|
if (!wide_string) {
|
||||||
return nas_err("dylib::dlopen", "malloc failed");
|
return nas_err("dylib::dlopen", "malloc failed");
|
||||||
}
|
}
|
||||||
memset(wide_string, 0, sizeof(wchar_t) * dlname.str().size() + 1);
|
memset(wide_string, 0, sizeof(wchar_t) * dlname.size() + 1);
|
||||||
mbstowcs(wide_string, dlname.str().c_str(), dlname.str().size() + 1);
|
mbstowcs(wide_string, dlname.c_str(), dlname.size() + 1);
|
||||||
// load library by using wide string name
|
// load library by using wide string name
|
||||||
void* dynamic_library_pointer = LoadLibraryA(dlname.str().c_str());
|
void* dynamic_library_pointer = LoadLibraryA(dlname.c_str());
|
||||||
delete []wide_string;
|
delete []wide_string;
|
||||||
#else
|
#else
|
||||||
void* dynamic_library_pointer = dlopen(
|
void* dynamic_library_pointer = dlopen(
|
||||||
dlname.str().c_str(), RTLD_LOCAL|RTLD_LAZY
|
dlname.c_str(), RTLD_LOCAL|RTLD_LAZY
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// check library pointer and insert into returned hashmap
|
// check library pointer and insert into returned hashmap
|
||||||
if (!dynamic_library_pointer) {
|
if (!dynamic_library_pointer) {
|
||||||
return nas_err("dylib::dlopen",
|
return nas_err("dylib::dlopen",
|
||||||
"cannot open dynamic lib <" + dlname.str() + ">"
|
"cannot open dynamic lib <" + dl.str() + ">"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
auto return_hash = ngc->temp = ngc->alloc(vm_type::vm_hash);
|
auto return_hash = ngc->temp = ngc->alloc(vm_type::vm_hash);
|
||||||
|
|
|
@ -11,10 +11,15 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace nasal {
|
namespace nasal {
|
||||||
|
|
||||||
void dynamic_library_destructor(void*);
|
void dynamic_library_destructor(void*);
|
||||||
|
|
||||||
|
std::string search_dynamic_library_path(const std::string&);
|
||||||
|
|
||||||
var builtin_dlopen(context*, gc*);
|
var builtin_dlopen(context*, gc*);
|
||||||
var builtin_dlclose(context*, gc*);
|
var builtin_dlclose(context*, gc*);
|
||||||
var builtin_dlcallv(context*, gc*);
|
var builtin_dlcallv(context*, gc*);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
namespace nasal {
|
namespace nasal {
|
||||||
|
|
||||||
const auto file_type_name = "file";
|
const auto file_type_name = "nasal::FILE";
|
||||||
|
|
||||||
void filehandle_destructor(void* ptr) {
|
void filehandle_destructor(void* ptr) {
|
||||||
fclose(static_cast<FILE*>(ptr));
|
fclose(static_cast<FILE*>(ptr));
|
||||||
|
|
|
@ -148,6 +148,36 @@ var builtin_subprocess_create(context* ctx, gc* ngc) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var builtin_subprocess_active(context* ctx, gc* ngc) {
|
||||||
|
auto obj = ctx->localr[1];
|
||||||
|
if (!obj.object_check(subprocess::name())) {
|
||||||
|
return nas_err("subprocess::active",
|
||||||
|
"need correct subprocess object"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
auto pi = &obj.ghost().get<subprocess>()->pi;
|
||||||
|
|
||||||
|
DWORD res;
|
||||||
|
GetExitCodeProcess(pi->hProcess, &res);
|
||||||
|
|
||||||
|
return res==STILL_ACTIVE? one:zero;
|
||||||
|
#else
|
||||||
|
auto pid = obj.ghost().get<subprocess>()->pid;
|
||||||
|
|
||||||
|
int status;
|
||||||
|
pid_t result = waitpid(pid, &status, WNOHANG);
|
||||||
|
|
||||||
|
// this means the child process is returned
|
||||||
|
if (result==pid) {
|
||||||
|
obj.ghost().get<subprocess>()->status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result==0? one:zero;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
var builtin_subprocess_terminate(context* ctx, gc* ngc) {
|
var builtin_subprocess_terminate(context* ctx, gc* ngc) {
|
||||||
auto obj = ctx->localr[1];
|
auto obj = ctx->localr[1];
|
||||||
if (!obj.object_check(subprocess::name())) {
|
if (!obj.object_check(subprocess::name())) {
|
||||||
|
@ -167,25 +197,36 @@ var builtin_subprocess_terminate(context* ctx, gc* ngc) {
|
||||||
|
|
||||||
CloseHandle(pi->hProcess);
|
CloseHandle(pi->hProcess);
|
||||||
CloseHandle(pi->hThread);
|
CloseHandle(pi->hThread);
|
||||||
|
|
||||||
|
return var::num(res);
|
||||||
#else
|
#else
|
||||||
auto pid = obj.ghost().get<subprocess>()->pid;
|
auto pid = obj.ghost().get<subprocess>()->pid;
|
||||||
|
|
||||||
int status;
|
int status;
|
||||||
pid_t result = waitpid(pid, &status, WNOHANG);
|
pid_t result = waitpid(pid, &status, WNOHANG);
|
||||||
|
|
||||||
// child process running
|
if (result<0) {
|
||||||
if (result==0) {
|
auto pstat = obj.ghost().get<subprocess>()->status;
|
||||||
kill(pid, SIGTERM);
|
// if pstat is not 0, means child process already exited
|
||||||
|
auto res = WIFEXITED(pstat)? WEXITSTATUS(pstat):-1;
|
||||||
|
return var::num(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res = WIFEXITED(status)? WEXITSTATUS(status):-1;
|
// child process is still running
|
||||||
#endif
|
if (result==0) {
|
||||||
|
kill(pid, SIGTERM);
|
||||||
|
return var::num(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// child process exited when calling the waitpid above
|
||||||
|
auto res = WIFEXITED(status)? WEXITSTATUS(status):-1;
|
||||||
return var::num(res);
|
return var::num(res);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
nasal_builtin_table subprocess_native[] = {
|
nasal_builtin_table subprocess_native[] = {
|
||||||
{"__subprocess_create", builtin_subprocess_create},
|
{"__subprocess_create", builtin_subprocess_create},
|
||||||
|
{"__subprocess_active", builtin_subprocess_active},
|
||||||
{"__subprocess_terminate", builtin_subprocess_terminate},
|
{"__subprocess_terminate", builtin_subprocess_terminate},
|
||||||
{nullptr, nullptr}
|
{nullptr, nullptr}
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace nasal {
|
||||||
struct subprocess {
|
struct subprocess {
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
int status = 0;
|
||||||
#else
|
#else
|
||||||
STARTUPINFOW si;
|
STARTUPINFOW si;
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
|
@ -31,6 +32,7 @@ public:
|
||||||
void subprocess_desc_dtor(void*);
|
void subprocess_desc_dtor(void*);
|
||||||
|
|
||||||
var builtin_subprocess_create(context*, gc*);
|
var builtin_subprocess_create(context*, gc*);
|
||||||
|
var builtin_subprocess_active(context*, gc*);
|
||||||
var builtin_subprocess_terminate(context*, gc*);
|
var builtin_subprocess_terminate(context*, gc*);
|
||||||
extern nasal_builtin_table subprocess_native[];
|
extern nasal_builtin_table subprocess_native[];
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace nasal {
|
namespace nasal {
|
||||||
|
|
||||||
const auto dir_type_name = "dir";
|
const auto dir_type_name = "nasal::DIR";
|
||||||
|
|
||||||
void dir_entry_destructor(void* ptr) {
|
void dir_entry_destructor(void* ptr) {
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
|
|
|
@ -8,22 +8,6 @@ use std.unix;
|
||||||
|
|
||||||
# open dynamic lib. return a hash including dl pointer and function pointers
|
# open dynamic lib. return a hash including dl pointer and function pointers
|
||||||
var dlopen = func(libname) {
|
var dlopen = func(libname) {
|
||||||
# find dynamic lib from local dir first
|
|
||||||
libname = (os.platform()=="windows"? ".\\":"./")~libname;
|
|
||||||
if (io.exists(libname))
|
|
||||||
return __dlopen(libname);
|
|
||||||
# find dynamic lib through PATH
|
|
||||||
var envpath = split(os.platform()=="windows"? ";":":", unix.getenv("PATH"));
|
|
||||||
# first find ./module
|
|
||||||
append(envpath, ".");
|
|
||||||
var path = os.platform()=="windows"? "\\module\\":"/module/";
|
|
||||||
foreach(var p;envpath) {
|
|
||||||
p ~= path~libname;
|
|
||||||
if (io.exists(p)) {
|
|
||||||
libname = p;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return __dlopen(libname);
|
return __dlopen(libname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,10 @@ var create = func(vec) {
|
||||||
return __subprocess_create(vec);
|
return __subprocess_create(vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var active = func(pid) {
|
||||||
|
return __subprocess_active(pid);
|
||||||
|
}
|
||||||
|
|
||||||
var terminate = func(pid) {
|
var terminate = func(pid) {
|
||||||
return __subprocess_terminate(pid);
|
return __subprocess_terminate(pid);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
|
||||||
println("coroutine yield: ",coroutine.resume(co));
|
println("coroutine yield: ",coroutine.resume(co));
|
||||||
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
|
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
|
||||||
|
|
||||||
var co=coroutine.create(func {
|
var co = coroutine.create(func {
|
||||||
var a=1;
|
var a=1;
|
||||||
var b = func() {
|
var b = func() {
|
||||||
b();
|
b();
|
||||||
|
|
|
@ -23,7 +23,7 @@ func() {
|
||||||
}();
|
}();
|
||||||
|
|
||||||
var speed_test = func() {
|
var speed_test = func() {
|
||||||
var dd = dylib.dlopen("libfib."~(os.platform()=="windows"? "dll":"so"));
|
var dd = dylib.dlopen("libfib");
|
||||||
println("[dylib ] ", dd);
|
println("[dylib ] ", dd);
|
||||||
var fd = dd.quick_fib;
|
var fd = dd.quick_fib;
|
||||||
var vec_call = dylib.dlcall;
|
var vec_call = dylib.dlcall;
|
||||||
|
|
|
@ -27,87 +27,68 @@ var usage = func() {
|
||||||
println(
|
println(
|
||||||
os_time(),
|
os_time(),
|
||||||
info_hd(),
|
info_hd(),
|
||||||
"\e[1musage: nasal watchdog.nas <filename> [\"argv\"]\e[0m"
|
"usage: nasal watchdog.nas <filename> [\"argv\"]"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var argv = runtime.argv();
|
var argv = runtime.argv();
|
||||||
if (size(argv)<1) {
|
if (size(argv)<1) {
|
||||||
println(
|
println(os_time(), err_hd(), "need correct file path to watch");
|
||||||
os_time(),
|
|
||||||
err_hd(),
|
|
||||||
"\e[1mneed correct file path to watch\e[0m"
|
|
||||||
);
|
|
||||||
usage();
|
usage();
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var filename = argv[0];
|
var filename = argv[0];
|
||||||
if (!io.exists(filename)) {
|
if (!io.exists(filename)) {
|
||||||
println(
|
println(os_time(), err_hd(), "file <", filename, "> does not exist");
|
||||||
os_time(),
|
|
||||||
err_hd(),
|
|
||||||
"\e[1mfile <",
|
|
||||||
filename,
|
|
||||||
"> does not exist\e[0m"
|
|
||||||
);
|
|
||||||
usage();
|
usage();
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var args = [];
|
var args = [];
|
||||||
if (size(argv)==2) {
|
if (size(argv)==2) {
|
||||||
println(
|
println(os_time(), info_hd(), "with argument(s) ", argv[1]);
|
||||||
os_time(),
|
|
||||||
info_hd(),
|
|
||||||
"\e[1mwith argument(s) ",
|
|
||||||
argv[1],
|
|
||||||
"\e[0m"
|
|
||||||
);
|
|
||||||
args = split(" ", argv[1]);
|
args = split(" ", argv[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var modified_time = io.fstat(filename).st_mtime;
|
var modified_time = io.fstat(filename).st_mtime;
|
||||||
println(os_time(), info_hd(), "\e[1mwatching ", filename, " ..\e[0m");
|
println(os_time(), info_hd(), "watching ", filename, " ..");
|
||||||
while(1) {
|
while(1) {
|
||||||
unix.sleep(1);
|
unix.sleep(1);
|
||||||
if (!io.exists(filename)) {
|
if (!io.exists(filename)) {
|
||||||
println(
|
println(os_time(), err_hd(), "file <", filename, "> does not exist");
|
||||||
os_time(),
|
|
||||||
err_hd(),
|
|
||||||
"\e[1mfile <",
|
|
||||||
filename,
|
|
||||||
"> does not exist\e[0m"
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var latest_modified_time = io.fstat(filename).st_mtime;
|
var latest_modified_time = io.fstat(filename).st_mtime;
|
||||||
if (latest_modified_time!=modified_time) {
|
if (latest_modified_time!=modified_time) {
|
||||||
modified_time = latest_modified_time;
|
modified_time = latest_modified_time;
|
||||||
println(os_time(), modified_hd(), "\e[1m", filename, "\e[0m");
|
println(os_time(), modified_hd(), filename);
|
||||||
|
|
||||||
var cmd = (os.platform()=="windows"?"":"./") ~ "nasal " ~ filename;
|
var cmd = "nasal " ~ filename;
|
||||||
foreach(var i; args) {
|
foreach(var i; args) {
|
||||||
cmd ~= " " ~ i;
|
cmd ~= " " ~ i;
|
||||||
}
|
}
|
||||||
println(
|
println(os_time(), info_hd(), "executing command \"", cmd, "\"");
|
||||||
os_time(),
|
|
||||||
info_hd(),
|
|
||||||
"\e[1mexecuting command \"",
|
|
||||||
cmd,
|
|
||||||
"\"\e[0m"
|
|
||||||
);
|
|
||||||
|
|
||||||
var subproc = subprocess.create(["nasal", filename]~args);
|
var subproc = subprocess.create(["nasal", filename] ~ args);
|
||||||
|
|
||||||
unix.sleep(2);
|
# check if active every 0.5s
|
||||||
|
var exited = false;
|
||||||
|
while(1) {
|
||||||
|
unix.sleep(0.5);
|
||||||
|
if (!subprocess.active(subproc)) {
|
||||||
|
exited = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (io.fstat(filename).st_mtime!=modified_time) {
|
||||||
|
println(os_time(), modified_hd(), "file changed, reloading..");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# get return value
|
||||||
var ret = subprocess.terminate(subproc);
|
var ret = subprocess.terminate(subproc);
|
||||||
|
println(os_time(), ret!=0? err_hd():info_hd(), "process returned ", ret);
|
||||||
println(
|
|
||||||
os_time(),
|
|
||||||
ret!=0? err_hd():info_hd(),
|
|
||||||
"\e[1mprocess returned " ~ ret ~ "\e[0m"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue