make fetchcontent fully functional

This commit is contained in:
2025-05-30 15:02:51 -05:00
parent 12f443a593
commit 4a454cc242
6 changed files with 338 additions and 20 deletions

4
.vscode/launch.json vendored
View File

@ -8,8 +8,8 @@
"name": "(gdb) Launch", "name": "(gdb) Launch",
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/builds/linux/crossvm", "program": "/usr/local/bin/crossint",
"args": ["builds/linux/out-1.0.0.0-prod.crvm"], "args": ["/home/mike/"],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"environment": [], "environment": [],

View File

@ -49,15 +49,16 @@ if(CROSSLANG_FETCHCONTENT)
set(TESSESFRAMEWORK_ENABLE_EXAMPLES OFF) set(TESSESFRAMEWORK_ENABLE_EXAMPLES OFF)
set(TESSESFRAMEWORK_ENABLE_APPS OFF) set(TESSESFRAMEWORK_ENABLE_APPS OFF)
set(CROSSLANG_ENABLE_SHARED OFF) #set(CROSSLANG_ENABLE_SHARED OFF)
set(TESSESFRAMEWORK_ENABLE_SHARED OFF) #set(TESSESFRAMEWORK_ENABLE_SHARED OFF)
set(CROSSLANG_SHARED_EXECUTABLES OFF) #set(CROSSLANG_SHARED_EXECUTABLES OFF)
include(FetchContent) include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
TessesFramework TessesFramework
GIT_REPOSITORY https://onedev.site.tesses.net/tesses-framework.git GIT_REPOSITORY https://onedev.site.tesses.net/tesses-framework.git
) )
FetchContent_MakeAvailable(TessesFramework) FetchContent_MakeAvailable(TessesFramework)
list(APPEND TessesCrossLangLibs ${TessesFrameworkTargets})
else() else()
find_package(TessesFramework REQUIRED) find_package(TessesFramework REQUIRED)
endif() endif()
@ -125,6 +126,7 @@ src/compiler/codegen.cpp
src/compiler/lexer.cpp src/compiler/lexer.cpp
src/compiler/parser.cpp src/compiler/parser.cpp
src/compiler/ast.cpp src/compiler/ast.cpp
src/runtime_methods/class.cpp
src/runtime_methods/console.cpp src/runtime_methods/console.cpp
src/runtime_methods/io.cpp src/runtime_methods/io.cpp
src/runtime_methods/std.cpp src/runtime_methods/std.cpp
@ -138,6 +140,7 @@ src/runtime_methods/ogc.cpp
src/runtime_methods/path.cpp src/runtime_methods/path.cpp
src/runtime_methods/env.cpp src/runtime_methods/env.cpp
src/runtime_methods/process.cpp src/runtime_methods/process.cpp
src/types/associativearray.cpp
src/types/any.cpp src/types/any.cpp
src/types/datetime.cpp src/types/datetime.cpp
src/types/ittr.cpp src/types/ittr.cpp
@ -189,6 +192,7 @@ if(CROSSLANG_ENABLE_STATIC)
add_library(crosslang_static STATIC ${CROSSLANG_SOURCE}) add_library(crosslang_static STATIC ${CROSSLANG_SOURCE})
CROSSLANG_LINK_DEPS(crosslang_static) CROSSLANG_LINK_DEPS(crosslang_static)
if(CROSSLANG_FETCHCONTENT) if(CROSSLANG_FETCHCONTENT)
target_link_libraries(crosslang_static PUBLIC tessesframework) target_link_libraries(crosslang_static PUBLIC tessesframework)
else() else()
target_link_libraries(crosslang_static PUBLIC TessesFramework::tessesframework) target_link_libraries(crosslang_static PUBLIC TessesFramework::tessesframework)

View File

