Add html expression, console error and streams

This commit is contained in:
2025-04-29 05:02:54 -05:00
parent cdc72478d3
commit 295f56231d
15 changed files with 705 additions and 262 deletions

View File

@ -18,6 +18,7 @@ option(CROSSLANG_ENABLE_SQLITE "Enable sqlite (Embedded database, supports Wii)"
option(CROSSLANG_ENABLE_PROCESS "Enable process" ON) option(CROSSLANG_ENABLE_PROCESS "Enable process" ON)
option(CROSSLANG_ENABLE_TERMIOS "Enable termios (For changing terminal options)" ON) option(CROSSLANG_ENABLE_TERMIOS "Enable termios (For changing terminal options)" ON)
option(CROSSLANG_ENABLE_PLATFORM_FOLDERS "Enable platform folders" ON) option(CROSSLANG_ENABLE_PLATFORM_FOLDERS "Enable platform folders" ON)
option(CROSSLANG_ENABLE_TIME "Enable Time" ON)
option(CROSSLANG_SHARED_EXECUTABLES "Link with libcrosslang_shared" ON) option(CROSSLANG_SHARED_EXECUTABLES "Link with libcrosslang_shared" ON)
option(CROSSLANG_FETCHCONTENT "Use fetchcontent" ON) option(CROSSLANG_FETCHCONTENT "Use fetchcontent" ON)
option(CROSSLANG_ENABLE_CONFIG_ENVVAR "Allow setting config directory via the environment variable CROSSLANG_CONFIG" ON) option(CROSSLANG_ENABLE_CONFIG_ENVVAR "Allow setting config directory via the environment variable CROSSLANG_CONFIG" ON)
@ -51,6 +52,9 @@ else()
find_package(TessesFramework REQUIRED) find_package(TessesFramework REQUIRED)
endif() endif()
function(CROSSLANG_LINK_DEPS CROSSLANG_TARGET_NAME) function(CROSSLANG_LINK_DEPS CROSSLANG_TARGET_NAME)
if(CROSSLANG_ENABLE_TIME)
target_compile_definitions(${CROSSLANG_TARGET_NAME} PUBLIC CROSSLANG_ENABLE_TIME)
endif()
if(CROSSLANG_ENABLE_CONFIG_ENVVAR) if(CROSSLANG_ENABLE_CONFIG_ENVVAR)
target_compile_definitions(${CROSSLANG_TARGET_NAME} PUBLIC CROSSLANG_ENABLE_CONFIG_ENVVAR) target_compile_definitions(${CROSSLANG_TARGET_NAME} PUBLIC CROSSLANG_ENABLE_CONFIG_ENVVAR)
endif() endif()

View File

@ -116,6 +116,14 @@ namespace Tesses::CrossLang {
{ {
this->SetVersion(versionData[0],versionData[1],versionData[2],versionData[3],versionData[4]); this->SetVersion(versionData[0],versionData[1],versionData[2],versionData[3],versionData[4]);
} }
void SetFromLong(uint64_t v)
{
this->major = (uint8_t)((v >> 32) & 0xFF);
this->minor = (uint8_t)(v >> 24) & 0xFF;
this->patch = (uint8_t)(v >> 16) & 0xFF;
this->build = (uint16_t)(v & 0xFFFF);
}
void ToArray(uint8_t* versionData) void ToArray(uint8_t* versionData)
{ {
versionData[0] = major; versionData[0] = major;
@ -139,6 +147,10 @@ namespace Tesses::CrossLang {
this->patch=0; this->patch=0;
this->SetBuild(0, TVMVersionStage::DevVersion); this->SetBuild(0, TVMVersionStage::DevVersion);
} }
TVMVersion(uint64_t v)
{
this->SetFromLong(v);
}
int CompareTo(TVMVersion& version) int CompareTo(TVMVersion& version)
{ {
if(this->major > version.major) return 1; if(this->major > version.major) return 1;
@ -315,6 +327,7 @@ typedef enum {
LexTokenLineInfo lineInfo; LexTokenLineInfo lineInfo;
LexTokenType type; LexTokenType type;
std::string text; std::string text;
std::string whiteSpaceCharsBefore;
}; };
int Lex(std::string filename, std::istream& strm, std::vector<LexToken>& tokens); int Lex(std::string filename, std::istream& strm, std::vector<LexToken>& tokens);
@ -538,7 +551,7 @@ class CodeGen {
~CodeGen(); ~CodeGen();
}; };
constexpr std::string_view HtmlRootExpression = "htmlRootExpression";
constexpr std::string_view EmbedExpression = "embedExpression"; constexpr std::string_view EmbedExpression = "embedExpression";
constexpr std::string_view NegativeExpression = "negativeExpression"; constexpr std::string_view NegativeExpression = "negativeExpression";
constexpr std::string_view NotExpression = "notExpression"; constexpr std::string_view NotExpression = "notExpression";
@ -628,6 +641,8 @@ SyntaxNode Deserialize(std::string astData);
std::string Serialize(SyntaxNode node); std::string Serialize(SyntaxNode node);
class Parser { class Parser {
uint32_t id;
uint32_t NewId();
uint64_t i; uint64_t i;
std::vector<LexToken> tokens; std::vector<LexToken> tokens;
@ -654,6 +669,7 @@ class Parser {
SyntaxNode ParseFactor(); SyntaxNode ParseFactor();
SyntaxNode ParseValue(); SyntaxNode ParseValue();
SyntaxNode ParseUnary(); SyntaxNode ParseUnary();
void ParseHtml(std::vector<SyntaxNode>& nodes,std::string var);
public: public:
Parser(std::vector<LexToken> tokens); Parser(std::vector<LexToken> tokens);
SyntaxNode ParseRoot() SyntaxNode ParseRoot()

View File

@ -1075,14 +1075,36 @@ namespace Tesses::CrossLang
instructions.push_back(new EmbedInstruction(GetResource(filename))); instructions.push_back(new EmbedInstruction(GetResource(filename)));
} }
else if(adv.nodeName == HtmlRootExpression)
{
scope++;
instructions.push_back(new SimpleInstruction(SCOPEBEGIN));
instructions.push_back(new StringInstruction(GetString(std::get<std::string>(adv.nodes[0]))));
instructions.push_back(new StringInstruction(GetString("")));
instructions.push_back(new SimpleInstruction(DECLAREVARIABLE));
instructions.push_back(new SimpleInstruction(POP));
for(size_t i = 1; i < adv.nodes.size(); i++)
{
GenNode(instructions,adv.nodes[i],scope,contscope,brkscope,contI,brkI);
GenPop(instructions,adv.nodes[i]);
}
instructions.push_back(new StringInstruction(GetString(std::get<std::string>(adv.nodes[0]))));
instructions.push_back(new SimpleInstruction(GETVARIABLE));
instructions.push_back(new SimpleInstruction(SCOPEEND));
scope--;
}
else if(adv.nodeName == ScopeNode) else if(adv.nodeName == ScopeNode)
{ {
scope++; scope++;
instructions.push_back(new SimpleInstruction(SCOPEBEGIN)); instructions.push_back(new SimpleInstruction(SCOPEBEGIN));
for(auto item : adv.nodes) for(size_t i = 0; i < adv.nodes.size(); i++)
{ {
GenNode(instructions,item,scope,contscope,brkscope,contI,brkI); GenNode(instructions,adv.nodes[i],scope,contscope,brkscope,contI,brkI);
GenPop(instructions,item); if(!adv.isExpression || i < adv.nodes.size()-1)
GenPop(instructions,adv.nodes[i]);
} }
instructions.push_back(new SimpleInstruction(SCOPEEND)); instructions.push_back(new SimpleInstruction(SCOPEEND));
scope--; scope--;
@ -1419,8 +1441,9 @@ namespace Tesses::CrossLang
void CodeGen::GenPop(std::vector<ByteCodeInstruction*>& instrs,SyntaxNode n) void CodeGen::GenPop(std::vector<ByteCodeInstruction*>& instrs,SyntaxNode n)
{ {
if(std::holds_alternative<AdvancedSyntaxNode>(n) && std::get<AdvancedSyntaxNode>(n).isExpression) if(std::holds_alternative<AdvancedSyntaxNode>(n))
{ {
if(std::get<AdvancedSyntaxNode>(n).isExpression)
instrs.push_back(new SimpleInstruction(POP)); instrs.push_back(new SimpleInstruction(POP));
} }
else else

View File

@ -140,33 +140,40 @@ namespace Tesses::CrossLang
lineInfo.line = 1; lineInfo.line = 1;
lineInfo.offset = 0; lineInfo.offset = 0;
std::string whiteSpaceCharsBefore="";
auto Flush = [&buffer,&tokens,&lineInfo,&whiteSpaceCharsBefore]() -> void {
auto Flush = [&buffer,&tokens,&lineInfo]() -> void {
if(!buffer.empty()) if(!buffer.empty())
{ {
LexToken token; LexToken token;
token.text = buffer; token.text = buffer;
token.whiteSpaceCharsBefore = whiteSpaceCharsBefore;
token.type = LexTokenType::Identifier; token.type = LexTokenType::Identifier;
token.lineInfo = lineInfo; token.lineInfo = lineInfo;
token.lineInfo.Subtract(buffer.size()); token.lineInfo.Subtract(buffer.size());
tokens.push_back(token); tokens.push_back(token);
buffer.clear(); buffer.clear();
whiteSpaceCharsBefore="";
} }
}; };
auto Symbol = [&tokens,&lineInfo](std::initializer_list<int> chrs)-> void { auto Symbol = [&tokens,&lineInfo,&whiteSpaceCharsBefore](std::initializer_list<int> chrs)-> void {
LexToken token; LexToken token;
token.type = LexTokenType::Symbol; token.type = LexTokenType::Symbol;
token.lineInfo = lineInfo; token.lineInfo = lineInfo;
token.whiteSpaceCharsBefore=whiteSpaceCharsBefore;
token.text.reserve(chrs.size()); token.text.reserve(chrs.size());
for(auto i : chrs) for(auto i : chrs)
token.text.push_back((char)i); token.text.push_back((char)i);
tokens.push_back(token); tokens.push_back(token);
whiteSpaceCharsBefore="";
}; };
auto ReadChr = [&lineInfo, &strm, Read]() -> std::pair<int,bool> { auto ReadChr = [&lineInfo, &strm, Read]() -> std::pair<int,bool> {
@ -436,8 +443,9 @@ namespace Tesses::CrossLang
while((read = Read()) != -1) while((read = Read()) != -1)
{ {
peek = Peek(); peek = Peek();
switch(read) switch(read)
{ {
@ -671,6 +679,7 @@ namespace Tesses::CrossLang
case '\r': case '\r':
case ' ': case ' ':
Flush(); Flush();
whiteSpaceCharsBefore += read;
break; break;
default: default:

View File

@ -108,6 +108,422 @@ namespace Tesses::CrossLang
this->i = 0; this->i = 0;
this->tokens = tokens; this->tokens = tokens;
} }
void Parser::ParseHtml(std::vector<SyntaxNode>& nodes,std::string var)
{
if(this->IsSymbol("!",true))
{
if(this->i < this->tokens.size() && this->tokens[this->i].type == LexTokenType::Identifier)
{
std::string identifier = this->tokens[this->i++].text;
if(identifier == "DOCTYPE")
{
if(this->i < this->tokens.size() && this->tokens[this->i].type == LexTokenType::Identifier)
{
std::string doctype_secArg = this->tokens[this->i++].text;
std::string r = "<!DOCTYPE " + doctype_secArg + ">";
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(AddExpression,true,{AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),r})}));
this->EnsureSymbol(">");
if(this->IsSymbol("<"))
{
ParseHtml(nodes,var);
}
}
}
}
}
else
{
auto parseFn = [this,var](std::vector<SyntaxNode>& nodes,std::string tagName)->void{
while(this->i < this->tokens.size())
{
if(this->IsSymbol("<",false))
{
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(AddExpression,true,{AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),Tesses::Framework::Http::HttpUtils::HtmlEncode(this->tokens[i].whiteSpaceCharsBefore)})}));
this->i++;
if(this->IsIdentifier("else",false) || this->IsIdentifier("elif",false))
{
this->i--;
return;
}
if(this->IsSymbol("/"))
{
if(!this->IsIdentifier(tagName))
{
//error
}
this->EnsureSymbol(">");
if(tagName != "if" && tagName != "for" && tagName != "while" && tagName != "do" && tagName != "each")
{
std::string myVal = "</";
myVal += tagName;
myVal += ">";
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(AddExpression,true,{AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),myVal})}));
}
break;
}
else
{
ParseHtml(nodes,var);
}
}
else if(this->IsSymbol("{",false))
{
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(AddExpression,true,{AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),Tesses::Framework::Http::HttpUtils::HtmlEncode(this->tokens[i].whiteSpaceCharsBefore)})}));
this->i++;
auto expr = ParseExpression();
this->EnsureSymbol("}");
//Net.Http.HtmlEncode(expr.ToString())
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{
AdvancedSyntaxNode::Create(AddExpression,true,{
AdvancedSyntaxNode::Create(GetVariableExpression,true,{var})
,
AdvancedSyntaxNode::Create(FunctionCallExpression,true,{
AdvancedSyntaxNode::Create(GetFieldExpression,true,{
AdvancedSyntaxNode::Create(GetFieldExpression,true, {
AdvancedSyntaxNode::Create(GetVariableExpression,true, {
"Net"
}),
"Http"
}),
"HtmlEncode"
}),
AdvancedSyntaxNode::Create(FunctionCallExpression,true,{
AdvancedSyntaxNode::Create(GetFieldExpression,true,{
AdvancedSyntaxNode::Create(ParenthesesExpression,true,{expr})
,
"ToString"
})
})
})
})
}));
}
else
{
std::string str = "";
while(this->i < this->tokens.size() && !this->IsSymbol("{",false) && !this->IsSymbol("<",false))
{
str+=this->tokens[this->i].whiteSpaceCharsBefore + this->tokens[this->i].text;
this->i++;
}
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(AddExpression,true,{AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),Tesses::Framework::Http::HttpUtils::HtmlEncode(str)})}));
}
}
};
if(this->i < this->tokens.size() && this->tokens[this->i].type == LexTokenType::Identifier)
{
std::string tagName = this->tokens[this->i++].text;
if(tagName == "if")
{
std::function<SyntaxNode()> readIf;
readIf = [this,&parseFn,var,&readIf]()->SyntaxNode {
EnsureSymbol("(");
auto expr = ParseExpression();
EnsureSymbol(")");
EnsureSymbol(">");
std::vector<SyntaxNode> trueNodes;
SyntaxNode falseNode=nullptr;
parseFn(trueNodes,"if");
if(this->IsSymbol("<",false) && this->i + 1 < this->tokens.size())
{
auto tkn = this->tokens[i+1];
if(tkn.type == LexTokenType::Identifier && tkn.text == "else")
{
i += 2;
EnsureSymbol(">");
std::vector<SyntaxNode> falseNodes;
parseFn(falseNodes,"if");
falseNode = AdvancedSyntaxNode::Create(ScopeNode,false,falseNodes);
}
else if(tkn.type == LexTokenType::Identifier && tkn.text == "elif")
{
i += 2;
falseNode = readIf();
}
}
return AdvancedSyntaxNode::Create(IfStatement,false,{
expr,
AdvancedSyntaxNode::Create(ScopeNode,false,trueNodes),
falseNode
});
} ;
nodes.push_back(readIf());
}
else if(tagName == "raw")
{
EnsureSymbol("(");
SyntaxNode expr = ParseExpression();
EnsureSymbol(")");
EnsureSymbol(">");
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{
AdvancedSyntaxNode::Create(AddExpression,true,{
AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),
AdvancedSyntaxNode::Create(FunctionCallExpression,true,{
AdvancedSyntaxNode::Create(GetFieldExpression,true,{
expr
,
"ToString"
})
})
})
}));
}
else if(tagName == "while")
{
EnsureSymbol("(");
SyntaxNode expr = ParseExpression();
SyntaxNode body = nullptr;
EnsureSymbol(")");
EnsureSymbol(">");
std::vector<SyntaxNode> _nodes;
parseFn(_nodes,"while");
body = AdvancedSyntaxNode::Create(ScopeNode,false,_nodes);
nodes.push_back(AdvancedSyntaxNode::Create(WhileStatement,false,{expr,body}));
}
else if(tagName == "do")
{
EnsureSymbol("(");
SyntaxNode expr = ParseExpression();
SyntaxNode body = nullptr;
EnsureSymbol(")");
EnsureSymbol(">");
std::vector<SyntaxNode> _nodes;
parseFn(_nodes,"do");
body = AdvancedSyntaxNode::Create(ScopeNode,false,_nodes);
nodes.push_back(AdvancedSyntaxNode::Create(DoStatement,false,{expr,body}));
}
else if(tagName == "for")
{
SyntaxNode init = nullptr;
SyntaxNode cond = true;
SyntaxNode inc = nullptr;
SyntaxNode body = nullptr;
EnsureSymbol("(");
if(!IsSymbol(";",false))
{
init = ParseExpression();
}
EnsureSymbol(";");
if(!IsSymbol(";",false))
{
cond = ParseExpression();
}
EnsureSymbol(";");
if(!IsSymbol(")",false))
{
inc = ParseExpression();
}
EnsureSymbol(")");
EnsureSymbol(">");
std::vector<SyntaxNode> _nodes;
parseFn(_nodes,"for");
body = AdvancedSyntaxNode::Create(ScopeNode,false,_nodes);
nodes.push_back(AdvancedSyntaxNode::Create(ForStatement,false,{init,cond,inc,body}));
}
else if(tagName == "each")
{
SyntaxNode item = nullptr;
EnsureSymbol("(");
SyntaxNode list = ParseExpression();
SyntaxNode body = nullptr;
if(IsSymbol(":"))
{
item = list;
list = ParseExpression();
}
EnsureSymbol(")");
EnsureSymbol(">");
std::vector<SyntaxNode> _nodes;
parseFn(_nodes,"each");
body = AdvancedSyntaxNode::Create(ScopeNode,false,_nodes);
nodes.push_back(AdvancedSyntaxNode::Create(EachStatement,false,{item,list,body}));
}
else
{
std::string s = "<";
s.append(tagName);
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(AddExpression,true,{AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),s})}));
while(!this->IsSymbol(">"))
{
//we need to get a name=value
if(this->i < this->tokens.size() && this->tokens[this->i].type == LexTokenType::Identifier)
{
std::string key = "";
while(this->i < this->tokens.size())
{
if(this->tokens[i].type == Identifier)
{
key += this->tokens[i].text;
i++;
}
else if(this->tokens[i].type == Symbol)
{
if(this->tokens[i].text == "-" || this->tokens[i].text == ":" || this->tokens[i].text == "--" || tokens[i].text == ".")
{
key += this->tokens[i].text;
i++;
}
else break;
}
else break;
}
if(this->IsSymbol(">"))
{
std::string myVal = " " + key;
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(AddExpression,true,{AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),myVal})}));
break;
}
else if(this->IsSymbol("="))
{
std::string myVal = " " + key + "=\"";
EnsureSymbol("{");
auto expr = ParseExpression();
EnsureSymbol("}");
if(std::holds_alternative<AdvancedSyntaxNode>(expr))
{
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{
AdvancedSyntaxNode::Create(AddExpression,true,{
AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),
AdvancedSyntaxNode::Create(AddExpression,true,{
myVal,
AdvancedSyntaxNode::Create(AddExpression,true,{
AdvancedSyntaxNode::Create(FunctionCallExpression,true,{
AdvancedSyntaxNode::Create(GetFieldExpression,true,{
AdvancedSyntaxNode::Create(GetFieldExpression,true, {
AdvancedSyntaxNode::Create(GetVariableExpression,true, {
"Net"
}),
"Http"
}),
"HtmlEncode"
}),
AdvancedSyntaxNode::Create(FunctionCallExpression,true,{
AdvancedSyntaxNode::Create(GetFieldExpression,true,{
expr
,
"ToString"
})
})
}),
"\"",
})
})
})
}));
}
else if(std::holds_alternative<double>(expr))
{
myVal += std::to_string(std::get<double>(expr)) + "\"";
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(AddExpression,true,{AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),myVal})}));
}
else if(std::holds_alternative<int64_t>(expr))
{
myVal += std::to_string(std::get<int64_t>(expr)) + "\"";
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(AddExpression,true,{AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),myVal})}));
}
else if(std::holds_alternative<bool>(expr))
{
myVal += std::holds_alternative<bool>(expr) ? "true\"" : "false\"";
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(AddExpression,true,{AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),myVal})}));
}
else if(std::holds_alternative<std::string>(expr))
{
myVal += Tesses::Framework::Http::HttpUtils::HtmlEncode(std::get<std::string>(expr)) + "\"";
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(AddExpression,true,{AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),myVal})}));
}
//key = value
}
else {
std::string myVal = " " + key;
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(AddExpression,true,{AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),myVal})}));
}
}
}
nodes.push_back(AdvancedSyntaxNode::Create(CompoundAssignExpression,true,{AdvancedSyntaxNode::Create(AddExpression,true,{AdvancedSyntaxNode::Create(GetVariableExpression,true,{var}),">"})}));
if(tagName != "img" && tagName != "input" && tagName != "br" && tagName != "hr" && tagName != "link" && tagName != "meta")
{
parseFn(nodes,tagName);
}
}
}
}
}
uint32_t Parser::NewId()
{
return id++;
}
SyntaxNode Parser::ParseValue() SyntaxNode Parser::ParseValue()
{ {
if(i >= tokens.size()) throw std::out_of_range("End of file"); if(i >= tokens.size()) throw std::out_of_range("End of file");
@ -125,6 +541,18 @@ namespace Tesses::CrossLang
i++; i++;
} }
else if(IsSymbol("<"))
{
uint32_t htmlId = NewId();
std::string compHtml = "__compGenHtml";
compHtml.append(std::to_string(htmlId));
std::vector<SyntaxNode> syntaxNode = {
compHtml
};
ParseHtml(syntaxNode,compHtml);
return AdvancedSyntaxNode::Create(HtmlRootExpression,true,syntaxNode);
}
else if(IsSymbol("[")) else if(IsSymbol("["))
{ {
if(IsSymbol("]",false)) if(IsSymbol("]",false))

View File

@ -1,7 +1,6 @@
#include "CrossLang.hpp" #include "CrossLang.hpp"
#include <iostream> #include <iostream>
#include "sago/platform_folders.h"
#include <mbedtls/error.h>
#include <string> #include <string>
using namespace Tesses::Framework; using namespace Tesses::Framework;
using namespace Tesses::CrossLang; using namespace Tesses::CrossLang;

View File

@ -161,6 +161,38 @@ namespace Tesses::CrossLang {
std::cout << ToString(ls.GetGC(),args[0]) << "\n"; std::cout << ToString(ls.GetGC(),args[0]) << "\n";
return Undefined(); return Undefined();
} }
TObject Console_Error(GCList& ls, std::vector<TObject> args)
{
if(args.size() < 1)
{
return Undefined();
}
std::cerr << ToString(ls.GetGC(),args[0]);
return Undefined();
}
TObject Console_ErrorLine(GCList& ls, std::vector<TObject> args)
{
if(args.size() < 1)
{
std::cout << "\n";
return Undefined();
}
std::cerr << ToString(ls.GetGC(),args[0]) << "\n";
return Undefined();
}
TObject Console_getIn(GCList& ls, std::vector<TObject> args)
{
return TStreamHeapObject::Create(ls, new Tesses::Framework::Streams::FileStream(stdin,false,"r",false));
}
TObject Console_getOut(GCList& ls, std::vector<TObject> args)
{
return TStreamHeapObject::Create(ls, new Tesses::Framework::Streams::FileStream(stdout,false,"w",false));
}
TObject Console_getError(GCList& ls, std::vector<TObject> args)
{
return TStreamHeapObject::Create(ls, new Tesses::Framework::Streams::FileStream(stderr,false,"w",false));
}
void TStd::RegisterConsole(GC* gc,TRootEnvironment* env) void TStd::RegisterConsole(GC* gc,TRootEnvironment* env)
{ {
env->permissions.canRegisterConsole=true; env->permissions.canRegisterConsole=true;
@ -181,8 +213,12 @@ namespace Tesses::CrossLang {
dict->DeclareFunction(gc,"ReadLine","Reads line from stdin",{},Console_ReadLine); dict->DeclareFunction(gc,"ReadLine","Reads line from stdin",{},Console_ReadLine);
dict->DeclareFunction(gc,"Write","Write text \"text\" to stdout",{"text"},Console_Write); dict->DeclareFunction(gc,"Write","Write text \"text\" to stdout",{"text"},Console_Write);
dict->DeclareFunction(gc,"WriteLine","Write text \"text\" to stdout with new line",{"text"},Console_WriteLine); dict->DeclareFunction(gc,"WriteLine","Write text \"text\" to stdout with new line",{"text"},Console_WriteLine);
dict->DeclareFunction(gc,"Error", "Write text \"error\" to stderr",{"error"},Console_Error);
dict->DeclareFunction(gc,"ErrorLine","Write text \"error\" to stderr",{"error"},Console_ErrorLine);
dict->DeclareFunction(gc,"Fatal","Stop the program with an optional error message",{"$text"},Console_Fatal); dict->DeclareFunction(gc,"Fatal","Stop the program with an optional error message",{"$text"},Console_Fatal);
dict->DeclareFunction(gc,"getIn","Get stdin Stream",{},Console_getIn);
dict->DeclareFunction(gc,"getOut","Get stdout Stream",{},Console_getOut);
dict->DeclareFunction(gc,"getError", "Get stderr Stream",{},Console_getError);
gc->BarrierBegin(); gc->BarrierBegin();
env->DeclareVariable("Console", dict); env->DeclareVariable("Console", dict);
gc->BarrierEnd(); gc->BarrierEnd();

View File

@ -1,59 +1,27 @@
#include "CrossLang.hpp" #include "CrossLang.hpp"
#include <TessesFramework/TessesFrameworkFeatures.h> using namespace Tesses::Framework::Crypto;
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
#include <iostream>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#include <mbedtls/sha512.h>
#include <mbedtls/base64.h>
#include <mbedtls/pkcs5.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/x509.h>
#include <mbedtls/ssl.h>
#include <mbedtls/net_sockets.h>
#include <mbedtls/error.h>
#include <cstring>
#endif
namespace Tesses::CrossLang namespace Tesses::CrossLang
{ {
#if defined(TESSESFRAMEWORK_ENABLE_MBED) static TObject Crypto_RandomBytes(GCList& ls, std::vector<TObject> args)
static TObject Crypto_RandomBytes(GCList& ls, std::vector<TObject> args)
{ {
int64_t size; int64_t size;
std::string personalStr; std::string personalStr;
if(GetArgument(args,0,size) && GetArgument(args,1,personalStr)) if(GetArgument(args,0,size) && GetArgument(args,1,personalStr))
{ {
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) personalStr.c_str(), personalStr.size());
if(ret != 0)
{
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
return nullptr;
}
std::vector<uint8_t> bytes; std::vector<uint8_t> bytes;
bytes.resize((size_t)size); bytes.resize((size_t)size);
ret = mbedtls_ctr_drbg_random(&ctr_drbg, bytes.data(),bytes.size()); if(RandomBytes(bytes,personalStr))
if (ret != 0)
{ {
mbedtls_ctr_drbg_free(&ctr_drbg); auto ba = TByteArray::Create(ls);
mbedtls_entropy_free(&entropy); ba->data = bytes;
return nullptr; return ba;
} }
mbedtls_ctr_drbg_free(&ctr_drbg); return nullptr;
mbedtls_entropy_free(&entropy);
TByteArray* ba = TByteArray::Create(ls);
ba->data = bytes;
return ba;
} }
return nullptr; return nullptr;
} }
@ -66,228 +34,45 @@ namespace Tesses::CrossLang
int64_t shanum; int64_t shanum;
if(GetArgument(args,0,pass) && GetArgumentHeap(args,1, bArraySalt) && GetArgument(args,2, itterations) && GetArgument(args,3,keylength) && GetArgument(args,4,shanum)) if(GetArgument(args,0,pass) && GetArgumentHeap(args,1, bArraySalt) && GetArgument(args,2, itterations) && GetArgument(args,3,keylength) && GetArgument(args,4,shanum))
{ {
mbedtls_md_context_t ctx; ShaVersion version = VERSION_SHA384;
mbedtls_md_init(&ctx);
const mbedtls_md_info_t* info = NULL;
switch(shanum) switch(shanum)
{ {
case 1: case 1:
info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); version = VERSION_SHA1;
break; break;
case 224: case 224:
info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA224); version = VERSION_SHA224;
break; break;
case 256: case 256:
info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); version = VERSION_SHA256;
break; break;
default: default:
case 384: case 384:
info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384); version = VERSION_SHA384;
break; break;
case 512: case 512:
info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); version = VERSION_SHA512;
break; break;
} }
mbedtls_md_setup(&ctx, info, 1);
std::vector<uint8_t> key; std::vector<uint8_t> key;
key.resize((size_t)keylength); key.resize((size_t)keylength);
if(mbedtls_pkcs5_pbkdf2_hmac(&ctx, (const unsigned char*)pass.c_str(), pass.size(), bArraySalt->data.data(), bArraySalt->data.size(), (int)itterations,(uint32_t)key.size(),key.data()) == 0) if(PBKDF2(key,pass,bArraySalt->data,(long)itterations,version))
{ {
auto ba = TByteArray::Create(ls); TByteArray* ba = TByteArray::Create(ls);
ba->data = key; ba->data = key;
mbedtls_md_free(&ctx);
return ba; return ba;
} }
mbedtls_md_free(&ctx);
} }
return nullptr; return nullptr;
} }
static TObject Crypto_Sha1(GCList& ls, std::vector<TObject> args)
{
TDictionary* dict = TDictionary::Create(ls);
mbedtls_sha1_context* ctx = new mbedtls_sha1_context();
mbedtls_sha1_init(ctx);
mbedtls_sha1_starts(ctx);
TNative* native = TNative::Create(ls,ctx,[](void* _ctx)->void{
if(_ctx == nullptr) return;
mbedtls_sha1_context* ctx = (mbedtls_sha1_context*)_ctx;
mbedtls_sha1_free(ctx);
delete ctx;
});
ls.GetGC()->BarrierBegin();
dict->SetValue("_native",native);
ls.GetGC()->BarrierEnd();
dict->DeclareFunction(ls.GetGC(),"Update","Write more bytes",{"buffer","offset","size"},[native](GCList& ls2,std::vector<TObject> args2)->TObject{
if(!native->GetDestroyed() && args2.size() == 3 && std::holds_alternative<THeapObjectHolder>(args2[0]) && std::holds_alternative<int64_t>(args2[1]) && std::holds_alternative<int64_t>(args2[2]))
{
auto buffer = dynamic_cast<TByteArray*>(std::get<THeapObjectHolder>(args2[0]).obj);
auto offset = (size_t)std::get<int64_t>(args2[1]);
auto len = (size_t)std::get<int64_t>(args2[2]);
if(buffer != nullptr && (len+offset) < buffer->data.size())
{
mbedtls_sha1_update((mbedtls_sha1_context*)native->GetPointer(),buffer->data.data() + offset, len);
}
}
return false;
});
dict->DeclareFunction(ls.GetGC(),"Finish","Get hash",{},[native](GCList& ls2,std::vector<TObject> args2)->TObject{
if(!native->GetDestroyed())
{
TByteArray* ba = TByteArray::Create(ls2);
ba->data.resize(20);
mbedtls_sha1_finish((mbedtls_sha1_context*)native->GetPointer(),ba->data.data());
return ba;
}
return false;
});
/*
mbedtls_sha1_update(&ctx, (const unsigned char*)"Demi Lovato", 11);
unsigned char sha1[20];
mbedtls_sha1_finish(&ctx,sha1);
for(int i = 0;i<20;i++)
{
printf("%02x", sha1[i]);
}
printf("\n");
mbedtls_sha1_free(&ctx);*/
return dict;
}
static TObject Crypto_Sha256(GCList& ls, std::vector<TObject> args)
{
bool is224=false;
if(args.size() == 1 && std::holds_alternative<bool>(args[0]))
{
is224 = std::get<bool>(args[1]);
}
TDictionary* dict = TDictionary::Create(ls);
mbedtls_sha256_context* ctx = new mbedtls_sha256_context();
mbedtls_sha256_init(ctx);
mbedtls_sha256_starts(ctx,is224 ? 1 : 0);
TNative* native = TNative::Create(ls,ctx,[](void* _ctx)->void{
if(_ctx == nullptr) return;
mbedtls_sha256_context* ctx = (mbedtls_sha256_context*)_ctx;
mbedtls_sha256_free(ctx);
delete ctx;
});
ls.GetGC()->BarrierBegin();
dict->SetValue("_native",native);
ls.GetGC()->BarrierEnd();
dict->DeclareFunction(ls.GetGC(),"Update","Write more bytes",{"buffer","offset","size"},[native](GCList& ls2,std::vector<TObject> args2)->TObject{
if(!native->GetDestroyed() && args2.size() == 3 && std::holds_alternative<THeapObjectHolder>(args2[0]) && std::holds_alternative<int64_t>(args2[1]) && std::holds_alternative<int64_t>(args2[2]))
{
auto buffer = dynamic_cast<TByteArray*>(std::get<THeapObjectHolder>(args2[0]).obj);
auto offset = (size_t)std::get<int64_t>(args2[1]);
auto len = (size_t)std::get<int64_t>(args2[2]);
if(buffer != nullptr && (len+offset) < buffer->data.size())
{
mbedtls_sha256_update((mbedtls_sha256_context*)native->GetPointer(),buffer->data.data() + offset, len);
}
}
return false;
});
dict->DeclareFunction(ls.GetGC(),"Finish","Get hash",{},[native](GCList& ls2,std::vector<TObject> args2)->TObject{
if(!native->GetDestroyed())
{
TByteArray* ba = TByteArray::Create(ls2);
ba->data.resize(32);
mbedtls_sha256_finish((mbedtls_sha256_context*)native->GetPointer(),ba->data.data());
return ba;
}
return false;
});
return dict;
}
static TObject Crypto_Sha512(GCList& ls, std::vector<TObject> args)
{
bool is384=false;
if(args.size() == 1 && std::holds_alternative<bool>(args[0]))
{
is384 = std::get<bool>(args[1]);
}
TDictionary* dict = TDictionary::Create(ls);
mbedtls_sha512_context* ctx = new mbedtls_sha512_context();
mbedtls_sha512_init(ctx);
mbedtls_sha512_starts(ctx,is384 ? 1 : 0);
TNative* native = TNative::Create(ls,ctx,[](void* _ctx)->void{
if(_ctx == nullptr) return;
mbedtls_sha512_context* ctx = (mbedtls_sha512_context*)_ctx;
mbedtls_sha512_free(ctx);
delete ctx;
});
ls.GetGC()->BarrierBegin();
dict->SetValue("_native",native);
ls.GetGC()->BarrierEnd();
dict->DeclareFunction(ls.GetGC(),"Update","Write more bytes",{"buffer","offset","size"},[native](GCList& ls2,std::vector<TObject> args2)->TObject{
if(!native->GetDestroyed() && args2.size() == 3 && std::holds_alternative<THeapObjectHolder>(args2[0]) && std::holds_alternative<int64_t>(args2[1]) && std::holds_alternative<int64_t>(args2[2]))
{
auto buffer = dynamic_cast<TByteArray*>(std::get<THeapObjectHolder>(args2[0]).obj);
auto offset = (size_t)std::get<int64_t>(args2[1]);
auto len = (size_t)std::get<int64_t>(args2[2]);
if(buffer != nullptr && (len+offset) < buffer->data.size())
{
mbedtls_sha512_update((mbedtls_sha512_context*)native->GetPointer(),buffer->data.data() + offset, len);
}
}
return Undefined();
});
dict->DeclareFunction(ls.GetGC(),"Finish","Get hash",{},[native](GCList& ls2,std::vector<TObject> args2)->TObject{
if(!native->GetDestroyed())
{
TByteArray* ba = TByteArray::Create(ls2);
ba->data.resize(64);
mbedtls_sha512_finish((mbedtls_sha512_context*)native->GetPointer(),ba->data.data());
return ba;
}
return Undefined();
});
return dict;
}
static TObject Crypto_Base64Encode(GCList& ls, std::vector<TObject> args) static TObject Crypto_Base64Encode(GCList& ls, std::vector<TObject> args)
{ {
TByteArray* byteArray; TByteArray* byteArray;
@ -313,26 +98,22 @@ namespace Tesses::CrossLang
} }
return nullptr; return nullptr;
} }
#endif
void TStd::RegisterCrypto(GC* gc,TRootEnvironment* env) void TStd::RegisterCrypto(GC* gc,TRootEnvironment* env)
{ {
env->permissions.canRegisterCrypto=true; env->permissions.canRegisterCrypto=true;
#if defined(TESSESFRAMEWORK_ENABLE_MBED) if(!HaveCrypto()) return;
GCList ls(gc); GCList ls(gc);
TDictionary* dict = TDictionary::Create(ls); TDictionary* dict = TDictionary::Create(ls);
dict->DeclareFunction(gc, "PBKDF2","Hash passwords with PBKDF2",{"pass","salt","itterations","keylen","shanum"},Crypto_PBKDF2); dict->DeclareFunction(gc, "PBKDF2","Hash passwords with PBKDF2",{"pass","salt","itterations","keylen","shanum"},Crypto_PBKDF2);
dict->DeclareFunction(gc, "RandomBytes","Create bytearray but with random bytes in it instead of zeros (this uses mbedtls by the way)",{"byteCount","personalString"},Crypto_RandomBytes); dict->DeclareFunction(gc, "RandomBytes","Create bytearray but with random bytes in it instead of zeros (this uses mbedtls by the way)",{"byteCount","personalString"},Crypto_RandomBytes);
dict->DeclareFunction(gc, "Sha1","Sha1 Algorithm (needed for WebSocket handshake/BitTorrent etc) (don't use unless you have no other choice)",{},Crypto_Sha1);
dict->DeclareFunction(gc, "Sha256","Sha256 Algorithm",{"$is224"},Crypto_Sha256);
dict->DeclareFunction(gc, "Sha512","Sha512 Algorithm",{"$is384"},Crypto_Sha512);
dict->DeclareFunction(gc, "Base64Encode","Base64 encode",{"data"},Crypto_Base64Encode); dict->DeclareFunction(gc, "Base64Encode","Base64 encode",{"data"},Crypto_Base64Encode);
dict->DeclareFunction(gc, "Base64Decode","Base64 decode",{"str"},Crypto_Base64Decode); dict->DeclareFunction(gc, "Base64Decode","Base64 decode",{"str"},Crypto_Base64Decode);
gc->BarrierBegin(); gc->BarrierBegin();
env->DeclareVariable("Crypto", dict); env->DeclareVariable("Crypto", dict);
gc->BarrierEnd(); gc->BarrierEnd();
#endif
} }
} }

