Fix crosslang Stat, StatVFS for custom crosslang filesystems and add queryable

This commit is contained in:
2026-05-08 23:10:20 -05:00
parent 28eff630c6
commit 7008a6ae61
13 changed files with 940 additions and 36 deletions

6
.vscode/launch.json vendored
View File

@@ -8,10 +8,10 @@
"name": "(gdb) Launch", "name": "(gdb) Launch",
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/builds/linux/crosslang", "program": "${workspaceFolder}/builds/l/crossint",
"args": ["token"], "args": ["queryable.tcross"],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}/builds/l",
"environment": [], "environment": [],
"externalConsole": false, "externalConsole": false,
"MIMode": "gdb", "MIMode": "gdb",

View File

@@ -1,5 +1,8 @@
# Changelog # Changelog
## 0.0.5
Fix crosslang Stat, StatVFS for custom crosslang filesystems and add queryable
## 0.0.4 ## 0.0.4
Rework for git.tesses.org, GC* is std::shared_ptr maybe will fix crash during exit Rework for git.tesses.org, GC* is std::shared_ptr maybe will fix crash during exit

View File

@@ -49,6 +49,7 @@ src/types/streamheapobject.cpp
src/types/class.cpp src/types/class.cpp
src/types/classenvironment.cpp src/types/classenvironment.cpp
src/types/random.cpp src/types/random.cpp
src/types/queryable.cpp
src/vm/filereader.cpp src/vm/filereader.cpp
src/vm/gc.cpp src/vm/gc.cpp
src/vm/gclist.cpp src/vm/gclist.cpp

View File

