diff --git a/.vscode/launch.json b/.vscode/launch.json index 71d45e9..22eaf55 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,10 +8,10 @@ "name": "(gdb) Launch", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/builds/linux/crosslang", - "args": ["token"], + "program": "${workspaceFolder}/builds/l/crossint", + "args": ["queryable.tcross"], "stopAtEntry": false, - "cwd": "${workspaceFolder}", + "cwd": "${workspaceFolder}/builds/l", "environment": [], "externalConsole": false, "MIMode": "gdb", diff --git a/changelog.md b/changelog.md index 749d581..3f3a60e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,8 @@ # Changelog +## 0.0.5 +Fix crosslang Stat, StatVFS for custom crosslang filesystems and add queryable + ## 0.0.4 Rework for git.tesses.org, GC* is std::shared_ptr maybe will fix crash during exit diff --git a/cmake/sources.cmake b/cmake/sources.cmake index d52ee02..3990624 100644 --- a/cmake/sources.cmake +++ b/cmake/sources.cmake @@ -49,6 +49,7 @@ src/types/streamheapobject.cpp src/types/class.cpp src/types/classenvironment.cpp src/types/random.cpp +src/types/queryable.cpp src/vm/filereader.cpp src/vm/gc.cpp src/vm/gclist.cpp diff --git a/include/CrossLang.hpp b/include/CrossLang.hpp index f8ae5d3..956e892 100644 --- a/include/CrossLang.hpp +++ b/include/CrossLang.hpp @@ -1030,6 +1030,11 @@ constexpr std::string_view ForStatement = "forStatement"; * */ constexpr std::string_view WhileStatement = "whileStatement"; +/** + * @brief using statement using(EXPR) + * + */ +constexpr std::string_view UsingStatement = "usingStatement"; /** * @brief Do statement do(COND) * @@ -2616,5 +2621,48 @@ class GC : public std::enable_shared_from_this { void CrossLangDump(std::shared_ptr strm); void CrossLangCompiler(std::vector& argv); - } + } + + enum class TQueryableMode { + Passthrough, + Skip, + SkipWhile, + Take, + TakeWhile, + Select, + Where + }; + + class TQueryable : public THeapObject { + + + TObject parent; + TQueryableMode mode; + std::vector args; + TQueryable(TObject parent); + TQueryable(TObject parent, TQueryableMode mode, std::vector args); + + public: + + static TQueryable* Create(GCList& ls, TObject parent); + static TQueryable* Create(GCList& ls, TObject parent, TQueryableMode mode, std::vector args); + + TQueryable* Skip(GCList& ls,int64_t no); + TQueryable* SkipWhile(GCList& ls, TCallable* call); + TQueryable* Take(GCList& ls, int64_t no); + TQueryable* TakeWhile(GCList& ls, TCallable* call); + TQueryable* Select(GCList& ls, TCallable* call); + TQueryable* Where(GCList& ls, TCallable* call); + void ForEach(std::shared_ptr gc, TCallable* call); + int64_t Count(std::shared_ptr gc, TCallable* call); + int64_t Count(std::shared_ptr gc); + bool Contains(std::shared_ptr, TObject value); + bool Any(std::shared_ptr gc, TCallable* call); + bool All(std::shared_ptr gc, TCallable* call); + + TList* ToList(GCList& ls); + TEnumerator* GetEnumerator(GCList& ls); + + void Mark(); + }; }; diff --git a/src/compiler/codegen.cpp b/src/compiler/codegen.cpp index 126b625..c4497a5 100644 --- a/src/compiler/codegen.cpp +++ b/src/compiler/codegen.cpp @@ -1383,6 +1383,104 @@ namespace Tesses::CrossLang instructions.push_back(new LabelInstruction(ifIdEnd)); } + else if(adv.nodeName == UsingStatement && adv.nodes.size() == 2) + { + //using(EXPRESSION) {} + //using(EXPRESSION) STATEMENT; + + //{ __compGen = EXPRESSION; defer { __compGen.Dispose(); } {}(unrolled) OR STATEMENT; } + + if(std::holds_alternative(adv.nodes[1])) + { + auto asn2 = std::get(adv.nodes[1]); + if(asn2.nodeName == ScopeNode) + { + scope++; + instructions.push_back(new SimpleInstruction(SCOPEBEGIN)); + + uint32_t exprId = NewId(); + std::string exprStr = "__compGenUsing"; + exprStr.append(std::to_string(exprId)); + + auto _assign=AdvancedSyntaxNode::Create(AssignExpression,true,{ + AdvancedSyntaxNode::Create(DeclareExpression,true,{exprStr}), + adv.nodes[0] + }); + + GenNode(instructions,_assign,scope,contscope,brkscope,contI,brkI); + GenPop(instructions,_assign); + + + auto _defer=AdvancedSyntaxNode::Create(DeferStatement,false,{ + AdvancedSyntaxNode::Create(ReturnStatement,false,{ + AdvancedSyntaxNode::Create(FunctionCallExpression,true,{ + AdvancedSyntaxNode::Create(GetFieldExpression,true,{ + AdvancedSyntaxNode::Create(GetVariableExpression, true, { + exprStr + }), + "Dispose" + }) + }) + }) + }); + + + GenNode(instructions,_defer,scope,contscope,brkscope,contI,brkI); + + for(size_t i = 0; i < asn2.nodes.size(); i++) + { + GenNode(instructions,asn2.nodes[i],scope,contscope,brkscope,contI,brkI); + if(!asn2.isExpression || i < asn2.nodes.size()-1) + GenPop(instructions,asn2.nodes[i]); + } + instructions.push_back(new SimpleInstruction(SCOPEEND)); + scope--; + return; + } + } + + { + scope++; + instructions.push_back(new SimpleInstruction(SCOPEBEGIN)); + + uint32_t exprId = NewId(); + std::string exprStr = "__compGenUsing"; + exprStr.append(std::to_string(exprId)); + + auto _assign=AdvancedSyntaxNode::Create(AssignExpression,true,{ + AdvancedSyntaxNode::Create(DeclareExpression,true,{exprStr}), + adv.nodes[0] + }); + + GenNode(instructions,_assign,scope,contscope,brkscope,contI,brkI); + GenPop(instructions,_assign); + + + auto _defer=AdvancedSyntaxNode::Create(DeferStatement,false,{ + AdvancedSyntaxNode::Create(ReturnStatement,false,{ + AdvancedSyntaxNode::Create(FunctionCallExpression,true,{ + AdvancedSyntaxNode::Create(GetFieldExpression,true,{ + AdvancedSyntaxNode::Create(GetVariableExpression, true, { + exprStr + }), + "Dispose" + }) + }) + }) + }); + + + GenNode(instructions,_defer,scope,contscope,brkscope,contI,brkI); + + + GenNode(instructions,adv.nodes[1],scope,contscope,brkscope,contI,brkI); + if(!adv.isExpression) + GenPop(instructions,adv.nodes[1]); + + instructions.push_back(new SimpleInstruction(SCOPEEND)); + scope--; + } + } else if(adv.nodeName == WhileStatement && adv.nodes.size() == 2) { auto old_contI = contI; diff --git a/src/compiler/parser.cpp b/src/compiler/parser.cpp index c57e699..ce400c0 100644 --- a/src/compiler/parser.cpp +++ b/src/compiler/parser.cpp @@ -615,7 +615,7 @@ namespace Tesses::CrossLang EnsureSymbol("("); SyntaxNode list = ParseExpression(); SyntaxNode body = nullptr; - if(IsSymbol(":")) + if(IsSymbol(":") || IsIdentifier("in")) { item = list; list = ParseExpression(); @@ -1406,6 +1406,20 @@ namespace Tesses::CrossLang } return AdvancedSyntaxNode::Create(WhileStatement,false,{cond,body}); } + if(IsIdentifier("using")) + { + EnsureSymbol("("); + SyntaxNode expr = ParseExpression(); + EnsureSymbol(")"); + + SyntaxNode body = nullptr; + if(!IsSymbol(";")) + { + body = ParseNode(); + } + + return AdvancedSyntaxNode::Create(UsingStatement, false, {expr,body}); + } if(IsIdentifier("do")) { EnsureSymbol("("); diff --git a/src/runtime_methods/sqlite.cpp b/src/runtime_methods/sqlite.cpp index 8b47663..f42a3f6 100644 --- a/src/runtime_methods/sqlite.cpp +++ b/src/runtime_methods/sqlite.cpp @@ -5,7 +5,7 @@ namespace Tesses::CrossLang { #if defined(TESSESFRAMEWORK_ENABLE_SQLITE) using namespace Tesses::Framework::Serialization; - TObject Sqlite_Escape(GCList& ls, std::vector args) + TObject Sqlite_Escape(GCList& ls, std::vector args) { int64_t n; double d; @@ -33,6 +33,58 @@ namespace Tesses::CrossLang { return "NULL"; } + TObject Sqlite_Prepare(GCList& ls, std::vector args) + { + std::string str; + TList* list; + + std::string newStr = ""; + if(GetArgument(args,0,str) && GetArgumentHeap(args,1,list)) + { + int64_t item = 0; + + + for(size_t i = 0; i < str.size(); i++) + { + if(str[i] == '@' && (i+1>=str.size() || str[i+1] != '@')) + { + auto v = list->Get(item); + int64_t n; + double d; + bool b; + + + std::string str; + if(GetObject(v,str)) + { + newStr+= SQLiteDatabase::Escape(str); + } + else if(GetObject(v,n)) + { + newStr+= std::to_string(n); + } + else if(GetObject(v,b)) + { + newStr+= (b ? "1" : "0"); + } + else if(GetObject(v,d)) + { + newStr+= std::to_string(d); + } + else { + + newStr+= "NULL"; + } + } + else { + newStr+=str[i]; + } + } + + + } + return newStr; + } class SQLiteObject : public TNativeObject { @@ -65,6 +117,9 @@ namespace Tesses::CrossLang { if(name == "Escape") { return Sqlite_Escape(ls,args); } + if(name == "Prepare") { + return Sqlite_Prepare(ls,args); + } if(name == "Exec") { std::string arg; @@ -105,6 +160,7 @@ namespace Tesses::CrossLang { } }; + TObject Sqlite_Open(GCList& ls, std::vector args,TRootEnvironment* env) { Tesses::Framework::Filesystem::VFSPath p; @@ -148,6 +204,7 @@ namespace Tesses::CrossLang { } return Undefined(); } + #endif void TStd::RegisterSqlite(std::shared_ptr gc,TRootEnvironment* env) @@ -163,6 +220,7 @@ namespace Tesses::CrossLang { dict->DeclareFunction(gc,"Exec","Execute sql (returns dictionary of columns key=value, an error message as string or undefined)",{"handle","sql"},Sqlite_Exec); dict->DeclareFunction(gc,"Close","Close sql database",{"handle"},Sqlite_Close); dict->DeclareFunction(gc,"Escape","Escape sql text",{"text"},Sqlite_Escape); + dict->DeclareFunction(gc,"Prepare", "Prepare sql",{"sql","items"}, Sqlite_Prepare); gc->BarrierBegin(); env->DeclareVariable("Sqlite", dict); diff --git a/src/runtime_methods/std.cpp b/src/runtime_methods/std.cpp index eb1fc5f..c5181ef 100644 --- a/src/runtime_methods/std.cpp +++ b/src/runtime_methods/std.cpp @@ -610,6 +610,12 @@ namespace Tesses::CrossLang std::shared_ptr dt; return GetArgument(args,0,dt); } + static TObject TypeIsQueryable(GCList& ls, std::vector args) + { + if(args.empty()) return nullptr; + TQueryable* queryable; + return GetArgumentHeap(args,0,queryable); + } static TObject New_SubdirFilesystem(GCList& ls, std::vector args) { std::shared_ptr vfs; @@ -902,6 +908,7 @@ namespace Tesses::CrossLang auto cobj = dynamic_cast(obj); auto aarray = dynamic_cast(obj); auto file = dynamic_cast(obj); + auto queryable = dynamic_cast(obj); if(rootEnv != nullptr) return "RootEnvironment"; if(subEnv != nullptr) return "SubEnvironment"; @@ -923,6 +930,7 @@ namespace Tesses::CrossLang if(native != nullptr) return "Native"; if(any != nullptr) return "Any"; if(file != nullptr) return "File"; + if(queryable != nullptr) return "Queryable"; return "HeapObject"; } @@ -1304,6 +1312,16 @@ namespace Tesses::CrossLang return nullptr; } + static TObject New_Queryable(GCList& ls, std::vector args) + { + if(!args.empty()) + { + return TQueryable::Create(ls, args.front()); + } + return nullptr; + } + + void TStd::RegisterRoot(std::shared_ptr gc, TRootEnvironment* env) { GCList ls(gc); @@ -1430,7 +1448,7 @@ namespace Tesses::CrossLang env->DeclareFunction(gc, "TypeIsByteReader","Get whether object is a ByteReader",{"object"},TypeIsByteReader); env->DeclareFunction(gc, "TypeIsByteWriter","Get whether object is a ByteWriter",{"object"},TypeIsByteWriter); env->DeclareFunction(gc, "TypeIsUuid","Get whether object is a Uuid",{"object"},TypeIsUuid); - + env->DeclareFunction(gc, "TypeIsQueryable","Get whether object is a Queryable",{"object"},TypeIsQueryable); newTypes->DeclareFunction(gc, "Regex", "Create regex object",{"regex"},[](GCList& ls,std::vector args)->TObject { std::string str; @@ -1476,6 +1494,7 @@ namespace Tesses::CrossLang 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, "Queryable", "Create a queryable", {"enumerable"}, New_Queryable); env->DeclareVariable("Version", TDictionary::Create(ls,{ TDItem("Parse",TExternalMethod::Create(ls,"Parse version from string",{"versionStr"},[](GCList& ls, std::vector args)->TObject{ diff --git a/src/types/ittr.cpp b/src/types/ittr.cpp index 1f15f65..2ca87f6 100644 --- a/src/types/ittr.cpp +++ b/src/types/ittr.cpp @@ -132,6 +132,7 @@ namespace Tesses::CrossLang TDynamicDictionary* dynDict; TDictionary* dict; TEnumerator* enumerator; + TQueryable* q; if(GetObject(obj,str)) { return TStringEnumerator::Create(ls, str); @@ -156,6 +157,14 @@ namespace Tesses::CrossLang return enumerator; } } + else if(GetObjectHeap(obj, q)) + { + return q->GetEnumerator(ls); + } + else if(GetObjectHeap(obj, enumerator)) + { + return enumerator; + } return nullptr; } TVFSPathEnumerator* TVFSPathEnumerator::Create(GCList& ls, Tesses::Framework::Filesystem::VFSPathEnumerator enumerator) diff --git a/src/types/queryable.cpp b/src/types/queryable.cpp new file mode 100644 index 0000000..cc76b97 --- /dev/null +++ b/src/types/queryable.cpp @@ -0,0 +1,522 @@ +#include "CrossLang.hpp" + +namespace Tesses::CrossLang +{ + TQueryable::TQueryable(TObject parent) : TQueryable(parent,TQueryableMode::Passthrough, {}) + { + + } + TQueryable::TQueryable(TObject parent, TQueryableMode mode, std::vector args): parent(parent), mode(mode), args(args) + { + + } + + TQueryable* TQueryable::Skip(GCList& ls,int64_t no) + { + return TQueryable::Create(ls,this,TQueryableMode::Skip, {no}); + } + TQueryable* TQueryable::SkipWhile(GCList& ls, TCallable* call) + { + return TQueryable::Create(ls,this,TQueryableMode::SkipWhile, {call}); + } + TQueryable* TQueryable::Take(GCList& ls, int64_t no) + { + return TQueryable::Create(ls,this,TQueryableMode::Take, {no}); + } + TQueryable* TQueryable::TakeWhile(GCList& ls, TCallable* call) + { + return TQueryable::Create(ls,this,TQueryableMode::TakeWhile, {call}); + } + TQueryable* TQueryable::Select(GCList& ls, TCallable* call) + { + return TQueryable::Create(ls,this,TQueryableMode::Select, {call}); + } + TQueryable* TQueryable::Where(GCList& ls, TCallable* call) + { + return TQueryable::Create(ls,this,TQueryableMode::Where, {call}); + } + + TList* TQueryable::ToList(GCList& ls) + { + auto gc = ls.GetGC(); + GCList ls2(gc); + auto enumerator = this->GetEnumerator(ls); + if(enumerator == nullptr) return nullptr; + auto list = TList::Create(ls); + while(enumerator->MoveNext(gc)) + { + gc->BarrierBegin(); + list->Add(enumerator->GetCurrent(ls)); + gc->BarrierEnd(); + } + return list; + } + TQueryable* TQueryable::Create(GCList& ls, TObject parent) + { + TQueryable* queryable = new TQueryable(parent); + std::shared_ptr gc = ls.GetGC(); + ls.Add(queryable); + gc->Watch(queryable); + return queryable; + } + TQueryable* TQueryable::Create(GCList& ls, TObject parent, TQueryableMode mode, std::vector args) + { + TQueryable* queryable = new TQueryable(parent, mode,args); + std::shared_ptr gc = ls.GetGC(); + ls.Add(queryable); + gc->Watch(queryable); + return queryable; + } + + + void TQueryable::Mark() + { + if(this->marked) return; + this->marked=true; + + GC::Mark(this->parent); + for(auto& item : args) + GC::Mark(item); + } + + void TQueryable::ForEach(std::shared_ptr gc, TCallable* call) + { + if(call == nullptr) return; + GCList ls(gc); + auto enumerator = this->GetEnumerator(ls); + if(enumerator == nullptr) return; + while(enumerator->MoveNext(gc)) + { + GCList ls2(gc); + call->Call(ls2,{enumerator->GetCurrent(ls2)}); + } + } + int64_t TQueryable::Count(std::shared_ptr gc, TCallable* call) + { + if(call == nullptr) return 0; + GCList ls(gc); + auto enumerator = this->GetEnumerator(ls); + if(enumerator == nullptr) return 0; + int64_t count=0; + while(enumerator->MoveNext(gc)) + { + GCList ls2(gc); + if(ToBool(call->Call(ls2,{enumerator->GetCurrent(ls2)}))) count++; + } + return count; + } + int64_t TQueryable::Count(std::shared_ptr gc) + { + GCList ls(gc); + auto enumerator = this->GetEnumerator(ls); + if(enumerator == nullptr) return 0; + int64_t count=0; + while(enumerator->MoveNext(gc)) + { + count++; + } + return count; + } + bool TQueryable::Contains(std::shared_ptr gc, TObject value) + { + GCList ls(gc); + auto enumerator = this->GetEnumerator(ls); + if(enumerator == nullptr) return false; + while(enumerator->MoveNext(gc)) + { + GCList ls2(gc); + + + if(Equals(gc,value,enumerator->GetCurrent(ls2))) + return true; + + } + return false; + } + bool TQueryable::Any(std::shared_ptr gc, TCallable* call) + { + if(call == nullptr) return false; + GCList ls(gc); + auto enumerator = this->GetEnumerator(ls); + if(enumerator == nullptr) return false; + + while(enumerator->MoveNext(gc)) + { + GCList ls2(gc); + if(ToBool(call->Call(ls2,{enumerator->GetCurrent(ls2)}))) return true; + } + return false; + } + bool TQueryable::All(std::shared_ptr gc, TCallable* call) + { + if(call == nullptr) return true; + GCList ls(gc); + auto enumerator = this->GetEnumerator(ls); + if(enumerator == nullptr) return true; + + while(enumerator->MoveNext(gc)) + { + GCList ls2(gc); + if(!ToBool(call->Call(ls2,{enumerator->GetCurrent(ls2)}))) return false; + } + return true; + } + + class SkipItterator : public TEnumerator { + private: + TEnumerator* parentEnum; + int64_t skipCount; + SkipItterator(TEnumerator* parentEnum, int64_t skipCount) : parentEnum(parentEnum), skipCount(skipCount) + { + + } + public: + static SkipItterator* Create(GCList& ls, TEnumerator* parentEnum, int64_t skipCount) + { + SkipItterator* queryable = new SkipItterator(parentEnum, skipCount); + std::shared_ptr gc = ls.GetGC(); + ls.Add(queryable); + gc->Watch(queryable); + return queryable; + } + bool MoveNext(std::shared_ptr ls) + { + if(this->parentEnum == nullptr) return false; + while(skipCount > 0) + { + if(!this->parentEnum->MoveNext(ls)) { + skipCount=0; + return false; + } + skipCount--; + } + return this->parentEnum->MoveNext(ls); + } + TObject GetCurrent(GCList& ls) + { + return this->parentEnum->GetCurrent(ls); + } + void Mark() + { + if(this->marked) return; + this->marked=true; + + if(parentEnum != nullptr) parentEnum->Mark(); + } + }; + class TakeItterator : public TEnumerator { + private: + TEnumerator* parentEnum; + int64_t takeCount; + TakeItterator(TEnumerator* parentEnum, int64_t takeCount) : parentEnum(parentEnum), takeCount(takeCount) + { + + } + public: + static TakeItterator* Create(GCList& ls, TEnumerator* parentEnum, int64_t takeCount) + { + TakeItterator* queryable = new TakeItterator(parentEnum, takeCount); + std::shared_ptr gc = ls.GetGC(); + ls.Add(queryable); + gc->Watch(queryable); + return queryable; + } + bool MoveNext(std::shared_ptr ls) + { + if(this->parentEnum == nullptr) return false; + if(takeCount > 0) + { + takeCount--; + return this->parentEnum->MoveNext(ls); + } + return false; + } + TObject GetCurrent(GCList& ls) + { + return this->parentEnum->GetCurrent(ls); + } + void Mark() + { + if(this->marked) return; + this->marked=true; + + if(parentEnum != nullptr) parentEnum->Mark(); + } + }; + class SkipWhileItterator : public TEnumerator { + private: + TEnumerator* parentEnum; + TCallable* callable; + SkipWhileItterator(TEnumerator* parentEnum, TCallable* callable) : parentEnum(parentEnum), callable(callable) + { + + } + public: + static SkipWhileItterator* Create(GCList& ls, TEnumerator* parentEnum, TCallable* callable) + { + SkipWhileItterator* queryable = new SkipWhileItterator(parentEnum, callable); + std::shared_ptr gc = ls.GetGC(); + ls.Add(queryable); + gc->Watch(queryable); + return queryable; + } + bool MoveNext(std::shared_ptr ls) + { + if(this->parentEnum == nullptr) return false; + ls->BarrierBegin(); + auto callable = this->callable; + ls->BarrierEnd(); + + if(callable != nullptr) + { + while(true) + { + if(this->parentEnum->MoveNext(ls)) + { + GCList ls2(ls); + auto result = callable->Call(ls2,{this->parentEnum->GetCurrent(ls2)}); + if(!ToBool(result)) + { + ls->BarrierBegin(); + this->callable=nullptr; + ls->BarrierEnd(); + return true; + } + + } + else + { + ls->BarrierBegin(); + this->callable=nullptr; + ls->BarrierEnd(); + return false; + } + } + } + else { + return this->parentEnum->MoveNext(ls); + } + return false; + } + TObject GetCurrent(GCList& ls) + { + return this->parentEnum->GetCurrent(ls); + } + void Mark() + { + if(this->marked) return; + this->marked=true; + + if(parentEnum != nullptr) parentEnum->Mark(); + if(callable != nullptr) callable->Mark(); + } + }; + class TakeWhileItterator : public TEnumerator { + private: + TEnumerator* parentEnum; + TCallable* callable; + TakeWhileItterator(TEnumerator* parentEnum, TCallable* callable) : parentEnum(parentEnum), callable(callable) + { + + } + public: + static TakeWhileItterator* Create(GCList& ls, TEnumerator* parentEnum, TCallable* callable) + { + TakeWhileItterator* queryable = new TakeWhileItterator(parentEnum, callable); + std::shared_ptr gc = ls.GetGC(); + ls.Add(queryable); + gc->Watch(queryable); + return queryable; + } + bool MoveNext(std::shared_ptr ls) + { + if(this->parentEnum == nullptr) return false; + ls->BarrierBegin(); + auto callable = this->callable; + ls->BarrierEnd(); + if(callable != nullptr) + { + if(this->parentEnum->MoveNext(ls)) + { + GCList ls2(ls); + auto result = callable->Call(ls2,{this->parentEnum->GetCurrent(ls2)}); + if(!ToBool(result)) + { + ls->BarrierBegin(); + this->callable=nullptr; + ls->BarrierEnd(); + return false; + } + return true; + } + } + return false; + } + TObject GetCurrent(GCList& ls) + { + return this->parentEnum->GetCurrent(ls); + } + void Mark() + { + if(this->marked) return; + this->marked=true; + + if(parentEnum != nullptr) parentEnum->Mark(); + if(callable != nullptr) callable->Mark(); + } + }; + class WhereItterator : public TEnumerator { + private: + TEnumerator* parentEnum; + TCallable* callable; + WhereItterator(TEnumerator* parentEnum, TCallable* callable) : parentEnum(parentEnum), callable(callable) + { + + } + public: + static WhereItterator* Create(GCList& ls, TEnumerator* parentEnum, TCallable* callable) + { + WhereItterator* queryable = new WhereItterator(parentEnum, callable); + std::shared_ptr gc = ls.GetGC(); + ls.Add(queryable); + gc->Watch(queryable); + return queryable; + } + bool MoveNext(std::shared_ptr ls) + { + if(this->parentEnum == nullptr || this->callable == nullptr) return false; + while(this->parentEnum->MoveNext(ls)) + { + GCList ls2(ls); + auto cur = this->parentEnum->GetCurrent(ls2); + if(ToBool(callable->Call(ls2,{cur}))) + return true; + + } + return false; + } + TObject GetCurrent(GCList& ls) + { + return this->parentEnum->GetCurrent(ls); + } + void Mark() + { + if(this->marked) return; + this->marked=true; + + if(parentEnum != nullptr) parentEnum->Mark(); + if(callable != nullptr) callable->Mark(); + } + }; + class SelectItterator : public TEnumerator { + private: + TEnumerator* parentEnum; + TCallable* callable; + TObject value; + SelectItterator(TEnumerator* parentEnum, TCallable* callable) : parentEnum(parentEnum), callable(callable) + { + + } + public: + static SelectItterator* Create(GCList& ls, TEnumerator* parentEnum, TCallable* callable) + { + SelectItterator* queryable = new SelectItterator(parentEnum, callable); + std::shared_ptr gc = ls.GetGC(); + ls.Add(queryable); + gc->Watch(queryable); + return queryable; + } + bool MoveNext(std::shared_ptr ls) + { + if(this->parentEnum == nullptr || this->callable == nullptr) return false; + if(this->parentEnum->MoveNext(ls)) + { + GCList ls2(ls); + auto cur = this->parentEnum->GetCurrent(ls2); + auto value = this->callable->Call(ls2,{cur}); + + ls->BarrierBegin(); + this->value = value; + ls->BarrierEnd(); + + return true; + } + return false; + } + TObject GetCurrent(GCList& ls) + { + ls.GetGC()->BarrierBegin(); + auto value=this->value; + ls.GetGC()->BarrierEnd(); + return value; + } + void Mark() + { + if(this->marked) return; + this->marked=true; + + if(parentEnum != nullptr) parentEnum->Mark(); + if(callable != nullptr) callable->Mark(); + + GC::Mark(this->value); + } + }; + + + TEnumerator* TQueryable::GetEnumerator(GCList& ls) + { + switch(this->mode) + { + case TQueryableMode::Skip: + { + int64_t skipCount; + if(GetArgument(args,0,skipCount)) + return SkipItterator::Create(ls, TEnumerator::CreateFromObject(ls, this->parent), skipCount); + } + break; + case TQueryableMode::Take: + { + int64_t takeCount; + if(GetArgument(args,0,takeCount)) + return TakeItterator::Create(ls, TEnumerator::CreateFromObject(ls, this->parent), takeCount); + + } + break; + case TQueryableMode::SkipWhile: + { + TCallable* callable; + if(GetArgumentHeap(args,0,callable)) + return SkipWhileItterator::Create(ls, TEnumerator::CreateFromObject(ls, this->parent), callable); + + } + break; + case TQueryableMode::TakeWhile: + { + TCallable* callable; + if(GetArgumentHeap(args,0,callable)) + return TakeWhileItterator::Create(ls, TEnumerator::CreateFromObject(ls, this->parent), callable); + + } + break; + case TQueryableMode::Select: + { + TCallable* callable; + if(GetArgumentHeap(args,0,callable)) + return SelectItterator::Create(ls, TEnumerator::CreateFromObject(ls, this->parent), callable); + + } + break; + case TQueryableMode::Where: + { + TCallable* callable; + if(GetArgumentHeap(args,0,callable)) + return WhereItterator::Create(ls, TEnumerator::CreateFromObject(ls, this->parent), callable); + + } + break; + } + + return TEnumerator::CreateFromObject(ls, this->parent); + } + +} \ No newline at end of file diff --git a/src/types/streamheapobject.cpp b/src/types/streamheapobject.cpp index 09eaa6e..3f9f38a 100644 --- a/src/types/streamheapobject.cpp +++ b/src/types/streamheapobject.cpp @@ -205,7 +205,7 @@ namespace Tesses::CrossLang TDictionary* dict; if(GetObjectHeap(this->obj, dict)) { - dict->CallMethod(*ls,"Close",{}); + dict->CallMethod(*ls,"Dispose",{}); } } TObjectStream::~TObjectStream() @@ -213,7 +213,7 @@ namespace Tesses::CrossLang TDictionary* dict; if(GetObjectHeap(this->obj, dict)) { - dict->CallMethod(*ls,"Close",{}); + dict->CallMethod(*ls,"Dispose",{}); } delete this->ls; } diff --git a/src/types/vfsheapobject.cpp b/src/types/vfsheapobject.cpp index 30515a5..17907c4 100644 --- a/src/types/vfsheapobject.cpp +++ b/src/types/vfsheapobject.cpp @@ -281,45 +281,45 @@ namespace Tesses::CrossLang { if(GetObjectHeap(res,_dict)) { this->ls->GetGC()->BarrierBegin(); - _o = dict->GetValue("BlockSize"); + _o = _dict->GetValue("BlockSize"); if(GetObject(_o,_num)) data.BlockSize = (uint64_t)_num; - _o = dict->GetValue("BlockCount"); + _o = _dict->GetValue("BlockCount"); if(GetObject(_o,_num)) data.BlockCount = (uint64_t)_num; - _o = dict->GetValue("Device"); + _o = _dict->GetValue("Device"); if(GetObject(_o,_num)) data.Device = (uint64_t)_num; - _o = dict->GetValue("DeviceId"); + _o = _dict->GetValue("DeviceId"); if(GetObject(_o,_num)) data.DeviceId = (uint64_t)_num; - _o = dict->GetValue("GroupId"); + _o = _dict->GetValue("GroupId"); if(GetObject(_o,_num)) data.GroupId = (uint32_t)_num; - _o = dict->GetValue("HardLinks"); + _o = _dict->GetValue("HardLinks"); if(GetObject(_o,_num)) data.HardLinks = (uint64_t)_num; std::shared_ptr dt; - _o = dict->GetValue("LastAccess"); + _o = _dict->GetValue("LastAccess"); if(GetObject(_o,dt)) data.LastAccess = dt ? *dt : Tesses::Framework::Date::DateTime(0); - _o = dict->GetValue("LastModified"); + _o = _dict->GetValue("LastModified"); if(GetObject(_o,dt)) data.LastModified = dt ? *dt : Tesses::Framework::Date::DateTime(0); - _o = dict->GetValue("LastStatus"); + _o = _dict->GetValue("LastStatus"); if(GetObject(_o,dt)) data.LastStatus = dt ? *dt : Tesses::Framework::Date::DateTime(0); - _o = dict->GetValue("Mode"); + _o = _dict->GetValue("Mode"); if(GetObject(_o,_num)) data.Mode = (uint32_t)_num; - _o = dict->GetValue("Size"); + _o = _dict->GetValue("Size"); if(GetObject(_o,_num)) data.Size = (uint64_t)_num; - _o = dict->GetValue("UserId"); + _o = _dict->GetValue("UserId"); if(GetObject(_o,_num)) data.UserId = (uint32_t)_num; @@ -344,28 +344,28 @@ namespace Tesses::CrossLang { if(GetObjectHeap(res,_dict)) { this->ls->GetGC()->BarrierBegin(); - _o = dict->GetValue("BlockSize"); + _o = _dict->GetValue("BlockSize"); if(GetObject(_o,_num)) data.BlockSize = (uint64_t)_num; - _o = dict->GetValue("FragmentSize"); + _o = _dict->GetValue("FragmentSize"); if(GetObject(_o,_num)) data.FragmentSize = (uint64_t)_num; - _o = dict->GetValue("Blocks"); + _o = _dict->GetValue("Blocks"); if(GetObject(_o,_num)) data.Blocks = (uint64_t)_num; - _o = dict->GetValue("BlocksFree"); + _o = _dict->GetValue("BlocksFree"); if(GetObject(_o,_num)) data.BlocksFree = (uint64_t)_num; - _o = dict->GetValue("BlocksAvailable"); + _o = _dict->GetValue("BlocksAvailable"); if(GetObject(_o,_num)) data.BlocksAvailable = (uint64_t)_num; - _o = dict->GetValue("TotalInodes"); + _o = _dict->GetValue("TotalInodes"); if(GetObject(_o,_num)) data.TotalInodes = (uint64_t)_num; - _o = dict->GetValue("FreeInodes"); + _o = _dict->GetValue("FreeInodes"); if(GetObject(_o,_num)) data.FreeInodes = (uint64_t)_num; - _o = dict->GetValue("AvailableInodes"); + _o = _dict->GetValue("AvailableInodes"); if(GetObject(_o,_num)) data.AvailableInodes = (uint64_t)_num; - _o = dict->GetValue("Id"); + _o = _dict->GetValue("Id"); if(GetObject(_o,_num)) data.Id = (uint64_t)_num; - _o = dict->GetValue("Flags"); + _o = _dict->GetValue("Flags"); if(GetObject(_o,_num)) data.Flags = (uint64_t)_num; - _o = dict->GetValue("MaxNameLength"); + _o = _dict->GetValue("MaxNameLength"); if(GetObject(_o,_num)) data.MaxNameLength = (uint64_t)_num; @@ -386,7 +386,7 @@ namespace Tesses::CrossLang { if(GetObjectHeap(this->obj, dict)) { GCList ls(this->ls->GetGC()); - dict->CallMethod(ls,"Close",{}); + dict->CallMethod(ls,"Dispose",{}); } } TObjectVFS::~TObjectVFS() @@ -395,7 +395,7 @@ namespace Tesses::CrossLang { if(GetObjectHeap(this->obj, dict)) { GCList ls(this->ls->GetGC()); - dict->CallMethod(ls,"Close",{}); + dict->CallMethod(ls,"Dispose",{}); } delete this->ls; } diff --git a/src/vm/bc/executemethod2.cpp b/src/vm/bc/executemethod2.cpp index 57fdcc7..c433467 100644 --- a/src/vm/bc/executemethod2.cpp +++ b/src/vm/bc/executemethod2.cpp @@ -668,7 +668,8 @@ namespace Tesses::CrossLang { { if(str[i] != c) break; } - cse.back()->Push(gc,str.substr(i)); + + cse.back()->Push(gc,(!str.empty() && i < str.size()) ? str.substr(i) : ""); return false; } } @@ -682,7 +683,8 @@ namespace Tesses::CrossLang { { if(str[i] != c) break; } - cse.back()->Push(gc,str.substr(0,i+1)); + + cse.back()->Push(gc, (!str.empty() && i < str.size()) ? str.substr(0,i+1) : ""); return false; } } @@ -2168,6 +2170,136 @@ namespace Tesses::CrossLang { auto ttask = dynamic_cast(obj); auto file = dynamic_cast(obj); + auto queryable = dynamic_cast(obj); + + if(queryable != nullptr) + { + if(key == "Skip") + { + int64_t count; + if(GetArgument(args,0,count)) + { + cse.back()->Push(gc, queryable->Skip(ls,count)); + return false; + } + } + if(key == "Take") + { + int64_t count; + if(GetArgument(args,0,count)) + { + cse.back()->Push(gc, queryable->Take(ls,count)); + return false; + } + } + if(key == "SkipWhile") + { + TCallable* callable; + if(GetArgumentHeap(args, 0, callable)) + { + cse.back()->Push(gc, queryable->SkipWhile(ls,callable)); + return false; + } + } + if(key == "TakeWhile") + { + TCallable* callable; + if(GetArgumentHeap(args, 0, callable)) + { + cse.back()->Push(gc, queryable->TakeWhile(ls,callable)); + return false; + } + } + if(key == "Select") + { + TCallable* callable; + if(GetArgumentHeap(args, 0, callable)) + { + cse.back()->Push(gc, queryable->Select(ls,callable)); + return false; + } + } + if(key == "Where") + { + TCallable* callable; + if(GetArgumentHeap(args, 0, callable)) + { + cse.back()->Push(gc, queryable->Where(ls,callable)); + return false; + } + } + if(key == "ToList") + { + cse.back()->Push(gc, queryable->ToList(ls)); + return false; + } + + + + if(key == "ForEach") + { + TCallable* call; + if(GetArgumentHeap(args,0,call)) + { + queryable->ForEach(gc, call); + } + + cse.back()->Push(gc, Undefined()); + return false; + } + + + + if(key == "Count") + { + TCallable* call; + if(GetArgumentHeap(args,0,call)) + { + cse.back()->Push(gc, queryable->Count(gc, call)); + return false; + } + else { + cse.back()->Push(gc, queryable->Count(gc)); + return false; + } + } + if(key == "Contains") + { + if(!args.empty()) + { + cse.back()->Push(gc, queryable->Contains(gc, args[0])); + return false; + } + } + if(key == "All") + { + TCallable* call; + if(GetArgumentHeap(args,0,call)) + { + cse.back()->Push(gc, queryable->All(gc, call)); + return false; + } + } + if(key == "Any") + { + TCallable* call; + if(GetArgumentHeap(args,0,call)) + { + cse.back()->Push(gc, queryable->Any(gc, call)); + return false; + } + } + + if(key == "GetEnumerator") + { + cse.back()->Push(gc, queryable->GetEnumerator(ls)); + return false; + } + + cse.back()->Push(gc, Undefined()); + return false; + } + if(file != nullptr) { if(key == "MetadataDecode")