mirror of
https://onedev.site.tesses.net/crosslang
synced 2026-02-08 17:15:45 +00:00
Change process code
This commit is contained in:
@@ -452,6 +452,7 @@ namespace Tesses::CrossLang
|
||||
TCallable* callable;
|
||||
TDictionary* dict;
|
||||
TServerHeapObject* server;
|
||||
TClassObject* clsObj;
|
||||
if(GetObjectHeap<TCallable*>(this->obj,callable))
|
||||
{
|
||||
GCList ls2(this->ls->GetGC());
|
||||
@@ -474,6 +475,23 @@ namespace Tesses::CrossLang
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if(GetObjectHeap(this->obj,clsObj) && clsObj->HasMethod("","Handle"))
|
||||
{
|
||||
GCList ls2(this->ls->GetGC());
|
||||
auto res = CreateDictionaryFromServerContext(ls2,&ctx);
|
||||
bool result;
|
||||
auto callableO = clsObj->GetValue("","Handle");
|
||||
TCallable* callable;
|
||||
if(GetObjectHeap(callableO, callable))
|
||||
{
|
||||
auto out = callable->Call(ls2,{res});
|
||||
if(GetObject(out,result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if(GetObjectHeap<TServerHeapObject*>(this->obj,server))
|
||||
{
|
||||
return server->server->Handle(ctx);
|
||||
@@ -536,6 +554,59 @@ namespace Tesses::CrossLang
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
class HttpServerNativeObject : public TNativeObject
|
||||
{
|
||||
HttpServer* server;
|
||||
public:
|
||||
HttpServerNativeObject(uint16_t port, TObjectHttpServer* httpServer,bool printIps)
|
||||
{
|
||||
server=new HttpServer(port,httpServer,true,printIps);
|
||||
}
|
||||
HttpServerNativeObject(std::string unixPath, TObjectHttpServer* httpServer)
|
||||
{
|
||||
server=new HttpServer(unixPath,httpServer,true);
|
||||
}
|
||||
std::string TypeName()
|
||||
{
|
||||
return "Net.Http.HttpServer";
|
||||
}
|
||||
TObject CallMethod(GCList& ls, std::string key, std::vector<TObject> args)
|
||||
{
|
||||
if(key == "getPort")
|
||||
{
|
||||
return (int64_t)server->GetPort();
|
||||
}
|
||||
if(key == "StartAccepting")
|
||||
server->StartAccepting();
|
||||
return nullptr;
|
||||
}
|
||||
~HttpServerNativeObject()
|
||||
{
|
||||
delete server;
|
||||
}
|
||||
};
|
||||
|
||||
static TObject Net_Http_HttpServer(GCList& ls, std::vector<TObject> args,TRootEnvironment* env)
|
||||
{
|
||||
int64_t port;
|
||||
std::string pathStr;
|
||||
if(GetArgument(args,1,port))
|
||||
{
|
||||
bool printIPs=true;
|
||||
GetArgument(args,2,printIPs);
|
||||
TObjectHttpServer* httpServer = new TObjectHttpServer(ls.GetGC(),args[0]);
|
||||
uint16_t p = (uint16_t)port;
|
||||
return TNativeObject::Create<HttpServerNativeObject>(ls,port,httpServer,printIPs);
|
||||
}
|
||||
if(GetArgument(args,1,pathStr) && env->permissions.canRegisterLocalFS)
|
||||
{
|
||||
TObjectHttpServer* httpServer = new TObjectHttpServer(ls.GetGC(),args[0]);
|
||||
|
||||
return TNativeObject::Create<HttpServerNativeObject>(ls,pathStr,httpServer);
|
||||
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static TObject Net_Http_ListenSimpleWithLoop(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
int64_t port;
|
||||
@@ -1007,6 +1078,9 @@ namespace Tesses::CrossLang
|
||||
http->DeclareFunction(gc, "DownloadToString","Return the http file's contents as a string",{"url"},Net_Http_DownloadToString);
|
||||
http->DeclareFunction(gc, "DownloadToStream","Download file to stream",{"url","stream"},Net_Http_DownloadToStream);
|
||||
http->DeclareFunction(gc, "DownloadToFile","Download file to file in vfs",{"url","vfs","path"},Net_Http_DownloadToFile);
|
||||
http->DeclareFunction(gc, "HttpServer", "Create a http server (allows multiple)",{"server","portOrUnixPath","$printIPs"},[env](GCList& ls, std::vector<TObject> args)->TObject{
|
||||
return Net_Http_HttpServer(ls,args,env);
|
||||
});
|
||||
http->DeclareFunction(gc, "ListenSimpleWithLoop", "Listen (creates application loop)", {"server","port"},Net_Http_ListenSimpleWithLoop);
|
||||
http->DeclareFunction(gc, "ListenOnUnusedPort","Listen on unused localhost port and print Port: theport",{"server"},Net_Http_ListenOnUnusedPort);
|
||||
//FileServer svr()
|
||||
|
||||
@@ -1,16 +1,189 @@
|
||||
#include "CrossLang.hpp"
|
||||
|
||||
#if defined(GEKKO) || defined(__SWITCH__)
|
||||
#undef CROSSLANG_ENABLE_PROCESS
|
||||
#endif
|
||||
|
||||
#if defined(CROSSLANG_ENABLE_PROCESS)
|
||||
#include "subprocess.h"
|
||||
#endif
|
||||
|
||||
namespace Tesses::CrossLang
|
||||
{
|
||||
#if defined(CROSSLANG_ENABLE_PROCESS)
|
||||
class ProcessObject : public TNativeObject {
|
||||
public:
|
||||
ProcessObject()
|
||||
{
|
||||
arguments=nullptr;
|
||||
environment=nullptr;
|
||||
|
||||
}
|
||||
ProcessObject(GCList& ls)
|
||||
{
|
||||
arguments = TList::Create(ls);
|
||||
environment = TList::Create(ls);
|
||||
process.includeThisEnv=true;
|
||||
process.redirectStdIn=false;
|
||||
|
||||
process.redirectStdOut=false;
|
||||
|
||||
process.redirectStdErr=false;
|
||||
}
|
||||
TList* arguments;
|
||||
TList* environment;
|
||||
Tesses::Framework::Platform::Process process;
|
||||
std::string TypeName()
|
||||
{
|
||||
return "Process";
|
||||
}
|
||||
void Mark()
|
||||
{
|
||||
if(this->marked) return;
|
||||
this->marked=true;
|
||||
if(arguments != nullptr) arguments->Mark();
|
||||
if(environment != nullptr) environment->Mark();
|
||||
}
|
||||
TObject CallMethod(GCList& ls, std::string key, std::vector<TObject> args)
|
||||
{
|
||||
if(key == "setFileName" && GetArgument(args,0,process.name))
|
||||
{
|
||||
return process.name;
|
||||
}
|
||||
if(key == "getFileName")
|
||||
{
|
||||
return process.name;
|
||||
}
|
||||
|
||||
if(key == "setRedirectStandardInput" && GetArgument(args,0,process.redirectStdIn))
|
||||
{
|
||||
return process.redirectStdIn;
|
||||
}
|
||||
if(key == "getRedirectStandardInput")
|
||||
{
|
||||
return process.redirectStdIn;
|
||||
}
|
||||
if(key == "setRedirectStandardOutput" && GetArgument(args,0,process.redirectStdOut))
|
||||
{
|
||||
return process.redirectStdOut;
|
||||
}
|
||||
if(key == "getRedirectStandardOutput")
|
||||
{
|
||||
return process.redirectStdOut;
|
||||
}
|
||||
if(key == "setRedirectStandardError" && GetArgument(args,0,process.redirectStdErr))
|
||||
{
|
||||
return process.redirectStdErr;
|
||||
}
|
||||
if(key == "getRedirectStandardError")
|
||||
{
|
||||
return process.redirectStdErr;
|
||||
}
|
||||
if(key == "setWorkingDirectory" && GetArgument(args,0,process.workingDirectory))
|
||||
{
|
||||
return process.workingDirectory;
|
||||
}
|
||||
if(key == "getWorkingDirectory")
|
||||
{
|
||||
return process.workingDirectory;
|
||||
}
|
||||
if(key == "setInheritParentEnvironment" && GetArgument(args,0,process.includeThisEnv))
|
||||
{
|
||||
return process.includeThisEnv;
|
||||
}
|
||||
if(key == "getInheritParentEnvironment")
|
||||
{
|
||||
return process.includeThisEnv;
|
||||
}
|
||||
if(key == "getArguments")
|
||||
{
|
||||
if(arguments == nullptr) return nullptr;
|
||||
return arguments;
|
||||
}
|
||||
if(key == "setArguments")
|
||||
{
|
||||
if(GetArgumentHeap(args,0,arguments))
|
||||
{
|
||||
return arguments;
|
||||
}
|
||||
}
|
||||
if(key == "getEnvironment")
|
||||
{
|
||||
if(environment == nullptr) return nullptr;
|
||||
return environment;
|
||||
}
|
||||
if(key == "getEnvironment")
|
||||
{
|
||||
if(GetArgumentHeap(args,0,environment))
|
||||
{
|
||||
return environment;
|
||||
}
|
||||
}
|
||||
if(key == "Start")
|
||||
{
|
||||
this->process.args.push_back(process.name);
|
||||
if(arguments != nullptr)
|
||||
{
|
||||
for(int64_t i = 0; i < arguments->Count(); i++)
|
||||
{
|
||||
TObject argVal;
|
||||
std::string argValStr;
|
||||
if(GetObject(argVal,argValStr))
|
||||
this->process.args.push_back(argValStr);
|
||||
}
|
||||
}
|
||||
if(environment != nullptr)
|
||||
{
|
||||
for(int64_t i = 0; i < environment->Count(); i++)
|
||||
{
|
||||
TObject arg = environment->Get(i);
|
||||
std::string argstr;
|
||||
if(GetObject(arg,argstr))
|
||||
{
|
||||
auto kvp = Tesses::Framework::Http::HttpUtils::SplitString(argstr,"=",2);
|
||||
if(kvp.size()==2)
|
||||
{
|
||||
process.env.push_back(std::pair<std::string,std::string>(kvp[0],kvp[1]));
|
||||
}
|
||||
else if(kvp.size()==1)
|
||||
{
|
||||
process.env.push_back(std::pair<std::string,std::string>(kvp[0],""));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return process.Start();
|
||||
}
|
||||
if(key == "Join" || key == "WaitForExit")
|
||||
{
|
||||
return (int64_t)process.WaitForExit();
|
||||
}
|
||||
if(key == "getHasExited")
|
||||
{
|
||||
return process.HasExited();
|
||||
}
|
||||
if(key == "Terminate")
|
||||
{
|
||||
process.Kill(SIGTERM);
|
||||
}
|
||||
if(key == "CloseStdInNow")
|
||||
{
|
||||
process.CloseStdInNow();
|
||||
|
||||
}
|
||||
int64_t k;
|
||||
if(key == "Kill" && GetArgument(args,0,k))
|
||||
{
|
||||
process.Kill((int)k);
|
||||
}
|
||||
if(key == "getStandardInput")
|
||||
{
|
||||
return TStreamHeapObject::Create(ls,process.GetStdinStream());
|
||||
}
|
||||
if(key == "getStandardOutput")
|
||||
{
|
||||
return TStreamHeapObject::Create(ls,process.GetStdoutStream());
|
||||
}
|
||||
if(key == "getStandardError")
|
||||
{
|
||||
return TStreamHeapObject::Create(ls,process.GetStderrStream());
|
||||
}
|
||||
return Undefined();
|
||||
}
|
||||
};
|
||||
static TObject Process_Start(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
|
||||
@@ -23,142 +196,88 @@ namespace Tesses::CrossLang
|
||||
|
||||
TDictionary* dict;
|
||||
|
||||
if(GetArgumentHeap(args, 0, dict))
|
||||
if(GetArgumentHeap(args,0,dict))
|
||||
{
|
||||
auto gc = ls.GetGC();
|
||||
gc->BarrierBegin();
|
||||
auto process = TNativeObject::Create<ProcessObject>(ls);
|
||||
auto name = dict->GetValue("FileName");
|
||||
auto inh = dict->GetValue("InheritParentEnvironment");
|
||||
auto rStdIn = dict->GetValue("RedirectStandardInput");
|
||||
auto rStdOut = dict->GetValue("RedirectStandardOutput");
|
||||
|
||||
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
|
||||
auto rStdErr = dict->GetValue("RedirectStandardError");
|
||||
auto workingDirectory = dict->GetValue("WorkingDirectory");
|
||||
process->process.includeThisEnv=true;
|
||||
process->process.redirectStdIn=false;
|
||||
|
||||
std::string filename;
|
||||
TList* _args;
|
||||
TList* env0;
|
||||
std::vector<std::string> _args2;
|
||||
std::vector<std::string> _env;
|
||||
int64_t options;
|
||||
process->process.redirectStdOut=false;
|
||||
|
||||
bool hasEnv=false;
|
||||
process->process.redirectStdErr=false;
|
||||
GetObject(inh,process->process.includeThisEnv);
|
||||
GetObject(rStdIn,process->process.redirectStdIn);
|
||||
GetObject(rStdOut,process->process.redirectStdOut);
|
||||
GetObject(rStdErr,process->process.redirectStdErr);
|
||||
|
||||
GetObject(name,process->process.name);
|
||||
|
||||
if(!GetObject(fobj,filename))
|
||||
Tesses::Framework::Filesystem::VFSPath wdPath;
|
||||
|
||||
if(GetObject(workingDirectory,wdPath))
|
||||
{
|
||||
gc->BarrierEnd();
|
||||
return nullptr;
|
||||
process->process.workingDirectory= wdPath.MakeAbsolute().ToString();
|
||||
}
|
||||
_args2.push_back(filename);
|
||||
if(GetObjectHeap(myargs,_args))
|
||||
|
||||
GetObject(workingDirectory,process->process.workingDirectory);
|
||||
|
||||
|
||||
|
||||
process->process.args.push_back(process->process.name);
|
||||
auto argumentsO = dict->GetValue("Arguments");
|
||||
TList* arguments;
|
||||
if(GetObjectHeap(argumentsO,arguments))
|
||||
{
|
||||
for(auto a : _args->items)
|
||||
for(int64_t i = 0; i < arguments->Count(); i++)
|
||||
{
|
||||
std::string a2;
|
||||
if(GetObject(a,a2))
|
||||
TObject arg = arguments->Get(i);
|
||||
std::string argstr;
|
||||
if(GetObject(arg,argstr))
|
||||
{
|
||||
_args2.push_back(a2);
|
||||
process->process.args.push_back(argstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(GetObjectHeap(env,env0))
|
||||
argumentsO = dict->GetValue("Environment");
|
||||
if(GetObjectHeap(argumentsO,arguments))
|
||||
{
|
||||
hasEnv=true;
|
||||
for(auto a : env0->items)
|
||||
for(int64_t i = 0; i < arguments->Count(); i++)
|
||||
{
|
||||
std::string a2;
|
||||
if(GetObject(a,a2))
|
||||
TObject arg = arguments->Get(i);
|
||||
std::string argstr;
|
||||
if(GetObject(arg,argstr))
|
||||
{
|
||||
_env.push_back(a2);
|
||||
auto kvp = Tesses::Framework::Http::HttpUtils::SplitString(argstr,"=",2);
|
||||
if(kvp.size()==2)
|
||||
{
|
||||
process->process.env.push_back(std::pair<std::string,std::string>(kvp[0],kvp[1]));
|
||||
}
|
||||
else if(kvp.size()==1)
|
||||
{
|
||||
process->process.env.push_back(std::pair<std::string,std::string>(kvp[0],""));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if(process->process.Start())
|
||||
{
|
||||
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();
|
||||
struct subprocess_s* subprocess=new struct subprocess_s();
|
||||
int r = subprocess_create_ex(args3,(int)options,env3,subprocess);
|
||||
if(r != 0)
|
||||
{
|
||||
|
||||
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<TObject> 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<TObject> 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<TObject> 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<TObject> 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<TObject> 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<TObject> 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<TObject> 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 process;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
static TObject New_Process(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
return TNativeObject::Create<ProcessObject>(ls,ls);
|
||||
}
|
||||
|
||||
void TStd::RegisterProcess(GC* gc,TRootEnvironment* env)
|
||||
{
|
||||
@@ -166,11 +285,12 @@ namespace Tesses::CrossLang
|
||||
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);
|
||||
auto process = env->EnsureDictionary(gc,"New");
|
||||
process->DeclareFunction(gc, "Process", "Create process",{},New_Process);
|
||||
gc->BarrierEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1017,7 +1017,7 @@ namespace Tesses::CrossLang
|
||||
TTF_CloseFont(res);
|
||||
return res2;
|
||||
}
|
||||
else if(args.size() > 1 && !std::holds_alternative<nullptr_t>(args[1]))
|
||||
else if(args.size() > 1 && !std::holds_alternative<std::nullptr_t>(args[1]))
|
||||
{
|
||||
|
||||
auto res = TTF_OpenFontRW(Tesses::Framework::SDL2::RwopsFromStream(new TObjectStream(ls.GetGC(),args[1])),1,pt);
|
||||
|
||||
@@ -30,6 +30,331 @@
|
||||
|
||||
namespace Tesses::CrossLang
|
||||
{
|
||||
class DocumentationParser : public TNativeObject
|
||||
{
|
||||
public:
|
||||
|
||||
std::vector<std::pair<std::string,TObject>> items;
|
||||
DocumentationParser(std::string doc)
|
||||
{
|
||||
size_t i=0;
|
||||
int state=-1;
|
||||
std::string key={};
|
||||
std::string value={};
|
||||
|
||||
auto add = [&]()->void{
|
||||
if(value == "true") {
|
||||
items.push_back(std::pair<std::string,TObject>(key,true));
|
||||
} else if(value == "false") {
|
||||
items.push_back(std::pair<std::string,TObject>(key,true));
|
||||
} else if(value == "null") {
|
||||
items.push_back(std::pair<std::string,TObject>(key,nullptr));
|
||||
} else {
|
||||
if(value[0] >= '0' && value[0] <= '9')
|
||||
{
|
||||
try {
|
||||
if(value.find('.') != std::string::npos)
|
||||
{
|
||||
|
||||
items.push_back(std::pair<std::string,TObject>(key,std::stod(value)));
|
||||
}
|
||||
else {
|
||||
items.push_back(std::pair<std::string,TObject>(key,std::stoll(value)));
|
||||
}
|
||||
}catch(...) {}
|
||||
}
|
||||
else {
|
||||
items.push_back(std::pair<std::string,TObject>(key,value));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto ReadChr = [&]() -> std::pair<int,bool> {
|
||||
int read=i < doc.size() ? (int)doc[i++] : -1;
|
||||
|
||||
if(read == -1)
|
||||
{
|
||||
|
||||
return std::pair<int,bool>(-1,false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(read == '\\')
|
||||
{
|
||||
read = i < doc.size() ? (int)doc[i++] : -1;
|
||||
|
||||
if(read == -1)
|
||||
{
|
||||
return std::pair<int,bool>(-1,true);
|
||||
}
|
||||
else if(read == 'n')
|
||||
{
|
||||
return std::pair<int,bool>('\n',true);
|
||||
}
|
||||
else if(read == 'r')
|
||||
{
|
||||
return std::pair<int,bool>('\r',true);
|
||||
}
|
||||
else if(read == 'f')
|
||||
{
|
||||
return std::pair<int,bool>('\f',true);
|
||||
}
|
||||
else if(read == 'b')
|
||||
{
|
||||
return std::pair<int,bool>('\b',true);
|
||||
}
|
||||
else if(read == 'a')
|
||||
{
|
||||
return std::pair<int,bool>('\a',true);
|
||||
}
|
||||
else if(read == '0')
|
||||
{
|
||||
return std::pair<int,bool>('\0',true);
|
||||
}
|
||||
else if(read == 'v')
|
||||
{
|
||||
return std::pair<int,bool>('\v',true);
|
||||
}
|
||||
else if(read == 'e')
|
||||
{
|
||||
return std::pair<int,bool>('\x1B',true);
|
||||
}
|
||||
else if(read == 't')
|
||||
{
|
||||
return std::pair<int,bool>('\t',true);
|
||||
}
|
||||
else if(read == 'x')
|
||||
{
|
||||
int r1 = i < doc.size() ? (int)doc[i++] : -1;
|
||||
|
||||
if(r1 == -1)
|
||||
{
|
||||
return std::pair<int,bool>(-1,true);
|
||||
}
|
||||
int r2 = i < doc.size() ? (int)doc[i++] : -1;
|
||||
|
||||
if(r2 == -1)
|
||||
{
|
||||
return std::pair<int,bool>(-1,true);
|
||||
}
|
||||
|
||||
uint8_t c = (uint8_t)std::stoi(std::string{(char)r1,(char)r2},nullptr,16);
|
||||
|
||||
return std::pair<int,bool>(c,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::pair<int,bool>(read,true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::pair<int,bool>(read,false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
for(; i < doc.size(); i++)
|
||||
{
|
||||
if(doc[i] == '@')
|
||||
{
|
||||
state = 0;
|
||||
key={};
|
||||
value={};
|
||||
if(i + 1 < doc.size())
|
||||
{
|
||||
if(doc[i+1] == '@')
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
i++;
|
||||
for(; i < doc.size(); i++)
|
||||
{
|
||||
switch(doc[i])
|
||||
{
|
||||
case '\'':
|
||||
{
|
||||
i++;
|
||||
auto c = ReadChr();
|
||||
i++;
|
||||
if(c.first != -1)
|
||||
{
|
||||
if(state == 0)
|
||||
key+={(char)c.first};
|
||||
else {
|
||||
this->items.push_back(std::pair<std::string,TObject>(key,(char)c.first));
|
||||
state = -1;
|
||||
goto outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '\"':
|
||||
{
|
||||
if(state == 0)
|
||||
{
|
||||
i++;
|
||||
auto rChr = ReadChr();
|
||||
while(rChr.first != '\"' || rChr.second)
|
||||
{
|
||||
if(rChr.first == -1) break;
|
||||
key += (char)rChr.first;
|
||||
rChr = ReadChr();
|
||||
}
|
||||
i--;
|
||||
}
|
||||
else {
|
||||
i++;
|
||||
auto rChr = ReadChr();
|
||||
|
||||
while(rChr.first != '\"' || rChr.second)
|
||||
{
|
||||
if(rChr.first == -1) break;
|
||||
value += (char)rChr.first;
|
||||
rChr = ReadChr();
|
||||
}
|
||||
this->items.push_back(std::pair<std::string,TObject>(key,value));
|
||||
state = -1;
|
||||
goto outer;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
case '\n':
|
||||
case '\t':
|
||||
case '\r':
|
||||
if(state == 0 && !key.empty())
|
||||
state=1;
|
||||
else
|
||||
if(state == 1 && !value.empty())
|
||||
{
|
||||
add();
|
||||
state = -1;
|
||||
goto outer;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(state == 0) key += doc[i];
|
||||
else value += doc[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
outer:;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if(state == 1 && !value.empty())
|
||||
{
|
||||
add();
|
||||
}
|
||||
}
|
||||
TObject CallMethod(GCList& ls, std::string key, std::vector<TObject> args);
|
||||
std::string TypeName()
|
||||
{
|
||||
return "DocumentationParser";
|
||||
}
|
||||
};
|
||||
class DocumentationParserEnumerator : public TEnumerator
|
||||
{
|
||||
int index;
|
||||
DocumentationParser* dict;
|
||||
public:
|
||||
static DocumentationParserEnumerator* Create(GCList& ls, DocumentationParser* dict)
|
||||
{
|
||||
auto dpe=new DocumentationParserEnumerator();
|
||||
auto gc = ls.GetGC();
|
||||
ls.Add(dpe);
|
||||
gc->Watch(dpe);
|
||||
dpe->dict = dict;
|
||||
dpe->index=-1;
|
||||
return dpe;
|
||||
}
|
||||
|
||||
bool MoveNext(GC* ls)
|
||||
{
|
||||
ls->BarrierBegin();
|
||||
bool r = ++index < this->dict->items.size();
|
||||
|
||||
ls->BarrierEnd();
|
||||
return r;
|
||||
}
|
||||
TObject GetCurrent(GCList& ls)
|
||||
{
|
||||
std::pair<std::string,TObject> item;
|
||||
ls.GetGC()->BarrierBegin();
|
||||
if(this->index > -1 && this->index < this->dict->items.size())
|
||||
{
|
||||
item = this->dict->items[(size_t)this->index];
|
||||
}
|
||||
ls.GetGC()->BarrierEnd();
|
||||
|
||||
return TDictionary::Create(ls,{
|
||||
TDItem("Key", item.first),
|
||||
TDItem("Value", item.second)
|
||||
});
|
||||
}
|
||||
void Mark()
|
||||
{
|
||||
if(this->marked) return;
|
||||
this->marked=true;
|
||||
dict->Mark();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TObject DocumentationParser::CallMethod(GCList& ls, std::string key, std::vector<TObject> args)
|
||||
{
|
||||
std::string myKey;
|
||||
if(key == "GetAt" && GetArgument(args,0,myKey))
|
||||
{
|
||||
for(auto item : this->items)
|
||||
if(item.first == myKey) return item.second;
|
||||
}
|
||||
if(key == "ToString")
|
||||
{
|
||||
std::string n={};
|
||||
for(auto item : this->items)
|
||||
{
|
||||
n.push_back('@');
|
||||
n.append(item.first);
|
||||
n.push_back(' ');
|
||||
std::string str;
|
||||
if(GetObject(item.second,str))
|
||||
{
|
||||
n.append(EscapeString(str,true));
|
||||
}
|
||||
else n.append(ToString(ls.GetGC(), item.second));
|
||||
n.push_back('\n');
|
||||
}
|
||||
return n;
|
||||
}
|
||||
if(key == "GetEnumerator")
|
||||
{
|
||||
return DocumentationParserEnumerator::Create(ls,this);
|
||||
}
|
||||
return Undefined();
|
||||
|
||||
}
|
||||
TObject New_DocumentationParser(GCList& ls, std::vector<TObject> args)
|
||||
{
|
||||
std::string doc;
|
||||
|
||||
if(GetArgument(args,0,doc))
|
||||
{
|
||||
return TNativeObject::Create<DocumentationParser>(ls, doc);
|
||||
}
|
||||
|
||||
return Undefined();
|
||||
}
|
||||
|
||||
|
||||
#if defined(CROSSLANG_ENABLE_SHARED)
|
||||
class DL {
|
||||
void* handle;
|
||||
@@ -1032,6 +1357,7 @@ namespace Tesses::CrossLang
|
||||
newTypes->DeclareFunction(gc,"AArray","alias for new AssociativeArray",{},[](GCList& ls, std::vector<TObject> args)->TObject {
|
||||
return TAssociativeArray::Create(ls);
|
||||
});
|
||||
newTypes->DeclareFunction(gc,"DocumentationParser","Parse documentation blocks",{"documentationString"},New_DocumentationParser);
|
||||
newTypes->DeclareFunction(gc,"ByteArray","Create bytearray, with optional either size (to size it) or string argument (to fill byte array)",{"$data"},ByteArray);
|
||||
|
||||
env->DeclareVariable("Version", TDictionary::Create(ls,{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user