Add reflective variables and fields

This commit is contained in:
2025-05-17 18:28:19 -05:00
parent a684c9ba45
commit bb19d2444c
8 changed files with 451 additions and 27 deletions

View File

@ -1945,7 +1945,15 @@ class GC {
TObject GetAt(GCList& ls, int64_t index); TObject GetAt(GCList& ls, int64_t index);
void SetAt(GCList& ls, int64_t index, TObject val); TObject SetAt(GCList& ls, int64_t index, TObject val);
TObject Add(GCList& ls, TObject v);
TObject Insert(GCList& ls, int64_t index, TObject v);
TObject RemoveAllEqual(GCList& ls, TObject v);
TObject Remove(GCList& ls, TObject v);
TObject RemoveAt(GCList& ls, int64_t v);
TObject Clear(GCList& ls);
TObject ToString(GCList& ls);
~TDynamicList(); ~TDynamicList();
}; };
@ -1961,7 +1969,7 @@ class GC {
TObject GetField(GCList& ls, std::string key); TObject GetField(GCList& ls, std::string key);
void SetField(GCList& ls, std::string key, TObject value); TObject SetField(GCList& ls, std::string key, TObject value);
TObject CallMethod(GCList& ls, std::string name, std::vector<TObject> args); TObject CallMethod(GCList& ls, std::string name, std::vector<TObject> args);

View File

@ -1021,16 +1021,16 @@ namespace Tesses::CrossLang
instructions.push_back(new JumpStyleInstruction(JMP,myJmp)); instructions.push_back(new JumpStyleInstruction(JMP,myJmp));
} }
} }
else if(adv.nodeName == GetVariableExpression && adv.nodes.size() == 1 && std::holds_alternative<std::string>(adv.nodes[0])) else if(adv.nodeName == GetVariableExpression && adv.nodes.size() == 1)
{ {
instructions.push_back(new StringInstruction(GetString(std::get<std::string>(adv.nodes[0])))); GenNode(instructions,adv.nodes[0],scope,contscope,brkscope,contI,brkI);
instructions.push_back(new SimpleInstruction(GETVARIABLE)); instructions.push_back(new SimpleInstruction(GETVARIABLE));
} }
else if(adv.nodeName == GetFieldExpression && adv.nodes.size() == 2 && std::holds_alternative<std::string>(adv.nodes[1])) else if(adv.nodeName == GetFieldExpression && adv.nodes.size() == 2)
{ {
GenNode(instructions,adv.nodes[0],scope,contscope,brkscope,contI,brkI); GenNode(instructions,adv.nodes[0],scope,contscope,brkscope,contI,brkI);
instructions.push_back(new StringInstruction(GetString(std::get<std::string>(adv.nodes[1])))); GenNode(instructions,adv.nodes[1],scope,contscope,brkscope,contI,brkI);
instructions.push_back(new SimpleInstruction(GETFIELD)); instructions.push_back(new SimpleInstruction(GETFIELD));
@ -1047,9 +1047,9 @@ namespace Tesses::CrossLang
{ {
auto varNode = std::get<AdvancedSyntaxNode>(adv.nodes[0]); auto varNode = std::get<AdvancedSyntaxNode>(adv.nodes[0]);
if(varNode.nodeName == GetVariableExpression && varNode.nodes.size() == 1 && std::holds_alternative<std::string>(varNode.nodes[0])) if(varNode.nodeName == GetVariableExpression && varNode.nodes.size() == 1)
{ {
instructions.push_back(new StringInstruction(GetString(std::get<std::string>(varNode.nodes[0])))); GenNode(instructions,varNode.nodes[0],scope,contscope,brkscope,contI,brkI);
GenNode(instructions,adv.nodes[1],scope,contscope,brkscope,contI,brkI); GenNode(instructions,adv.nodes[1],scope,contscope,brkscope,contI,brkI);
instructions.push_back(new SimpleInstruction(SETVARIABLE)); instructions.push_back(new SimpleInstruction(SETVARIABLE));
} }
@ -1067,7 +1067,7 @@ namespace Tesses::CrossLang
} }
else if(varNode.nodeName == DeclareExpression && varNode.nodes.size() == 1 && std::holds_alternative<std::string>(varNode.nodes[0])) else if(varNode.nodeName == DeclareExpression && varNode.nodes.size() == 1 && std::holds_alternative<std::string>(varNode.nodes[0]))
{ {
instructions.push_back(new StringInstruction(GetString(std::get<std::string>(varNode.nodes[0])))); GenNode(instructions,varNode.nodes[0],scope,contscope,brkscope,contI,brkI);
GenNode(instructions,adv.nodes[1],scope,contscope,brkscope,contI,brkI); GenNode(instructions,adv.nodes[1],scope,contscope,brkscope,contI,brkI);
instructions.push_back(new SimpleInstruction(DECLAREVARIABLE)); instructions.push_back(new SimpleInstruction(DECLAREVARIABLE));
} }
@ -1091,7 +1091,8 @@ namespace Tesses::CrossLang
else if(varNode.nodeName == GetFieldExpression && varNode.nodes.size() == 2 && std::holds_alternative<std::string>(varNode.nodes[1])) else if(varNode.nodeName == GetFieldExpression && varNode.nodes.size() == 2 && std::holds_alternative<std::string>(varNode.nodes[1]))
{ {
GenNode(instructions,varNode.nodes[0],scope,contscope,brkscope,contI,brkI); GenNode(instructions,varNode.nodes[0],scope,contscope,brkscope,contI,brkI);
instructions.push_back(new StringInstruction(GetString(std::get<std::string>(varNode.nodes[1]))));
GenNode(instructions,varNode.nodes[1],scope,contscope,brkscope,contI,brkI);
GenNode(instructions,adv.nodes[1],scope,contscope,brkscope,contI,brkI); GenNode(instructions,adv.nodes[1],scope,contscope,brkscope,contI,brkI);
instructions.push_back(new SimpleInstruction(SETFIELD)); instructions.push_back(new SimpleInstruction(SETFIELD));
} }
@ -1394,6 +1395,7 @@ namespace Tesses::CrossLang
{ {
name.push_back(GetString(std::get<std::string>(res.nodes[1]))); name.push_back(GetString(std::get<std::string>(res.nodes[1])));
} }
} }
else if(res.nodeName == GetVariableExpression && res.nodes.size() == 1) else if(res.nodeName == GetVariableExpression && res.nodes.size() == 1)
{ {

View File

@ -547,6 +547,20 @@ namespace Tesses::CrossLang
i++; i++;
} }
else if(tokens[i].type == LexTokenType::Symbol && tokens[i].text == ".")
{
i++;
if(IsSymbol("["))
{
node = AdvancedSyntaxNode::Create(GetVariableExpression,true,{ParseExpression()});
EnsureSymbol("]");
}
else
{
node = AdvancedSyntaxNode::Create(RelativePathExpression, true, {});
}
}
else if(IsSymbol("<")) else if(IsSymbol("<"))
{ {
uint32_t htmlId = NewId(); uint32_t htmlId = NewId();
@ -590,7 +604,15 @@ namespace Tesses::CrossLang
auto variable = tokens[i]; auto variable = tokens[i];
i++; i++;
if(variable.type == LexTokenType::Symbol && variable.text == "[") if(variable.type == LexTokenType::Symbol && variable.text == ".")
{
EnsureSymbol("[");
node = AdvancedSyntaxNode::Create(DeclareExpression,true,{
AdvancedSyntaxNode::Create(GetVariableExpression ,true,{ParseExpression()})
});
EnsureSymbol("]");
}
else if(variable.type == LexTokenType::Symbol && variable.text == "[")
{ {
node = AdvancedSyntaxNode::Create(DeclareExpression,true,{ node = AdvancedSyntaxNode::Create(DeclareExpression,true,{
AdvancedSyntaxNode::Create(ArrayExpression ,true,{ParseExpression()}) AdvancedSyntaxNode::Create(ArrayExpression ,true,{ParseExpression()})
@ -725,6 +747,13 @@ namespace Tesses::CrossLang
if(tkn.text == ".") if(tkn.text == ".")
{ {
if(i>=tokens.size()) throw std::out_of_range("End of file"); if(i>=tokens.size()) throw std::out_of_range("End of file");
if(IsSymbol("["))
{
node = AdvancedSyntaxNode::Create(GetFieldExpression, true, {node, ParseExpression()});
EnsureSymbol("]");
continue;
}
if(tokens[i].type != LexTokenType::Identifier) throw std::exception(); if(tokens[i].type != LexTokenType::Identifier) throw std::exception();
std::string name = tokens[i].text; std::string name = tokens[i].text;
if(name == "operator") if(name == "operator")
@ -807,10 +836,7 @@ namespace Tesses::CrossLang
return AdvancedSyntaxNode::Create(RootPathExpression,true,{}); return AdvancedSyntaxNode::Create(RootPathExpression,true,{});
} }
} }
else if(IsSymbol("."))
{
return AdvancedSyntaxNode::Create(RelativePathExpression, true, {});
}
return ParseValue(); return ParseValue();
} }

View File

@ -311,7 +311,7 @@ namespace Tesses::CrossLang
{ {
ctx->StartWebSocketSession([dict,&ls](std::function<void(WebSocketMessage&)> sendMessage,std::function<void()> ping)->void{ ctx->StartWebSocketSession([dict,&ls](std::function<void(WebSocketMessage&)> sendMessage,std::function<void()> ping,std::function<void()> close)->void{
GCList ls2(ls.GetGC()); GCList ls2(ls.GetGC());
dict->CallMethod(ls2,"Open",{ dict->CallMethod(ls2,"Open",{
TExternalMethod::Create(ls2,"Send a message",{"messageTextOrByteArray"},[sendMessage](GCList& ls,std::vector<TObject> args)->TObject{ TExternalMethod::Create(ls2,"Send a message",{"messageTextOrByteArray"},[sendMessage](GCList& ls,std::vector<TObject> args)->TObject{
@ -332,6 +332,10 @@ namespace Tesses::CrossLang
TExternalMethod::Create(ls2, "Ping client", {},[ping](GCList& ls,std::vector<TObject> args)->TObject { TExternalMethod::Create(ls2, "Ping client", {},[ping](GCList& ls,std::vector<TObject> args)->TObject {
ping(); ping();
return nullptr; return nullptr;
}),
TExternalMethod::Create(ls2, "Close client",{},[close](GCList& ls,std::vector<TObject> args)->TObject {
close();
return nullptr;
}) })
}); });
}, [dict,&ls](WebSocketMessage& msg)->void { }, [dict,&ls](WebSocketMessage& msg)->void {
@ -358,6 +362,8 @@ namespace Tesses::CrossLang
} }
return nullptr; return nullptr;
}); });
//dict->DeclareFunction(gc,"getOriginalPathWithQuery","Get original path with query parameters",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {return ctx->GetOriginalPathWithQuery();}); //dict->DeclareFunction(gc,"getOriginalPathWithQuery","Get original path with query parameters",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {return ctx->GetOriginalPathWithQuery();});
dict->DeclareFunction(gc,"getPath","Get path",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {return ctx->path;}); dict->DeclareFunction(gc,"getPath","Get path",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {return ctx->path;});
@ -696,7 +702,7 @@ namespace Tesses::CrossLang
return nullptr; return nullptr;
} }
static TObject Net_Smtp_Send(GCList& ls, std::vector<TObject> args) static TObject Net_Smtp_Send(GCList& ls, std::vector<TObject> args)
{ {
TDictionary* dict; TDictionary* dict;
@ -833,7 +839,119 @@ namespace Tesses::CrossLang
} }
return nullptr; return nullptr;
} }
static TObject Net_Http_WebSocketClient(GCList& ls, std::vector<TObject> args)
{
std::string url;
TList* headers;
TDictionary* dict;
TCallable* callable=nullptr;
TObject _obj;
if(GetArgument(args,0,url) && GetArgumentHeap(args,1,headers) && GetArgumentHeap(args,2,dict))
{
GetArgumentHeap(args,3,callable);
HttpDictionary hdict;
for(int64_t index = 0; index < headers->Count();index ++)
{
_obj = headers->Get(index);
TDictionary* dict;
if(GetObjectHeap(_obj,dict))
{
std::string key={};
std::string value={};
_obj = dict->GetValue("Key");
GetObject(_obj,key);
_obj = dict->GetValue("Value");
hdict.AddValue(key,value);
}
}
CallbackWebSocketConnection conn([dict,&ls](std::function<void(WebSocketMessage&)> sendMessage,std::function<void()> ping,std::function<void()> close)->void{
GCList ls2(ls.GetGC());
dict->CallMethod(ls2,"Open",{
TExternalMethod::Create(ls2,"Send a message",{"messageTextOrByteArray"},[sendMessage](GCList& ls,std::vector<TObject> args)->TObject{
std::string str;
TByteArray* bArray;
if(GetArgument(args,0,str))
{
WebSocketMessage msg(str);
sendMessage(msg);
}
else if(GetArgumentHeap(args,0,bArray))
{
WebSocketMessage msg(bArray->data);
sendMessage(msg);
}
return nullptr;
}),
TExternalMethod::Create(ls2, "Ping client", {},[ping](GCList& ls,std::vector<TObject> args)->TObject {
ping();
return nullptr;
}),
TExternalMethod::Create(ls2, "Close client",{},[close](GCList& ls,std::vector<TObject> args)->TObject {
close();
return nullptr;
})
});
}, [dict,&ls](WebSocketMessage& msg)->void {
GCList ls2(ls.GetGC());
TObject v;
if(msg.isBinary)
{
auto r = TByteArray::Create(ls2);
r->data = msg.data;
v = r;
}
else
{
v = msg.ToString();
}
dict->CallMethod(ls2,"Receive",{v});
}, [dict,&ls](bool close)->void {
GCList ls2(ls.GetGC());
dict->CallMethod(ls2,"Close",{close});
});
WebSocketClient(url, hdict, conn, [&ls,callable](Tesses::Framework::Http::HttpDictionary& dict, bool success)->bool {
if(callable != nullptr)
return ToBool(callable->Call(ls,{CreateDictionaryFromHttpDictionary(ls,&dict),success}));
return true;
});
}
return nullptr;
//Net.Http.CreateWebSocketConnection("wss://example.com/",[],conn, (dict, success)=>{ return true;})
}
static TObject Net_Http_DownloadToString(GCList& ls, std::vector<TObject> args)
{
std::string url;
if(GetArgument(args,0,url))
return DownloadToStringSimple(url);
return nullptr;
}
static TObject Net_Http_DownloadToStream(GCList& ls, std::vector<TObject> args)
{
std::string url;
TStreamHeapObject* strm;
if(GetArgument(args,0,url) && GetArgumentHeap(args,1,strm))
{
DownloadToStreamSimple(url,strm->stream);
}
return nullptr;
}
static TObject Net_Http_DownloadToFile(GCList& ls, std::vector<TObject> args)
{
std::string url;
TVFSHeapObject* vfs;
Tesses::Framework::Filesystem::VFSPath path;
if(GetArgument(args,0,url) && GetArgumentHeap(args,1,vfs) && GetArgumentAsPath(args,2, path))
{
DownloadToFileSimple(url,vfs->vfs,path);
}
return nullptr;
}
void TStd::RegisterNet(GC* gc, TRootEnvironment* env) void TStd::RegisterNet(GC* gc, TRootEnvironment* env)
{ {
@ -877,6 +995,10 @@ namespace Tesses::CrossLang
return nullptr; return nullptr;
}); });
http->DeclareFunction(gc, "MakeRequest", "Create an http request", {"url","$extra"}, Net_Http_MakeRequest); http->DeclareFunction(gc, "MakeRequest", "Create an http request", {"url","$extra"}, Net_Http_MakeRequest);
http->DeclareFunction(gc, "WebSocketClient", "Create a websocket connection",{"url","headers","conn","$successCB"},Net_Http_WebSocketClient);
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, "ListenSimpleWithLoop", "Listen (creates application loop)", {"server","port"},Net_Http_ListenSimpleWithLoop); 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); http->DeclareFunction(gc, "ListenOnUnusedPort","Listen on unused localhost port and print Port: theport",{"server"},Net_Http_ListenOnUnusedPort);
//FileServer svr() //FileServer svr()

