diff --git a/.vscode/launch.json b/.vscode/launch.json index 68c6be3..85bef4e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,8 +8,8 @@ "name": "(gdb) Launch", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/builds/linux/crossvm", - "args": ["builds/linux/out-1.0.0.0-prod.crvm"], + "program": "/usr/local/bin/crossint", + "args": ["/home/mike/"], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], diff --git a/CMakeLists.txt b/CMakeLists.txt index ce02fa5..fd01be3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,15 +49,16 @@ if(CROSSLANG_FETCHCONTENT) set(TESSESFRAMEWORK_ENABLE_EXAMPLES OFF) set(TESSESFRAMEWORK_ENABLE_APPS OFF) -set(CROSSLANG_ENABLE_SHARED OFF) -set(TESSESFRAMEWORK_ENABLE_SHARED OFF) -set(CROSSLANG_SHARED_EXECUTABLES OFF) +#set(CROSSLANG_ENABLE_SHARED OFF) +#set(TESSESFRAMEWORK_ENABLE_SHARED OFF) +#set(CROSSLANG_SHARED_EXECUTABLES OFF) include(FetchContent) FetchContent_Declare( TessesFramework GIT_REPOSITORY https://onedev.site.tesses.net/tesses-framework.git ) FetchContent_MakeAvailable(TessesFramework) +list(APPEND TessesCrossLangLibs ${TessesFrameworkTargets}) else() find_package(TessesFramework REQUIRED) endif() @@ -125,6 +126,7 @@ src/compiler/codegen.cpp src/compiler/lexer.cpp src/compiler/parser.cpp src/compiler/ast.cpp +src/runtime_methods/class.cpp src/runtime_methods/console.cpp src/runtime_methods/io.cpp src/runtime_methods/std.cpp @@ -138,6 +140,7 @@ src/runtime_methods/ogc.cpp src/runtime_methods/path.cpp src/runtime_methods/env.cpp src/runtime_methods/process.cpp +src/types/associativearray.cpp src/types/any.cpp src/types/datetime.cpp src/types/ittr.cpp @@ -189,6 +192,7 @@ if(CROSSLANG_ENABLE_STATIC) add_library(crosslang_static STATIC ${CROSSLANG_SOURCE}) CROSSLANG_LINK_DEPS(crosslang_static) if(CROSSLANG_FETCHCONTENT) + target_link_libraries(crosslang_static PUBLIC tessesframework) else() target_link_libraries(crosslang_static PUBLIC TessesFramework::tessesframework) diff --git a/include/CrossLang.hpp b/include/CrossLang.hpp index c6a8412..33d22b7 100644 --- a/include/CrossLang.hpp +++ b/include/CrossLang.hpp @@ -1537,6 +1537,22 @@ class GC { void EnsureCanRunInCrossLang(); }; + class TAssociativeArray : public THeapObject + { + public: + std::vector> 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 { @@ -1746,6 +1762,7 @@ class GC { bool canRegisterPath; bool canRegisterOGC; bool canRegisterEnv; + bool canRegisterClass; bool sqlite3Scoped; bool locked; }; @@ -1804,7 +1821,7 @@ class GC { static void RegisterOGC(GC* gc, TRootEnvironment* env); static void RegisterEnv(GC* gc, TRootEnvironment* env); static void RegisterProcess(GC* gc, TRootEnvironment* env); - + static void RegisterClass(GC* gc, TRootEnvironment* env); }; class TSubEnvironment : public TEnvironment @@ -1879,6 +1896,17 @@ class GC { virtual TObject GetCurrent(GCList& ls)=0; 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 { public: @@ -1916,6 +1944,7 @@ class GC { bool MoveNext(GC* ls); TObject GetCurrent(GCList& ls); }; + class TListEnumerator : public TEnumerator { int64_t index; @@ -2455,4 +2484,6 @@ class GC { MarkedTObject CreateMarkedTObject(GC& gc, TObject o); MarkedTObject CreateMarkedTObject(GCList* gc, TObject o); MarkedTObject CreateMarkedTObject(GCList& gc, TObject o); + std::string JoinPeriod(std::vector& p); + TObject GetClassInfo(GCList& ls,TFile* f, uint32_t index); }; diff --git a/src/runtime_methods/std.cpp b/src/runtime_methods/std.cpp index f935d0e..2e7b1e1 100644 --- a/src/runtime_methods/std.cpp +++ b/src/runtime_methods/std.cpp @@ -622,15 +622,18 @@ namespace Tesses::CrossLang auto subEnv = dynamic_cast(obj); auto env = dynamic_cast(obj); auto natObj = dynamic_cast(obj); - + auto cobj = dynamic_cast(obj); + auto aarray = dynamic_cast(obj); if(rootEnv != nullptr) return "RootEnvironment"; if(subEnv != nullptr) return "SubEnvironment"; if(env != nullptr) return "Environment"; + if(cobj != nullptr) return cobj->TypeName(); if(cse != nullptr) return "YieldedClosure"; if(dynDict != nullptr) return "DynamicDictionary"; if(dynList != nullptr) return "DynamicList"; + if(aarray != nullptr) return "AssociativeArray"; if(natObj != nullptr) return natObj->TypeName(); if(strm != nullptr) { @@ -998,6 +1001,12 @@ namespace Tesses::CrossLang return TDynamicDictionary::Create(ls,callable); return nullptr; }); + newTypes->DeclareFunction(gc,"AssociativeArray","Create a new AssociativeArray",{},[](GCList& ls, std::vector args)->TObject { + return TAssociativeArray::Create(ls); + }); + newTypes->DeclareFunction(gc,"AArray","alias for new AssociativeArray",{},[](GCList& ls, std::vector 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); gc->BarrierBegin(); env->DeclareVariable("Version", TDictionary::Create(ls,{ @@ -1056,6 +1065,7 @@ namespace Tesses::CrossLang RegisterCrypto(gc,env); RegisterOGC(gc, env); RegisterProcess(gc,env); + RegisterClass(gc,env); gc->RegisterEverything(env); diff --git a/src/types/ittr.cpp b/src/types/ittr.cpp index 1be45c5..4931260 100644 --- a/src/types/ittr.cpp +++ b/src/types/ittr.cpp @@ -286,6 +286,53 @@ namespace Tesses::CrossLang 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* liste=new TDynamicListEnumerator(); diff --git a/src/vm/vm.cpp b/src/vm/vm.cpp index 82f79b1..2d71bd1 100644 --- a/src/vm/vm.cpp +++ b/src/vm/vm.cpp @@ -52,6 +52,7 @@ namespace Tesses::CrossLang { { auto o = std::get(obj).obj; auto ls = dynamic_cast(o); + auto aarray = dynamic_cast(o); auto dict = dynamic_cast(o); auto ba = dynamic_cast(o); auto nat = dynamic_cast(o); @@ -69,6 +70,10 @@ namespace Tesses::CrossLang { { return ls->Count() != 0; } + if(aarray != nullptr) + { + return aarray->Count() != 0; + } else if(dict != nullptr) { return !dict->items.empty(); @@ -963,6 +968,7 @@ namespace Tesses::CrossLang { auto dynDict = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); + if(cls != nullptr) { gc->BarrierBegin(); @@ -3143,6 +3149,8 @@ namespace Tesses::CrossLang { auto svr = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); + auto aArray=dynamic_cast(obj); + if(natObj != nullptr) { cse.back()->Push(gc, natObj->CallMethod(ls,key,args)); @@ -4431,6 +4439,120 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, Undefined()); 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(args[0])) + { + throw VMException("AArray.GetKey must only accept a long"); + } + + gc->BarrierBegin(); + auto res = aArray->GetKey(std::get(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(args[0])) + { + throw VMException("AArray.GetValue must only accept a long"); + } + + gc->BarrierBegin(); + auto res = aArray->GetValue(std::get(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(args[0])) + { + throw VMException("AArray.SetKey first argument must only accept a long"); + } + + gc->BarrierBegin(); + aArray->SetKey(std::get(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(args[0])) + { + throw VMException("AArray.SetValue first argument must only accept a long"); + } + + gc->BarrierBegin(); + aArray->SetValue(std::get(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) { @@ -4465,7 +4587,7 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, Undefined()); return false; } - if(key == "Add") + else if(key == "Add") { if(args.size() != 1) { @@ -4477,7 +4599,57 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, Undefined()); 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) { @@ -4488,17 +4660,20 @@ namespace Tesses::CrossLang { gc->BarrierBegin(); 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); i--; - } + }else gc->BarrierBegin(); } gc->BarrierEnd(); cse.back()->Push(gc, Undefined()); return false; } - if(key == "Remove") + else if(key == "Remove") { if(args.size() != 1) { @@ -4509,17 +4684,22 @@ namespace Tesses::CrossLang { gc->BarrierBegin(); 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); + gc->BarrierEnd(); break; } + gc->BarrierBegin(); } gc->BarrierEnd(); cse.back()->Push(gc, Undefined()); return false; } - if(key == "RemoveAt") + else if(key == "RemoveAt") { if(args.size() != 1) { @@ -4536,7 +4716,7 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, Undefined()); return false; } - if(key == "Clear") + else if(key == "Clear") { gc->BarrierBegin(); list->Clear(); @@ -4544,7 +4724,7 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, Undefined()); return false; } - if(key == "GetAt") + else if(key == "GetAt") { if(args.size() != 1) { @@ -4564,7 +4744,7 @@ namespace Tesses::CrossLang { } } - if(key == "SetAt") + else if(key == "SetAt") { if(args.size() != 2) { @@ -4585,7 +4765,7 @@ namespace Tesses::CrossLang { } - if(key == "Count" || key == "Length") + else if(key == "Count" || key == "Length") { gc->BarrierBegin(); cse.back()->Push(gc, list->Count()); @@ -5010,7 +5190,18 @@ namespace Tesses::CrossLang { auto chunk = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); - if(cls != nullptr) + auto aarray = dynamic_cast(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(); auto obj=cls->GetValue(cse.back()->callable->className,"get"+key); @@ -5152,11 +5343,25 @@ namespace Tesses::CrossLang { cse.back()->Push(gc, list); 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") { auto list = TList::Create(ls); gc->BarrierBegin(); - for(auto item : file->functions) + for(auto& item : file->functions) { TDictionary* dict = TDictionary::Create(ls); if(!item.first.empty()) @@ -6905,6 +7110,27 @@ namespace Tesses::CrossLang { auto bArray = dynamic_cast(obj); auto natObj = dynamic_cast(obj); auto cls = dynamic_cast(obj); + auto aArray = dynamic_cast(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) { auto res = cls->GetValue("","ToString");