From 1205c6d788afef2ed93784da06fa4b5fbcaf80ef Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sat, 8 Jun 2024 00:30:20 +0800 Subject: [PATCH 1/4] :sparkles: improve vm::value_info --- CMakeLists.txt | 2 +- src/nasal.h | 2 +- src/nasal_vm.cpp | 93 +++++++++++++++++++++++++++++++----------------- src/nasal_vm.h | 1 + 4 files changed, 64 insertions(+), 34 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 64d7e3c..420a92d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ 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}") diff --git a/src/nasal.h b/src/nasal.h index 664200d..fb5ed9f 100644 --- a/src/nasal.h +++ b/src/nasal.h @@ -1,7 +1,7 @@ #pragma once #ifndef __nasver__ -#define __nasver__ "11.2" +#define __nasver__ "11.3" #endif #include diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index 006a392..c58b502 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -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) { const auto p = reinterpret_cast(val.val.gcobj); switch(val.type) { case vm_type::vm_none: std::clog << "| null |"; break; - case vm_type::vm_ret: std::clog << "| pc | 0x" << std::hex - << val.ret() << std::dec; break; - case vm_type::vm_addr: std::clog << "| addr | 0x" << std::hex - << reinterpret_cast(val.addr()) - << std::dec; break; + case vm_type::vm_ret: + std::clog << "| pc | 0x" << std::hex << val.ret() << std::dec; + break; + case vm_type::vm_addr: + std::clog << "| addr | 0x"; + std::clog << std::hex << reinterpret_cast(val.addr()) << std::dec; + 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_num: std::clog << "| num | " << val.num(); break; - case vm_type::vm_str: std::clog << "| str | <0x" << std::hex << p - << "> \"" << util::rawstr(val.str(), 16) - << "\"" << std::dec; break; - case vm_type::vm_func: std::clog << "| func | <0x" << std::hex << p - << std::dec << "> " << val.func(); - break; - case vm_type::vm_upval:std::clog << "| upval| <0x" << std::hex << p - << std::dec << "> [" << val.upval().size - << " val]"; break; - case vm_type::vm_vec: std::clog << "| vec | <0x" << std::hex << p - << std::dec << "> [" << val.vec().size() - << " val]"; break; - case vm_type::vm_hash: std::clog << "| hash | <0x" << std::hex << p - << std::dec << "> {" << val.hash().size() - << " val}"; break; - case vm_type::vm_ghost:std::clog << "| obj | <0x" << std::hex << p - << "> obj:0x" - << reinterpret_cast(val.ghost().pointer) - << std::dec; break; - case vm_type::vm_co: std::clog << "| co | <0x" << std::hex << p - << std::dec << "> coroutine"; break; - case vm_type::vm_map: std::clog << "| nmspc| <0x" << std::hex << p - << std::dec << "> namespace [" - << val.map().mapper.size() - << " val]"; break; - default: std::clog << "| err | <0x" << std::hex << p - << std::dec << "> unknown object"; break; + case vm_type::vm_str: + std::clog << "| str | <0x" << std::hex << p << "> " << std::dec; + std::clog << "\"" << util::rawstr(val.str(), 16) << "\""; + break; + case vm_type::vm_func: + std::clog << "| func | <0x" << std::hex << p << std::dec << "> "; + std::clog << 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; + case vm_type::vm_hash: + std::clog << "| hash | <0x" << std::hex << p << std::dec << "> "; + 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; + break; + case vm_type::vm_co: + std::clog << "| co | <0x" << std::hex << p << std::dec; + std::clog << "> coroutine"; + 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"; } diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 392dfaa..27b9678 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -65,6 +65,7 @@ protected: protected: /* debug functions */ bool verbose = false; + void hash_value_info(var&); void value_info(var&); void function_detail_info(const nas_func&); void function_call_trace(); From 7e3c6d06b25a6c3a6ca0498f2bcc02945b62fc6a Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Sun, 9 Jun 2024 00:21:11 +0800 Subject: [PATCH 2/4] :sparkles: add framework for subprocess --- CMakeLists.txt | 1 + makefile | 10 ++++++++++ src/nasal_codegen.cpp | 1 + src/nasal_codegen.h | 5 ++++- src/natives/subprocess.cpp | 14 ++++++++++++++ src/natives/subprocess.h | 13 +++++++++++++ std/subprocess.nas | 3 +++ 7 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/natives/subprocess.cpp create mode 100644 src/natives/subprocess.h create mode 100644 std/subprocess.nas diff --git a/CMakeLists.txt b/CMakeLists.txt index 420a92d..c5d36d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ set(NASAL_OBJECT_SOURCE_FILE ${CMAKE_SOURCE_DIR}/src/natives/math_lib.cpp ${CMAKE_SOURCE_DIR}/src/natives/dylib_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/repl/repl.cpp ${CMAKE_SOURCE_DIR}/src/util/fs.cpp diff --git a/makefile b/makefile index 17a35e8..7cde7a3 100644 --- a/makefile +++ b/makefile @@ -37,6 +37,7 @@ NASAL_HEADER = \ src/natives/unix_lib.h\ src/natives/coroutine.h\ src/natives/regex_lib.h\ + src/natives/subprocess.h\ src/repl/repl.h\ src/util/fs.h\ src/util/util.h @@ -61,6 +62,7 @@ NASAL_OBJECT = \ build/math_lib.o\ build/unix_lib.o\ build/dylib_lib.o\ + build/subprocess.o\ build/json_lib.o\ build/coroutine.o\ build/nasal_type.o\ @@ -212,6 +214,14 @@ build/regex_lib.o: \ src/natives/regex_lib.h src/natives/regex_lib.cpp | build $(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: \ src/nasal.h\ src/nasal_type.h\ diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index 9209a96..e68b3db 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -39,6 +39,7 @@ void codegen::init_native_function() { load_native_function_table(unix_lib_native); load_native_function_table(json_lib_native); load_native_function_table(regex_lib_native); + load_native_function_table(subprocess_native); } void codegen::check_id_exist(identifier* node) { diff --git a/src/nasal_codegen.h b/src/nasal_codegen.h index ffa2ab7..2eb44f3 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -18,6 +18,7 @@ #include "natives/dylib_lib.h" #include "natives/regex_lib.h" #include "natives/unix_lib.h" +#include "natives/subprocess.h" #include #include @@ -57,7 +58,9 @@ private: "__dlopen", "__dlclose", "__dlcallv", "__dlcall", // unix "__pipe", "__fork", "__waitpid", "__chdir", - "__environ", "__getcwd", "__getenv" + "__environ", "__getcwd", "__getenv", + // subprocess + "__subprocess_run" }; // file mapper for file -> index diff --git a/src/natives/subprocess.cpp b/src/natives/subprocess.cpp new file mode 100644 index 0000000..0e999a3 --- /dev/null +++ b/src/natives/subprocess.cpp @@ -0,0 +1,14 @@ +#include "natives/subprocess.h" + +namespace nasal { + +var builtin_subprocess_run(context* ctx, gc* ngc) { + return nil; +} + +nasal_builtin_table subprocess_native[] = { + {"__subprocess_run", builtin_subprocess_run}, + {nullptr, nullptr} +}; + +} \ No newline at end of file diff --git a/src/natives/subprocess.h b/src/natives/subprocess.h new file mode 100644 index 0000000..f1a2680 --- /dev/null +++ b/src/natives/subprocess.h @@ -0,0 +1,13 @@ +#pragma once + +#include "nasal.h" +#include "nasal_gc.h" +#include "natives/builtin.h" + +namespace nasal { + +var builtin_subprocess_run(context*, gc*); + +extern nasal_builtin_table subprocess_native[]; + +} \ No newline at end of file diff --git a/std/subprocess.nas b/std/subprocess.nas new file mode 100644 index 0000000..b418896 --- /dev/null +++ b/std/subprocess.nas @@ -0,0 +1,3 @@ +var run = func() { + return __subprocess_run(); +} \ No newline at end of file From d48c9f44e8809f769a7e911bd6b3c24d9e57d21c Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Mon, 10 Jun 2024 00:30:30 +0800 Subject: [PATCH 3/4] :sparkles: add native functions of subprocess --- src/nasal_codegen.h | 4 +- src/natives/subprocess.cpp | 55 ++++++++++++++++++-- src/natives/subprocess.h | 5 +- std/subprocess.nas | 12 ++++- test/watchdog.nas | 103 +++++++++++++++++++++++++++---------- 5 files changed, 146 insertions(+), 33 deletions(-) diff --git a/src/nasal_codegen.h b/src/nasal_codegen.h index 2eb44f3..ab742c9 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -60,7 +60,9 @@ private: "__pipe", "__fork", "__waitpid", "__chdir", "__environ", "__getcwd", "__getenv", // subprocess - "__subprocess_run" + "__subprocess_popen", + "__subprocess_pclose", + "__subprocess_read_stdout" }; // file mapper for file -> index diff --git a/src/natives/subprocess.cpp b/src/natives/subprocess.cpp index 0e999a3..16161bd 100644 --- a/src/natives/subprocess.cpp +++ b/src/natives/subprocess.cpp @@ -1,13 +1,62 @@ #include "natives/subprocess.h" +#include + namespace nasal { -var builtin_subprocess_run(context* ctx, gc* ngc) { - return nil; +const auto subprocess_object_name = "subprocess"; + +void subprocess_destructor(void* ptr) { + pclose(static_cast(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(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(fd.ghost().pointer))!=nullptr) { + res.str() += buffer; + } + return res; } nasal_builtin_table subprocess_native[] = { - {"__subprocess_run", builtin_subprocess_run}, + {"__subprocess_popen", builtin_subprocess_popen}, + {"__subprocess_pclose", builtin_subprocess_pclose}, + {"__subprocess_read_stdout", builtin_subprocess_read_stdout}, {nullptr, nullptr} }; diff --git a/src/natives/subprocess.h b/src/natives/subprocess.h index f1a2680..23029a4 100644 --- a/src/natives/subprocess.h +++ b/src/natives/subprocess.h @@ -6,8 +6,11 @@ namespace nasal { -var builtin_subprocess_run(context*, gc*); +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[]; } \ No newline at end of file diff --git a/std/subprocess.nas b/std/subprocess.nas index b418896..e82cf8b 100644 --- a/std/subprocess.nas +++ b/std/subprocess.nas @@ -1,3 +1,11 @@ -var run = func() { - return __subprocess_run(); +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); } \ No newline at end of file diff --git a/test/watchdog.nas b/test/watchdog.nas index e0e2a9f..5c3c32b 100644 --- a/test/watchdog.nas +++ b/test/watchdog.nas @@ -3,62 +3,113 @@ use std.os; use std.io; use std.unix; +use std.subprocess; + +runtime.windows.set_utf8_output(); + var os_time = func() { - return "\e[33;1m["~os.time()~"]\e[0m "; + return "\e[33;1m[" ~ os.time() ~ "]\e[0m "; } + var err_hd = func() { return "\e[91;1m[error]\e[0m "; } + var info_hd = func() { return "\e[96;1m[info]\e[0m "; } + var modified_hd = func() { return "\e[92;1m[modified]\e[0m "; } + var usage = func() { - println(os_time(),info_hd(),"\e[1musage: nasal watchdog.nas [\"argv\"]\e[0m"); + println( + os_time(), + info_hd(), + "\e[1musage: nasal watchdog.nas [\"argv\"]\e[0m" + ); } -var argv=runtime.argv(); +var argv = runtime.argv(); if (size(argv)<1) { - println(os_time(),err_hd(),"\e[1mneed correct file path to watch\e[0m"); - usage(); - exit(-1); -} -var filename=argv[0]; -if (!io.exists(filename)) { - println(os_time(),err_hd(),"\e[1mfile <",filename,"> does not exist\e[0m"); + println( + os_time(), + err_hd(), + "\e[1mneed correct file path to watch\e[0m" + ); usage(); 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) { - println(os_time(),info_hd(),"\e[1mwith argument(s) ",argv[1],"\e[0m"); - args=split(" ",argv[1]); + println( + os_time(), + info_hd(), + "\e[1mwith argument(s) ", + argv[1], + "\e[0m" + ); + args = split(" ", argv[1]); } 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) { unix.sleep(5); 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; } + var latest_modified_time = io.fstat(filename).st_mtime; if (latest_modified_time!=modified_time) { - modified_time=latest_modified_time; - println(os_time(),modified_hd(),"\e[1m",filename,"\e[0m"); - var cmd=(os.platform()=="windows"?"":"./")~"nasal "~filename; - foreach(var i;args) - cmd~=" "~i; - println(os_time(),info_hd(),"\e[1mexecuting command \"",cmd,"\"\e[0m"); - 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"); + modified_time = latest_modified_time; + println(os_time(), modified_hd(), "\e[1m", filename, "\e[0m"); + + var cmd = (os.platform()=="windows"?"":"./") ~ "nasal " ~ filename; + foreach(var i; args) { + cmd ~= " " ~ i; } + 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" + ); } } \ No newline at end of file From 2337994b081484f8f258db35e27208abac37808f Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Mon, 10 Jun 2024 00:36:52 +0800 Subject: [PATCH 4/4] :bug: fix compilation error on MSVC --- src/natives/subprocess.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/natives/subprocess.cpp b/src/natives/subprocess.cpp index 16161bd..f6974e0 100644 --- a/src/natives/subprocess.cpp +++ b/src/natives/subprocess.cpp @@ -1,5 +1,11 @@ #include "natives/subprocess.h" +// if you ask why, i will say: only MSVC +#ifdef _MSC_VER +#define popen _popen +#define pclose _pclose +#endif + #include namespace nasal {