From bb19d2444c5f6791d85cdb2635cc2d92ceca0a0b Mon Sep 17 00:00:00 2001 From: Mike Nolan Date: Sat, 17 May 2025 18:28:19 -0500 Subject: [PATCH] Add reflective variables and fields --- include/CrossLang.hpp | 12 ++- src/compiler/codegen.cpp | 18 ++-- src/compiler/parser.cpp | 36 ++++++- src/runtime_methods/net.cpp | 128 ++++++++++++++++++++++++- src/runtime_methods/std.cpp | 12 +++ src/types/dictionary.cpp | 12 +-- src/types/list.cpp | 74 +++++++++++++- src/vm/vm.cpp | 186 +++++++++++++++++++++++++++++++++++- 8 files changed, 451 insertions(+), 27 deletions(-) diff --git a/include/CrossLang.hpp b/include/CrossLang.hpp index 73e9753..fa7961b 100644 --- a/include/CrossLang.hpp +++ b/include/CrossLang.hpp @@ -1945,7 +1945,15 @@ class GC { 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(); }; @@ -1961,7 +1969,7 @@ class GC { 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 args); diff --git a/src/compiler/codegen.cpp b/src/compiler/codegen.cpp index 669b7d5..677bea8 100644 --- a/src/compiler/codegen.cpp +++ b/src/compiler/codegen.cpp @@ -1021,16 +1021,16 @@ namespace Tesses::CrossLang instructions.push_back(new JumpStyleInstruction(JMP,myJmp)); } } - else if(adv.nodeName == GetVariableExpression && adv.nodes.size() == 1 && std::holds_alternative(adv.nodes[0])) + else if(adv.nodeName == GetVariableExpression && adv.nodes.size() == 1) { - instructions.push_back(new StringInstruction(GetString(std::get(adv.nodes[0])))); + GenNode(instructions,adv.nodes[0],scope,contscope,brkscope,contI,brkI); instructions.push_back(new SimpleInstruction(GETVARIABLE)); } - else if(adv.nodeName == GetFieldExpression && adv.nodes.size() == 2 && std::holds_alternative(adv.nodes[1])) + else if(adv.nodeName == GetFieldExpression && adv.nodes.size() == 2) { GenNode(instructions,adv.nodes[0],scope,contscope,brkscope,contI,brkI); - instructions.push_back(new StringInstruction(GetString(std::get(adv.nodes[1])))); + GenNode(instructions,adv.nodes[1],scope,contscope,brkscope,contI,brkI); instructions.push_back(new SimpleInstruction(GETFIELD)); @@ -1047,9 +1047,9 @@ namespace Tesses::CrossLang { auto varNode = std::get(adv.nodes[0]); - if(varNode.nodeName == GetVariableExpression && varNode.nodes.size() == 1 && std::holds_alternative(varNode.nodes[0])) + if(varNode.nodeName == GetVariableExpression && varNode.nodes.size() == 1) { - instructions.push_back(new StringInstruction(GetString(std::get(varNode.nodes[0])))); + GenNode(instructions,varNode.nodes[0],scope,contscope,brkscope,contI,brkI); GenNode(instructions,adv.nodes[1],scope,contscope,brkscope,contI,brkI); 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(varNode.nodes[0])) { - instructions.push_back(new StringInstruction(GetString(std::get(varNode.nodes[0])))); + GenNode(instructions,varNode.nodes[0],scope,contscope,brkscope,contI,brkI); GenNode(instructions,adv.nodes[1],scope,contscope,brkscope,contI,brkI); 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(varNode.nodes[1])) { GenNode(instructions,varNode.nodes[0],scope,contscope,brkscope,contI,brkI); - instructions.push_back(new StringInstruction(GetString(std::get(varNode.nodes[1])))); + + GenNode(instructions,varNode.nodes[1],scope,contscope,brkscope,contI,brkI); GenNode(instructions,adv.nodes[1],scope,contscope,brkscope,contI,brkI); instructions.push_back(new SimpleInstruction(SETFIELD)); } @@ -1394,6 +1395,7 @@ namespace Tesses::CrossLang { name.push_back(GetString(std::get(res.nodes[1]))); } + } else if(res.nodeName == GetVariableExpression && res.nodes.size() == 1) { diff --git a/src/compiler/parser.cpp b/src/compiler/parser.cpp index c71ee48..8c4dcb2 100644 --- a/src/compiler/parser.cpp +++ b/src/compiler/parser.cpp @@ -547,6 +547,20 @@ namespace Tesses::CrossLang 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("<")) { uint32_t htmlId = NewId(); @@ -590,7 +604,15 @@ namespace Tesses::CrossLang auto variable = tokens[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,{ AdvancedSyntaxNode::Create(ArrayExpression ,true,{ParseExpression()}) @@ -725,6 +747,13 @@ namespace Tesses::CrossLang if(tkn.text == ".") { 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(); std::string name = tokens[i].text; if(name == "operator") @@ -807,10 +836,7 @@ namespace Tesses::CrossLang return AdvancedSyntaxNode::Create(RootPathExpression,true,{}); } } - else if(IsSymbol(".")) - { - return AdvancedSyntaxNode::Create(RelativePathExpression, true, {}); - } + return ParseValue(); } diff --git a/src/runtime_methods/net.cpp b/src/runtime_methods/net.cpp index 33ff3fb..831ba65 100644 --- a/src/runtime_methods/net.cpp +++ b/src/runtime_methods/net.cpp @@ -311,7 +311,7 @@ namespace Tesses::CrossLang { - ctx->StartWebSocketSession([dict,&ls](std::function sendMessage,std::function ping)->void{ + ctx->StartWebSocketSession([dict,&ls](std::function sendMessage,std::function ping,std::function close)->void{ GCList ls2(ls.GetGC()); dict->CallMethod(ls2,"Open",{ TExternalMethod::Create(ls2,"Send a message",{"messageTextOrByteArray"},[sendMessage](GCList& ls,std::vector args)->TObject{ @@ -332,6 +332,10 @@ namespace Tesses::CrossLang TExternalMethod::Create(ls2, "Ping client", {},[ping](GCList& ls,std::vector args)->TObject { ping(); return nullptr; + }), + TExternalMethod::Create(ls2, "Close client",{},[close](GCList& ls,std::vector args)->TObject { + close(); + return nullptr; }) }); }, [dict,&ls](WebSocketMessage& msg)->void { @@ -358,6 +362,8 @@ namespace Tesses::CrossLang } return nullptr; }); + + //dict->DeclareFunction(gc,"getOriginalPathWithQuery","Get original path with query parameters",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector args2)->TObject {return ctx->GetOriginalPathWithQuery();}); dict->DeclareFunction(gc,"getPath","Get path",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector args2)->TObject {return ctx->path;}); @@ -696,7 +702,7 @@ namespace Tesses::CrossLang return nullptr; } - + static TObject Net_Smtp_Send(GCList& ls, std::vector args) { TDictionary* dict; @@ -833,7 +839,119 @@ namespace Tesses::CrossLang } return nullptr; } - + static TObject Net_Http_WebSocketClient(GCList& ls, std::vector 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 sendMessage,std::function ping,std::function close)->void{ + GCList ls2(ls.GetGC()); + dict->CallMethod(ls2,"Open",{ + TExternalMethod::Create(ls2,"Send a message",{"messageTextOrByteArray"},[sendMessage](GCList& ls,std::vector 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 args)->TObject { + ping(); + return nullptr; + }), + TExternalMethod::Create(ls2, "Close client",{},[close](GCList& ls,std::vector 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 args) + { + std::string url; + if(GetArgument(args,0,url)) + return DownloadToStringSimple(url); + return nullptr; + } + static TObject Net_Http_DownloadToStream(GCList& ls, std::vector 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 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) { @@ -877,6 +995,10 @@ namespace Tesses::CrossLang return nullptr; }); 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, "ListenOnUnusedPort","Listen on unused localhost port and print Port: theport",{"server"},Net_Http_ListenOnUnusedPort); //FileServer svr() diff --git a/src/runtime_methods/std.cpp b/src/runtime_methods/std.cpp index dd9f164..5ac07a9 100644 --- a/src/runtime_methods/std.cpp +++ b/src/runtime_methods/std.cpp @@ -628,6 +628,18 @@ namespace Tesses::CrossLang } return Undefined(); }); + newTypes->DeclareFunction(gc,"DynamicList","Create a dynamic list",{},[](GCList& ls,std::vector 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 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); gc->BarrierBegin(); env->DeclareVariable("Version", TDictionary::Create(ls,{ diff --git a/src/types/dictionary.cpp b/src/types/dictionary.cpp index b520f6c..cc671b1 100644 --- a/src/types/dictionary.cpp +++ b/src/types/dictionary.cpp @@ -35,10 +35,10 @@ namespace Tesses::CrossLang { dict->SetValue("Type", "GetField"); dict->SetValue("Key", key); 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); ls.GetGC()->BarrierBegin(); @@ -46,7 +46,7 @@ namespace Tesses::CrossLang { dict->SetValue("Key", key); dict->SetValue("Value", value); ls.GetGC()->BarrierEnd(); - cb->Call(ls,{dict}); + return this->cb->Call(ls,{dict}); } TObject TDynamicDictionary::CallMethod(GCList& ls, std::string name, std::vector args) @@ -59,7 +59,7 @@ namespace Tesses::CrossLang { argVal->items = args; dict->SetValue("Arguments", argVal); ls.GetGC()->BarrierEnd(); - return cb->Call(ls,{dict}); + return this->cb->Call(ls,{dict}); } TEnumerator* TDynamicDictionary::GetEnumerator(GCList& ls) @@ -70,7 +70,7 @@ namespace Tesses::CrossLang { 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) { @@ -90,7 +90,7 @@ namespace Tesses::CrossLang { ls.GetGC()->BarrierEnd(); - auto res = cb->Call(ls,{dict}); + auto res = this->cb->Call(ls,{dict}); bool r2; if(GetObject(res,r2)) return r2; return false; diff --git a/src/types/list.cpp b/src/types/list.cpp index 1aa6d9c..c7d11d5 100644 --- a/src/types/list.cpp +++ b/src/types/list.cpp @@ -38,6 +38,76 @@ namespace Tesses::CrossLang { if(GetObject(res,n)) return n; 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) { @@ -50,7 +120,7 @@ namespace Tesses::CrossLang { 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); ls.GetGC()->BarrierBegin(); @@ -58,7 +128,7 @@ namespace Tesses::CrossLang { dict->SetValue("Index",index); dict->SetValue("Value",val); ls.GetGC()->BarrierEnd(); - cb->Call(ls,{dict}); + return cb->Call(ls,{dict}); } TDynamicList::~TDynamicList() diff --git a/src/vm/vm.cpp b/src/vm/vm.cpp index bc8693e..f3358d8 100644 --- a/src/vm/vm.cpp +++ b/src/vm/vm.cpp @@ -9,7 +9,7 @@ #include namespace Tesses::CrossLang { - thread_local CallStackEntry* current_function=nullptr; + thread_local CallStackEntry* current_function=nullptr; bool ToBool(TObject obj) { @@ -2535,8 +2535,10 @@ namespace Tesses::CrossLang { { auto obj = std::get(instance).obj; auto list = dynamic_cast(obj); + auto dynList = dynamic_cast(obj); auto bArray = dynamic_cast(obj); auto dict = dynamic_cast(obj); + auto dynDict = dynamic_cast(obj); auto ittr = dynamic_cast(obj); auto strm = dynamic_cast(obj); auto vfs = dynamic_cast(obj); @@ -3996,6 +3998,139 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, Undefined()); 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(args[0])) + { + throw VMException("List.RemoveAt must only accept a long"); + } + cse.back()->Push(gc,dynList->RemoveAt(ls,std::get(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(args[0])) + { + throw VMException("List.GetAt must only accept a long"); + } + + int64_t index = std::get(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(args[0])) + { + throw VMException("List.SetAt first argument must only accept a long"); + } + + int64_t index = std::get(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) { if(key == "ToString" && !dict->MethodExists(ls, key) && args.empty()) @@ -4010,6 +4145,14 @@ namespace Tesses::CrossLang { 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) { if(key == "Call") @@ -4237,6 +4380,8 @@ namespace Tesses::CrossLang { auto bA = dynamic_cast(obj); auto list = dynamic_cast(obj); auto dict = dynamic_cast(obj); + auto dynDict = dynamic_cast(obj); + auto dynList = dynamic_cast(obj); auto tcallable = dynamic_cast(obj); auto closure = dynamic_cast(obj); auto externalMethod = dynamic_cast(obj); @@ -4246,6 +4391,7 @@ namespace Tesses::CrossLang { auto callstackEntry = dynamic_cast(obj); auto file = dynamic_cast(obj); auto chunk = dynamic_cast(obj); + if(file != nullptr) { @@ -4538,6 +4684,29 @@ namespace Tesses::CrossLang { 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) { @@ -4590,6 +4759,8 @@ namespace Tesses::CrossLang { auto vfs = dynamic_cast(obj); auto strm = dynamic_cast(obj); auto dict = dynamic_cast(obj); + auto dynDict = dynamic_cast(obj); + auto tcallable = dynamic_cast(obj); 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) { gc->BarrierBegin();