View File

@ -46,7 +46,8 @@ namespace Tesses::CrossLang
using namespace Tesses::Framework::Filesystem; using namespace Tesses::Framework::Filesystem;
using namespace Tesses::Framework::Http; using namespace Tesses::Framework::Http;
LocalFilesystem lfs; LocalFilesystem lfs;
if(!realPath.relative) return realPath; if(!realPath.relative) return realPath.MakeAbsolute();
if(lfs.FileExists(realPath)) return realPath.MakeAbsolute();
const char* path = std::getenv("PATH"); const char* path = std::getenv("PATH");
#if defined(_WIN32) #if defined(_WIN32)
const char* pathext = std::getenv("PATHEXT"); const char* pathext = std::getenv("PATHEXT");
@ -61,7 +62,7 @@ namespace Tesses::CrossLang
if(lfs.FileExists(newPath)) return newPath; if(lfs.FileExists(newPath)) return newPath;
} }
} }
return realPath.RelativeCurrentDirectory(); return realPath;
#else #else
auto pathParts = HttpUtils::SplitString(path,":"); auto pathParts = HttpUtils::SplitString(path,":");
@ -70,7 +71,7 @@ namespace Tesses::CrossLang
auto newPath = lfs.SystemToVFSPath(item) / realPath; auto newPath = lfs.SystemToVFSPath(item) / realPath;
if(lfs.FileExists(newPath)) return newPath; if(lfs.FileExists(newPath)) return newPath;
} }
return realPath.RelativeCurrentDirectory(); return realPath.MakeAbsolute();
#endif #endif
} }

View File

@ -239,6 +239,15 @@ namespace Tesses::CrossLang
ctx->WithSingleHeader(key,value); ctx->WithSingleHeader(key,value);
return dict; return dict;
}); });
dict->DeclareFunction(gc,"SendStream","Send stream",{"strm"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
TStreamHeapObject* strmHeapObj;
if(GetArgumentHeap(args2,0,strmHeapObj))
{
ctx->SendStream(strmHeapObj->stream);
}
return nullptr;
});
dict->DeclareFunction(gc,"SendBytes","Send bytes",{"ba"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{ dict->DeclareFunction(gc,"SendBytes","Send bytes",{"ba"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
TByteArray* ba; TByteArray* ba;
if(GetArgumentHeap(args2,0,ba)) if(GetArgumentHeap(args2,0,ba))

View File

@ -468,6 +468,14 @@ namespace Tesses::CrossLang
return TVMVersion(ba->data.data()+o); return TVMVersion(ba->data.data()+o);
} }
return nullptr; return nullptr;
})),
TDItem("FromLong", TExternalMethod::Create(ls, "Create from long",{"longBasedVersion"},[](GCList& ls, std::vector<TObject> args)->TObject {
int64_t num;
if(GetArgument(args,0,num))
{
return TVMVersion((uint64_t)num);
}
return nullptr;
})) }))
})); }));
env->DeclareVariable("InvokeMethod",MethodInvoker()); env->DeclareVariable("InvokeMethod",MethodInvoker());

View File

@ -1,5 +1,6 @@
#include "CrossLang.hpp" #include "CrossLang.hpp"
#if defined(CROSSLANG_ENABLE_TIME)
#if defined(_WIN32) #if defined(_WIN32)
#include <windows.h> #include <windows.h>
@ -10,10 +11,12 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#include "../HowardHinnant_date/date.h" #include "../HowardHinnant_date/date.h"
#endif
namespace Tesses::CrossLang namespace Tesses::CrossLang
{ {
#if defined(CROSSLANG_ENABLE_TIME)
static int64_t ToLocalTime(int64_t local) static int64_t ToLocalTime(int64_t local)
{ {
#if defined(__SWITCH__) || defined(_WIN32) #if defined(__SWITCH__) || defined(_WIN32)
@ -135,6 +138,53 @@ namespace Tesses::CrossLang
return nullptr; return nullptr;
} }
static TObject Time_LocalUsSlashDate(GCList& ls, std::vector<TObject> args)
{
//THIS code isn't the best but should work
int64_t local;
if(GetArgument(args,0,local))
{
local = ToLocalTime(local);
std::chrono::duration<int64_t> local_epoch_time(local);
date::hh_mm_ss hms(local_epoch_time%86400);
auto epoch = date::sys_days{date::January/1/1970};
epoch += date::days(local/86400);
//date::days<int64_t> sys_days_since_epoch = date::days<int64_t>(gmt);
// Convert sys_days to year_month_day
date::year_month_day ymd = date::year_month_day(epoch);
return std::to_string((uint32_t)ymd.month()) + "/" + std::to_string((uint32_t)ymd.day()) + "/" + std::to_string((int)ymd.year());
}
return "";
}
static TObject Time_UTCUsSlashDate(GCList& ls,std::vector<TObject> args)
{
int64_t gmt;
if(GetArgument(args,0,gmt))
{
std::chrono::duration<int64_t> epoch_time(gmt);
date::hh_mm_ss hms(epoch_time%86400);
auto epoch = date::sys_days{date::January/1/1970};
epoch += date::days(gmt/86400);
//date::days<int64_t> sys_days_since_epoch = date::days<int64_t>(gmt);
// Convert sys_days to year_month_day
date::year_month_day ymd = date::year_month_day(epoch);
return std::to_string((uint32_t)ymd.month()) + "/" + std::to_string((uint32_t)ymd.day()) + "/" + std::to_string((int)ymd.year());
}
return "";
}
static TObject Time_GMTTime(GCList& ls, std::vector<TObject> args) static TObject Time_GMTTime(GCList& ls, std::vector<TObject> args)
{ {
int64_t gmt; int64_t gmt;
@ -166,9 +216,10 @@ namespace Tesses::CrossLang
} }
return nullptr; return nullptr;
} }
#endif
void TStd::RegisterTime(GC* gc,TRootEnvironment* env) void TStd::RegisterTime(GC* gc,TRootEnvironment* env)
{ {
#if defined(CROSSLANG_ENABLE_TIME)
env->permissions.canRegisterTime=true; env->permissions.canRegisterTime=true;
@ -178,7 +229,9 @@ namespace Tesses::CrossLang
dict->DeclareFunction(gc, "GetGMTTime","Get the GMT time from epoch value",{"epoch"},Time_GMTTime); dict->DeclareFunction(gc, "GetGMTTime","Get the GMT time from epoch value",{"epoch"},Time_GMTTime);
dict->DeclareFunction(gc, "getNow","Get the time right now, returns C's time(NULL) return value",{},Time_getNow); dict->DeclareFunction(gc, "getNow","Get the time right now, returns C's time(NULL) return value",{},Time_getNow);
dict->DeclareFunction(gc, "Sleep","Sleep for a specified amount of milliseconds (multiply seconds by 1000 to get milliseconds)", {"ms"},Time_Sleep); dict->DeclareFunction(gc, "Sleep","Sleep for a specified amount of milliseconds (multiply seconds by 1000 to get milliseconds)", {"ms"},Time_Sleep);
dict->DeclareFunction(gc, "UTCUsSlashDate","Get a utc date like 8/20/1992 from epoch value",{"epoch"},Time_UTCUsSlashDate);
dict->DeclareFunction(gc, "LocalUsSlashDate","Get a local date like 8/20/1992 from epoch value",{"epoch"},Time_LocalUsSlashDate);
gc->BarrierBegin(); gc->BarrierBegin();
#if defined(__SWITCH__) || defined(_WIN32) #if defined(__SWITCH__) || defined(_WIN32)
dict->SetValue("Zone", (int64_t)-(_timezone)); dict->SetValue("Zone", (int64_t)-(_timezone));
@ -190,5 +243,6 @@ namespace Tesses::CrossLang
env->DeclareVariable("Time", dict); env->DeclareVariable("Time", dict);
gc->BarrierEnd(); gc->BarrierEnd();
#endif
} }
} }

View File

@ -317,6 +317,7 @@ namespace Tesses::CrossLang
dict->DeclareFunction(gc, "getRuntimeVersion","Get the runtime version",{},[](GCList& ls,std::vector<TObject> args)->TObject { 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); return TVMVersion(TVM_MAJOR,TVM_MINOR,TVM_PATCH,TVM_BUILD,TVM_VERSIONSTAGE);
}); });
gc->BarrierBegin(); gc->BarrierBegin();
env->DeclareVariable("VM", dict); env->DeclareVariable("VM", dict);
gc->BarrierEnd(); gc->BarrierEnd();

View File

@ -10,6 +10,7 @@ namespace Tesses::CrossLang
{ {
this->ls = new GCList(gc); this->ls = new GCList(gc);
this->ls->Add(obj); this->ls->Add(obj);
this->obj = obj;
TDictionary* dict; TDictionary* dict;
if(GetObjectHeap(obj,dict)) if(GetObjectHeap(obj,dict))
{ {

View File

@ -69,6 +69,7 @@ namespace Tesses::CrossLang {
{ {
return !thrd->hasReturned; return !thrd->hasReturned;
} }
return true;
} }
return false; return false;
@ -873,12 +874,14 @@ namespace Tesses::CrossLang {
auto left = cse.back()->Pop(ls); auto left = cse.back()->Pop(ls);
if(std::holds_alternative<std::nullptr_t>(left) && std::holds_alternative<std::nullptr_t>(right)) if(std::holds_alternative<std::nullptr_t>(left) && std::holds_alternative<std::nullptr_t>(right))
{ {
return true; cse.back()->Push(gc,true);
return false;
} }
else if(std::holds_alternative<Undefined>(left) && std::holds_alternative<Undefined>(right)) else if(std::holds_alternative<Undefined>(left) && std::holds_alternative<Undefined>(right))
{ {
return true; cse.back()->Push(gc,true);
return false;
} }
else if(std::holds_alternative<int64_t>(left) && std::holds_alternative<int64_t>(right)) else if(std::holds_alternative<int64_t>(left) && std::holds_alternative<int64_t>(right))
@ -934,6 +937,7 @@ namespace Tesses::CrossLang {
auto dict = dynamic_cast<TDictionary*>(obj); auto dict = dynamic_cast<TDictionary*>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj); auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
auto native = dynamic_cast<TNative*>(obj);
if(dict != nullptr) if(dict != nullptr)
{ {
gc->BarrierBegin(); gc->BarrierBegin();
@ -953,20 +957,48 @@ namespace Tesses::CrossLang {
return false; return false;
} }
} }
else if(native != nullptr && std::holds_alternative<std::nullptr_t>(right)){
cse.back()->Push(gc, native->GetDestroyed());
return false;
}
if(std::holds_alternative<THeapObjectHolder>(right)) if(std::holds_alternative<THeapObjectHolder>(right))
{ {
cse.back()->Push(gc,obj == std::get<THeapObjectHolder>(right).obj); cse.back()->Push(gc,obj == std::get<THeapObjectHolder>(right).obj);
return false; return false;
} }
else if(std::holds_alternative<std::nullptr_t>(right))
{
cse.back()->Push(gc, false);
return false;
}
else if(std::holds_alternative<Undefined>(right))
{
cse.back()->Push(gc, false);
return false;
}
else else
{ {
cse.back()->Push(gc,Undefined()); cse.back()->Push(gc,Undefined());
} }
} }
else if(std::holds_alternative<std::nullptr_t>(right))
{
cse.back()->Push(gc, false);
return false;
}
else if(std::holds_alternative<Undefined>(right))
{
cse.back()->Push(gc, false);
return false;
}
else else
{ {
cse.back()->Push(gc, Undefined()); cse.back()->Push(gc, Undefined());
} }
return false; return false;
@ -980,10 +1012,12 @@ namespace Tesses::CrossLang {
if(std::holds_alternative<std::nullptr_t>(left) && std::holds_alternative<std::nullptr_t>(right)) if(std::holds_alternative<std::nullptr_t>(left) && std::holds_alternative<std::nullptr_t>(right))
{ {
cse.back()->Push(gc,false);
return false; return false;
} }
else if(std::holds_alternative<Undefined>(left) && std::holds_alternative<Undefined>(right)) else if(std::holds_alternative<Undefined>(left) && std::holds_alternative<Undefined>(right))
{ {
cse.back()->Push(gc,false);
return false; return false;
} }
else if(std::holds_alternative<int64_t>(left) && std::holds_alternative<int64_t>(right)) else if(std::holds_alternative<int64_t>(left) && std::holds_alternative<int64_t>(right))
@ -1033,6 +1067,7 @@ namespace Tesses::CrossLang {
{ {
auto obj = std::get<THeapObjectHolder>(left).obj; auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary*>(obj); auto dict = dynamic_cast<TDictionary*>(obj);
auto native = dynamic_cast<TNative*>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj); auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
if(dict != nullptr) if(dict != nullptr)
@ -1054,17 +1089,42 @@ namespace Tesses::CrossLang {
return false; return false;
} }
} }
else if(native != nullptr && std::holds_alternative<std::nullptr_t>(right)){
cse.back()->Push(gc, !native->GetDestroyed());
return false;
}
if(std::holds_alternative<THeapObjectHolder>(right)) if(std::holds_alternative<THeapObjectHolder>(right))
{ {
cse.back()->Push(gc,obj != std::get<THeapObjectHolder>(right).obj); cse.back()->Push(gc,obj != std::get<THeapObjectHolder>(right).obj);
return false; return false;
} }
else if(std::holds_alternative<std::nullptr_t>(right))
{
cse.back()->Push(gc, true);
return false;
}
else if(std::holds_alternative<Undefined>(right))
{
cse.back()->Push(gc, true);
return false;
}
else else
{ {
cse.back()->Push(gc,Undefined()); cse.back()->Push(gc,Undefined());
} }
} }
else if(std::holds_alternative<Undefined>(right))
{
cse.back()->Push(gc, true);
return false;
}
else if(std::holds_alternative<std::nullptr_t>(right))
{
cse.back()->Push(gc, true);
return false;
}
else else
{ {
cse.back()->Push(gc, Undefined()); cse.back()->Push(gc, Undefined());
@ -3826,6 +3886,7 @@ namespace Tesses::CrossLang {
} }
else { else {
cse.back()->Push(gc, nullptr); cse.back()->Push(gc, nullptr);
return false;
} }
} }
cse.back()->Push(gc, Undefined()); cse.back()->Push(gc, Undefined());
@ -4177,6 +4238,7 @@ namespace Tesses::CrossLang {
auto value = stk->Pop(ls); auto value = stk->Pop(ls);
auto key = stk->Pop(ls); auto key = stk->Pop(ls);
if(std::holds_alternative<std::string>(key)) if(std::holds_alternative<std::string>(key))
{ {
gc->BarrierBegin(); gc->BarrierBegin();
@ -4420,6 +4482,17 @@ namespace Tesses::CrossLang {
{ {
stk->Push(gc, tryC->Call(ls,{})); stk->Push(gc, tryC->Call(ls,{}));
} }
catch(TextException& ex)
{
TDictionary* dict = TDictionary::Create(ls);
auto gc = ls.GetGC();
gc->BarrierBegin();
dict->SetValue("Type","NativeException");
dict->SetValue("Text",ex.what());
gc->BarrierEnd();
stk->Push(gc, catchC->Call(ls,{dict}));
}
catch(VMException& ex) catch(VMException& ex)
{ {