Merge pull request #47 from ValKmjolnir/develop
👾 try adding new module `subprocess`
This commit is contained in:
commit
0c216e95e8
|
@ -1,6 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
project(nasal VERSION 11.2)
|
project(nasal VERSION 11.3)
|
||||||
|
|
||||||
message("CMAKE_HOST_SYSTEM_NAME: ${CMAKE_HOST_SYSTEM_NAME}")
|
message("CMAKE_HOST_SYSTEM_NAME: ${CMAKE_HOST_SYSTEM_NAME}")
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ set(NASAL_OBJECT_SOURCE_FILE
|
||||||
${CMAKE_SOURCE_DIR}/src/natives/math_lib.cpp
|
${CMAKE_SOURCE_DIR}/src/natives/math_lib.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/natives/dylib_lib.cpp
|
${CMAKE_SOURCE_DIR}/src/natives/dylib_lib.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/natives/regex_lib.cpp
|
${CMAKE_SOURCE_DIR}/src/natives/regex_lib.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/natives/subprocess.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/natives/unix_lib.cpp
|
${CMAKE_SOURCE_DIR}/src/natives/unix_lib.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/repl/repl.cpp
|
${CMAKE_SOURCE_DIR}/src/repl/repl.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/util/fs.cpp
|
${CMAKE_SOURCE_DIR}/src/util/fs.cpp
|
||||||
|
|
10
makefile
10
makefile
|
@ -37,6 +37,7 @@ NASAL_HEADER = \
|
||||||
src/natives/unix_lib.h\
|
src/natives/unix_lib.h\
|
||||||
src/natives/coroutine.h\
|
src/natives/coroutine.h\
|
||||||
src/natives/regex_lib.h\
|
src/natives/regex_lib.h\
|
||||||
|
src/natives/subprocess.h\
|
||||||
src/repl/repl.h\
|
src/repl/repl.h\
|
||||||
src/util/fs.h\
|
src/util/fs.h\
|
||||||
src/util/util.h
|
src/util/util.h
|
||||||
|
@ -61,6 +62,7 @@ NASAL_OBJECT = \
|
||||||
build/math_lib.o\
|
build/math_lib.o\
|
||||||
build/unix_lib.o\
|
build/unix_lib.o\
|
||||||
build/dylib_lib.o\
|
build/dylib_lib.o\
|
||||||
|
build/subprocess.o\
|
||||||
build/json_lib.o\
|
build/json_lib.o\
|
||||||
build/coroutine.o\
|
build/coroutine.o\
|
||||||
build/nasal_type.o\
|
build/nasal_type.o\
|
||||||
|
@ -212,6 +214,14 @@ build/regex_lib.o: \
|
||||||
src/natives/regex_lib.h src/natives/regex_lib.cpp | build
|
src/natives/regex_lib.h src/natives/regex_lib.cpp | build
|
||||||
$(CXX) $(CXXFLAGS) src/natives/regex_lib.cpp -o build/regex_lib.o
|
$(CXX) $(CXXFLAGS) src/natives/regex_lib.cpp -o build/regex_lib.o
|
||||||
|
|
||||||
|
build/subprocess.o: \
|
||||||
|
src/nasal.h\
|
||||||
|
src/nasal_type.h\
|
||||||
|
src/nasal_gc.h\
|
||||||
|
src/natives/subprocess.h src/natives/subprocess.cpp | build
|
||||||
|
$(CXX) $(CXXFLAGS) src/natives/subprocess.cpp -o build/subprocess.o
|
||||||
|
|
||||||
|
|
||||||
build/fg_props.o: \
|
build/fg_props.o: \
|
||||||
src/nasal.h\
|
src/nasal.h\
|
||||||
src/nasal_type.h\
|
src/nasal_type.h\
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef __nasver__
|
#ifndef __nasver__
|
||||||
#define __nasver__ "11.2"
|
#define __nasver__ "11.3"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
|
@ -39,6 +39,7 @@ void codegen::init_native_function() {
|
||||||
load_native_function_table(unix_lib_native);
|
load_native_function_table(unix_lib_native);
|
||||||
load_native_function_table(json_lib_native);
|
load_native_function_table(json_lib_native);
|
||||||
load_native_function_table(regex_lib_native);
|
load_native_function_table(regex_lib_native);
|
||||||
|
load_native_function_table(subprocess_native);
|
||||||
}
|
}
|
||||||
|
|
||||||
void codegen::check_id_exist(identifier* node) {
|
void codegen::check_id_exist(identifier* node) {
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "natives/dylib_lib.h"
|
#include "natives/dylib_lib.h"
|
||||||
#include "natives/regex_lib.h"
|
#include "natives/regex_lib.h"
|
||||||
#include "natives/unix_lib.h"
|
#include "natives/unix_lib.h"
|
||||||
|
#include "natives/subprocess.h"
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
@ -57,7 +58,11 @@ private:
|
||||||
"__dlopen", "__dlclose", "__dlcallv", "__dlcall",
|
"__dlopen", "__dlclose", "__dlcallv", "__dlcall",
|
||||||
// unix
|
// unix
|
||||||
"__pipe", "__fork", "__waitpid", "__chdir",
|
"__pipe", "__fork", "__waitpid", "__chdir",
|
||||||
"__environ", "__getcwd", "__getenv"
|
"__environ", "__getcwd", "__getenv",
|
||||||
|
// subprocess
|
||||||
|
"__subprocess_popen",
|
||||||
|
"__subprocess_pclose",
|
||||||
|
"__subprocess_read_stdout"
|
||||||
};
|
};
|
||||||
|
|
||||||
// file mapper for file -> index
|
// file mapper for file -> index
|
||||||
|
|
|
@ -63,45 +63,74 @@ void vm::context_and_global_init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vm::hash_value_info(var& val) {
|
||||||
|
std::clog << "{";
|
||||||
|
usize count = 0;
|
||||||
|
for(const auto& i : val.hash().elems) {
|
||||||
|
++count;
|
||||||
|
if (count>3) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::clog << i.first;
|
||||||
|
if (count!=val.hash().size()) {
|
||||||
|
std::clog << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (val.hash().size()>3) {
|
||||||
|
std::clog << "...";
|
||||||
|
}
|
||||||
|
std::clog << "}";
|
||||||
|
}
|
||||||
|
|
||||||
void vm::value_info(var& val) {
|
void vm::value_info(var& val) {
|
||||||
const auto p = reinterpret_cast<u64>(val.val.gcobj);
|
const auto p = reinterpret_cast<u64>(val.val.gcobj);
|
||||||
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: std::clog << "| pc | 0x" << std::hex
|
case vm_type::vm_ret:
|
||||||
<< val.ret() << std::dec; break;
|
std::clog << "| pc | 0x" << std::hex << val.ret() << std::dec;
|
||||||
case vm_type::vm_addr: std::clog << "| addr | 0x" << std::hex
|
break;
|
||||||
<< reinterpret_cast<u64>(val.addr())
|
case vm_type::vm_addr:
|
||||||
<< std::dec; break;
|
std::clog << "| addr | 0x";
|
||||||
|
std::clog << std::hex << reinterpret_cast<u64>(val.addr()) << std::dec;
|
||||||
|
break;
|
||||||
case vm_type::vm_cnt: std::clog << "| cnt | " << val.cnt(); break;
|
case vm_type::vm_cnt: std::clog << "| cnt | " << val.cnt(); break;
|
||||||
case vm_type::vm_nil: std::clog << "| nil |"; break;
|
case vm_type::vm_nil: std::clog << "| nil |"; break;
|
||||||
case vm_type::vm_num: std::clog << "| num | " << val.num(); break;
|
case vm_type::vm_num: std::clog << "| num | " << val.num(); break;
|
||||||
case vm_type::vm_str: std::clog << "| str | <0x" << std::hex << p
|
case vm_type::vm_str:
|
||||||
<< "> \"" << util::rawstr(val.str(), 16)
|
std::clog << "| str | <0x" << std::hex << p << "> " << std::dec;
|
||||||
<< "\"" << std::dec; break;
|
std::clog << "\"" << util::rawstr(val.str(), 16) << "\"";
|
||||||
case vm_type::vm_func: std::clog << "| func | <0x" << std::hex << p
|
break;
|
||||||
<< std::dec << "> " << val.func();
|
case vm_type::vm_func:
|
||||||
break;
|
std::clog << "| func | <0x" << std::hex << p << std::dec << "> ";
|
||||||
case vm_type::vm_upval:std::clog << "| upval| <0x" << std::hex << p
|
std::clog << val.func();
|
||||||
<< std::dec << "> [" << val.upval().size
|
break;
|
||||||
<< " val]"; break;
|
case vm_type::vm_upval:
|
||||||
case vm_type::vm_vec: std::clog << "| vec | <0x" << std::hex << p
|
std::clog << "| upval| <0x" << std::hex << p << std::dec;
|
||||||
<< std::dec << "> [" << val.vec().size()
|
std::clog << "> [" << val.upval().size << " val]"; break;
|
||||||
<< " val]"; break;
|
case vm_type::vm_vec:
|
||||||
case vm_type::vm_hash: std::clog << "| hash | <0x" << std::hex << p
|
std::clog << "| vec | <0x" << std::hex << p << std::dec;
|
||||||
<< std::dec << "> {" << val.hash().size()
|
std::clog << "> [" << val.vec().size() << " val]"; break;
|
||||||
<< " val}"; break;
|
case vm_type::vm_hash:
|
||||||
case vm_type::vm_ghost:std::clog << "| obj | <0x" << std::hex << p
|
std::clog << "| hash | <0x" << std::hex << p << std::dec << "> ";
|
||||||
<< "> obj:0x"
|
hash_value_info(val);
|
||||||
<< reinterpret_cast<u64>(val.ghost().pointer)
|
break;
|
||||||
<< std::dec; break;
|
case vm_type::vm_ghost:
|
||||||
case vm_type::vm_co: std::clog << "| co | <0x" << std::hex << p
|
std::clog << "| obj | <0x" << std::hex << p << "> " << std::dec;
|
||||||
<< std::dec << "> coroutine"; break;
|
std::clog << "obj:" << val.ghost().type_name;
|
||||||
case vm_type::vm_map: std::clog << "| nmspc| <0x" << std::hex << p
|
break;
|
||||||
<< std::dec << "> namespace ["
|
case vm_type::vm_co:
|
||||||
<< val.map().mapper.size()
|
std::clog << "| co | <0x" << std::hex << p << std::dec;
|
||||||
<< " val]"; break;
|
std::clog << "> coroutine";
|
||||||
default: std::clog << "| err | <0x" << std::hex << p
|
break;
|
||||||
<< std::dec << "> unknown object"; break;
|
case vm_type::vm_map:
|
||||||
|
std::clog << "| nmspc| <0x" << std::hex << p << std::dec;
|
||||||
|
std::clog << "> namespace [" << val.map().mapper.size() << " val]";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::clog << "| err | <0x" << std::hex << p << std::dec;
|
||||||
|
std::clog << "> unknown object";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
std::clog << "\n";
|
std::clog << "\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,7 @@ protected:
|
||||||
protected:
|
protected:
|
||||||
/* debug functions */
|
/* debug functions */
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
|
void hash_value_info(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();
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
#include "natives/subprocess.h"
|
||||||
|
|
||||||
|
// if you ask why, i will say: only MSVC
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define popen _popen
|
||||||
|
#define pclose _pclose
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
namespace nasal {
|
||||||
|
|
||||||
|
const auto subprocess_object_name = "subprocess";
|
||||||
|
|
||||||
|
void subprocess_destructor(void* ptr) {
|
||||||
|
pclose(static_cast<FILE*>(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
var builtin_subprocess_popen(context* ctx, gc* ngc) {
|
||||||
|
auto command = ctx->localr[1];
|
||||||
|
if (!command.is_str()) {
|
||||||
|
return nas_err("subprocess::popen", "expect a string as the command");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fd = popen(command.str().c_str(), "r");
|
||||||
|
if (fd == nullptr) {
|
||||||
|
return nas_err("subprocess::popen", "failed to create sub-process");
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = ngc->alloc(vm_type::vm_ghost);
|
||||||
|
ret.ghost().set(subprocess_object_name, subprocess_destructor, nullptr, fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
var builtin_subprocess_pclose(context* ctx, gc* ngc) {
|
||||||
|
auto fd = ctx->localr[1];
|
||||||
|
if (!fd.object_check(subprocess_object_name)) {
|
||||||
|
return nas_err("subprocess::pclose", "not a valid subprocess");
|
||||||
|
}
|
||||||
|
auto res = pclose(static_cast<FILE*>(fd.ghost().pointer));
|
||||||
|
fd.ghost().pointer = nullptr;
|
||||||
|
fd.ghost().clear();
|
||||||
|
return var::num(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
var builtin_subprocess_read_stdout(context* ctx, gc* ngc) {
|
||||||
|
auto fd = ctx->localr[1];
|
||||||
|
if (!fd.object_check(subprocess_object_name)) {
|
||||||
|
return nas_err("subprocess::pclose", "not a valid subprocess");
|
||||||
|
}
|
||||||
|
char buffer[1025];
|
||||||
|
auto res = ngc->alloc(vm_type::vm_str);
|
||||||
|
while(fgets(
|
||||||
|
buffer,
|
||||||
|
sizeof(buffer)-1,
|
||||||
|
static_cast<FILE*>(fd.ghost().pointer))!=nullptr) {
|
||||||
|
res.str() += buffer;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
nasal_builtin_table subprocess_native[] = {
|
||||||
|
{"__subprocess_popen", builtin_subprocess_popen},
|
||||||
|
{"__subprocess_pclose", builtin_subprocess_pclose},
|
||||||
|
{"__subprocess_read_stdout", builtin_subprocess_read_stdout},
|
||||||
|
{nullptr, nullptr}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "nasal.h"
|
||||||
|
#include "nasal_gc.h"
|
||||||
|
#include "natives/builtin.h"
|
||||||
|
|
||||||
|
namespace nasal {
|
||||||
|
|
||||||
|
void subprocess_destructor(void*);
|
||||||
|
|
||||||
|
var builtin_subprocess_popen(context*, gc*);
|
||||||
|
var builtin_subprocess_pclose(context*, gc*);
|
||||||
|
var builtin_subprocess_read_stdout(context*, gc*);
|
||||||
|
extern nasal_builtin_table subprocess_native[];
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
var popen = func(cmd) {
|
||||||
|
return __subprocess_popen(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
var pclose = func(subproc) {
|
||||||
|
return __subprocess_pclose(subproc);
|
||||||
|
}
|
||||||
|
|
||||||
|
var read = func(subproc) {
|
||||||
|
return __subprocess_read_stdout(subproc);
|
||||||
|
}
|
|
@ -3,62 +3,113 @@ use std.os;
|
||||||
use std.io;
|
use std.io;
|
||||||
use std.unix;
|
use std.unix;
|
||||||
|
|
||||||
|
use std.subprocess;
|
||||||
|
|
||||||
|
runtime.windows.set_utf8_output();
|
||||||
|
|
||||||
var os_time = func() {
|
var os_time = func() {
|
||||||
return "\e[33;1m["~os.time()~"]\e[0m ";
|
return "\e[33;1m[" ~ os.time() ~ "]\e[0m ";
|
||||||
}
|
}
|
||||||
|
|
||||||
var err_hd = func() {
|
var err_hd = func() {
|
||||||
return "\e[91;1m[error]\e[0m ";
|
return "\e[91;1m[error]\e[0m ";
|
||||||
}
|
}
|
||||||
|
|
||||||
var info_hd = func() {
|
var info_hd = func() {
|
||||||
return "\e[96;1m[info]\e[0m ";
|
return "\e[96;1m[info]\e[0m ";
|
||||||
}
|
}
|
||||||
|
|
||||||
var modified_hd = func() {
|
var modified_hd = func() {
|
||||||
return "\e[92;1m[modified]\e[0m ";
|
return "\e[92;1m[modified]\e[0m ";
|
||||||
}
|
}
|
||||||
|
|
||||||
var usage = func() {
|
var usage = func() {
|
||||||
println(os_time(),info_hd(),"\e[1musage: nasal watchdog.nas <filename> [\"argv\"]\e[0m");
|
println(
|
||||||
|
os_time(),
|
||||||
|
info_hd(),
|
||||||
|
"\e[1musage: nasal watchdog.nas <filename> [\"argv\"]\e[0m"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var argv=runtime.argv();
|
var argv = runtime.argv();
|
||||||
if (size(argv)<1) {
|
if (size(argv)<1) {
|
||||||
println(os_time(),err_hd(),"\e[1mneed correct file path to watch\e[0m");
|
println(
|
||||||
usage();
|
os_time(),
|
||||||
exit(-1);
|
err_hd(),
|
||||||
}
|
"\e[1mneed correct file path to watch\e[0m"
|
||||||
var filename=argv[0];
|
);
|
||||||
if (!io.exists(filename)) {
|
|
||||||
println(os_time(),err_hd(),"\e[1mfile <",filename,"> does not exist\e[0m");
|
|
||||||
usage();
|
usage();
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var args=[];
|
var filename = argv[0];
|
||||||
|
if (!io.exists(filename)) {
|
||||||
|
println(
|
||||||
|
os_time(),
|
||||||
|
err_hd(),
|
||||||
|
"\e[1mfile <",
|
||||||
|
filename,
|
||||||
|
"> does not exist\e[0m"
|
||||||
|
);
|
||||||
|
usage();
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var args = [];
|
||||||
if (size(argv)==2) {
|
if (size(argv)==2) {
|
||||||
println(os_time(),info_hd(),"\e[1mwith argument(s) ",argv[1],"\e[0m");
|
println(
|
||||||
args=split(" ",argv[1]);
|
os_time(),
|
||||||
|
info_hd(),
|
||||||
|
"\e[1mwith argument(s) ",
|
||||||
|
argv[1],
|
||||||
|
"\e[0m"
|
||||||
|
);
|
||||||
|
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(), "\e[1mwatching ", filename, " ..\e[0m");
|
||||||
while(1) {
|
while(1) {
|
||||||
unix.sleep(5);
|
unix.sleep(5);
|
||||||
if (!io.exists(filename)) {
|
if (!io.exists(filename)) {
|
||||||
println(os_time(),err_hd(),"\e[1mfile <",filename,"> does not exist\e[0m");
|
println(
|
||||||
|
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(), "\e[1m", filename, "\e[0m");
|
||||||
var cmd=(os.platform()=="windows"?"":"./")~"nasal "~filename;
|
|
||||||
foreach(var i;args)
|
var cmd = (os.platform()=="windows"?"":"./") ~ "nasal " ~ filename;
|
||||||
cmd~=" "~i;
|
foreach(var i; args) {
|
||||||
println(os_time(),info_hd(),"\e[1mexecuting command \"",cmd,"\"\e[0m");
|
cmd ~= " " ~ i;
|
||||||
var ret=system(cmd);
|
|
||||||
if (ret!=0) {
|
|
||||||
println(os_time(),err_hd(),"\e[1mprocess returned ",ret,"\e[0m");
|
|
||||||
} else {
|
|
||||||
println(os_time(),info_hd(),"\e[1mprocess returned ",ret,"\e[0m");
|
|
||||||
}
|
}
|
||||||
|
cmd ~= " 2>&1";
|
||||||
|
println(
|
||||||
|
os_time(),
|
||||||
|
info_hd(),
|
||||||
|
"\e[1mexecuting command \"",
|
||||||
|
cmd,
|
||||||
|
"\"\e[0m"
|
||||||
|
);
|
||||||
|
|
||||||
|
var subproc = subprocess.popen(cmd);
|
||||||
|
var stdout_info = subprocess.read(subproc);
|
||||||
|
var ret = subprocess.pclose(subproc);
|
||||||
|
if (size(stdout_info)>0) {
|
||||||
|
println(stdout_info);
|
||||||
|
}
|
||||||
|
println(
|
||||||
|
os_time(),
|
||||||
|
ret!=0? err_hd():info_hd(),
|
||||||
|
"\e[1mprocess returned " ~ ret ~ "\e[0m"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue