Add thumbnailer support and TVMVersion and TFile are now accessable from language

This commit is contained in:
2025-03-28 22:01:56 -05:00
parent 0a87476cfa
commit 0af37d2b9f
29 changed files with 1706 additions and 101 deletions

View File

@ -3,7 +3,7 @@
namespace Tesses::CrossLang
{
void CrossArchiveCreate(Tesses::Framework::Filesystem::VFS* vfs,Tesses::Framework::Streams::Stream* strm,std::string name, TVMVersion version, std::string info)
void CrossArchiveCreate(Tesses::Framework::Filesystem::VFS* vfs,Tesses::Framework::Streams::Stream* strm,std::string name, TVMVersion version, std::string info, std::string icon)
{
std::vector<std::string> ignored_files;
std::string file = "/.crossarchiveignore";
@ -125,6 +125,8 @@ namespace Tesses::CrossLang
};
walkFS(std::string("/"));
if(!icon.empty())
ensureResource(icon);
uint8_t main_header[18];
memcpy(main_header,"TCROSSVM",8);
@ -132,7 +134,7 @@ namespace Tesses::CrossLang
rtVersion.ToArray(main_header+8);
version.ToArray(main_header+13);
strm->WriteBlock(main_header,sizeof(main_header));
writeInt(strm,(uint32_t)(5+resources.size()));
writeInt(strm,(uint32_t)((icon.empty() ? 5 : 6)+resources.size()));
strm->WriteBlock((const uint8_t*)"STRS",4);
uint32_t sz=4;
for(auto str : strs)

View File

@ -103,14 +103,14 @@ static json_t* Serialize2(SyntaxNode node)
{
char c = std::get<char>(node);
json_t* json = json_object();
json_object_set_new(json,"type",json_string(CharExpression.begin()));
json_object_set_new(json,"type",json_string((const char*)CharExpression.data()));
json_object_set_new(json, "value", json_integer((uint8_t)c));
return json;
}
if(std::holds_alternative<Undefined>(node))
{
json_t* json = json_object();
json_object_set_new(json,"type",json_string(UndefinedExpression.begin()));
json_object_set_new(json,"type",json_string((const char*)UndefinedExpression.data()));
return json;
}
@ -148,4 +148,4 @@ return str;
return "";
}
}
}

View File

@ -42,14 +42,28 @@ namespace Tesses::CrossLang
uint32_t sections=5;
uint32_t name = GetString(this->name);
uint32_t info = GetString(this->info);
for(auto& dep : this->dependencies)
{
GetString(dep.first);
sections++;
}
for(auto& tool : this->tools)
{
GetString(tool.first);
sections++;
}
if(!this->icon.empty())
{
this->GetResource(this->icon);
}
for(auto& res : this->res)
sections++;
if(!this->icon.empty())
sections++;
WriteInt(stream,sections);
uint32_t strSz=4;
@ -81,6 +95,15 @@ namespace Tesses::CrossLang
dep.second.ToArray(buffer);
Write(stream,buffer,5);
}
for(auto& tool : this->tools)
{
memcpy(buffer,"TOOL",4);
Write(stream,buffer,4);
WriteInt(stream,9); //even though its ignored
WriteInt(stream,GetString(tool.first));
tool.second.ToArray(buffer);
Write(stream,buffer,5);
}
uint32_t fnLen=4;
@ -155,7 +178,7 @@ namespace Tesses::CrossLang
WriteInt(stream,(uint32_t)buffer.size());
Write(stream,buffer.data(),buffer.size());
}
for(auto& reso : res)
{
memcpy(buffer,"RESO",4);
@ -186,6 +209,14 @@ namespace Tesses::CrossLang
WriteInt(stream,0);
}
}
if(!this->icon.empty())
{
memcpy(buffer,"ICON",4);
Write(stream,buffer,4);
WriteInt(stream,4);
WriteInt(stream,this->GetResource(this->icon));
}
}
@ -430,7 +461,15 @@ namespace Tesses::CrossLang
TWO_EXPR(NotEqualsExpression, NEQ)
TWO_EXPR(EqualsExpression, EQ)
TWO_EXPR(XOrExpression, XOR)
if(adv.nodeName == SwitchStatement && adv.nodes.size() == 2)
if(adv.nodeName == RelativePathExpression)
{
instructions.push_back(new SimpleInstruction(Instruction::PUSHRELATIVEPATH));
}
else if(adv.nodeName == RootPathExpression)
{
instructions.push_back(new SimpleInstruction(Instruction::PUSHROOTPATH));
}
else if(adv.nodeName == SwitchStatement && adv.nodes.size() == 2)
{
//THIS CODE WORKED FIRST TRY, I DON'T SEE THAT EVERY DAY, PRAISE GOD!!!!!!!
auto expr = adv.nodes[0];

View File

@ -1,5 +1,6 @@
#include "CrossLang.hpp"
#include <iostream>
#include <stdexcept>
namespace Tesses::CrossLang
{
std::string LexTokenType_ToString(LexTokenType t)
@ -135,24 +136,25 @@ namespace Tesses::CrossLang
else if(IsSymbol("{"))
{
if(IsSymbol("}",false))
node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{});
node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{});
else
node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{ParseExpression()});
node = AdvancedSyntaxNode::Create(DictionaryExpression,true,{ParseExpression()});
EnsureSymbol("}");
}
else if(IsSymbol("("))
{
if(IsSymbol(")",false))
node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{});
node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{});
else
node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{ParseExpression()});
node = AdvancedSyntaxNode::Create(ParenthesesExpression,true,{ParseExpression()});
EnsureSymbol(")");
}
else if(IsIdentifier("var"))
{
if(i >= tokens.size()) throw std::out_of_range("End of file");
auto variable = tokens[i];
i++;
auto variable = tokens[i];
i++;
if(variable.type != LexTokenType::Identifier) throw SyntaxException(variable.lineInfo, "Expected an identifier got a " + LexTokenType_ToString(variable.type) + " \"" + variable.text + "\"");
node = AdvancedSyntaxNode::Create(DeclareExpression,true,{variable.text});
}
@ -347,6 +349,23 @@ namespace Tesses::CrossLang
{
return AdvancedSyntaxNode::Create(PrefixDecrementExpression,true,{ParseUnary()});
}
else if(IsSymbol("/"))
{
if(this->i < this->tokens.size() && (this->tokens[this->i].type == LexTokenType::String || this->tokens[this->i].type == LexTokenType::Identifier))
{
return AdvancedSyntaxNode::Create(DivideExpression,true,{
AdvancedSyntaxNode::Create(RootPathExpression,true,{}),
ParseValue()
});
}
else {
return AdvancedSyntaxNode::Create(RootPathExpression,true,{});
}
}
else if(IsSymbol("."))
{
return AdvancedSyntaxNode::Create(RelativePathExpression, true, {});
}
return ParseValue();
}
@ -569,6 +588,98 @@ namespace Tesses::CrossLang
if(IsIdentifier("object"))
{
//TODO: complete this
if(i < tokens.size())
{
std::string name = tokens[i++].text;
EnsureSymbol("{");
std::vector<SyntaxNode> name_and_methods;
name_and_methods.push_back(name);
while(!IsSymbol("}",false) && i < tokens.size())
{
std::string documentation = "";
bool hasDocumentation=false;
if(tokens[i].type == LexTokenType::Documentation)
{
hasDocumentation=true;
documentation = tokens[i++].text;
}
if(i < tokens.size())
{
if(IsIdentifier("method"))
{
auto nameAndArgs = ParseExpression();
if(IsSymbol("{",false))
{
auto r = AdvancedSyntaxNode::Create(MethodDeclaration,false,{nameAndArgs,ParseNode()});
if(hasDocumentation)
{
name_and_methods.push_back(AdvancedSyntaxNode::Create(DocumentationStatement,false,{documentation,r}));
}
else
{
name_and_methods.push_back(r);
}
}
else
{
auto v = ParseExpression();
EnsureSymbol(";");
auto r= AdvancedSyntaxNode::Create(MethodDeclaration,false,{nameAndArgs,AdvancedSyntaxNode::Create(ReturnStatement,false,{v})});
if(hasDocumentation)
{
name_and_methods.push_back(AdvancedSyntaxNode::Create(DocumentationStatement,false,{documentation,r}));
}
else
{
name_and_methods.push_back(r);
}
}
}
else if(IsIdentifier("static"))
{
auto nameAndArgs = ParseExpression();
if(IsSymbol("{",false))
{
auto r = AdvancedSyntaxNode::Create(StaticStatement,false,{nameAndArgs,ParseNode()});
if(hasDocumentation)
{
name_and_methods.push_back(AdvancedSyntaxNode::Create(DocumentationStatement,false,{documentation,r}));
}
else
{
name_and_methods.push_back(r);
}
}
else
{
auto v = ParseExpression();
EnsureSymbol(";");
auto r= AdvancedSyntaxNode::Create(StaticStatement,false,{nameAndArgs,AdvancedSyntaxNode::Create(ReturnStatement,false,{v})});
if(hasDocumentation)
{
name_and_methods.push_back(AdvancedSyntaxNode::Create(DocumentationStatement,false,{documentation,r}));
}
else
{
name_and_methods.push_back(r);
}
}
}
}
}
EnsureSymbol("}");
return AdvancedSyntaxNode::Create(ObjectStatement, false, name_and_methods);
}
else throw std::out_of_range("End of file");
}
if(IsIdentifier("enumerable"))
{

View File

@ -8,6 +8,7 @@ void Help(const char* filename)
printf("USAGE: %s [OPTIONS] <dirasroot> <archive.crvm>\n", filename);
printf("OPTIONS:\n");
printf(" -i: Set info (ex {\"maintainer\": \"Mike Nolan\", \"repo\": \"https://example.com/\", \"homepage\": \"https://example.com/\",\"license\":\"MIT\"})\n");
printf(" -I: Set icon name (relative to dirasroot), should be a 128x128 png\n");
printf(" -v: Set version (1.0.0.0-prod defaults to 1.0.0.0-dev)\n");
printf(" -n: Set name (MyAppOrLibName defaults to out)\n");
printf(" -h, --help: Prints help\n");
@ -19,6 +20,7 @@ int main(int argc, char** argv)
std::string name="out";
std::string info="{}";
TVMVersion version;
std::string icon="";
std::vector<std::string> args;
for(int i = 1; i < argc; i++)
{
@ -34,6 +36,14 @@ int main(int argc, char** argv)
info = argv[i];
}
}
else if(strcmp(argv[i], "-I") == 0)
{
i++;
if(i < argc)
{
icon = argv[i];
}
}
else if(strcmp(argv[i], "-n") == 0)
{
i++;
@ -77,7 +87,7 @@ int main(int argc, char** argv)
}
FileStream strm(f,true,"wb",true);
CrossArchiveCreate(&sdfs,&strm,name,version,info);
CrossArchiveCreate(&sdfs,&strm,name,version,info,icon);
return 0;
}

View File

@ -10,8 +10,10 @@ void Help(const char* filename)
printf("OPTIONS:\n");
printf(" -o: Output directory (OUTDIR, defaults to ./bin)\n");
printf(" -i: Set info (ex {\"maintainer\": \"Mike Nolan\", \"repo\": \"https://example.com/\", \"homepage\": \"https://example.com/\",\"license\":\"MIT\"})\n");
printf(" -I: Set icon resource name (in the resource folder), should be a 128x128 png\n");
printf(" -v: Set version (1.0.0.0-prod defaults to 1.0.0.0-dev)\n");
printf(" -d: Add dependency (DependencyName-1.0.0.0-prod)\n");
printf(" -t: Declare a tool (ToolName-1.0.0.0-prod)\n");
printf(" -n: Set name (MyAppOrLibName defaults to out)\n");
printf(" -r: Set resource directory (RESDIR defaults to res)\n");
printf(" -h, --help: Prints help\n");
@ -37,8 +39,10 @@ int main(int argc, char** argv)
std::vector<std::filesystem::path> source;
std::filesystem::path resourceDir = std::filesystem::current_path() / "res";
std::vector<std::pair<std::string, TVMVersion>> dependencies;
std::vector<std::pair<std::string, TVMVersion>> tools;
std::string name="out";
std::string info="{}";
std::string icon="";
TVMVersion version;
@ -72,6 +76,14 @@ int main(int argc, char** argv)
info = argv[i];
}
}
else if(strcmp(argv[i],"-I") == 0)
{
i++;
if(i < argc)
{
icon = argv[i];
}
}
else if(strcmp(argv[i], "-d") == 0)
{
i++;
@ -106,6 +118,40 @@ int main(int argc, char** argv)
}
}
}
else if(strcmp(argv[i], "-t") == 0)
{
i++;
if(i < argc)
{
std::string str = argv[i];
auto lastDash = str.find_last_of('-');
if(lastDash < str.size())
{
std::string str2 = str.substr(lastDash+1);
if(str2 == "dev" || str2 == "alpha" || str2 == "beta" || str2 == "prod")
{
lastDash = str.find_last_of('-',lastDash-1);
}
std::string str1 = str.substr(0,lastDash);
str2 = str.substr(lastDash+1);
TVMVersion v2;
if(!TVMVersion::TryParse(str2,v2))
{
printf("ERROR: Invalid syntax for version\n");
printf("Expected MAJOR[.MINOR[.PATCH[.BUILD[-dev,-alpha,-beta,-prod]]]]\n");
exit(1);
}
tools.push_back(std::pair<std::string,TVMVersion>(str1,v2));
}
else
{
printf("ERROR: Tool must have version\n");
exit(1);
}
}
}
else if(strcmp(argv[i], "-n") == 0)
{
i++;
@ -154,10 +200,16 @@ int main(int argc, char** argv)
gen.name = name;
gen.version = version;
gen.info = info;
gen.icon = icon;
for(auto deps : dependencies)
{
gen.dependencies.push_back(deps);
}
for(auto tool : tools)
{
gen.tools.push_back(tool);
}
std::filesystem::create_directory(outputDir);
{

View File

@ -53,13 +53,18 @@ void DumpFile(std::filesystem::path p)
char table_name[4];
bool hasIcon=false;
for(size_t i = 0; i < _len; i++)
{
Ensure(strm,(uint8_t*)table_name,sizeof(table_name));
size_t tableLen = (size_t)EnsureInt(strm);
std::string tableName(table_name,4);
if(tableName == "STRS")
if(tableName == "ICON")
{
hasIcon=true;
}
else if(tableName == "STRS")
{
size_t strsLen = (size_t)EnsureInt(strm);
for(size_t j = 0;j < strsLen;j++)
@ -129,6 +134,10 @@ void DumpFile(std::filesystem::path p)
strm.Seek((int64_t)tableLen,Tesses::Framework::Streams::SeekOrigin::Current);
}
}
if(hasIcon)
std::cout << "Has Icon: yes" << std::endl;
else
std::cout << "Has Icon: no" << std::endl;
for(size_t i = 1; i < closures.size(); i++)
{

61
src/crossthumbnailer.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "CrossLang.hpp"
#include <TessesFramework/Common.hpp>
#include <TessesFramework/Filesystem/LocalFS.hpp>
#include <TessesFramework/Filesystem/VFS.hpp>
#include <TessesFramework/Streams/Stream.hpp>
#include <ios>
#include <iostream>
#include <fstream>
int main(int argc,char** argv)
{
std::string p = argv[0];
auto emptyThumb =Tesses::CrossLang::GetRealExecutablePath(p).GetParent().GetParent() / "share" / "icons" / "crosslang.png";
if(argc < 3)
{
std::cout << "USAGE: " << argv[0] << " CRVMFILE NEWPNG" << std::endl;
return 1;
}
std::string crvm = argv[1];
std::string png = argv[2];
Tesses::Framework::Filesystem::LocalFilesystem lfs;
if(lfs.FileExists(crvm))
{
Tesses::CrossLang::TFile file;
auto f = lfs.OpenFile(crvm, "rb");
file.Load(nullptr,f);
delete f;
if(file.icon >= 0 && file.icon < file.resources.size())
{
auto f2 = lfs.OpenFile(png, "wb");
if(f2 != nullptr)
{
auto& icon = file.resources[file.icon];
f2->WriteBlock(icon.data(),icon.size());
delete f2;
}
return 0;
}
}
if(lfs.FileExists(emptyThumb))
{
auto src = lfs.OpenFile(emptyThumb,"rb");
auto dest = lfs.OpenFile(png,"wb");
if(src != nullptr && dest != nullptr)
{
src->CopyTo(dest);
}
delete src;
delete dest;
}
return 0;
}

View File

@ -82,11 +82,13 @@ namespace Tesses::CrossLang
std::string name;
std::string version;
std::string info;
std::string icon="";
TVMVersion version2;
if(GetArgumentHeap(args,0,vfs) && GetArgumentHeap(args,1,strm) && GetArgument(args,2,name) && GetArgument(args,3,version) && GetArgument(args,4,info) && TVMVersion::TryParse(version,version2))
if(GetArgumentHeap(args,0,vfs) && GetArgumentHeap(args,1,strm) && GetArgument(args,2,name) && GetArgument(args,4,info) && ((GetArgument(args,3,version) && TVMVersion::TryParse(version,version2)) || GetArgument(args,3,version2)))
{
CrossArchiveCreate(vfs->vfs,strm->stream,name,version2,info);
GetArgument(args,5,icon);
CrossArchiveCreate(vfs->vfs,strm->stream,name,version2,info,icon);
}
return nullptr;
}

View File

@ -80,7 +80,7 @@ namespace Tesses::CrossLang
return json_null();
}
static TObject Json_Encode(GCList& ls2, std::vector<TObject> args)
static TObject JsonEncode(GCList& ls2, std::vector<TObject> args)
{
if(args.size() >= 1)
{
@ -141,7 +141,7 @@ namespace Tesses::CrossLang
}
return Undefined();
}
static TObject Json_Decode(GCList& ls2,std::vector<TObject> args)
static TObject JsonDecode(GCList& ls2,std::vector<TObject> args)
{
if(args.size() > 0 && std::holds_alternative<std::string>(args[0]))
{
@ -155,6 +155,31 @@ namespace Tesses::CrossLang
return Undefined();
}
#endif
std::string Json_Encode(TObject o,bool indent)
{
#if defined(CROSSLANG_ENABLE_JSON)
auto json = JsonSerialize(o);
char* txt = json_dumps(json, indent ? JSON_INDENT(4) : 0);
std::string str = txt;
free(txt);
json_decref(json);
return str;
#else
return "";
#endif
}
TObject Json_Decode(GCList ls,std::string str)
{
#if defined(CROSSLANG_ENABLE_JSON)
json_t* json = json_loadb(str.c_str(), str.size(),0,NULL);
auto res = JsonDeserialize(ls,json);
json_decref(json);
return res;
#else
return nullptr;
#endif
}
void TStd::RegisterJson(GC* gc,TRootEnvironment* env)
{
@ -162,8 +187,8 @@ namespace Tesses::CrossLang
#if defined(CROSSLANG_ENABLE_JSON)
GCList ls(gc);
TDictionary* dict = TDictionary::Create(ls);
dict->DeclareFunction(gc, "Decode","Deserialize Json",{"Json string"},Json_Decode);
dict->DeclareFunction(gc, "Encode","Serialize Json",{"any","$indent"},Json_Encode);
dict->DeclareFunction(gc, "Decode","Deserialize Json",{"Json string"},JsonDecode);
dict->DeclareFunction(gc, "Encode","Serialize Json",{"any","$indent"},JsonEncode);
gc->BarrierBegin();

View File

@ -1,4 +1,10 @@
#include "CrossLang.hpp"
#include <TessesFramework/Crypto/ClientTLSStream.hpp>
#include <TessesFramework/Http/HttpClient.hpp>
#include <TessesFramework/Mail/Smtp.hpp>
#include <TessesFramework/Streams/MemoryStream.hpp>
#include <TessesFramework/Streams/NetworkStream.hpp>
#include <TessesFramework/Streams/Stream.hpp>
#include <sys/types.h>
#include <csignal>
#include <iostream>
@ -6,8 +12,33 @@
#include <cstring>
using namespace Tesses::Framework::Streams;
using namespace Tesses::Framework::Http;
using namespace Tesses::Framework::Mail;
namespace Tesses::CrossLang
{
static SMTPBody* TObjectToSMTPBody(GCList& ls,std::string mimeType, TObject obj)
{
SMTPBody* body = nullptr;
std::string text;
TByteArray* ba;
TStreamHeapObject* sho;
if(GetObject(obj,text))
{
body = new SMTPStringBody(text,mimeType);
}
else if(GetObjectHeap(obj,ba)) {
MemoryStream* ms = new MemoryStream(true);
ms->WriteBlock(ba->data.data(), ba->data.size());
ms->Seek(0L, SeekOrigin::Begin);
body = new SMTPStreamBody(mimeType,ms,true);
}
else if(GetObjectHeap(obj,sho))
{
ls.Add(sho);
body = new SMTPStreamBody(mimeType,sho->stream,false);
}
return body;
}
TServerHeapObject* TServerHeapObject::Create(GCList& ls, Tesses::Framework::Http::IHttpServer* svr)
{
TServerHeapObject* ho = new TServerHeapObject();
@ -157,7 +188,17 @@ namespace Tesses::CrossLang
dict->DeclareFunction(gc,"OpenResponseStream","Open Response Stream",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {
return TStreamHeapObject::Create(ls2, ctx->OpenResponseStream());
});
dict->DeclareFunction(gc, "ParseFormData","Parse the form data",{},[ctx](GCList& ls, std::vector<TObject> args)->TObject {
TCallable* callable;
if(GetArgumentHeap(args, 0, callable))
{
ctx->ParseFormData([callable,&ls](std::string a,std::string b, std::string c)->Tesses::Framework::Streams::Stream*{
auto res = callable->Call(ls,{a,b,c});
return new Tesses::CrossLang::TObjectStream(ls.GetGC(),res);
});
}
return nullptr;
});
dict->DeclareFunction(gc,"getNeedToParseFormData","Check if Need to parse form data",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
return ctx->NeedToParseFormData();
});
@ -169,13 +210,13 @@ namespace Tesses::CrossLang
dict->DeclareFunction(gc,"SendText","Send response text",{"text"},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
std::string text;
if(GetArgument(args2,0,text))
ctx->SendText(text);
ctx->SendText(text);
return nullptr;
});
dict->DeclareFunction(gc,"WithMimeType","Set mime type",{"mimeType"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
std::string text;
if(GetArgument(args2,0,text))
ctx->WithMimeType(text);
ctx->WithMimeType(text);
return dict;
});
dict->DeclareFunction(gc,"WithContentDisposition","Set content disposition",{"filename","inline"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
@ -205,6 +246,11 @@ namespace Tesses::CrossLang
ctx->SendBytes(ba->data);
return nullptr;
});
dict->DeclareFunction(gc,"WriteHeaders","Send the headers",{},[ctx](GCList& ls, std::vector<TObject> args)->TObject{
ctx->WriteHeaders();
return nullptr;
});
// dict->DeclareFunction(gc,"getUrlWithQuery","Get original path with query parameters",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {return ctx->GetUrlWithQuery();});
dict->DeclareFunction(gc,"StartWebSocketSession","Start websocket session",{"dict"}, [ctx](GCList& ls,std::vector<TObject> args)->TObject {
TDictionary* dict;
@ -582,6 +628,143 @@ namespace Tesses::CrossLang
return nullptr;
}
static TObject Net_Smtp_Send(GCList& ls, std::vector<TObject> args)
{
TDictionary* dict;
if(GetArgumentHeap(args,0,dict))
{
//the body should be either type text/plain or text/html
//the body and attachment data can also point to bytearray of stream
//server can also be a stream
//as of right now the email is fire and forget (ie no error checking)
//check function return type just in case (this function returns a empty string if no error)
//we rolled our own smtp client
/*
dict looks like this from crosslang's point of view
{
server = {
host = "smtp.example.com",
tls = true
},
auth = {
username = "from",
password = "THEPASSWORD"
},
domain = "example.com",
from = {
name = "The name shown in the mail where it is from",
email = "from@example.com"
},
to = "to@example.com",
subject = "My little message",
body = {
type = "text/html",
data = "<h1>Hello, world</h1>"
},
attachments = [
{
name = "myimg.png",
type = "image/png",
data = embed("myimg.png")
}
]
}
*/
ls.GetGC()->BarrierBegin();
auto server = dict->GetValue("server");
TDictionary* dict2;
Tesses::Framework::Streams::Stream* strm=nullptr;
bool ownsStream=true;
TStreamHeapObject* objStrm;
if(GetObjectHeap(server,dict2))
{
auto tlsO = dict2->GetValue("tls");
auto hostO = dict2->GetValue("host");
auto portO = dict2->GetValue("port");
std::string host;
bool tls=false;
int64_t port;
GetObject(tlsO,tls);
if(!GetObject(portO, port)) port = tls ? 465 : 25;
GetObject(hostO,host);
strm = new NetworkStream(host,(uint16_t)port,false,false,false);
if(tls)
{
strm = new Framework::Crypto::ClientTLSStream(strm,true,true,host);
}
}
else if (GetObjectHeap(server, objStrm)) {
ownsStream=false;
strm = objStrm->stream;
}
Tesses::Framework::Mail::SMTPClient client(strm,ownsStream);
auto o = dict->GetValue("domain");
GetObject(o,client.domain);
o = dict->GetValue("to");
GetObject(o,client.to);
o = dict->GetValue("subject");
GetObject(o,client.subject);
o = dict->GetValue("auth");
if(GetObjectHeap(o, dict2))
{
o = dict2->GetValue("username");
GetObject(o,client.username);
o = dict2->GetValue("password");
GetObject(o, client.password);
}
o = dict->GetValue("from");
if(GetObjectHeap(o, dict2))
{
o = dict2->GetValue("email");
GetObject(o,client.from);
o = dict2->GetValue("name");
GetObject(o, client.from_name);
}
o = dict->GetValue("body");
if(GetObjectHeap(o, dict2))
{
//type, data
std::string type = "text/plain";
o = dict2->GetValue("type");
GetObject(o,type);
o = dict2->GetValue("data");
client.body = TObjectToSMTPBody(ls,type,o);
}
o = dict->GetValue("attachments");
TList* als;
if(GetObjectHeap(o,als))
{
for(int64_t i = 0; i < als->Count(); i++)
{
auto item = als->Get(i);
if(GetObjectHeap(item, dict2))
{
o = dict2->GetValue("name");
std::string name;
GetObject(o,name);
std::string type = "text/plain";
o = dict2->GetValue("type");
GetObject(o,type);
o = dict2->GetValue("data");
client.attachments.push_back(std::pair<std::string,SMTPBody*>(name,TObjectToSMTPBody(ls, type, o)));
}
}
}
ls.GetGC()->BarrierEnd();
client.Send();
return "";
}
return nullptr;
}
void TStd::RegisterNet(GC* gc, TRootEnvironment* env)
{
@ -591,6 +774,7 @@ namespace Tesses::CrossLang
TDictionary* dict = TDictionary::Create(ls);
TDictionary* http = TDictionary::Create(ls);
TDictionary* smtp = TDictionary::Create(ls);
http->DeclareFunction(gc, "HtmlEncode","Html encode",{"param"}, Net_HtmlEncode);
http->DeclareFunction(gc, "UrlEncode","Url encode query param",{"param"}, Net_UrlEncode);
@ -601,6 +785,29 @@ namespace Tesses::CrossLang
//http->DeclareFunction(gc, "ProcessServer","Process HTTP server connection",{"networkstream","server","ip","port","encrypted"},, Net_ProcessServer);
http->DeclareFunction(gc, "StreamHttpRequestBody","Create a stream request body",{"stream","mimeType"},[](GCList& ls, std::vector<TObject> args)->TObject {
std::string mimeType;
if(GetArgument(args, 1, mimeType))
{
auto res = TNative::Create(ls,new StreamHttpRequestBody(new TObjectStream(ls.GetGC(),args[0]), true, mimeType),[](void* ptr)->void {
delete static_cast<StreamHttpRequestBody*>(ptr);
});
return res;
}
return nullptr;
});
http->DeclareFunction(gc, "TextHttpRequestBody","Create a text request body",{"text","mimeType"},[](GCList& ls, std::vector<TObject> args)->TObject {
std::string text;
std::string mimeType;
if(GetArgument(args, 0, text) && GetArgument(args, 1, mimeType))
{
auto res = TNative::Create(ls,new TextHttpRequestBody(text, mimeType),[](void* ptr)->void {
delete static_cast<TextHttpRequestBody*>(ptr);
});
return res;
}
return nullptr;
});
http->DeclareFunction(gc, "MakeRequest", "Create an http request", {"url","$extra"}, Net_Http_MakeRequest);
http->DeclareFunction(gc, "ListenSimpleWithLoop", "Listen (creates application loop)", {"server","port"},Net_Http_ListenSimpleWithLoop);
//FileServer svr()
@ -626,8 +833,10 @@ namespace Tesses::CrossLang
return nullptr;
});
dict->DeclareFunction(gc, "NetworkStream","Create a network stream",{"ipv6","datagram"},Net_NetworkStream);
smtp->DeclareFunction(gc, "Send","Send email via smtp server",{"messageStruct"},Net_Smtp_Send);
gc->BarrierBegin();
dict->SetValue("Http", http);
dict->SetValue("Smtp", smtp);
env->DeclareVariable("Net", dict);
gc->BarrierEnd();
}

View File

@ -65,5 +65,8 @@ namespace Tesses::CrossLang
gc->BarrierEnd();
#endif
env->permissions.canRegisterOGC=true;
}
}

View File

@ -118,18 +118,7 @@ namespace Tesses::CrossLang
TVFSHeapObject* vfs;
return GetArgumentHeap(args,0,vfs);
}
static TObject New_Color(GCList& ls, std::vector<TObject> args)
{
int64_t r,g,b,a;
if(GetArgument(args,0,r) && GetArgument(args,1,g) && GetArgument(args,2,b))
{
if(!GetArgument(args,3,a)) {
a = 255;
}
return Tesses::Framework::Graphics::Color((uint8_t)r,(uint8_t)g,(uint8_t)b,(uint8_t)a);
}
return Tesses::Framework::Graphics::Colors::Black;
}
static TObject TypeOf(GCList& ls, std::vector<TObject> args)
{
if(args.size() < 1) return "Undefined";
@ -345,6 +334,30 @@ namespace Tesses::CrossLang
env->permissions.canRegisterRoot=true;
TDictionary* newTypes = TDictionary::Create(ls);
newTypes->DeclareFunction(gc,"Version","Create a version object",{"$major","$minor","$patch","$build","$stage"},[](GCList& ls, std::vector<TObject> args)->TObject{
int64_t major=1;
int64_t minor=0;
int64_t patch=0;
int64_t build=0;
std::string stageS="prod";
TVMVersionStage stage=TVMVersionStage::ProductionVersion;
GetArgument(args, 0,major);
GetArgument(args, 1,minor);
GetArgument(args, 2,patch);
GetArgument(args, 3,build);
GetArgument(args, 4,stageS);
if(stageS == "dev")
stage = TVMVersionStage::DevVersion;
else if(stageS == "alpha")
stage = TVMVersionStage::AlphaVersion;
else if(stageS == "beta")
stage = TVMVersionStage::BetaVersion;
return TVMVersion((uint8_t)major,(uint8_t)minor,(uint8_t)patch,(uint16_t)build,stage);
});
env->DeclareFunction(gc, "ParseLong","Parse Long from String",{"arg","$base"},ParseLong);
env->DeclareFunction(gc, "ParseDouble","Parse Double from String",{"arg"},ParseDouble);
env->DeclareFunction(gc, "YieldEmumerable","Turn yield in function into enumerable",{"closure"},YieldEnumerableFunc);
@ -428,8 +441,35 @@ namespace Tesses::CrossLang
return Undefined();
});
env->DeclareFunction(gc,"ByteArray","Create bytearray, with optional either size (to size it) or string argument (to fill byte array)",{"$data"},ByteArray);
newTypes->DeclareFunction(gc,"Color","Create a new color",{"red","green","blue","$alpha"},New_Color);
gc->BarrierBegin();
env->DeclareVariable("Version", TDictionary::Create(ls,{
TDItem("Parse",TExternalMethod::Create(ls,"Parse version from string",{"versionStr"},[](GCList& ls, std::vector<TObject> args)->TObject{
std::string str;
if(GetArgument(args, 0, str))
{
TVMVersion version;
if(TVMVersion::TryParse(str,version))
{
return version;
}
}
return nullptr;
})),
TDItem("FromByteArray",TExternalMethod::Create(ls,"Create from ByteArray",{"byteArray","$offset"},[](GCList& ls,std::vector<TObject> args)->TObject {
TByteArray* ba;
if(GetArgumentHeap(args,0, ba))
{
int64_t offset=0;
GetArgument(args, 1, offset);
if(ba->data.size() < 5) throw VMException("ByteArray too small");
size_t o = (size_t)offset;
if((o + 5) > ba->data.size() || (o + 5) < 5) throw VMException("ByteArray too small");
return TVMVersion(ba->data.data()+o);
}
return nullptr;
}))
}));
env->DeclareVariable("InvokeMethod",MethodInvoker());
env->DeclareVariable("New", newTypes);
gc->BarrierEnd();

View File

@ -78,29 +78,7 @@ namespace Tesses::CrossLang
int64_t msec;
if(GetArgument(args,0,msec))
{
if((msec % 100) == 0)
{
msec /= 100;
for(int64_t i = 0; i < msec; i++)
{
usleep(100000);
}
}
else if((msec % 10) == 0)
{
msec /= 10;
for(int64_t i = 0; i < msec; i++)
{
usleep(10000);
}
}
else
{
for(int64_t i = 0; i < msec; i++)
{
usleep(1000);
}
}
usleep(1000*msec);
}
return nullptr;
}

View File

@ -134,7 +134,9 @@ namespace Tesses::CrossLang
std::vector<std::pair<std::string,std::string>> sources;
TVMVersion version(TVM_MAJOR,TVM_MINOR,TVM_PATCH,TVM_BUILD,TVM_VERSIONSTAGE);
std::vector<std::pair<std::string,TVMVersion>> dependencies;
std::vector<std::pair<std::string,TVMVersion>> tools;
std::string info;
std::string icon;
TVFSHeapObject* vfsHO =nullptr;
ls.GetGC()->BarrierBegin();
@ -142,17 +144,23 @@ namespace Tesses::CrossLang
TObject _version = dict->GetValue("Version");
TObject _sources = dict->GetValue("Sources");
TObject _dependencies = dict->GetValue("Dependencies");
TObject _tools = dict->GetValue("Tools");
TObject _info = dict->GetValue("Info");
TObject _icon = dict->GetValue("Icon");
TObject _resourceFileSystem = dict->GetValue("ResourceFileSystem");
TObject _out = dict->GetValue("Output");
TList* _toolList;
TList* _depList; TList* srcLst;
GetObject<std::string>(_name,name);
GetObject<std::string>(_info,info);
GetObject<std::string>(_icon,icon);
GetObjectHeap(_resourceFileSystem, vfsHO);
std::string v2;
if(GetObject<std::string>(_version,v2))
TVMVersion::TryParse(v2, version);
else
GetObject(_version,version);
if(GetObjectHeap<TList*>(_dependencies,_depList))
{
@ -172,6 +180,36 @@ namespace Tesses::CrossLang
{
dependencies.push_back(std::pair<std::string,TVMVersion>(name2, version02));
}
else if(GetObject<std::string>(_name2,name2) && GetObject(_version2,version02))
{
dependencies.push_back(std::pair<std::string,TVMVersion>(name2, version02));
}
}
}
}
if(GetObjectHeap<TList*>(_tools,_toolList))
{
for(int64_t i = 0; i < _toolList->Count(); i++)
{
TObject _dep = _toolList->Get(i);
TDictionary* _depD;
if(GetObjectHeap<TDictionary*>(_dep, _depD))
{
TObject _name2 = _depD->GetValue("Name");
TObject _version2 = _depD->GetValue("Version");
std::string name2;
std::string version2;
TVMVersion version02;
if(GetObject<std::string>(_name2,name2) && GetObject<std::string>(_version2,version2) && TVMVersion::TryParse(version2,version02))
{
tools.push_back(std::pair<std::string,TVMVersion>(name2, version02));
}
else if(GetObject<std::string>(_name2,name2) && GetObject(_version2,version02))
{
tools.push_back(std::pair<std::string,TVMVersion>(name2, version02));
}
}
}
@ -220,9 +258,11 @@ namespace Tesses::CrossLang
CodeGen gen;
gen.GenRoot(n);
gen.dependencies = dependencies;
gen.tools = tools;
gen.info = info;
gen.name = name;
gen.version = version;
gen.icon = icon;
std::string outpath;
TStreamHeapObject* stream;
if(GetObjectHeap<TStreamHeapObject*>(_out, stream))
@ -274,7 +314,9 @@ namespace Tesses::CrossLang
dict->DeclareFunction(gc, "Compile", "Compile Source",{"dict"},VM_Compile);
dict->DeclareFunction(gc, "SourceToAst", "Convert source to ast", {"source"}, VM_SourceToAst);
dict->DeclareFunction(gc, "getRuntimeVersion","Get the runtime version",{},[](GCList& ls,std::vector<TObject> args)->TObject {
return TVMVersion(TVM_MAJOR,TVM_MINOR,TVM_PATCH,TVM_BUILD,TVM_VERSIONSTAGE);
});
gc->BarrierBegin();
env->DeclareVariable("VM", dict);
gc->BarrierEnd();

View File

@ -32,6 +32,13 @@ namespace Tesses::CrossLang {
if(this->marked) return;
this->marked = true;
this->callable->Mark();
GC::Mark(this->tag);
}
void TCallable::Mark()
{
if(this->marked) return;
this->marked=true;
GC::Mark(this->tag);
}
void TClosure::Mark()
{
@ -40,7 +47,7 @@ namespace Tesses::CrossLang {
this->file->Mark();
this->env->Mark();
this->closure->Mark();
GC::Mark(this->tag);
}
TClosure* TClosure::Create(GCList& ls,TEnvironment* env,TFile* file,uint32_t chunkId,bool ownScope)
{

View File

@ -72,6 +72,15 @@ namespace Tesses::CrossLang {
return TEnumerator::CreateFromObject(ls,cb->Call(ls,{dict}));
}
bool TDictionary::MethodExists(GCList& ls,std::string method)
{
ls.GetGC()->BarrierBegin();
auto r = this->GetValue(method);
TCallable* callable;
bool res = GetObjectHeap(r,callable);
ls.GetGC()->BarrierEnd();
return res;
}
bool TDynamicDictionary::MethodExists(GCList& ls,std::string name)
{
auto dict = TDictionary::Create(ls);

View File

@ -10,6 +10,7 @@ namespace Tesses::CrossLang
TFile* TFile::Create(GCList& ls)
{
TFile* f = new TFile();
f->icon = -1;
GC* _gc = ls.GetGC();
ls.Add(f);
_gc->Watch(f);
@ -18,6 +19,7 @@ namespace Tesses::CrossLang
TFile* TFile::Create(GCList* ls)
{
TFile* f = new TFile();
f->icon=-1;
GC* _gc = ls->GetGC();
ls->Add(f);
_gc->Watch(f);
@ -91,13 +93,13 @@ namespace Tesses::CrossLang
std::string TFile::GetString(Tesses::Framework::Streams::Stream* stream)
{
uint32_t index=EnsureInt(stream);
if(index > this->strings.size()) throw VMException("String does not exist in TCrossVM file, expected string index: " + std::to_string(index) + ", total strings: " + std::to_string(this->strings.size()));
if(index >= this->strings.size()) throw VMException("String does not exist in TCrossVM file, expected string index: " + std::to_string(index) + ", total strings: " + std::to_string(this->strings.size()));
return this->strings[index];
}
void TFile::Load(GC* gc, Tesses::Framework::Streams::Stream* stream)
{
GCList ls(gc);
uint8_t main_header[18];
Ensure(stream,main_header,sizeof(main_header));
if(strncmp((const char*)main_header,"TCROSSVM",8) != 0) throw VMException("Invalid TCrossVM image.");
@ -133,6 +135,14 @@ namespace Tesses::CrossLang
TVMVersion depVersion(version_bytes);
this->dependencies.push_back(std::pair<std::string,TVMVersion>(name, depVersion));
}
else if(strncmp(table_name,"TOOL",4) == 0) //compile tools (for package manager)
{
std::string name = GetString(stream);
uint8_t version_bytes[5];
Ensure(stream,version_bytes,sizeof(version_bytes));
TVMVersion depVersion(version_bytes);
this->tools.push_back(std::pair<std::string,TVMVersion>(name, depVersion));
}
else if(strncmp(table_name,"RESO",4) == 0) //resources (using embed)
{
std::vector<uint8_t> data;
@ -140,11 +150,13 @@ namespace Tesses::CrossLang
Ensure(stream,data.data(), tableLen);
this->resources.push_back(data);
}
else if(strncmp(table_name,"CHKS",4) == 0) //chunks
else if(strncmp(table_name,"CHKS",4) == 0 && gc != nullptr) //chunks
{
GCList ls(gc);
size_t chunkCount = (size_t)EnsureInt(stream);
for(size_t j = 0; j < chunkCount; j++)
{
auto chunk = TFileChunk::Create(ls);
chunk->file = this;
size_t argCount = (size_t)EnsureInt(stream);
@ -159,6 +171,7 @@ namespace Tesses::CrossLang
this->chunks.push_back(chunk);
}
}
else if(strncmp(table_name,"FUNS",4) == 0) //functions
{
@ -187,6 +200,10 @@ namespace Tesses::CrossLang
this->strings.push_back(EnsureString(stream));
}
}
else if(strncmp(table_name,"ICON",4) == 0) //icon
{
this->icon = (int32_t)EnsureInt(stream);
}
else
{
Skip(stream,tableLen);

View File

@ -1,8 +1,11 @@
#include "CrossLang.hpp"
#include <TessesFramework/Filesystem/VFS.hpp>
#include <cstddef>
#include <iostream>
#include <cmath>
#include <cstring>
#include <sstream>
#include <variant>
namespace Tesses::CrossLang {
thread_local CallStackEntry* current_function=nullptr;
@ -13,6 +16,11 @@ namespace Tesses::CrossLang {
{
return true;
}
if(std::holds_alternative<TVMVersion>(obj))
{
auto v = std::get<TVMVersion>(obj);
return v.AsLong() != 0;
}
if(std::holds_alternative<std::string>(obj))
{
return !std::get<std::string>(obj).empty();
@ -192,6 +200,7 @@ namespace Tesses::CrossLang {
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary*>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
if(dict != nullptr)
{
gc->BarrierBegin();
@ -568,7 +577,13 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc,std::get<int64_t>(left) < std::get<double>(right));
}
else if(std::holds_alternative<TVMVersion>(left) && std::holds_alternative<TVMVersion>(right))
{
auto lver= std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r < 0);
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
@ -624,7 +639,13 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc,std::get<int64_t>(left) > std::get<double>(right));
}
else if(std::holds_alternative<TVMVersion>(left) && std::holds_alternative<TVMVersion>(right))
{
auto lver= std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r > 0);
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
@ -680,7 +701,13 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc,std::get<int64_t>(left) <= std::get<double>(right));
}
else if(std::holds_alternative<TVMVersion>(left) && std::holds_alternative<TVMVersion>(right))
{
auto lver= std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r <= 0);
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
@ -736,7 +763,14 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc,std::get<int64_t>(left) >= std::get<double>(right));
}
else if(std::holds_alternative<TVMVersion>(left) && std::holds_alternative<TVMVersion>(right))
{
auto lver= std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r >= 0);
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
@ -816,7 +850,13 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc,std::get<char>(left) == std::get<char>(right));
}
else if(std::holds_alternative<TVMVersion>(left) && std::holds_alternative<TVMVersion>(right))
{
auto lver= std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r == 0);
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
@ -903,7 +943,13 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc,std::get<char>(left) != std::get<char>(right));
}
else if(std::holds_alternative<TVMVersion>(left) && std::holds_alternative<TVMVersion>(right))
{
auto lver= std::get<TVMVersion>(left);
auto rver = std::get<TVMVersion>(right);
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r != 0);
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
@ -1373,7 +1419,26 @@ namespace Tesses::CrossLang {
{
GCList ls(gc);
std::regex regex;
if(GetObject(instance,regex))
TVMVersion version;
if(GetObject(instance, version))
{
if(key == "ToString")
{
cse.back()->Push(gc, version.ToString());
return false;
}
if(key == "ToByteArray")
{
TByteArray* ba = TByteArray::Create(ls);
ba->data.resize(5);
version.ToArray(ba->data.data());
cse.back()->Push(gc,ba);
return false;
}
cse.back()->Push(gc, Undefined());
return false;
}
else if(GetObject(instance,regex))
{
if(key == "Search")
{
@ -1682,9 +1747,9 @@ namespace Tesses::CrossLang {
{
size_t idx = (size_t)idx;
if(idx < path.path.size())
cse.back()->Push(gc, path.path[idx]);
cse.back()->Push(gc, path.path[idx]);
else
cse.back()->Push(gc, nullptr);
cse.back()->Push(gc, nullptr);
return false;
}
}
@ -1728,11 +1793,6 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, path.CollapseRelativeParents());
return false;
}
if(key == "RelativeCurrentDirectory")
{
cse.back()->Push(gc, path.RelativeCurrentDirectory());
return false;
}
if(key == "IsRelative")
{
cse.back()->Push(gc, path.relative);
@ -3230,12 +3290,20 @@ namespace Tesses::CrossLang {
}
else if(list != nullptr)
{
if(key == "GetEnumerator")
{
cse.back()->Push(gc, TListEnumerator::Create(ls,list));
return false;
}
if(key == "Insert")
else if(key == "ToString")
{
cse.back()->Push(gc,Json_Encode(list));
return false;
}
else if(key == "Insert")
{
if(args.size() != 2)
{
@ -3344,9 +3412,15 @@ namespace Tesses::CrossLang {
}
else if(dict != nullptr)
{
if(key == "ToString" && !dict->MethodExists(ls, key) && args.empty())
{
cse.back()->Push(gc,Json_Encode(dict));
return false;
}
gc->BarrierBegin();
auto o = dict->GetValue(key);
gc->BarrierEnd();
return InvokeMethod(ls,o,dict,args);
}
@ -3473,7 +3547,57 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, Undefined());
return false;
}
if(std::holds_alternative<TVMVersion>(instance))
{
TVMVersion& version = std::get<TVMVersion>(instance);
if(key == "Major")
{
stk->Push(gc, (int64_t)version.Major());
return false;
}
if(key == "Minor")
{
stk->Push(gc, (int64_t)version.Minor());
return false;
}
if(key == "Patch")
{
stk->Push(gc, (int64_t)version.Patch());
return false;
}
if(key == "Build")
{
stk->Push(gc, (int64_t)version.Build());
return false;
}
if(key == "VersionInt")
{
stk->Push(gc,(int64_t)version.AsLong());
return false;
}
if(key == "Stage")
{
switch(version.VersionStage())
{
case TVMVersionStage::DevVersion:
stk->Push(gc,"dev");
break;
case TVMVersionStage::AlphaVersion:
stk->Push(gc,"alpha");
break;
case TVMVersionStage::BetaVersion:
stk->Push(gc,"beta");
break;
case TVMVersionStage::ProductionVersion:
stk->Push(gc,"prod");
break;
}
return false;
}
stk->Push(gc, Undefined());
return false;
}
if(std::holds_alternative<THeapObjectHolder>(instance))
{
auto obj = std::get<THeapObjectHolder>(instance).obj;
@ -3487,6 +3611,123 @@ namespace Tesses::CrossLang {
auto strm = dynamic_cast<TStreamHeapObject*>(obj);
auto vfs = dynamic_cast<TVFSHeapObject*>(obj);
auto callstackEntry = dynamic_cast<CallStackEntry*>(obj);
auto file = dynamic_cast<TFile*>(obj);
auto chunk = dynamic_cast<TFileChunk*>(obj);
if(file != nullptr)
{
if(key == "Version")
{
cse.back()->Push(gc,file->version);
return false;
}
else if(key == "Name")
{
cse.back()->Push(gc,file->name);
return false;
}
else if(key == "Info")
{
cse.back()->Push(gc, file->info);
return false;
}
else if(key == "Dependencies")
{
auto list = TList::Create(ls);
gc->BarrierBegin();
for(auto item : file->dependencies)
{
auto res = TDictionary::Create(ls);
res->SetValue("Name", item.first);
res->SetValue("Version", item.second);
list->Add(res);
}
gc->BarrierEnd();
cse.back()->Push(gc, list);
return false;
}
else if(key == "Tools")
{
auto list = TList::Create(ls);
gc->BarrierBegin();
for(auto item : file->tools)
{
auto res = TDictionary::Create(ls);
res->SetValue("Name", item.first);
res->SetValue("Version", item.second);
list->Add(res);
}
gc->BarrierEnd();
cse.back()->Push(gc, list);
return false;
}
else if(key == "Strings")
{
auto list = TList::Create(ls);
gc->BarrierBegin();
for(auto item : file->name)
{
list->Add(item);
}
gc->BarrierEnd();
cse.back()->Push(gc, list);
return false;
}
else if(key == "Chunks")
{
auto list = TList::Create(ls);
gc->BarrierBegin();
for(auto item : file->chunks)
{
list->Add(item);
}
gc->BarrierEnd();
cse.back()->Push(gc, list);
return false;
}
else if(key == "Functions")
{
auto list = TList::Create(ls);
gc->BarrierBegin();
for(auto item : file->functions)
{
TDictionary* dict = TDictionary::Create(ls);
if(!item.first.empty())
dict->SetValue("Documentation", item.first[0]);
TList* nameParts = TList::Create(ls);
for(size_t i = 1; i < item.first.size(); i++)
{
nameParts->Add(item.first[i]);
}
dict->SetValue("NameParts", nameParts);
dict->SetValue("ChunkId", (int64_t)item.second);
list->Add(dict);
}
cse.back()->Push(gc, list);
gc->BarrierEnd();
return false;
}
else if(key == "Icon")
{
if(file->icon >= 0 && file->icon < file->resources.size())
{
TByteArray* ba = TByteArray::Create(ls);
ba->data = file->resources[file->icon];
cse.back()->Push(gc, ba);
return false;
}
else {
cse.back()->Push(gc, nullptr);
}
}
cse.back()->Push(gc, Undefined());
return false;
}
if(callstackEntry != nullptr)
{
@ -3591,7 +3832,7 @@ namespace Tesses::CrossLang {
}
if(closure != nullptr)
{
if(key == "args")
if(key == "Arguments")
{
GCList ls2(gc);
TList* ls = TList::Create(ls2);
@ -3602,10 +3843,15 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc,ls);
return false;
}
if(key == "File")
{
cse.back()->Push(gc,closure->file);
return false;
}
}
if(externalMethod != nullptr)
{
if(key == "args")
if(key == "Arguments")
{
GCList ls2(gc);
TList* ls = TList::Create(ls2);
@ -3620,11 +3866,18 @@ namespace Tesses::CrossLang {
if(tcallable != nullptr)
{
if(key == "documentation")
if(key == "Documentation")
{
cse.back()->Push(gc, tcallable->documentation);
return false;
}
if(key == "Tag")
{
gc->BarrierBegin();
cse.back()->Push(gc, tcallable->tag);
gc->BarrierEnd();
return false;
}
cse.back()->Push(gc,Undefined());
return false;
}
@ -3703,7 +3956,18 @@ namespace Tesses::CrossLang {
auto vfs = dynamic_cast<TVFSHeapObject*>(obj);
auto strm = dynamic_cast<TStreamHeapObject*>(obj);
auto dict = dynamic_cast<TDictionary*>(obj);
auto tcallable = dynamic_cast<TCallable*>(obj);
if(tcallable != nullptr)
{
if(key == "Tag")
{
gc->BarrierBegin();
tcallable->tag = value;
gc->BarrierEnd();
cse.back()->Push(gc,nullptr);
return false;
}
}
if(strm != nullptr)
{
auto netStrm = dynamic_cast<Tesses::Framework::Streams::NetworkStream*>(strm->stream);
@ -4347,6 +4611,28 @@ namespace Tesses::CrossLang {
return false;
}
bool InterperterThread::PushRelativePath(GC* gc)
{
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
auto stk = cse.back();
auto p = Framework::Filesystem::VFSPath();
p.relative=true;
p.path={};
stk->Push(gc, p);
return false;
}
bool InterperterThread::PushRootPath(GC* gc)
{
std::vector<CallStackEntry*>& cse=this->call_stack_entries;
auto stk = cse.back();
auto p = Framework::Filesystem::VFSPath();
p.relative=false;
p.path={};
stk->Push(gc, p);
return false;
}
bool InterperterThread::Illegal(GC* gc)
{
@ -4373,7 +4659,7 @@ namespace Tesses::CrossLang {
if(!cse.empty())
{
auto stk = cse.back();
current_function = stk;
@ -4675,7 +4961,7 @@ namespace Tesses::CrossLang {
ls.GetGC()->BarrierBegin();
CallStackEntry* cse = CallStackEntry::Create(ls);
cse->callable = closure;
cse->env = closure->chunkId == 0 ? closure->env : closure->env->GetSubEnvironment(ls);
cse->env = closure->chunkId == 0 ? closure->env : closure->ownScope ? closure->env->GetSubEnvironment(ls) : closure->env;
cse->ip = 0;
if(closure->closure->args.empty() && closure->chunkId != 0)
{
@ -4717,7 +5003,7 @@ namespace Tesses::CrossLang {
};
size_t required = requiredArguments();
if(args.size() < requiredArguments())
if(args.size() < required)
{
throw VMException("Called a function that expected at least " + std::to_string(required) + " args but got " + std::to_string(args.size()));
}
@ -4729,10 +5015,11 @@ namespace Tesses::CrossLang {
}
if(i == closure->closure->args.size()-1)
{
auto argName = closure->closure->args[i];
auto lsArgs = TList::Create(ls);
for(;i<args.size(); i++)
lsArgs->Add(args[i]);
cse->env->DeclareVariable(trimStart(closure->closure->args[i]), lsArgs);
cse->env->DeclareVariable(trimStart(argName), lsArgs);
i = args.size();
}
if(i<args.size())
@ -4755,6 +5042,10 @@ namespace Tesses::CrossLang {
{
return std::get<std::string>(o);
}
if(std::holds_alternative<TVMVersion>(o))
{
return std::get<TVMVersion>(o).ToString();
}
if(std::holds_alternative<int64_t>(o))
{
return std::to_string(std::get<int64_t>(o));
@ -4786,14 +5077,28 @@ namespace Tesses::CrossLang {
{
auto obj = std::get<THeapObjectHolder>(o).obj;
auto dict = dynamic_cast<TDictionary*>(obj);
auto list = dynamic_cast<TList*>(obj);
auto bArray = dynamic_cast<TByteArray*>(obj);
if(dict != nullptr)
{
GCList ls(gc);
GCList ls(gc);
if(dict->MethodExists(ls,"ToString"))
return ToString(gc,dict->CallMethod(ls,"ToString",{}));
else
{
return Json_Encode(dict);
}
}
else if(bArray != nullptr)
{
return std::string(bArray->data.begin(),bArray->data.end());
}
else if(list != nullptr)
{
return Json_Encode(list);
}
}
return "";
}
}
}

File diff suppressed because one or more lines are too long