@ -1537,6 +1537,22 @@ class GC {
void EnsureCanRunInCrossLang(); void EnsureCanRunInCrossLang();
}; };
class TAssociativeArray : public THeapObject
{
public:
std::vector<std::pair<TObject,TObject>> items;
static TAssociativeArray* Create(GCList& ls);
static TAssociativeArray* Create(GCList* ls);
void Set(GC* gc, TObject key, TObject value);
TObject Get(GC* gc, TObject key);
TObject GetKey(int64_t index);
TObject GetValue(int64_t index);
void SetKey(int64_t index, TObject key);
void SetValue(int64_t index,TObject value);
int64_t Count();
void Mark();
};
class TList : public THeapObject class TList : public THeapObject
{ {
@ -1746,6 +1762,7 @@ class GC {
bool canRegisterPath; bool canRegisterPath;
bool canRegisterOGC; bool canRegisterOGC;
bool canRegisterEnv; bool canRegisterEnv;
bool canRegisterClass;
bool sqlite3Scoped; bool sqlite3Scoped;
bool locked; bool locked;
}; };
@ -1804,7 +1821,7 @@ class GC {
static void RegisterOGC(GC* gc, TRootEnvironment* env); static void RegisterOGC(GC* gc, TRootEnvironment* env);
static void RegisterEnv(GC* gc, TRootEnvironment* env); static void RegisterEnv(GC* gc, TRootEnvironment* env);
static void RegisterProcess(GC* gc, TRootEnvironment* env); static void RegisterProcess(GC* gc, TRootEnvironment* env);
static void RegisterClass(GC* gc, TRootEnvironment* env);
}; };
class TSubEnvironment : public TEnvironment class TSubEnvironment : public TEnvironment
@ -1879,6 +1896,17 @@ class GC {
virtual TObject GetCurrent(GCList& ls)=0; virtual TObject GetCurrent(GCList& ls)=0;
static TEnumerator* CreateFromObject(GCList& ls, TObject obj); static TEnumerator* CreateFromObject(GCList& ls, TObject obj);
}; };
class TAssociativeArrayEnumerator : public TEnumerator
{
int64_t index;
TAssociativeArray* ls;
public:
static TAssociativeArrayEnumerator* Create(GCList& ls, TAssociativeArray* list);
static TAssociativeArrayEnumerator* Create(GCList* ls, TAssociativeArray* list);
bool MoveNext(GC* ls);
TObject GetCurrent(GCList& ls);
void Mark();
};
class TCustomEnumerator : public TEnumerator { class TCustomEnumerator : public TEnumerator {
public: public:
@ -1916,6 +1944,7 @@ class GC {
bool MoveNext(GC* ls); bool MoveNext(GC* ls);
TObject GetCurrent(GCList& ls); TObject GetCurrent(GCList& ls);
}; };
class TListEnumerator : public TEnumerator class TListEnumerator : public TEnumerator
{ {
int64_t index; int64_t index;
@ -2455,4 +2484,6 @@ class GC {
MarkedTObject CreateMarkedTObject(GC& gc, TObject o); MarkedTObject CreateMarkedTObject(GC& gc, TObject o);
MarkedTObject CreateMarkedTObject(GCList* gc, TObject o); MarkedTObject CreateMarkedTObject(GCList* gc, TObject o);
MarkedTObject CreateMarkedTObject(GCList& gc, TObject o); MarkedTObject CreateMarkedTObject(GCList& gc, TObject o);
std::string JoinPeriod(std::vector<std::string>& p);
TObject GetClassInfo(GCList& ls,TFile* f, uint32_t index);
}; };

View File

@ -622,15 +622,18 @@ namespace Tesses::CrossLang
auto subEnv = dynamic_cast<TSubEnvironment*>(obj); auto subEnv = dynamic_cast<TSubEnvironment*>(obj);
auto env = dynamic_cast<TEnvironment*>(obj); auto env = dynamic_cast<TEnvironment*>(obj);
auto natObj = dynamic_cast<TNativeObject*>(obj); auto natObj = dynamic_cast<TNativeObject*>(obj);
auto cobj = dynamic_cast<TClassObject*>(obj);
auto aarray = dynamic_cast<TAssociativeArray*>(obj);
if(rootEnv != nullptr) return "RootEnvironment"; if(rootEnv != nullptr) return "RootEnvironment";
if(subEnv != nullptr) return "SubEnvironment"; if(subEnv != nullptr) return "SubEnvironment";
if(env != nullptr) return "Environment"; if(env != nullptr) return "Environment";
if(cobj != nullptr) return cobj->TypeName();
if(cse != nullptr) return "YieldedClosure"; if(cse != nullptr) return "YieldedClosure";
if(dynDict != nullptr) return "DynamicDictionary"; if(dynDict != nullptr) return "DynamicDictionary";
if(dynList != nullptr) return "DynamicList"; if(dynList != nullptr) return "DynamicList";
if(aarray != nullptr) return "AssociativeArray";
if(natObj != nullptr) return natObj->TypeName(); if(natObj != nullptr) return natObj->TypeName();
if(strm != nullptr) if(strm != nullptr)
{ {
@ -998,6 +1001,12 @@ namespace Tesses::CrossLang
return TDynamicDictionary::Create(ls,callable); return TDynamicDictionary::Create(ls,callable);
return nullptr; return nullptr;
}); });
newTypes->DeclareFunction(gc,"AssociativeArray","Create a new AssociativeArray",{},[](GCList& ls, std::vector<TObject> args)->TObject {
return TAssociativeArray::Create(ls);
});
newTypes->DeclareFunction(gc,"AArray","alias for new AssociativeArray",{},[](GCList& ls, std::vector<TObject> args)->TObject {
return TAssociativeArray::Create(ls);
});
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,{
@ -1056,6 +1065,7 @@ namespace Tesses::CrossLang
RegisterCrypto(gc,env); RegisterCrypto(gc,env);
RegisterOGC(gc, env); RegisterOGC(gc, env);
RegisterProcess(gc,env); RegisterProcess(gc,env);
RegisterClass(gc,env);
gc->RegisterEverything(env); gc->RegisterEverything(env);

View File

@ -286,6 +286,53 @@ namespace Tesses::CrossLang
this->ls->Mark(); this->ls->Mark();
} }
TAssociativeArrayEnumerator* TAssociativeArrayEnumerator::Create(GCList& ls, TAssociativeArray* list)
{
TAssociativeArrayEnumerator* liste=new TAssociativeArrayEnumerator();
liste->ls = list;
liste->index = -1;
GC* _gc = ls.GetGC();
ls.Add(liste);
_gc->Watch(liste);
return liste;
}
TAssociativeArrayEnumerator* TAssociativeArrayEnumerator::Create(GCList* ls, TAssociativeArray* list)
{
TAssociativeArrayEnumerator* liste=new TAssociativeArrayEnumerator();
liste->ls = list;
liste->index = -1;
GC* _gc = ls->GetGC();
ls->Add(liste);
_gc->Watch(liste);
return liste;
}
bool TAssociativeArrayEnumerator::MoveNext(GC* ls)
{
this->index++;
return this->index >= 0 && this->index < this->ls->Count();
}
TObject TAssociativeArrayEnumerator::GetCurrent(GCList& ls)
{
if(this->index < -1) return nullptr;
if(this->ls->Count() == 0) return nullptr;
if(this->index >= this->ls->Count()) return nullptr;
ls.GetGC()->BarrierBegin();
TDictionary* dict = TDictionary::Create(ls);
dict->SetValue("Key",this->ls->GetKey(this->index));
dict->SetValue("Value",this->ls->GetValue(this->index));
ls.GetGC()->BarrierEnd();
return dict;
}
void TAssociativeArrayEnumerator::Mark()
{
if(this->marked) return;
this->marked = true;
this->ls->Mark();
}
TDynamicListEnumerator* TDynamicListEnumerator::Create(GCList& ls, TDynamicList* list) TDynamicListEnumerator* TDynamicListEnumerator::Create(GCList& ls, TDynamicList* list)
{ {
TDynamicListEnumerator* liste=new TDynamicListEnumerator(); TDynamicListEnumerator* liste=new TDynamicListEnumerator();

View File

@ -52,6 +52,7 @@ namespace Tesses::CrossLang {
{ {
auto o = std::get<THeapObjectHolder>(obj).obj; auto o = std::get<THeapObjectHolder>(obj).obj;
auto ls = dynamic_cast<TList*>(o); auto ls = dynamic_cast<TList*>(o);
auto aarray = dynamic_cast<TAssociativeArray*>(o);
auto dict = dynamic_cast<TDictionary*>(o); auto dict = dynamic_cast<TDictionary*>(o);
auto ba = dynamic_cast<TByteArray*>(o); auto ba = dynamic_cast<TByteArray*>(o);
auto nat = dynamic_cast<TNative*>(o); auto nat = dynamic_cast<TNative*>(o);
@ -69,6 +70,10 @@ namespace Tesses::CrossLang {
{ {
return ls->Count() != 0; return ls->Count() != 0;
} }
if(aarray != nullptr)
{
return aarray->Count() != 0;
}
else if(dict != nullptr) else if(dict != nullptr)
{ {
return !dict->items.empty(); return !dict->items.empty();
@ -963,6 +968,7 @@ namespace Tesses::CrossLang {
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj); auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
auto natObj = dynamic_cast<TNativeObject*>(obj); auto natObj = dynamic_cast<TNativeObject*>(obj);
auto cls = dynamic_cast<TClassObject*>(obj); auto cls = dynamic_cast<TClassObject*>(obj);
if(cls != nullptr) if(cls != nullptr)
{ {
gc->BarrierBegin(); gc->BarrierBegin();
@ -3143,6 +3149,8 @@ namespace Tesses::CrossLang {
auto svr = dynamic_cast<TServerHeapObject*>(obj); auto svr = dynamic_cast<TServerHeapObject*>(obj);
auto natObj = dynamic_cast<TNativeObject*>(obj); auto natObj = dynamic_cast<TNativeObject*>(obj);
auto cls = dynamic_cast<TClassObject*>(obj); auto cls = dynamic_cast<TClassObject*>(obj);
auto aArray=dynamic_cast<TAssociativeArray*>(obj);
if(natObj != nullptr) if(natObj != nullptr)
{ {
cse.back()->Push(gc, natObj->CallMethod(ls,key,args)); cse.back()->Push(gc, natObj->CallMethod(ls,key,args));
@ -4431,6 +4439,120 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, Undefined()); cse.back()->Push(gc, Undefined());
return false; return false;
} }
else if(aArray != nullptr)
{
if(key == "ToString")
{
cse.back()->Push(gc,ToString(gc,aArray));
return false;
}
else if(key == "GetAt")
{
if(args.size() != 1)
{
throw VMException("AArray.GetAt must only accept one argument");
}
cse.back()->Push(gc, aArray->Get(gc,args[0]));
return false;
}
else if(key == "SetAt")
{
if(args.size() != 2)
{
throw VMException("AArray.SetAt must only accept two arguments");
}
aArray->Set(gc,args[0],args[1]);
cse.back()->Push(gc, args[1]);
return false;
}
else if(key == "GetKey")
{
if(args.size() != 1)
{
throw VMException("AArray.GetKey must only accept one argument");
}
if(!std::holds_alternative<int64_t>(args[0]))
{
throw VMException("AArray.GetKey must only accept a long");
}
gc->BarrierBegin();
auto res = aArray->GetKey(std::get<int64_t>(args[0]));
gc->BarrierEnd();
cse.back()->Push(gc, res);
return false;
}
else if(key == "GetValue")
{
if(args.size() != 1)
{
throw VMException("AArray.GetValue must only accept one argument");
}
if(!std::holds_alternative<int64_t>(args[0]))
{
throw VMException("AArray.GetValue must only accept a long");
}
gc->BarrierBegin();
auto res = aArray->GetValue(std::get<int64_t>(args[0]));
gc->BarrierEnd();
cse.back()->Push(gc, res);
return false;
}
else if(key == "SetKey")
{
if(args.size() != 2)
{
throw VMException("AArray.SetKey must only accept two arguments");
}
if(!std::holds_alternative<int64_t>(args[0]))
{
throw VMException("AArray.SetKey first argument must only accept a long");
}
gc->BarrierBegin();
aArray->SetKey(std::get<int64_t>(args[0]),args[1]);
gc->BarrierEnd();
cse.back()->Push(gc, args[1]);
return false;
}
else if(key == "SetValue")
{
if(args.size() != 2)
{
throw VMException("AArray.SetValue must only accept two arguments");
}
if(!std::holds_alternative<int64_t>(args[0]))
{
throw VMException("AArray.SetValue first argument must only accept a long");
}
gc->BarrierBegin();
aArray->SetValue(std::get<int64_t>(args[0]),args[1]);
gc->BarrierEnd();
cse.back()->Push(gc, args[1]);
return false;
}
else if(key == "Count" || key == "Length")
{
gc->BarrierBegin();
cse.back()->Push(gc, aArray->Count());
gc->BarrierEnd();
return false;
}
else if(key == "GetEnumerator")
{
cse.back()->Push(gc,TAssociativeArrayEnumerator::Create(ls,aArray));
return false;
}
cse.back()->Push(gc,Undefined());
return false;
}
else if(list != nullptr) else if(list != nullptr)
{ {
@ -4465,7 +4587,7 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, Undefined()); cse.back()->Push(gc, Undefined());
return false; return false;
} }
if(key == "Add") else if(key == "Add")
{ {
if(args.size() != 1) if(args.size() != 1)
{ {
@ -4477,7 +4599,57 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, Undefined()); cse.back()->Push(gc, Undefined());
return false; return false;
} }
if(key == "RemoveAllEqual") else if(key == "Contains")
{
if(args.size() != 1)
{
throw VMException("List.Contains must only accept one argument");
}
gc->BarrierBegin();
for(int64_t i = 0; i < list->Count(); i++)
{
auto item = list->Get(i);
gc->BarrierEnd();
if(Equals(gc,args[0],item))
{
cse.back()->Push(gc, true);
return false;
}
gc->BarrierBegin();
}
gc->BarrierEnd();
cse.back()->Push(gc, false);
return false;
}
else if(key == "IndexOf")
{
//IndexOf(obj, $idx)
if(args.size() < 1 || args.size() > 2)
{
throw VMException("List.IndexOf must either have one or two arguments");
}
int64_t i=0;
GetArgument(args,1,i);
gc->BarrierBegin();
for(; i < list->Count(); i++)
{
auto item = list->Get(i);
gc->BarrierEnd();
if(Equals(gc,args[0],item))
{
cse.back()->Push(gc,i);
return false;
}
gc->BarrierBegin();
}
gc->BarrierEnd();
cse.back()->Push(gc,(int64_t)-1);
return false;
}
else if(key == "RemoveAllEqual")
{ {
if(args.size() != 1) if(args.size() != 1)
{ {
@ -4488,17 +4660,20 @@ namespace Tesses::CrossLang {
gc->BarrierBegin(); gc->BarrierBegin();
for(int64_t i = 0; i < list->Count(); i++) for(int64_t i = 0; i < list->Count(); i++)
{ {
if(Equals(gc,args[0],list->Get(i))) auto item = list->Get(i);
gc->BarrierEnd();
if(Equals(gc,args[0],item))
{ {
gc->BarrierBegin();
list->RemoveAt(i); list->RemoveAt(i);
i--; i--;
} }else gc->BarrierBegin();
} }
gc->BarrierEnd(); gc->BarrierEnd();
cse.back()->Push(gc, Undefined()); cse.back()->Push(gc, Undefined());
return false; return false;
} }
if(key == "Remove") else if(key == "Remove")
{ {
if(args.size() != 1) if(args.size() != 1)
{ {
@ -4509,17 +4684,22 @@ namespace Tesses::CrossLang {
gc->BarrierBegin(); gc->BarrierBegin();
for(int64_t i = 0; i < list->Count(); i++) for(int64_t i = 0; i < list->Count(); i++)
{ {
if(Equals(gc,args[0],list->Get(i))) auto item = list->Get(i);
gc->BarrierEnd();
if(Equals(gc,args[0],item))
{ {
gc->BarrierBegin();
list->RemoveAt(i); list->RemoveAt(i);
gc->BarrierEnd();
break; break;
} }
gc->BarrierBegin();
} }
gc->BarrierEnd(); gc->BarrierEnd();
cse.back()->Push(gc, Undefined()); cse.back()->Push(gc, Undefined());
return false; return false;
} }
if(key == "RemoveAt") else if(key == "RemoveAt")
{ {
if(args.size() != 1) if(args.size() != 1)
{ {
@ -4536,7 +4716,7 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, Undefined()); cse.back()->Push(gc, Undefined());
return false; return false;
} }
if(key == "Clear") else if(key == "Clear")
{ {
gc->BarrierBegin(); gc->BarrierBegin();
list->Clear(); list->Clear();
@ -4544,7 +4724,7 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, Undefined()); cse.back()->Push(gc, Undefined());
return false; return false;
} }
if(key == "GetAt") else if(key == "GetAt")
{ {
if(args.size() != 1) if(args.size() != 1)
{ {
@ -4564,7 +4744,7 @@ namespace Tesses::CrossLang {
} }
} }
if(key == "SetAt") else if(key == "SetAt")
{ {
if(args.size() != 2) if(args.size() != 2)
{ {
@ -4585,7 +4765,7 @@ namespace Tesses::CrossLang {
} }
if(key == "Count" || key == "Length") else if(key == "Count" || key == "Length")
{ {
gc->BarrierBegin(); gc->BarrierBegin();
cse.back()->Push(gc, list->Count()); cse.back()->Push(gc, list->Count());
@ -5010,7 +5190,18 @@ namespace Tesses::CrossLang {
auto chunk = dynamic_cast<TFileChunk*>(obj); auto chunk = dynamic_cast<TFileChunk*>(obj);
auto natObj = dynamic_cast<TNativeObject*>(obj); auto natObj = dynamic_cast<TNativeObject*>(obj);
auto cls = dynamic_cast<TClassObject*>(obj); auto cls = dynamic_cast<TClassObject*>(obj);
if(cls != nullptr) auto aarray = dynamic_cast<TAssociativeArray*>(obj);
if(aarray != nullptr)
{
if(key == "Count" || key == "Length")
{
cse.back()->Push(gc,aarray->Count());
return false;
}
cse.back()->Push(gc, Undefined());
return false;
}
else if(cls != nullptr)
{ {
gc->BarrierBegin(); gc->BarrierBegin();
auto obj=cls->GetValue(cse.back()->callable->className,"get"+key); auto obj=cls->GetValue(cse.back()->callable->className,"get"+key);
@ -5152,11 +5343,25 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, list); cse.back()->Push(gc, list);
return false; return false;
} }
else if(key == "Classes")
{
auto list = TList::Create(ls);
gc->BarrierBegin();
for(uint32_t i = 0; i < (uint32_t)file->classes.size(); i++)
{
list->Add(GetClassInfo(ls,file,i));
}
cse.back()->Push(gc, list);
gc->BarrierEnd();
return false;
}
else if(key == "Functions") else if(key == "Functions")
{ {
auto list = TList::Create(ls); auto list = TList::Create(ls);
gc->BarrierBegin(); gc->BarrierBegin();
for(auto item : file->functions) for(auto& item : file->functions)
{ {
TDictionary* dict = TDictionary::Create(ls); TDictionary* dict = TDictionary::Create(ls);
if(!item.first.empty()) if(!item.first.empty())
@ -6905,6 +7110,27 @@ namespace Tesses::CrossLang {
auto bArray = dynamic_cast<TByteArray*>(obj); auto bArray = dynamic_cast<TByteArray*>(obj);
auto natObj = dynamic_cast<TNativeObject*>(obj); auto natObj = dynamic_cast<TNativeObject*>(obj);
auto cls = dynamic_cast<TClassObject*>(obj); auto cls = dynamic_cast<TClassObject*>(obj);
auto aArray = dynamic_cast<TAssociativeArray*>(obj);
if(aArray != nullptr)
{
std::string str={};
gc->BarrierBegin();
bool first=true;
for(auto item : aArray->items)
{
if(!first) str.push_back('\n');
first=false;
str.push_back('[');
str.append(Json_Encode(item.first));
str.append("] = ");
str.append(Json_Encode(item.second));
str.append(";");
}
gc->BarrierEnd();
return str;
}
if(cls != nullptr) if(cls != nullptr)
{ {
auto res = cls->GetValue("","ToString"); auto res = cls->GetValue("","ToString");