View File

@ -628,6 +628,18 @@ namespace Tesses::CrossLang
} }
return Undefined(); return Undefined();
}); });
newTypes->DeclareFunction(gc,"DynamicList","Create a dynamic list",{},[](GCList& ls,std::vector<TObject> args)->TObject {
TCallable* callable;
if(GetArgumentHeap(args,0,callable))
return TDynamicList::Create(ls,callable);
return nullptr;
});
newTypes->DeclareFunction(gc,"DynamicDictionary","Create a dynamic dictionary",{},[](GCList& ls, std::vector<TObject> args)->TObject {
TCallable* callable;
if(GetArgumentHeap(args,0,callable))
return TDynamicDictionary::Create(ls,callable);
return nullptr;
});
newTypes->DeclareFunction(gc,"ByteArray","Create bytearray, with optional either size (to size it) or string argument (to fill byte array)",{"$data"},ByteArray); newTypes->DeclareFunction(gc,"ByteArray","Create bytearray, with optional either size (to size it) or string argument (to fill byte array)",{"$data"},ByteArray);
gc->BarrierBegin(); gc->BarrierBegin();
env->DeclareVariable("Version", TDictionary::Create(ls,{ env->DeclareVariable("Version", TDictionary::Create(ls,{

View File

@ -35,10 +35,10 @@ namespace Tesses::CrossLang {
dict->SetValue("Type", "GetField"); dict->SetValue("Type", "GetField");
dict->SetValue("Key", key); dict->SetValue("Key", key);
ls.GetGC()->BarrierEnd(); ls.GetGC()->BarrierEnd();
return cb->Call(ls,{dict}); return this->cb->Call(ls,{dict});
} }
void TDynamicDictionary::SetField(GCList& ls, std::string key, TObject value) TObject TDynamicDictionary::SetField(GCList& ls, std::string key, TObject value)
{ {
auto dict = TDictionary::Create(ls); auto dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin(); ls.GetGC()->BarrierBegin();
@ -46,7 +46,7 @@ namespace Tesses::CrossLang {
dict->SetValue("Key", key); dict->SetValue("Key", key);
dict->SetValue("Value", value); dict->SetValue("Value", value);
ls.GetGC()->BarrierEnd(); ls.GetGC()->BarrierEnd();
cb->Call(ls,{dict}); return this->cb->Call(ls,{dict});
} }
TObject TDynamicDictionary::CallMethod(GCList& ls, std::string name, std::vector<TObject> args) TObject TDynamicDictionary::CallMethod(GCList& ls, std::string name, std::vector<TObject> args)
@ -59,7 +59,7 @@ namespace Tesses::CrossLang {
argVal->items = args; argVal->items = args;
dict->SetValue("Arguments", argVal); dict->SetValue("Arguments", argVal);
ls.GetGC()->BarrierEnd(); ls.GetGC()->BarrierEnd();
return cb->Call(ls,{dict}); return this->cb->Call(ls,{dict});
} }
TEnumerator* TDynamicDictionary::GetEnumerator(GCList& ls) TEnumerator* TDynamicDictionary::GetEnumerator(GCList& ls)
@ -70,7 +70,7 @@ namespace Tesses::CrossLang {
ls.GetGC()->BarrierEnd(); ls.GetGC()->BarrierEnd();
return TEnumerator::CreateFromObject(ls,cb->Call(ls,{dict})); return TEnumerator::CreateFromObject(ls,this->cb->Call(ls,{dict}));
} }
bool TDictionary::MethodExists(GCList& ls,std::string method) bool TDictionary::MethodExists(GCList& ls,std::string method)
{ {
@ -90,7 +90,7 @@ namespace Tesses::CrossLang {
ls.GetGC()->BarrierEnd(); ls.GetGC()->BarrierEnd();
auto res = cb->Call(ls,{dict}); auto res = this->cb->Call(ls,{dict});
bool r2; bool r2;
if(GetObject(res,r2)) return r2; if(GetObject(res,r2)) return r2;
return false; return false;

View File

@ -38,6 +38,76 @@ namespace Tesses::CrossLang {
if(GetObject(res,n)) return n; if(GetObject(res,n)) return n;
return 0; return 0;
} }
TObject TDynamicList::Add(GCList& ls, TObject v)
{
auto dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("Type", "Add");
dict->SetValue("Value",v);
ls.GetGC()->BarrierEnd();
return cb->Call(ls,{dict});
}
TObject TDynamicList::Insert(GCList& ls, int64_t index, TObject v)
{
auto dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("Type", "Insert");
dict->SetValue("Index",index);
dict->SetValue("Value",v);
ls.GetGC()->BarrierEnd();
return cb->Call(ls,{dict});
}
TObject TDynamicList::Clear(GCList& ls)
{
auto dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("Type", "Clear");
ls.GetGC()->BarrierEnd();
return cb->Call(ls,{dict});
}
TObject TDynamicList::Remove(GCList& ls, TObject obj)
{
auto dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("Type", "Remove");
dict->SetValue("Value", obj);
ls.GetGC()->BarrierEnd();
return cb->Call(ls,{dict});
}
TObject TDynamicList::RemoveAllEqual(GCList& ls, TObject obj)
{
auto dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("Type", "RemoveAllEqual");
dict->SetValue("Value", obj);
ls.GetGC()->BarrierEnd();
return cb->Call(ls,{dict});
}
TObject TDynamicList::RemoveAt(GCList& ls, int64_t index)
{
auto dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("Type", "RemoveAt");
dict->SetValue("Index", index);
ls.GetGC()->BarrierEnd();
return cb->Call(ls,{dict});
}
TObject TDynamicList::ToString(GCList& ls)
{
auto dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("Type", "ToString");
ls.GetGC()->BarrierEnd();
return cb->Call(ls,{dict});
}
TObject TDynamicList::GetAt(GCList& ls, int64_t index) TObject TDynamicList::GetAt(GCList& ls, int64_t index)
{ {
@ -50,7 +120,7 @@ namespace Tesses::CrossLang {
return cb->Call(ls,{dict}); return cb->Call(ls,{dict});
} }
void TDynamicList::SetAt(GCList& ls, int64_t index, TObject val) TObject TDynamicList::SetAt(GCList& ls, int64_t index, TObject val)
{ {
auto dict = TDictionary::Create(ls); auto dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin(); ls.GetGC()->BarrierBegin();
@ -58,7 +128,7 @@ namespace Tesses::CrossLang {
dict->SetValue("Index",index); dict->SetValue("Index",index);
dict->SetValue("Value",val); dict->SetValue("Value",val);
ls.GetGC()->BarrierEnd(); ls.GetGC()->BarrierEnd();
cb->Call(ls,{dict}); return cb->Call(ls,{dict});
} }
TDynamicList::~TDynamicList() TDynamicList::~TDynamicList()

View File

@ -9,7 +9,7 @@
#include <variant> #include <variant>
namespace Tesses::CrossLang { namespace Tesses::CrossLang {
thread_local CallStackEntry* current_function=nullptr; thread_local CallStackEntry* current_function=nullptr;
bool ToBool(TObject obj) bool ToBool(TObject obj)
{ {
@ -2535,8 +2535,10 @@ namespace Tesses::CrossLang {
{ {
auto obj = std::get<THeapObjectHolder>(instance).obj; auto obj = std::get<THeapObjectHolder>(instance).obj;
auto list = dynamic_cast<TList*>(obj); auto list = dynamic_cast<TList*>(obj);
auto dynList = dynamic_cast<TDynamicList*>(obj);
auto bArray = dynamic_cast<TByteArray*>(obj); auto bArray = dynamic_cast<TByteArray*>(obj);
auto dict = dynamic_cast<TDictionary*>(obj); auto dict = dynamic_cast<TDictionary*>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
auto ittr = dynamic_cast<TEnumerator*>(obj); auto ittr = dynamic_cast<TEnumerator*>(obj);
auto strm = dynamic_cast<TStreamHeapObject*>(obj); auto strm = dynamic_cast<TStreamHeapObject*>(obj);
auto vfs = dynamic_cast<TVFSHeapObject*>(obj); auto vfs = dynamic_cast<TVFSHeapObject*>(obj);
@ -3996,6 +3998,139 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, Undefined()); cse.back()->Push(gc, Undefined());
return false; return false;
} }
else if(dynList != nullptr)
{
if(key == "GetEnumerator")
{
cse.back()->Push(gc, TDynamicListEnumerator::Create(ls, dynList));
return false;
}
else if(key == "ToString")
{
cse.back()->Push(gc, dynList->ToString(ls));
return false;
}
else if(key == "Insert")
{
if(args.size() != 2)
{
throw VMException("List.Insert must only accept two arguments");
}
int64_t index;
if(!GetArgument(args,0,index))
{
throw VMException("List.Insert first argument must be Long");
}
cse.back()->Push(gc, dynList->Insert(ls,index,args[0]));
return false;
}
if(key == "Add")
{
if(args.size() != 1)
{
throw VMException("List.Add must only accept one argument");
}
cse.back()->Push(gc,dynList->Add(ls,args[0]));
return false;
}
if(key == "RemoveAllEqual")
{
if(args.size() != 1)
{
throw VMException("List.RemoveAllEqual must only accept one argument");
}
cse.back()->Push(gc,dynList->RemoveAllEqual(ls, args[0]));
return false;
}
if(key == "Remove")
{
if(args.size() != 1)
{
throw VMException("List.Remove must only accept one argument");
}
cse.back()->Push(gc,dynList->Remove(ls, args[0]));
return false;
}
if(key == "RemoveAt")
{
if(args.size() != 1)
{
throw VMException("List.RemoveAt must only accept one argument");
}
if(!std::holds_alternative<int64_t>(args[0]))
{
throw VMException("List.RemoveAt must only accept a long");
}
cse.back()->Push(gc,dynList->RemoveAt(ls,std::get<int64_t>(args[0])));
return false;
}
if(key == "Clear")
{
cse.back()->Push(gc, dynList->Clear(ls));
return false;
}
if(key == "GetAt")
{
if(args.size() != 1)
{
throw VMException("List.GetAt must only accept one argument");
}
if(!std::holds_alternative<int64_t>(args[0]))
{
throw VMException("List.GetAt must only accept a long");
}
int64_t index = std::get<int64_t>(args[0]);
if(index >= 0)
{
cse.back()->Push(gc, dynList->GetAt(ls,index));
return false;
}
}
if(key == "SetAt")
{
if(args.size() != 2)
{
throw VMException("List.SetAt must only accept two arguments");
}
if(!std::holds_alternative<int64_t>(args[0]))
{
throw VMException("List.SetAt first argument must only accept a long");
}
int64_t index = std::get<int64_t>(args[0]);
if(index >= 0)
{
cse.back()->Push(gc,dynList->SetAt(ls,index,args[1]));
return false;
}
}
if(key == "Count" || key == "Length")
{
cse.back()->Push(gc, dynList->Count(ls));
return false;
}
cse.back()->Push(gc, Undefined());
return false;
}
else if(dict != nullptr) else if(dict != nullptr)
{ {
if(key == "ToString" && !dict->MethodExists(ls, key) && args.empty()) if(key == "ToString" && !dict->MethodExists(ls, key) && args.empty())
@ -4010,6 +4145,14 @@ namespace Tesses::CrossLang {
return InvokeMethod(ls,o,dict,args); return InvokeMethod(ls,o,dict,args);
} }
else if(dynDict != nullptr)
{
cse.back()->Push(gc,dict->CallMethod(ls, key, args));
return false;
}
else if(callable != nullptr) else if(callable != nullptr)
{ {
if(key == "Call") if(key == "Call")
@ -4237,6 +4380,8 @@ namespace Tesses::CrossLang {
auto bA = dynamic_cast<TByteArray*>(obj); auto bA = dynamic_cast<TByteArray*>(obj);
auto list = dynamic_cast<TList*>(obj); auto list = dynamic_cast<TList*>(obj);
auto dict = dynamic_cast<TDictionary*>(obj); auto dict = dynamic_cast<TDictionary*>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
auto dynList = dynamic_cast<TDynamicList*>(obj);
auto tcallable = dynamic_cast<TCallable*>(obj); auto tcallable = dynamic_cast<TCallable*>(obj);
auto closure = dynamic_cast<TClosure*>(obj); auto closure = dynamic_cast<TClosure*>(obj);
auto externalMethod = dynamic_cast<TExternalMethod*>(obj); auto externalMethod = dynamic_cast<TExternalMethod*>(obj);
@ -4246,6 +4391,7 @@ namespace Tesses::CrossLang {
auto callstackEntry = dynamic_cast<CallStackEntry*>(obj); auto callstackEntry = dynamic_cast<CallStackEntry*>(obj);
auto file = dynamic_cast<TFile*>(obj); auto file = dynamic_cast<TFile*>(obj);
auto chunk = dynamic_cast<TFileChunk*>(obj); auto chunk = dynamic_cast<TFileChunk*>(obj);
if(file != nullptr) if(file != nullptr)
{ {
@ -4538,6 +4684,29 @@ namespace Tesses::CrossLang {
return false; return false;
} }
} }
if(dynList != nullptr)
{
if(key == "Count" || key == "Length")
{
int64_t len = dynList->Count(ls);
if(len < 0) len = 0;
stk->Push(gc, len);
return false;
}
}
if(dynDict != nullptr)
{
if(dynDict->MethodExists(ls,"get" + key))
{
cse.back()->Push(gc,dynDict->CallMethod(ls,"get" + key, {}));
}
else
{
cse.back()->Push(gc, dynDict->GetField(ls,key));
}
return false;
}
if(dict != nullptr) if(dict != nullptr)
{ {
@ -4590,6 +4759,8 @@ namespace Tesses::CrossLang {
auto vfs = dynamic_cast<TVFSHeapObject*>(obj); auto vfs = dynamic_cast<TVFSHeapObject*>(obj);
auto strm = dynamic_cast<TStreamHeapObject*>(obj); auto strm = dynamic_cast<TStreamHeapObject*>(obj);
auto dict = dynamic_cast<TDictionary*>(obj); auto dict = dynamic_cast<TDictionary*>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
auto tcallable = dynamic_cast<TCallable*>(obj); auto tcallable = dynamic_cast<TCallable*>(obj);
if(tcallable != nullptr) if(tcallable != nullptr)
{ {
@ -4627,6 +4798,19 @@ namespace Tesses::CrossLang {
} }
} }
if(dynDict != nullptr)
{
if(dynDict->MethodExists(ls,"set" + key))
{
cse.back()->Push(gc,dynDict->CallMethod(ls,"set" + key, {value}));
}
else
{
dynDict->SetField(ls,key,value);
cse.back()->Push(gc,value);
}
return false;
}
if(dict != nullptr) if(dict != nullptr)
{ {
gc->BarrierBegin(); gc->BarrierBegin();