From 01a034a77b129fe393ba3b22d0b6b4b0ce2dd30c Mon Sep 17 00:00:00 2001 From: Mike Nolan Date: Sun, 12 Jan 2025 19:33:43 -0600 Subject: [PATCH] Finish process --- CMakeLists.txt | 8 +-- include/CrossLang.hpp | 8 +++ src/runtime_methods/process.cpp | 118 +++++++++++++++++++++++++++++--- src/runtime_methods/std.cpp | 12 ++++ src/vm/gc.cpp | 10 +++ src/vm/vm.cpp | 67 ++++++++++++++---- 6 files changed, 195 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 477883a..79744f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,8 @@ project(TessesCrossLang VERSION 1.0) set(CMAKE_CXX_STANDARD 20) -set(ENABLE_TESTING OFF) + +include(CMakePackageConfigHelpers) option(CROSSLANG_ENABLE_STATIC "Enable Tesses CrossLang static libraries" ON) option(CROSSLANG_ENABLE_SHARED "Enable Tesses CrossLang shared libraries" ON) option(CROSSLANG_ENABLE_BINARIES "Enable Tesses CrossLang binaries" ON) @@ -66,7 +67,7 @@ find_package(SDL2_ttf REQUIRED) target_include_directories(${CROSSLANG_TARGET_NAME} PUBLIC ${SDL2_INCLUDE_DIRS}) -target_link_libraries(${CROSSLANG_TARGET_NAME} PUBLIC ${SDL2_LIBRARIES}) +target_link_libraries(${CROSSLANG_TARGET_NAME} PUBLIC SDL2::SDL2) if("${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoWii" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoGameCube") target_link_libraries(${CROSSLANG_TARGET_NAME} PUBLIC SDL2_image png jpeg z) else() @@ -106,6 +107,7 @@ src/runtime_methods/crypto.cpp src/runtime_methods/ogc.cpp src/runtime_methods/path.cpp src/runtime_methods/env.cpp +src/runtime_methods/process.cpp src/types/ittr.cpp src/types/closure.cpp src/types/dictionary.cpp @@ -184,8 +186,6 @@ install(EXPORT TessesCrossLangTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TessesCrossLang ) - -include(CMakePackageConfigHelpers) configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/TessesCrossLangConfig.cmake" INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TessesCrossLang) diff --git a/include/CrossLang.hpp b/include/CrossLang.hpp index da920ce..556a975 100644 --- a/include/CrossLang.hpp +++ b/include/CrossLang.hpp @@ -650,12 +650,15 @@ class Parser { }; using TObject = std::variant; +class TRootEnvironment; +class GC; class GC { Tesses::Framework::Threading::Thread* thrd; Tesses::Framework::Threading::Mutex* mtx; volatile std::atomic running; std::vector roots; std::vector objects; + std::vector> register_everything; public: bool UsingNullThreads(); GC(); @@ -669,6 +672,8 @@ class GC { void SetRoot(TObject obj); void UnsetRoot(TObject obj); static void Mark(TObject obj); + void RegisterEverythingCallback(std::function cb); + void RegisterEverything(TRootEnvironment* env); ~GC(); }; @@ -824,6 +829,7 @@ class GC { public: EnvironmentPermissions(); Tesses::Framework::Filesystem::VFSPath sqliteOffsetPath; + bool canRegisterEverything; bool canRegisterConsole; bool canRegisterIO; bool canRegisterLocalFS; @@ -835,6 +841,7 @@ class GC { bool canRegisterCrypto; bool canRegisterSDL2; bool canRegisterRoot; + bool canRegisterProcess; bool canRegisterPath; bool canRegisterOGC; bool canRegisterEnv; @@ -884,6 +891,7 @@ class GC { static void RegisterPath(GC* gc, TRootEnvironment* env); static void RegisterOGC(GC* gc, TRootEnvironment* env); static void RegisterEnv(GC* gc, TRootEnvironment* env); + static void RegisterProcess(GC* gc, TRootEnvironment* env); }; class TSubEnvironment : public TEnvironment diff --git a/src/runtime_methods/process.cpp b/src/runtime_methods/process.cpp index c1f7461..7f87ac3 100644 --- a/src/runtime_methods/process.cpp +++ b/src/runtime_methods/process.cpp @@ -4,13 +4,13 @@ #undef CROSSLANG_ENABLE_PROCESS #endif -//#if defined(CROSSLANG_ENABLE_PROCESS) +#if defined(CROSSLANG_ENABLE_PROCESS) #include "subprocess.h" -//#endif +#endif namespace Tesses::CrossLang { - //#if defined(CROSSLANG_ENABLE_PROCESS) + #if defined(CROSSLANG_ENABLE_PROCESS) static TObject Process_Start(GCList& ls, std::vector args) { @@ -30,14 +30,22 @@ namespace Tesses::CrossLang auto fobj = dict->GetValue("FileName"); auto myargs = dict->GetValue("Arguments"); auto env = dict->GetValue("Environment"); + auto opt = dict->GetValue("Options"); + //for any C# version + //RedirectStandardIn + //RedirectStandardOut + //RedirectStandardError std::string filename; TList* _args; - TList* env; + TList* env0; std::vector _args2; std::vector _env; + int64_t options; - if(GetObject(fobj,filename)) + bool hasEnv=false; + + if(!GetObject(fobj,filename)) { gc->BarrierEnd(); return nullptr; @@ -54,24 +62,114 @@ namespace Tesses::CrossLang } } } - if(GetObjectHeap(myargs,_args)) + if(GetObjectHeap(env,env0)) { - for(auto a : _args->items) + hasEnv=true; + for(auto a : env0->items) { std::string a2; if(GetObject(a,a2)) { - _args2.push_back(a2); + _env.push_back(a2); } } } + const char** args3 = new const char*[sizeof(char*) * (_args2.size()+1)]; + const char** env3 = hasEnv ? new const char*[sizeof(char*) * (_env.size()+1)] : nullptr; + for(size_t i = 0; i < _args2.size();i++) + args3[i] = _args2[i].c_str(); + args3[_args2.size()]=NULL; + + if(hasEnv) + { + for(size_t i = 0; i < _env.size();i++) + env3[i] = _env[i].c_str(); + env3[_env.size()]=NULL; + } + + + if(!GetObject(opt,options))options=hasEnv ? 0 : subprocess_option_inherit_environment; gc->BarrierEnd(); - subprocess_create_ex() + struct subprocess_s* subprocess=new struct subprocess_s(); + int r = subprocess_create_ex(args3,(int)options,env3,subprocess); + if(r != 0) + { + printf("Here2 %i\n",r); + delete[] args3; + delete[] env3; + delete subprocess; + return nullptr; + } + else + { + delete[] args3; + delete[] env3; + + TDictionary* dict=TDictionary::Create(ls); + auto r = TNative::Create(ls,subprocess,[](void* v)->void{ + delete (struct subprocess_s*)v; + }); + gc->BarrierBegin(); + dict->SetValue("_native",r); + gc->BarrierEnd(); + dict->DeclareFunction(gc,"getHasExited","Gets whether process has stopped",{},[r](GCList& ls, std::vector args)->TObject{ + if(r->GetDestroyed()) return true; + return subprocess_alive((struct subprocess_s*)r->GetPointer()) == 0; + }); + dict->DeclareFunction(gc,"Join","Wait till process exits and get its return code",{},[r](GCList& ls, std::vector args)->TObject{ + if(r->GetDestroyed()) return nullptr; + int returnCode; + if(subprocess_join((struct subprocess_s*)r->GetPointer(),&returnCode) == 0) + { + return (int64_t)returnCode; + } + return nullptr; + }); + + dict->DeclareFunction(gc,"Terminate","Terminate the process",{},[r](GCList& ls, std::vector args)->TObject{ + if(r->GetDestroyed()) return nullptr; + subprocess_terminate((struct subprocess_s*)r->GetPointer()); + return nullptr; + }); + dict->DeclareFunction(gc,"Close","Wait till process exits and get its return code",{},[r](GCList& ls, std::vector args)->TObject{ + if(r->GetDestroyed()) return nullptr; + r->Destroy(); + return nullptr; + }); + + dict->DeclareFunction(gc,"getStandardInput","Gets the standard input stream",{},[r](GCList& ls,std::vector args)->TObject { + if(r->GetDestroyed()) return nullptr; + return TStreamHeapObject::Create(ls,new Tesses::Framework::Streams::FileStream(subprocess_stdin((struct subprocess_s*)r->GetPointer()),false,"w",false)); + }); + dict->DeclareFunction(gc,"getStandardOutput","Gets the standard output stream",{},[r](GCList& ls,std::vector args)->TObject { + if(r->GetDestroyed()) return nullptr; + return TStreamHeapObject::Create(ls,new Tesses::Framework::Streams::FileStream(subprocess_stdout((struct subprocess_s*)r->GetPointer()),false,"r",false)); + }); + dict->DeclareFunction(gc,"getStandardError","Gets the standard error stream",{},[r](GCList& ls,std::vector args)->TObject { + if(r->GetDestroyed()) return nullptr; + return TStreamHeapObject::Create(ls,new Tesses::Framework::Streams::FileStream(subprocess_stderr((struct subprocess_s*)r->GetPointer()),false,"r",false)); + }); + return dict; + } } return nullptr; } - //#endif + #endif + + void TStd::RegisterProcess(GC* gc,TRootEnvironment* env) + { + + env->permissions.canRegisterProcess=true; + GCList ls(gc); + TDictionary* dict = TDictionary::Create(ls); + #if defined(CROSSLANG_ENABLE_PROCESS) + dict->DeclareFunction(gc,"Start","Start a process",{"process_object"},Process_Start); + #endif + gc->BarrierBegin(); + env->SetVariable("Process",dict); + gc->BarrierEnd(); + } } \ No newline at end of file diff --git a/src/runtime_methods/std.cpp b/src/runtime_methods/std.cpp index bb9091d..9ee56c7 100644 --- a/src/runtime_methods/std.cpp +++ b/src/runtime_methods/std.cpp @@ -188,6 +188,7 @@ namespace Tesses::CrossLang this->canRegisterNet=false; this->canRegisterOGC=false; this->canRegisterPath=false; + this->canRegisterProcess=false; this->canRegisterRoot=false; this->canRegisterSDL2=false; this->canRegisterSqlite=false; @@ -224,6 +225,7 @@ namespace Tesses::CrossLang } void TStd::RegisterStd(GC* gc, TRootEnvironment* env) { + env->permissions.canRegisterEverything=true; RegisterEnv(gc, env); RegisterRoot(gc,env); RegisterPath(gc,env); @@ -237,6 +239,16 @@ namespace Tesses::CrossLang RegisterCrypto(gc,env); RegisterSDL2(gc, env); RegisterOGC(gc, env); + RegisterProcess(gc,env); + + gc->RegisterEverything(env); + + GCList ls(gc); + + TDictionary* dict = TDictionary::Create(ls); + gc->BarrierBegin(); + env->SetVariable("Reflection",dict); + gc->BarrierEnd(); env->permissions.locked=true; } } \ No newline at end of file diff --git a/src/vm/gc.cpp b/src/vm/gc.cpp index 68d5e80..5fc70e5 100644 --- a/src/vm/gc.cpp +++ b/src/vm/gc.cpp @@ -226,6 +226,16 @@ namespace Tesses::CrossLang for(auto item : objects) delete item; delete this->mtx; } + + void GC::RegisterEverythingCallback(std::function cb) + { + this->register_everything.push_back(cb); + } + void GC::RegisterEverything(TRootEnvironment* env) + { + for(auto item : this->register_everything) + item(this,env); + } void GC::Collect() { this->BarrierBegin(); diff --git a/src/vm/vm.cpp b/src/vm/vm.cpp index 2fd07cc..3e154e7 100644 --- a/src/vm/vm.cpp +++ b/src/vm/vm.cpp @@ -1772,6 +1772,7 @@ namespace Tesses::CrossLang { auto vfs = dynamic_cast(obj); auto env = dynamic_cast(obj); auto rootEnv = dynamic_cast(obj); + auto callable = dynamic_cast(obj); if(rootEnv != nullptr) { @@ -1784,12 +1785,17 @@ namespace Tesses::CrossLang { //TStd::RegisterOGC //TStd::RegisterPath //TStd::RegisterRoot - //TStd::RegisterSDL2 //TStd::RegisterSqlite //TStd::RegisterVM auto myEnv = cse.back()->env->GetRootEnvironment(); if(key == "RegisterEverything") { + if(myEnv->permissions.canRegisterEverything) + { + TStd::RegisterStd(gc, rootEnv); + } + else + { if(myEnv->permissions.canRegisterConsole && !rootEnv->permissions.locked) TStd::RegisterConsole(gc, rootEnv); @@ -1829,34 +1835,44 @@ namespace Tesses::CrossLang { if(myEnv->permissions.canRegisterVM && !rootEnv->permissions.locked) TStd::RegisterVM(gc, rootEnv); + if(myEnv->permissions.canRegisterProcess && !rootEnv->permissions.locked) + TStd::RegisterProcess(gc, rootEnv); + } cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterConsole") { - if(myEnv->permissions.canRegisterConsole && !rootEnv->permissions.locked) + if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterConsole) && !rootEnv->permissions.locked) TStd::RegisterConsole(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } + if(key == "RegisterProcess") + { + if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterProcess) && !rootEnv->permissions.locked) + TStd::RegisterProcess(gc, rootEnv); + cse.back()->Push(gc,nullptr); + return false; + } if(key == "RegisterCrypto") { - if(myEnv->permissions.canRegisterCrypto && !rootEnv->permissions.locked) + if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterCrypto) && !rootEnv->permissions.locked) TStd::RegisterCrypto(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterDictionary") { - if(myEnv->permissions.canRegisterDictionary && !rootEnv->permissions.locked) + if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterDictionary) && !rootEnv->permissions.locked) TStd::RegisterDictionary(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterEnv") { - if(myEnv->permissions.canRegisterEnv && !rootEnv->permissions.locked) + if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterEnv) && !rootEnv->permissions.locked) TStd::RegisterDictionary(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; @@ -1866,7 +1882,7 @@ namespace Tesses::CrossLang { bool r; if(GetArgument(args,0,r)) { - if(myEnv->permissions.canRegisterIO && !rootEnv->permissions.locked) + if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterIO) && !rootEnv->permissions.locked) TStd::RegisterIO(gc, rootEnv, myEnv->permissions.canRegisterLocalFS ? r : false); } cse.back()->Push(gc,nullptr); @@ -1875,35 +1891,35 @@ namespace Tesses::CrossLang { } if(key == "RegisterJson") { - if(myEnv->permissions.canRegisterJSON && !rootEnv->permissions.locked) + if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterJSON) && !rootEnv->permissions.locked) TStd::RegisterJson(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterNet") { - if(myEnv->permissions.canRegisterNet && !rootEnv->permissions.locked) + if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterNet) && !rootEnv->permissions.locked) TStd::RegisterNet(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterOGC") { - if(myEnv->permissions.canRegisterOGC && !rootEnv->permissions.locked) + if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterOGC) && !rootEnv->permissions.locked) TStd::RegisterOGC(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterPath") { - if(myEnv->permissions.canRegisterPath && !rootEnv->permissions.locked) + if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterPath) && !rootEnv->permissions.locked) TStd::RegisterPath(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterRoot") { - if(myEnv->permissions.canRegisterRoot && !rootEnv->permissions.locked) + if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterRoot) && !rootEnv->permissions.locked) TStd::RegisterRoot(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; @@ -1911,14 +1927,14 @@ namespace Tesses::CrossLang { if(key == "RegisterSDL2") { - if(myEnv->permissions.canRegisterSDL2 && !rootEnv->permissions.locked) + if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterSDL2) && !rootEnv->permissions.locked) TStd::RegisterSDL2(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; } if(key == "RegisterSqlite") { - if(myEnv->permissions.canRegisterSqlite && !rootEnv->permissions.locked) + if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterSqlite) && !rootEnv->permissions.locked) TStd::RegisterSqlite(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; @@ -1958,7 +1974,7 @@ namespace Tesses::CrossLang { } if(key == "RegisterVM") { - if(myEnv->permissions.canRegisterVM && !rootEnv->permissions.locked) + if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterVM) && !rootEnv->permissions.locked) TStd::RegisterVM(gc, rootEnv); cse.back()->Push(gc,nullptr); return false; @@ -3040,6 +3056,29 @@ namespace Tesses::CrossLang { return InvokeMethod(ls,o,dict,args); } + else if(callable != nullptr) + { + if(key == "Call") + { + TList* argls; + if(GetArgumentHeap(args,0,argls)) + { + TClosure* clo = dynamic_cast(callable); + if(clo != nullptr) + { + AddCallStackEntry(ls,clo,argls->items); + return true; + } + else + { + cse.back()->Push(gc,callable->Call(ls, argls->items)); + return false; + } + } + } + cse.back()->Push(gc,nullptr); + return false; + } else { cse.back()->Push(gc, Undefined());