@@ -1030,6 +1030,11 @@ constexpr std::string_view ForStatement = "forStatement";
* *
*/ */
constexpr std::string_view WhileStatement = "whileStatement"; constexpr std::string_view WhileStatement = "whileStatement";
/**
* @brief using statement using(EXPR)
*
*/
constexpr std::string_view UsingStatement = "usingStatement";
/** /**
* @brief Do statement do(COND) * @brief Do statement do(COND)
* *
@@ -2617,4 +2622,47 @@ class GC : public std::enable_shared_from_this<GC> {
void CrossLangDump(std::shared_ptr<Tesses::Framework::Streams::Stream> strm); void CrossLangDump(std::shared_ptr<Tesses::Framework::Streams::Stream> strm);
void CrossLangCompiler(std::vector<std::string>& argv); void CrossLangCompiler(std::vector<std::string>& argv);
} }
enum class TQueryableMode {
Passthrough,
Skip,
SkipWhile,
Take,
TakeWhile,
Select,
Where
};
class TQueryable : public THeapObject {
TObject parent;
TQueryableMode mode;
std::vector<TObject> args;
TQueryable(TObject parent);
TQueryable(TObject parent, TQueryableMode mode, std::vector<TObject> args);
public:
static TQueryable* Create(GCList& ls, TObject parent);
static TQueryable* Create(GCList& ls, TObject parent, TQueryableMode mode, std::vector<TObject> 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> gc, TCallable* call);
int64_t Count(std::shared_ptr<GC> gc, TCallable* call);
int64_t Count(std::shared_ptr<GC> gc);
bool Contains(std::shared_ptr<GC>, TObject value);
bool Any(std::shared_ptr<GC> gc, TCallable* call);
bool All(std::shared_ptr<GC> gc, TCallable* call);
TList* ToList(GCList& ls);
TEnumerator* GetEnumerator(GCList& ls);
void Mark();
};
}; };

View File

@@ -1383,6 +1383,104 @@ namespace Tesses::CrossLang
instructions.push_back(new LabelInstruction(ifIdEnd)); 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<AdvancedSyntaxNode>(adv.nodes[1]))
{
auto asn2 = std::get<AdvancedSyntaxNode>(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) else if(adv.nodeName == WhileStatement && adv.nodes.size() == 2)
{ {
auto old_contI = contI; auto old_contI = contI;

View File

@@ -615,7 +615,7 @@ namespace Tesses::CrossLang
EnsureSymbol("("); EnsureSymbol("(");
SyntaxNode list = ParseExpression(); SyntaxNode list = ParseExpression();
SyntaxNode body = nullptr; SyntaxNode body = nullptr;
if(IsSymbol(":")) if(IsSymbol(":") || IsIdentifier("in"))
{ {
item = list; item = list;
list = ParseExpression(); list = ParseExpression();
@@ -1406,6 +1406,20 @@ namespace Tesses::CrossLang
} }
return AdvancedSyntaxNode::Create(WhileStatement,false,{cond,body}); 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")) if(IsIdentifier("do"))
{ {
EnsureSymbol("("); EnsureSymbol("(");

View File

@@ -5,7 +5,7 @@
namespace Tesses::CrossLang { namespace Tesses::CrossLang {
#if defined(TESSESFRAMEWORK_ENABLE_SQLITE) #if defined(TESSESFRAMEWORK_ENABLE_SQLITE)
using namespace Tesses::Framework::Serialization; using namespace Tesses::Framework::Serialization;
TObject Sqlite_Escape(GCList& ls, std::vector<TObject> args) TObject Sqlite_Escape(GCList& ls, std::vector<TObject> args)
{ {
int64_t n; int64_t n;
double d; double d;
@@ -33,6 +33,58 @@ namespace Tesses::CrossLang {
return "NULL"; return "NULL";
} }
TObject Sqlite_Prepare(GCList& ls, std::vector<TObject> 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 class SQLiteObject : public TNativeObject
{ {
@@ -65,6 +117,9 @@ namespace Tesses::CrossLang {
if(name == "Escape") { if(name == "Escape") {
return Sqlite_Escape(ls,args); return Sqlite_Escape(ls,args);
} }
if(name == "Prepare") {
return Sqlite_Prepare(ls,args);
}
if(name == "Exec") if(name == "Exec")
{ {
std::string arg; std::string arg;
@@ -105,6 +160,7 @@ namespace Tesses::CrossLang {
} }
}; };
TObject Sqlite_Open(GCList& ls, std::vector<TObject> args,TRootEnvironment* env) TObject Sqlite_Open(GCList& ls, std::vector<TObject> args,TRootEnvironment* env)
{ {
Tesses::Framework::Filesystem::VFSPath p; Tesses::Framework::Filesystem::VFSPath p;
@@ -149,6 +205,7 @@ namespace Tesses::CrossLang {
return Undefined(); return Undefined();
} }
#endif #endif
void TStd::RegisterSqlite(std::shared_ptr<GC> gc,TRootEnvironment* env) void TStd::RegisterSqlite(std::shared_ptr<GC> 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,"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,"Close","Close sql database",{"handle"},Sqlite_Close);
dict->DeclareFunction(gc,"Escape","Escape sql text",{"text"},Sqlite_Escape); dict->DeclareFunction(gc,"Escape","Escape sql text",{"text"},Sqlite_Escape);
dict->DeclareFunction(gc,"Prepare", "Prepare sql",{"sql","items"}, Sqlite_Prepare);
gc->BarrierBegin(); gc->BarrierBegin();
env->DeclareVariable("Sqlite", dict); env->DeclareVariable("Sqlite", dict);

View File

@@ -610,6 +610,12 @@ namespace Tesses::CrossLang
std::shared_ptr<Tesses::Framework::Date::TimeSpan> dt; std::shared_ptr<Tesses::Framework::Date::TimeSpan> dt;
return GetArgument(args,0,dt); return GetArgument(args,0,dt);
} }
static TObject TypeIsQueryable(GCList& ls, std::vector<TObject> args)
{
if(args.empty()) return nullptr;
TQueryable* queryable;
return GetArgumentHeap(args,0,queryable);
}
static TObject New_SubdirFilesystem(GCList& ls, std::vector<TObject> args) static TObject New_SubdirFilesystem(GCList& ls, std::vector<TObject> args)
{ {
std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs; std::shared_ptr<Tesses::Framework::Filesystem::VFS> vfs;
@@ -902,6 +908,7 @@ namespace Tesses::CrossLang
auto cobj = dynamic_cast<TClassObject*>(obj); auto cobj = dynamic_cast<TClassObject*>(obj);
auto aarray = dynamic_cast<TAssociativeArray*>(obj); auto aarray = dynamic_cast<TAssociativeArray*>(obj);
auto file = dynamic_cast<TFile*>(obj); auto file = dynamic_cast<TFile*>(obj);
auto queryable = dynamic_cast<TQueryable*>(obj);
if(rootEnv != nullptr) return "RootEnvironment"; if(rootEnv != nullptr) return "RootEnvironment";
if(subEnv != nullptr) return "SubEnvironment"; if(subEnv != nullptr) return "SubEnvironment";
@@ -923,6 +930,7 @@ namespace Tesses::CrossLang
if(native != nullptr) return "Native"; if(native != nullptr) return "Native";
if(any != nullptr) return "Any"; if(any != nullptr) return "Any";
if(file != nullptr) return "File"; if(file != nullptr) return "File";
if(queryable != nullptr) return "Queryable";
return "HeapObject"; return "HeapObject";
} }
@@ -1304,6 +1312,16 @@ namespace Tesses::CrossLang
return nullptr; return nullptr;
} }
static TObject New_Queryable(GCList& ls, std::vector<TObject> args)
{
if(!args.empty())
{
return TQueryable::Create(ls, args.front());
}
return nullptr;
}
void TStd::RegisterRoot(std::shared_ptr<GC> gc, TRootEnvironment* env) void TStd::RegisterRoot(std::shared_ptr<GC> gc, TRootEnvironment* env)
{ {
GCList ls(gc); 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, "TypeIsByteReader","Get whether object is a ByteReader",{"object"},TypeIsByteReader);
env->DeclareFunction(gc, "TypeIsByteWriter","Get whether object is a ByteWriter",{"object"},TypeIsByteWriter); 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, "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<TObject> args)->TObject { newTypes->DeclareFunction(gc, "Regex", "Create regex object",{"regex"},[](GCList& ls,std::vector<TObject> args)->TObject {
std::string str; std::string str;
@@ -1476,6 +1494,7 @@ namespace Tesses::CrossLang
return TAssociativeArray::Create(ls); 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);
newTypes->DeclareFunction(gc, "Queryable", "Create a queryable", {"enumerable"}, New_Queryable);
env->DeclareVariable("Version", TDictionary::Create(ls,{ env->DeclareVariable("Version", TDictionary::Create(ls,{
TDItem("Parse",TExternalMethod::Create(ls,"Parse version from string",{"versionStr"},[](GCList& ls, std::vector<TObject> args)->TObject{ TDItem("Parse",TExternalMethod::Create(ls,"Parse version from string",{"versionStr"},[](GCList& ls, std::vector<TObject> args)->TObject{

View File

@@ -132,6 +132,7 @@ namespace Tesses::CrossLang
TDynamicDictionary* dynDict; TDynamicDictionary* dynDict;
TDictionary* dict; TDictionary* dict;
TEnumerator* enumerator; TEnumerator* enumerator;
TQueryable* q;
if(GetObject(obj,str)) if(GetObject(obj,str))
{ {
return TStringEnumerator::Create(ls, str); return TStringEnumerator::Create(ls, str);
@@ -156,6 +157,14 @@ namespace Tesses::CrossLang
return enumerator; return enumerator;
} }
} }
else if(GetObjectHeap(obj, q))
{
return q->GetEnumerator(ls);
}
else if(GetObjectHeap(obj, enumerator))
{
return enumerator;
}
return nullptr; return nullptr;
} }
TVFSPathEnumerator* TVFSPathEnumerator::Create(GCList& ls, Tesses::Framework::Filesystem::VFSPathEnumerator enumerator) TVFSPathEnumerator* TVFSPathEnumerator::Create(GCList& ls, Tesses::Framework::Filesystem::VFSPathEnumerator enumerator)

522
src/types/queryable.cpp Normal file
View File

@@ -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<TObject> 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> gc = ls.GetGC();
ls.Add(queryable);
gc->Watch(queryable);
return queryable;
}
TQueryable* TQueryable::Create(GCList& ls, TObject parent, TQueryableMode mode, std::vector<TObject> args)
{
TQueryable* queryable = new TQueryable(parent, mode,args);
std::shared_ptr<GC> 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> 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> 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> 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> 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> 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> 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> gc = ls.GetGC();
ls.Add(queryable);
gc->Watch(queryable);
return queryable;
}
bool MoveNext(std::shared_ptr<GC> 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> gc = ls.GetGC();
ls.Add(queryable);
gc->Watch(queryable);
return queryable;
}
bool MoveNext(std::shared_ptr<GC> 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> gc = ls.GetGC();
ls.Add(queryable);
gc->Watch(queryable);
return queryable;
}
bool MoveNext(std::shared_ptr<GC> 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> gc = ls.GetGC();
ls.Add(queryable);
gc->Watch(queryable);
return queryable;
}
bool MoveNext(std::shared_ptr<GC> 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> gc = ls.GetGC();
ls.Add(queryable);
gc->Watch(queryable);
return queryable;
}
bool MoveNext(std::shared_ptr<GC> 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> gc = ls.GetGC();
ls.Add(queryable);
gc->Watch(queryable);
return queryable;
}
bool MoveNext(std::shared_ptr<GC> 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);
}
}

View File

@@ -205,7 +205,7 @@ namespace Tesses::CrossLang
TDictionary* dict; TDictionary* dict;
if(GetObjectHeap(this->obj, dict)) if(GetObjectHeap(this->obj, dict))
{ {
dict->CallMethod(*ls,"Close",{}); dict->CallMethod(*ls,"Dispose",{});
} }
} }
TObjectStream::~TObjectStream() TObjectStream::~TObjectStream()
@@ -213,7 +213,7 @@ namespace Tesses::CrossLang
TDictionary* dict; TDictionary* dict;
if(GetObjectHeap(this->obj, dict)) if(GetObjectHeap(this->obj, dict))
{ {
dict->CallMethod(*ls,"Close",{}); dict->CallMethod(*ls,"Dispose",{});
} }
delete this->ls; delete this->ls;
} }

View File

@@ -281,45 +281,45 @@ namespace Tesses::CrossLang {
if(GetObjectHeap(res,_dict)) if(GetObjectHeap(res,_dict))
{ {
this->ls->GetGC()->BarrierBegin(); this->ls->GetGC()->BarrierBegin();
_o = dict->GetValue("BlockSize"); _o = _dict->GetValue("BlockSize");
if(GetObject(_o,_num)) data.BlockSize = (uint64_t)_num; 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; 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; 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; 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; 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; if(GetObject(_o,_num)) data.HardLinks = (uint64_t)_num;
std::shared_ptr<Tesses::Framework::Date::DateTime> dt; std::shared_ptr<Tesses::Framework::Date::DateTime> dt;
_o = dict->GetValue("LastAccess"); _o = _dict->GetValue("LastAccess");
if(GetObject(_o,dt)) data.LastAccess = dt ? *dt : Tesses::Framework::Date::DateTime(0); 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); 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); 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; 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; 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; if(GetObject(_o,_num)) data.UserId = (uint32_t)_num;
@@ -344,28 +344,28 @@ namespace Tesses::CrossLang {
if(GetObjectHeap(res,_dict)) if(GetObjectHeap(res,_dict))
{ {
this->ls->GetGC()->BarrierBegin(); this->ls->GetGC()->BarrierBegin();
_o = dict->GetValue("BlockSize"); _o = _dict->GetValue("BlockSize");
if(GetObject(_o,_num)) data.BlockSize = (uint64_t)_num; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; if(GetObject(_o,_num)) data.MaxNameLength = (uint64_t)_num;
@@ -386,7 +386,7 @@ namespace Tesses::CrossLang {
if(GetObjectHeap(this->obj, dict)) if(GetObjectHeap(this->obj, dict))
{ {
GCList ls(this->ls->GetGC()); GCList ls(this->ls->GetGC());
dict->CallMethod(ls,"Close",{}); dict->CallMethod(ls,"Dispose",{});
} }
} }
TObjectVFS::~TObjectVFS() TObjectVFS::~TObjectVFS()
@@ -395,7 +395,7 @@ namespace Tesses::CrossLang {
if(GetObjectHeap(this->obj, dict)) if(GetObjectHeap(this->obj, dict))
{ {
GCList ls(this->ls->GetGC()); GCList ls(this->ls->GetGC());
dict->CallMethod(ls,"Close",{}); dict->CallMethod(ls,"Dispose",{});
} }
delete this->ls; delete this->ls;
} }

View File

@@ -668,7 +668,8 @@ namespace Tesses::CrossLang {
{ {
if(str[i] != c) break; 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; return false;
} }
} }
@@ -682,7 +683,8 @@ namespace Tesses::CrossLang {
{ {
if(str[i] != c) break; 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; return false;
} }
} }
@@ -2168,6 +2170,136 @@ namespace Tesses::CrossLang {
auto ttask = dynamic_cast<TTask*>(obj); auto ttask = dynamic_cast<TTask*>(obj);
auto file = dynamic_cast<TFile*>(obj); auto file = dynamic_cast<TFile*>(obj);
auto queryable = dynamic_cast<TQueryable*>(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(file != nullptr)
{ {
if(key == "MetadataDecode") if(key == "MetadataDecode")