Build and Deploy on Tag / 🔨 Build for PowerPC (push) Successful in 1m11s
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-riscv64:latest, riscv64-linux-gnu, riscv64) (push) Successful in 3m22s
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-x64:latest, x86_64-linux-gnu, amd64) (push) Successful in 3m34s
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-arm:latest, arm-linux-gnueabihf, arm7) (push) Successful in 3m37s
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-arm64:latest, aarch64-linux-gnu, arm64) (push) Successful in 3m39s
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-x86:latest, i386-linux-gnu, 386) (push) Successful in 55s
Build and Deploy on Tag / update-tap (push) Failing after 4m8s
1908 lines
80 KiB
C++
1908 lines
80 KiB
C++
#include "CrossLang.hpp"
|
|
#include <iostream>
|
|
#include <stdexcept>
|
|
namespace Tesses::CrossLang {
|
|
SyntaxNode TObject2SyntaxNode(TObject o) {
|
|
if (std::holds_alternative<Undefined>(o))
|
|
return Undefined();
|
|
if (std::holds_alternative<std::nullptr_t>(o))
|
|
return nullptr;
|
|
if (std::holds_alternative<std::string>(o))
|
|
return std::get<std::string>(o);
|
|
if (std::holds_alternative<int64_t>(o))
|
|
return std::get<int64_t>(o);
|
|
if (std::holds_alternative<double>(o))
|
|
return std::get<double>(o);
|
|
if (std::holds_alternative<char>(o))
|
|
return std::get<char>(o);
|
|
if (std::holds_alternative<bool>(o))
|
|
return std::get<bool>(o);
|
|
TList *list;
|
|
TDictionary *dict;
|
|
TByteArray *byteArray;
|
|
|
|
if (GetObjectHeap(o, list)) {
|
|
if (list->Count() == 0)
|
|
return AdvancedSyntaxNode::Create(ArrayExpression, true, {});
|
|
|
|
SyntaxNode node = TObject2SyntaxNode(list->Get(0));
|
|
|
|
for (int64_t i = 1; i < list->Count(); i++)
|
|
node = AdvancedSyntaxNode::Create(
|
|
CommaExpression, true,
|
|
{node, TObject2SyntaxNode(list->Get(i))});
|
|
|
|
return AdvancedSyntaxNode::Create(ArrayExpression, true, {node});
|
|
}
|
|
if (GetObjectHeap(o, dict)) {
|
|
bool has = false;
|
|
SyntaxNode node = nullptr;
|
|
|
|
for (auto item : dict->items) {
|
|
if (has) {
|
|
node = AdvancedSyntaxNode::Create(
|
|
CommaExpression, true,
|
|
{node, AdvancedSyntaxNode::Create(
|
|
AssignExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
GetVariableExpression, true,
|
|
{TObject2SyntaxNode(item.first)}),
|
|
TObject2SyntaxNode(item.second)})});
|
|
} else {
|
|
node = AdvancedSyntaxNode::Create(
|
|
AssignExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
GetVariableExpression, true,
|
|
{TObject2SyntaxNode(item.first)}),
|
|
TObject2SyntaxNode(item.second)});
|
|
has = true;
|
|
}
|
|
}
|
|
|
|
if (has)
|
|
return AdvancedSyntaxNode::Create(DictionaryExpression, true,
|
|
{node});
|
|
return AdvancedSyntaxNode::Create(DictionaryExpression, true, {});
|
|
}
|
|
if (GetObjectHeap(o, byteArray)) {
|
|
return byteArray->data;
|
|
}
|
|
return Undefined();
|
|
}
|
|
|
|
std::string LexTokenType_ToString(LexTokenType t) {
|
|
switch (t) {
|
|
case LexTokenType::Char:
|
|
return "char";
|
|
case LexTokenType::Documentation:
|
|
return "documentation";
|
|
case LexTokenType::Identifier:
|
|
return "identifier";
|
|
case LexTokenType::String:
|
|
return "string";
|
|
case LexTokenType::Symbol:
|
|
return "symbol";
|
|
}
|
|
|
|
return "";
|
|
}
|
|
bool Parser::IsAnyIdentifier(std::initializer_list<std::string> idents,
|
|
bool pop) {
|
|
if (i < tokens.size()) {
|
|
if (tokens[i].type != LexTokenType::Identifier)
|
|
return false;
|
|
for (auto item : idents) {
|
|
if (item == tokens[i].text) {
|
|
tkn = tokens[i];
|
|
if (pop)
|
|
i++;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
bool Parser::IsIdentifier(std::string txt, bool pop) {
|
|
if (i < tokens.size()) {
|
|
if (tokens[i].type != LexTokenType::Identifier)
|
|
return false;
|
|
if (tokens[i].text == txt) {
|
|
tkn = tokens[i];
|
|
if (pop)
|
|
i++;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
bool Parser::IsAnySymbol(std::initializer_list<std::string> idents, bool pop) {
|
|
if (i < tokens.size()) {
|
|
if (tokens[i].type != LexTokenType::Symbol)
|
|
return false;
|
|
for (auto item : idents) {
|
|
if (item == tokens[i].text) {
|
|
tkn = tokens[i];
|
|
if (pop)
|
|
i++;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
bool Parser::IsSymbol(std::string txt, bool pop) {
|
|
if (i < tokens.size()) {
|
|
if (tokens[i].type != LexTokenType::Symbol)
|
|
return false;
|
|
if (tokens[i].text == txt) {
|
|
tkn = tokens[i];
|
|
if (pop)
|
|
i++;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
static std::string EnsureSafeVariable(LexToken token) {
|
|
if (token.text.find("__compGen") == 0) {
|
|
throw SyntaxException(token.lineInfo,
|
|
"__compGen* is reserved for compilers (this "
|
|
"error is enforced by the compiler)");
|
|
}
|
|
return token.text;
|
|
}
|
|
void Parser::EnsureSymbol(std::string txt) {
|
|
if (i < tokens.size()) {
|
|
if (tokens[i].type != LexTokenType::Symbol) {
|
|
throw SyntaxException(
|
|
tokens[i].lineInfo,
|
|
"expected the symbol \"" + txt + "\" but got the " +
|
|
LexTokenType_ToString(tokens[i].type) + " \"" +
|
|
tokens[i].text + "\" which is not a symbol at all.");
|
|
}
|
|
if (tokens[i].text != txt) {
|
|
|
|
throw SyntaxException(tokens[i].lineInfo,
|
|
"expected the symbol \"" + txt +
|
|
"\" but got the symbol \"" +
|
|
tokens[i].text + "\"");
|
|
}
|
|
tkn = tokens[i];
|
|
i++;
|
|
return;
|
|
}
|
|
throw std::out_of_range("End of file");
|
|
}
|
|
Parser::Parser(std::vector<LexToken> tokens)
|
|
: Parser(tokens, nullptr, nullptr) {}
|
|
Parser::Parser(std::vector<LexToken> tokens, std::shared_ptr<GC> gc,
|
|
TRootEnvironment *env) {
|
|
this->i = 0;
|
|
this->tokens = tokens;
|
|
this->gc = gc;
|
|
this->env = env;
|
|
}
|
|
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->IsSymbol("/")) {
|
|
if (this->IsIdentifier("if", false) &&
|
|
tagName == "if") {
|
|
this->i -= 2;
|
|
break;
|
|
}
|
|
if (!this->IsIdentifier(tagName)) {
|
|
// error
|
|
}
|
|
this->EnsureSymbol(">");
|
|
if (tagName != "if" && tagName != "true" &&
|
|
tagName != "false" && tagName != "for" &&
|
|
tagName != "while" && tagName != "do" &&
|
|
tagName != "each" && tagName != "null" &&
|
|
tagName != "return") {
|
|
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 == "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 == "plink") {
|
|
EnsureSymbol("(");
|
|
SyntaxNode expr = ParseExpression();
|
|
|
|
EnsureSymbol(")");
|
|
EnsureSymbol(">");
|
|
|
|
nodes.push_back(AdvancedSyntaxNode::Create(
|
|
CompoundAssignExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
AddExpression, true,
|
|
{AdvancedSyntaxNode::Create(GetVariableExpression, true,
|
|
{var}),
|
|
AdvancedSyntaxNode::Create(
|
|
AddExpression, true,
|
|
{"<p>",
|
|
AdvancedSyntaxNode::Create(
|
|
AddExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
FunctionCallExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
GetFieldExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
GetFieldExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
GetVariableExpression,
|
|
true, {"Net"}),
|
|
"Http"}),
|
|
"HtmlP"}),
|
|
expr}),
|
|
"</p>"})})})}));
|
|
} else if (tagName == "if") {
|
|
EnsureSymbol("(");
|
|
SyntaxNode expr = ParseExpression();
|
|
SyntaxNode truth = nullptr;
|
|
SyntaxNode falsey = nullptr;
|
|
|
|
EnsureSymbol(")");
|
|
EnsureSymbol(">");
|
|
|
|
while (this->IsSymbol("<")) {
|
|
if (this->IsSymbol("/")) {
|
|
if (!this->IsIdentifier("if")) {
|
|
this->i -= 3;
|
|
}
|
|
this->EnsureSymbol(">");
|
|
break;
|
|
} else if (this->IsIdentifier("true")) {
|
|
this->EnsureSymbol(">");
|
|
|
|
std::vector<SyntaxNode> _nodes;
|
|
parseFn(_nodes, "true");
|
|
truth = AdvancedSyntaxNode::Create(ScopeNode, false,
|
|
_nodes);
|
|
|
|
} else if (this->IsIdentifier("false")) {
|
|
this->EnsureSymbol(">");
|
|
std::vector<SyntaxNode> _nodes;
|
|
parseFn(_nodes, "false");
|
|
falsey = AdvancedSyntaxNode::Create(ScopeNode, false,
|
|
_nodes);
|
|
}
|
|
}
|
|
nodes.push_back(AdvancedSyntaxNode::Create(
|
|
IfStatement, false, {expr, truth, falsey}));
|
|
} else if (tagName == "null") {
|
|
EnsureSymbol(">");
|
|
std::vector<SyntaxNode> _nodes;
|
|
parseFn(_nodes, "null");
|
|
nodes.push_back(
|
|
AdvancedSyntaxNode::Create(ScopeNode, false, _nodes));
|
|
|
|
} else if (tagName == "return") {
|
|
EnsureSymbol(">");
|
|
std::vector<SyntaxNode> _nodes;
|
|
parseFn(_nodes, "return");
|
|
nodes.push_back(
|
|
AdvancedSyntaxNode::Create(ScopeNode, false, _nodes));
|
|
} 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(":") || IsIdentifier("in")) {
|
|
item = list;
|
|
list = ParseExpression();
|
|
}
|
|
EnsureSymbol(")");
|
|
EnsureSymbol(">");
|
|
|
|
if (std::holds_alternative<std::nullptr_t>(item))
|
|
item = AdvancedSyntaxNode::Create(
|
|
DeclareExpression, true,
|
|
{"item"});
|
|
|
|
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 + "=\"";
|
|
SyntaxNode expr;
|
|
if (this->i < this->tokens.size() &&
|
|
this->tokens[this->i].type ==
|
|
LexTokenType::String) {
|
|
expr = this->tokens[this->i++].text;
|
|
|
|
} else {
|
|
EnsureSymbol("{");
|
|
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,
|
|
"ToStr"
|
|
"in"
|
|
"g"})})}),
|
|
"\"",
|
|
})
|
|
|
|
})})}));
|
|
|
|
} 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() {
|
|
if (i >= tokens.size())
|
|
throw std::out_of_range("End of file");
|
|
auto tkn2 = tokens[i];
|
|
SyntaxNode node = nullptr;
|
|
if (tokens[i].type == LexTokenType::String) {
|
|
node = tkn2.text;
|
|
i++;
|
|
|
|
} else if (tokens[i].type == LexTokenType::Char) {
|
|
node = tkn2.text.empty() ? '\0' : tkn2.text.front();
|
|
i++;
|
|
|
|
} else if (tokens[i].type == LexTokenType::Symbol &&
|
|
tokens[i].text == ".") {
|
|
i++;
|
|
if (IsSymbol("[")) {
|
|
node = AdvancedSyntaxNode::Create(GetVariableExpression, true,
|
|
{ParseExpression()});
|
|
EnsureSymbol("]");
|
|
} else {
|
|
node = AdvancedSyntaxNode::Create(RelativePathExpression, true, {});
|
|
}
|
|
} 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("[")) {
|
|
if (IsSymbol("]", false))
|
|
node = AdvancedSyntaxNode::Create(ArrayExpression, true, {});
|
|
else
|
|
node = AdvancedSyntaxNode::Create(ArrayExpression, true,
|
|
{ParseExpression()});
|
|
EnsureSymbol("]");
|
|
} else if (IsSymbol("{")) {
|
|
if (IsSymbol("}", false))
|
|
node = AdvancedSyntaxNode::Create(DictionaryExpression, true, {});
|
|
else
|
|
node = AdvancedSyntaxNode::Create(DictionaryExpression, true,
|
|
{ParseExpression()});
|
|
|
|
EnsureSymbol("}");
|
|
} else if (IsSymbol("(")) {
|
|
if (IsSymbol(")", false))
|
|
node = AdvancedSyntaxNode::Create(ParenthesesExpression, true, {});
|
|
else
|
|
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++;
|
|
if (variable.type == LexTokenType::Symbol && variable.text == ".") {
|
|
EnsureSymbol("[");
|
|
node = AdvancedSyntaxNode::Create(
|
|
DeclareExpression, true,
|
|
{AdvancedSyntaxNode::Create(GetVariableExpression, true,
|
|
{ParseExpression()})});
|
|
EnsureSymbol("]");
|
|
} else if (variable.type == LexTokenType::Symbol &&
|
|
variable.text == "[") {
|
|
node = AdvancedSyntaxNode::Create(
|
|
DeclareExpression, true,
|
|
{AdvancedSyntaxNode::Create(ArrayExpression, true,
|
|
{ParseExpression()})});
|
|
EnsureSymbol("]");
|
|
} else if (variable.type != LexTokenType::Identifier)
|
|
throw SyntaxException(variable.lineInfo,
|
|
"Expected an identifier got a " +
|
|
LexTokenType_ToString(variable.type) +
|
|
" \"" + variable.text + "\"");
|
|
else {
|
|
node = AdvancedSyntaxNode::Create(DeclareExpression, true,
|
|
{EnsureSafeVariable(variable)});
|
|
}
|
|
} else if (IsIdentifier("const")) {
|
|
if (i >= tokens.size())
|
|
throw std::out_of_range("End of file");
|
|
auto variable = tokens[i];
|
|
|
|
i++;
|
|
if (variable.type == LexTokenType::Symbol && variable.text == ".") {
|
|
EnsureSymbol("[");
|
|
node = AdvancedSyntaxNode::Create(
|
|
ConstExpression, true,
|
|
{AdvancedSyntaxNode::Create(GetVariableExpression, true,
|
|
{ParseExpression()})});
|
|
EnsureSymbol("]");
|
|
} else if (variable.type == LexTokenType::Symbol &&
|
|
variable.text == "[") {
|
|
node = AdvancedSyntaxNode::Create(
|
|
ConstExpression, true,
|
|
{AdvancedSyntaxNode::Create(ArrayExpression, true,
|
|
{ParseExpression()})});
|
|
EnsureSymbol("]");
|
|
} else if (variable.type != LexTokenType::Identifier)
|
|
throw SyntaxException(variable.lineInfo,
|
|
"Expected an identifier got a " +
|
|
LexTokenType_ToString(variable.type) +
|
|
" \"" + variable.text + "\"");
|
|
else {
|
|
node = AdvancedSyntaxNode::Create(ConstExpression, true,
|
|
{EnsureSafeVariable(variable)});
|
|
}
|
|
} else if (IsIdentifier("comptime")) {
|
|
SyntaxNode n = nullptr;
|
|
if (IsSymbol("{", false)) {
|
|
n = ParseNode();
|
|
if (std::holds_alternative<AdvancedSyntaxNode>(n)) {
|
|
std::get<AdvancedSyntaxNode>(n).nodeName = NodeList;
|
|
}
|
|
} else {
|
|
n = AdvancedSyntaxNode::Create(ReturnStatement, false,
|
|
{ParseExpression()});
|
|
}
|
|
if (gc != nullptr && env != nullptr) {
|
|
GCList ls(gc);
|
|
|
|
CodeGen gen;
|
|
gen.GenRoot(n);
|
|
|
|
auto ms =
|
|
std::make_shared<Tesses::Framework::Streams::MemoryStream>(
|
|
true);
|
|
|
|
gen.Save(ms);
|
|
|
|
ms->Seek(0, Tesses::Framework::Streams::SeekOrigin::Begin);
|
|
|
|
TFile *f = TFile::Create(ls);
|
|
f->Load(gc, ms);
|
|
|
|
node = TObject2SyntaxNode(env->LoadFile(gc, f));
|
|
} else {
|
|
node = Undefined();
|
|
}
|
|
|
|
} else if (IsIdentifier("operator")) {
|
|
if (i >= tokens.size())
|
|
throw std::out_of_range("End of file");
|
|
auto variable = tokens[i];
|
|
i++;
|
|
if (variable.type != LexTokenType::Identifier &&
|
|
variable.type != LexTokenType::Symbol)
|
|
throw SyntaxException(variable.lineInfo,
|
|
"Expected an identifier or a symbol got a " +
|
|
LexTokenType_ToString(variable.type) +
|
|
" \"" + variable.text + "\"");
|
|
node = AdvancedSyntaxNode::Create(GetVariableExpression, true,
|
|
{"operator" + variable.text});
|
|
|
|
} else if (IsIdentifier("new")) {
|
|
if (i >= tokens.size())
|
|
throw std::out_of_range("End of file");
|
|
auto variable = tokens[i];
|
|
i++;
|
|
if (variable.type != LexTokenType::Identifier &&
|
|
variable.type != LexTokenType::Symbol)
|
|
throw SyntaxException(variable.lineInfo,
|
|
"Expected an identifier or a symbol got a " +
|
|
LexTokenType_ToString(variable.type) +
|
|
" \"" + variable.text + "\"");
|
|
node = AdvancedSyntaxNode::Create(
|
|
GetFieldExpression, true,
|
|
{AdvancedSyntaxNode::Create(GetVariableExpression, true, {"New"}),
|
|
variable.text});
|
|
} else if (IsIdentifier("embed")) {
|
|
EnsureSymbol("(");
|
|
if (i >= tokens.size())
|
|
throw std::out_of_range("End of file");
|
|
auto embed = tokens[i];
|
|
i++;
|
|
if (embed.type != LexTokenType::String)
|
|
throw SyntaxException(embed.lineInfo,
|
|
"Expected an string for embed got a " +
|
|
LexTokenType_ToString(embed.type) +
|
|
" \"" + embed.text + "\"");
|
|
EnsureSymbol(")");
|
|
node = AdvancedSyntaxNode::Create(EmbedExpression, true, {embed.text});
|
|
} else if (IsIdentifier("embedstrm")) {
|
|
EnsureSymbol("(");
|
|
if (i >= tokens.size())
|
|
throw std::out_of_range("End of file");
|
|
auto embed = tokens[i];
|
|
i++;
|
|
if (embed.type != LexTokenType::String)
|
|
throw SyntaxException(embed.lineInfo,
|
|
"Expected an string for embed got a " +
|
|
LexTokenType_ToString(embed.type) +
|
|
" \"" + embed.text + "\"");
|
|
EnsureSymbol(")");
|
|
node = AdvancedSyntaxNode::Create(EmbedStreamExpression, true,
|
|
{embed.text});
|
|
} else if (IsIdentifier("embeddir")) {
|
|
EnsureSymbol("(");
|
|
if (i >= tokens.size())
|
|
throw std::out_of_range("End of file");
|
|
auto embed = tokens[i];
|
|
i++;
|
|
if (embed.type != LexTokenType::String)
|
|
throw SyntaxException(embed.lineInfo,
|
|
"Expected an string for embed got a " +
|
|
LexTokenType_ToString(embed.type) +
|
|
" \"" + embed.text + "\"");
|
|
EnsureSymbol(")");
|
|
node = AdvancedSyntaxNode::Create(EmbedDirectoryExpression, true,
|
|
{embed.text});
|
|
} else if (IsIdentifier("private")) {
|
|
node = AdvancedSyntaxNode::Create(GetPrivateExpression, true, {});
|
|
} else if (tokens[i].type == LexTokenType::Identifier) {
|
|
auto token = tokens[i];
|
|
|
|
i++;
|
|
|
|
bool hasNumber = true;
|
|
int64_t lngNum = 0;
|
|
|
|
if (token.text.size() == 1 && token.text[0] == '0') {
|
|
lngNum = 0;
|
|
} else if (token.text.size() > 0 && token.text[0] == '0') {
|
|
if (token.text.size() > 1 && token.text[1] == 'x') {
|
|
lngNum = std::stoll(token.text.substr(2), nullptr, 16);
|
|
} else if (token.text.size() > 1 && token.text[1] == 'b') {
|
|
lngNum = std::stoll(token.text.substr(2), nullptr, 2);
|
|
} else {
|
|
lngNum = std::stoll(token.text.substr(1), nullptr, 8);
|
|
}
|
|
|
|
} else if (token.text.size() > 0 && token.text[0] >= '0' &&
|
|
token.text[0] <= '9') {
|
|
lngNum = std::stoll(token.text, nullptr, 10);
|
|
} else {
|
|
hasNumber = false;
|
|
}
|
|
|
|
if (hasNumber && this->IsSymbol(".", false) && i + 1 < tokens.size() &&
|
|
tokens[i + 1].type == LexTokenType::Identifier) {
|
|
std::string myToken = tokens[i + 1].text;
|
|
if (myToken.size() > 0 && myToken[0] >= '0' && myToken[0] <= '9') {
|
|
i += 2;
|
|
std::string myN = std::to_string(lngNum) + "." + myToken;
|
|
|
|
double v = std::stod(myN, nullptr);
|
|
|
|
node = v;
|
|
} else {
|
|
node = lngNum;
|
|
}
|
|
} else if (hasNumber) {
|
|
|
|
node = lngNum;
|
|
}
|
|
|
|
if (!hasNumber) {
|
|
if (token.text == "true")
|
|
node = true;
|
|
else if (token.text == "false")
|
|
node = false;
|
|
else if (token.text == "null")
|
|
node = nullptr;
|
|
else if (token.text == "undefined")
|
|
node = Undefined();
|
|
else {
|
|
node = AdvancedSyntaxNode::Create(GetVariableExpression, true,
|
|
{EnsureSafeVariable(token)});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsSymbol("=>")) {
|
|
if (IsSymbol("{", false)) {
|
|
node = AdvancedSyntaxNode::Create(ClosureExpression, true,
|
|
{node, ParseNode()});
|
|
} else {
|
|
node = AdvancedSyntaxNode::Create(
|
|
ClosureExpression, true,
|
|
{node, AdvancedSyntaxNode::Create(ReturnStatement, false,
|
|
{ParseExpression()})});
|
|
}
|
|
}
|
|
while (IsAnySymbol({".", "[", "("})) {
|
|
if (tkn.text == ".") {
|
|
if (i >= tokens.size())
|
|
throw std::out_of_range("End of file");
|
|
if (IsSymbol("[")) {
|
|
|
|
node = AdvancedSyntaxNode::Create(GetFieldExpression, true,
|
|
{node, ParseExpression()});
|
|
EnsureSymbol("]");
|
|
continue;
|
|
}
|
|
if (tokens[i].type != LexTokenType::Identifier)
|
|
throw std::runtime_error("Not an identifier (member)");
|
|
std::string name = tokens[i].text;
|
|
if (name == "operator") {
|
|
if (i >= tokens.size())
|
|
throw std::out_of_range("End of file");
|
|
auto op = tokens[i];
|
|
if (op.type != LexTokenType::Identifier &&
|
|
op.type != LexTokenType::Symbol)
|
|
throw SyntaxException(
|
|
op.lineInfo,
|
|
"Expected an identifier or a symbol got a " +
|
|
LexTokenType_ToString(op.type) + " \"" + op.text +
|
|
"\"");
|
|
|
|
name += tokens[i + 1].text;
|
|
i++;
|
|
}
|
|
i++;
|
|
node = AdvancedSyntaxNode::Create(GetFieldExpression, true,
|
|
{node, name});
|
|
} else if (tkn.text == "[") {
|
|
node = AdvancedSyntaxNode::Create(GetArrayExpression, true,
|
|
{node, ParseExpression()});
|
|
EnsureSymbol("]");
|
|
} else if (tkn.text == "(") {
|
|
if (IsSymbol(")", false)) {
|
|
node = AdvancedSyntaxNode::Create(FunctionCallExpression, true,
|
|
{node});
|
|
} else {
|
|
node = AdvancedSyntaxNode::Create(FunctionCallExpression, true,
|
|
{node, ParseExpression()});
|
|
}
|
|
EnsureSymbol(")");
|
|
}
|
|
}
|
|
|
|
if (IsSymbol("++")) {
|
|
node = AdvancedSyntaxNode::Create(PostfixIncrementExpression, true,
|
|
{node});
|
|
} else if (IsSymbol("--")) {
|
|
node = AdvancedSyntaxNode::Create(PostfixDecrementExpression, true,
|
|
{node});
|
|
}
|
|
|
|
return node;
|
|
}
|
|
SyntaxNode Parser::ParseUnary() {
|
|
if (IsSymbol("-")) {
|
|
return AdvancedSyntaxNode::Create(NegativeExpression, true,
|
|
{ParseUnary()});
|
|
} else if (IsSymbol("!")) {
|
|
return AdvancedSyntaxNode::Create(NotExpression, true, {ParseUnary()});
|
|
} else if (IsSymbol("~")) {
|
|
return AdvancedSyntaxNode::Create(BitwiseNotExpression, true,
|
|
{ParseUnary()});
|
|
} else if (IsSymbol("++")) {
|
|
return AdvancedSyntaxNode::Create(PrefixIncrementExpression, true,
|
|
{ParseUnary()});
|
|
} else if (IsSymbol("--")) {
|
|
return AdvancedSyntaxNode::Create(PrefixDecrementExpression, true,
|
|
{ParseUnary()});
|
|
} else if (IsIdentifier("await")) {
|
|
return AdvancedSyntaxNode::Create(YieldStatement, true, {ParseValue()});
|
|
} else if (IsIdentifier("async")) {
|
|
auto tkn = this->tkn;
|
|
auto v = ParseValue();
|
|
if (std::holds_alternative<AdvancedSyntaxNode>(v)) {
|
|
auto asn = std::get<AdvancedSyntaxNode>(v);
|
|
if (asn.nodeName != ClosureExpression)
|
|
throw SyntaxException(tkn.lineInfo,
|
|
"async must be used only with a closure");
|
|
if (asn.nodes.size() != 2)
|
|
throw SyntaxException(tkn.lineInfo, "invalid closure");
|
|
|
|
return AdvancedSyntaxNode::Create(
|
|
ClosureExpression, true,
|
|
{asn.nodes[0],
|
|
AdvancedSyntaxNode::Create(
|
|
ReturnStatement, false,
|
|
{AdvancedSyntaxNode::Create(
|
|
FunctionCallExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
GetFieldExpression, true,
|
|
{AdvancedSyntaxNode::Create(GetVariableExpression,
|
|
true, {"Task"}),
|
|
"AsyncClosure"}),
|
|
AdvancedSyntaxNode::Create(
|
|
ClosureExpression, true,
|
|
{AdvancedSyntaxNode::Create(ParenthesesExpression,
|
|
true, {}),
|
|
asn.nodes[1]})})})});
|
|
} else {
|
|
throw SyntaxException(
|
|
tkn.lineInfo,
|
|
"async must be used only with a closure, not a simple value");
|
|
}
|
|
} else if (IsIdentifier("enumerable")) {
|
|
|
|
auto tkn = this->tkn;
|
|
auto v = ParseValue();
|
|
if (std::holds_alternative<AdvancedSyntaxNode>(v)) {
|
|
auto asn = std::get<AdvancedSyntaxNode>(v);
|
|
if (asn.nodeName != ClosureExpression)
|
|
throw SyntaxException(
|
|
tkn.lineInfo,
|
|
"enumerable must be used only with a closure");
|
|
if (asn.nodes.size() != 2)
|
|
throw SyntaxException(tkn.lineInfo, "invalid closure");
|
|
|
|
return AdvancedSyntaxNode::Create(
|
|
ClosureExpression, true,
|
|
{asn.nodes[0],
|
|
AdvancedSyntaxNode::Create(
|
|
ReturnStatement, false,
|
|
{AdvancedSyntaxNode::Create(
|
|
FunctionCallExpression, true,
|
|
{AdvancedSyntaxNode::Create(GetVariableExpression,
|
|
true, {"YieldEmumerable"}),
|
|
AdvancedSyntaxNode::Create(
|
|
ClosureExpression, true,
|
|
{AdvancedSyntaxNode::Create(ParenthesesExpression,
|
|
true, {}),
|
|
asn.nodes[1]})})})});
|
|
} else {
|
|
throw SyntaxException(tkn.lineInfo,
|
|
"enumerable must be used only with a "
|
|
"closure, not a simple value");
|
|
}
|
|
} 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, {});
|
|
}
|
|
}
|
|
|
|
return ParseValue();
|
|
}
|
|
|
|
SyntaxNode Parser::ParseFactor() {
|
|
SyntaxNode expr = ParseUnary();
|
|
while (IsAnySymbol({"*", "/", "%"}, true)) {
|
|
if (tkn.text == "*") {
|
|
expr = AdvancedSyntaxNode::Create(TimesExpression, true,
|
|
{expr, ParseUnary()});
|
|
} else if (tkn.text == "/") {
|
|
expr = AdvancedSyntaxNode::Create(DivideExpression, true,
|
|
{expr, ParseUnary()});
|
|
} else if (tkn.text == "%") {
|
|
expr = AdvancedSyntaxNode::Create(ModExpression, true,
|
|
{expr, ParseUnary()});
|
|
}
|
|
}
|
|
return expr;
|
|
}
|
|
SyntaxNode Parser::ParseSum() {
|
|
SyntaxNode expr = ParseFactor();
|
|
while (IsAnySymbol({"+", "-"}, true)) {
|
|
if (tkn.text == "+") {
|
|
expr = AdvancedSyntaxNode::Create(AddExpression, true,
|
|
{expr, ParseFactor()});
|
|
} else if (tkn.text == "-") {
|
|
expr = AdvancedSyntaxNode::Create(SubExpression, true,
|
|
{expr, ParseFactor()});
|
|
}
|
|
}
|
|
return expr;
|
|
}
|
|
SyntaxNode Parser::ParseAssignment() {
|
|
SyntaxNode node = ParseTernary();
|
|
if (IsSymbol("=")) {
|
|
return AdvancedSyntaxNode::Create(AssignExpression, true,
|
|
{node, ParseAssignment()});
|
|
} else if (IsSymbol("+=")) {
|
|
return AdvancedSyntaxNode::Create(
|
|
CompoundAssignExpression, true,
|
|
{AdvancedSyntaxNode::Create(AddExpression, true,
|
|
{node, ParseAssignment()})});
|
|
} else if (IsSymbol("-=")) {
|
|
return AdvancedSyntaxNode::Create(
|
|
CompoundAssignExpression, true,
|
|
{AdvancedSyntaxNode::Create(SubExpression, true,
|
|
{node, ParseAssignment()})});
|
|
} else if (IsSymbol("*=")) {
|
|
return AdvancedSyntaxNode::Create(
|
|
CompoundAssignExpression, true,
|
|
{AdvancedSyntaxNode::Create(TimesExpression, true,
|
|
{node, ParseAssignment()})});
|
|
} else if (IsSymbol("/=")) {
|
|
return AdvancedSyntaxNode::Create(
|
|
CompoundAssignExpression, true,
|
|
{AdvancedSyntaxNode::Create(DivideExpression, true,
|
|
{node, ParseAssignment()})});
|
|
} else if (IsSymbol("%=")) {
|
|
return AdvancedSyntaxNode::Create(
|
|
CompoundAssignExpression, true,
|
|
{AdvancedSyntaxNode::Create(ModExpression, true,
|
|
{node, ParseAssignment()})});
|
|
} else if (IsSymbol("<<=")) {
|
|
return AdvancedSyntaxNode::Create(
|
|
CompoundAssignExpression, true,
|
|
{AdvancedSyntaxNode::Create(LeftShiftExpression, true,
|
|
{node, ParseAssignment()})});
|
|
} else if (IsSymbol(">>=")) {
|
|
return AdvancedSyntaxNode::Create(
|
|
CompoundAssignExpression, true,
|
|
{AdvancedSyntaxNode::Create(RightShiftExpression, true,
|
|
{node, ParseAssignment()})});
|
|
} else if (IsSymbol("|=")) {
|
|
return AdvancedSyntaxNode::Create(
|
|
CompoundAssignExpression, true,
|
|
{AdvancedSyntaxNode::Create(BitwiseOrExpression, true,
|
|
{node, ParseAssignment()})});
|
|
} else if (IsSymbol("&=")) {
|
|
return AdvancedSyntaxNode::Create(
|
|
CompoundAssignExpression, true,
|
|
{AdvancedSyntaxNode::Create(BitwiseAndExpression, true,
|
|
{node, ParseAssignment()})});
|
|
} else if (IsSymbol("^=")) {
|
|
return AdvancedSyntaxNode::Create(
|
|
CompoundAssignExpression, true,
|
|
{AdvancedSyntaxNode::Create(XOrExpression, true,
|
|
{node, ParseAssignment()})});
|
|
} else if (IsSymbol("?\?=")) {
|
|
return AdvancedSyntaxNode::Create(
|
|
CompoundAssignExpression, true,
|
|
{AdvancedSyntaxNode::Create(NullCoalescingExpression, true,
|
|
{node, ParseAssignment()})});
|
|
}
|
|
return node;
|
|
}
|
|
bool Parser::CanEmit(LexTokenLineInfo &ifo) {
|
|
if (!this->debug)
|
|
return false;
|
|
bool same = ifo.line == this->lastLine && ifo.filename == this->lastFile;
|
|
this->lastFile = ifo.filename;
|
|
this->lastLine = ifo.line;
|
|
|
|
return !same;
|
|
}
|
|
SyntaxNode Parser::ParseNode(bool isRoot) {
|
|
std::string documentation = "";
|
|
if (i < tokens.size() && !isRoot && tokens[i].type == Documentation) {
|
|
auto txt = tokens[i].text;
|
|
i++;
|
|
if (i < tokens.size() && tokens[i].text == "class" &&
|
|
tokens[i].type == LexTokenType::Identifier)
|
|
documentation = txt;
|
|
else
|
|
return AdvancedSyntaxNode::Create(DocumentationStatement, false,
|
|
{txt, ParseNode()});
|
|
}
|
|
if (IsSymbol("{") || isRoot) {
|
|
AdvancedSyntaxNode aSN;
|
|
aSN.isExpression = false;
|
|
aSN.nodeName = isRoot ? NodeList : ScopeNode;
|
|
|
|
while (i < tokens.size() && (isRoot || !IsSymbol("}", false))) {
|
|
auto token = tokens[i];
|
|
if (CanEmit(token.lineInfo))
|
|
aSN.nodes.push_back(AdvancedSyntaxNode::Create(
|
|
LineNode, false,
|
|
{(int64_t)tokens[i].lineInfo.line,
|
|
tokens[i].lineInfo.filename}));
|
|
aSN.nodes.push_back(ParseNode());
|
|
IsSymbol(";");
|
|
}
|
|
|
|
if (!isRoot)
|
|
EnsureSymbol("}");
|
|
return aSN;
|
|
}
|
|
|
|
if (IsIdentifier("if")) {
|
|
EnsureSymbol("(");
|
|
SyntaxNode cond = ParseExpression();
|
|
EnsureSymbol(")");
|
|
SyntaxNode truthy = nullptr;
|
|
SyntaxNode falsey = nullptr;
|
|
|
|
if (!IsIdentifier("else", false)) {
|
|
truthy = ParseNode();
|
|
}
|
|
|
|
if (IsIdentifier("else")) {
|
|
falsey = ParseNode();
|
|
}
|
|
|
|
return AdvancedSyntaxNode::Create(IfStatement, false,
|
|
{cond, truthy, falsey});
|
|
}
|
|
if (IsIdentifier("switch")) {
|
|
EnsureSymbol("(");
|
|
SyntaxNode cond = ParseExpression();
|
|
EnsureSymbol(")");
|
|
|
|
SyntaxNode body = ParseNode();
|
|
|
|
return AdvancedSyntaxNode::Create(SwitchStatement, false, {cond, body});
|
|
}
|
|
if (IsIdentifier("while")) {
|
|
EnsureSymbol("(");
|
|
SyntaxNode cond = ParseExpression();
|
|
EnsureSymbol(")");
|
|
|
|
SyntaxNode body = nullptr;
|
|
if (!IsSymbol(";")) {
|
|
body = ParseNode();
|
|
}
|
|
return AdvancedSyntaxNode::Create(WhileStatement, false, {cond, body});
|
|
}
|
|
if (IsIdentifier("using")) {
|
|
EnsureSymbol("(");
|
|
SyntaxNode expr = ParseExpression();
|
|
EnsureSymbol(")");
|
|
|
|
SyntaxNode body = nullptr;
|
|
if (!IsSymbol(";")) {
|
|
body = ParseNode();
|
|
}
|
|
|
|
return AdvancedSyntaxNode::Create(UsingStatement, false, {expr, body});
|
|
}
|
|
if (IsIdentifier("do")) {
|
|
EnsureSymbol("(");
|
|
SyntaxNode cond = ParseExpression();
|
|
EnsureSymbol(")");
|
|
|
|
SyntaxNode body = nullptr;
|
|
if (!IsSymbol(";")) {
|
|
body = ParseNode();
|
|
}
|
|
return AdvancedSyntaxNode::Create(DoStatement, false, {cond, body});
|
|
}
|
|
if (IsIdentifier("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(")");
|
|
|
|
if (!IsSymbol(";")) {
|
|
body = ParseNode();
|
|
}
|
|
return AdvancedSyntaxNode::Create(ForStatement, false,
|
|
{init, cond, inc, body});
|
|
}
|
|
if (IsIdentifier("each")) {
|
|
SyntaxNode item = nullptr;
|
|
EnsureSymbol("(");
|
|
SyntaxNode list = ParseExpression();
|
|
SyntaxNode body = nullptr;
|
|
if (IsSymbol(":") || IsIdentifier("in")) {
|
|
item = list;
|
|
list = ParseExpression();
|
|
}
|
|
EnsureSymbol(")");
|
|
|
|
if (!IsSymbol(";")) {
|
|
body = ParseNode();
|
|
}
|
|
if (std::holds_alternative<std::nullptr_t>(item))
|
|
item = AdvancedSyntaxNode::Create(
|
|
DeclareExpression, true,
|
|
{"item"});
|
|
|
|
return AdvancedSyntaxNode::Create(EachStatement, false,
|
|
{item, list, body});
|
|
}
|
|
if (IsIdentifier("class")) {
|
|
if (i < tokens.size()) {
|
|
std::vector<SyntaxNode> name_and_methods = {documentation};
|
|
|
|
auto name = ParseExpression();
|
|
name_and_methods.push_back(name);
|
|
|
|
if (IsSymbol(":", true)) {
|
|
name_and_methods.push_back(ParseExpression());
|
|
} else {
|
|
name_and_methods.push_back(AdvancedSyntaxNode::Create(
|
|
GetVariableExpression, true, {"ClassObject"}));
|
|
}
|
|
EnsureSymbol("{");
|
|
|
|
while (!IsSymbol("}", false) && i < tokens.size()) {
|
|
documentation = "";
|
|
|
|
if (tokens[i].type == LexTokenType::Documentation) {
|
|
documentation = tokens[i++].text;
|
|
}
|
|
|
|
if (i < tokens.size()) {
|
|
if (IsAnyIdentifier(
|
|
{"public", "private", "protected", "static"})) {
|
|
auto myTkn = tkn;
|
|
if (IsIdentifier("abstract")) {
|
|
if (myTkn.text == "static")
|
|
throw SyntaxException(
|
|
myTkn.lineInfo, "Static abstract function "
|
|
"doesn't make sense");
|
|
auto nameAndArgs = ParseExpression();
|
|
EnsureSymbol(";");
|
|
|
|
name_and_methods.push_back(
|
|
AdvancedSyntaxNode::Create(
|
|
AbstractMethodStatement, false,
|
|
{documentation, myTkn.text, nameAndArgs}));
|
|
|
|
} else if (i + 1 < tokens.size() &&
|
|
(tokens[i + 1].text == "=" ||
|
|
tokens[i + 1].text == ";") &&
|
|
tokens[i + 1].type == LexTokenType::Symbol) {
|
|
auto setter = ParseExpression();
|
|
EnsureSymbol(";");
|
|
|
|
SyntaxNode field = AdvancedSyntaxNode::Create(
|
|
FieldStatement, false,
|
|
{documentation, myTkn.text,
|
|
|
|
setter});
|
|
|
|
name_and_methods.push_back(field);
|
|
|
|
} else {
|
|
if (IsIdentifier("async")) {
|
|
auto nameAndArgs = ParseExpression();
|
|
|
|
if (IsSymbol("{", false)) {
|
|
|
|
name_and_methods.push_back(AdvancedSyntaxNode::Create(
|
|
MethodStatement, false,
|
|
{documentation, myTkn.text, nameAndArgs,
|
|
AdvancedSyntaxNode::Create(
|
|
ReturnStatement, false,
|
|
{AdvancedSyntaxNode::Create(
|
|
FunctionCallExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
GetFieldExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
GetVariableExpression,
|
|
true, {"Task"}),
|
|
"AsyncClosure"}),
|
|
AdvancedSyntaxNode::Create(
|
|
ClosureExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
ParenthesesExpression,
|
|
true, {}),
|
|
ParseNode()})})})}));
|
|
|
|
} else {
|
|
auto v = ParseExpression();
|
|
EnsureSymbol(";");
|
|
|
|
name_and_methods.push_back(AdvancedSyntaxNode::Create(
|
|
MethodStatement, false,
|
|
{documentation, myTkn.text, nameAndArgs,
|
|
AdvancedSyntaxNode::Create(
|
|
ReturnStatement, false,
|
|
{AdvancedSyntaxNode::Create(
|
|
FunctionCallExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
GetFieldExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
GetVariableExpression,
|
|
true, {"Task"}),
|
|
"AsyncClosure"}),
|
|
AdvancedSyntaxNode::Create(
|
|
ClosureExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
ParenthesesExpression,
|
|
true, {}),
|
|
AdvancedSyntaxNode::
|
|
Create(
|
|
ReturnStatement,
|
|
false,
|
|
{v})})})})}));
|
|
}
|
|
} else if (IsIdentifier("enumerable")) {
|
|
auto nameAndArgs = ParseExpression();
|
|
|
|
if (IsSymbol("{", false)) {
|
|
|
|
name_and_methods.push_back(
|
|
AdvancedSyntaxNode::Create(
|
|
MethodStatement, false,
|
|
{documentation, myTkn.text,
|
|
nameAndArgs,
|
|
AdvancedSyntaxNode::Create(
|
|
ReturnStatement, false,
|
|
{AdvancedSyntaxNode::Create(
|
|
FunctionCallExpression,
|
|
true,
|
|
{AdvancedSyntaxNode::Create(
|
|
GetVariableExpression,
|
|
true,
|
|
{"YieldEmumerable"}),
|
|
AdvancedSyntaxNode::Create(
|
|
ClosureExpression,
|
|
true,
|
|
{AdvancedSyntaxNode::
|
|
Create(
|
|
ParenthesesExpression,
|
|
true, {}),
|
|
ParseNode()})})})}));
|
|
|
|
} else {
|
|
throw SyntaxException(
|
|
tokens[i].lineInfo,
|
|
"expected the symbol \"{\" on "
|
|
"enumerable but got the symbol or "
|
|
"other token \"" +
|
|
tokens[i].text + "\"");
|
|
}
|
|
} else {
|
|
auto nameAndArgs = ParseExpression();
|
|
|
|
if (IsSymbol("{", false)) {
|
|
|
|
name_and_methods.push_back(
|
|
AdvancedSyntaxNode::Create(
|
|
MethodStatement, false,
|
|
{documentation, myTkn.text,
|
|
nameAndArgs, ParseNode()}));
|
|
|
|
} else {
|
|
auto v = ParseExpression();
|
|
EnsureSymbol(";");
|
|
name_and_methods.push_back(
|
|
AdvancedSyntaxNode::Create(
|
|
MethodStatement, false,
|
|
{documentation, myTkn.text,
|
|
nameAndArgs,
|
|
AdvancedSyntaxNode::Create(
|
|
ReturnStatement, false,
|
|
{v})}));
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
throw SyntaxException(
|
|
tokens[i].lineInfo,
|
|
"Need public, private, protected or static");
|
|
}
|
|
}
|
|
}
|
|
EnsureSymbol("}");
|
|
return AdvancedSyntaxNode::Create(ClassStatement, false,
|
|
name_and_methods);
|
|
} else
|
|
throw std::out_of_range("End of file");
|
|
}
|
|
|
|
if (IsIdentifier("enumerable", false) && i + 1 < tokens.size() &&
|
|
tokens[i + 1].text == "func" && i + 1 < tokens.size() &&
|
|
tokens[i + 1].type == LexTokenType::Identifier) {
|
|
i += 2;
|
|
auto nameAndArgs = ParseExpression();
|
|
|
|
if (IsSymbol("{", false)) {
|
|
return AdvancedSyntaxNode::Create(
|
|
FunctionStatement, false,
|
|
{nameAndArgs,
|
|
AdvancedSyntaxNode::Create(
|
|
ReturnStatement, false,
|
|
{AdvancedSyntaxNode::Create(
|
|
FunctionCallExpression, true,
|
|
{AdvancedSyntaxNode::Create(GetVariableExpression,
|
|
true, {"YieldEmumerable"}),
|
|
AdvancedSyntaxNode::Create(
|
|
ClosureExpression, true,
|
|
{AdvancedSyntaxNode::Create(ParenthesesExpression,
|
|
true, {}),
|
|
ParseNode()})})})});
|
|
} else {
|
|
throw SyntaxException(tokens[i].lineInfo,
|
|
"expected the symbol \"{\" on enumerable but "
|
|
"got the symbol or other token \"" +
|
|
tokens[i].text + "\"");
|
|
}
|
|
}
|
|
if (IsIdentifier("async", false) && i + 1 < tokens.size() &&
|
|
tokens[i + 1].text == "func" &&
|
|
tokens[i + 1].type == LexTokenType::Identifier) {
|
|
i += 2;
|
|
// async func
|
|
auto nameAndArgs = ParseExpression();
|
|
|
|
if (IsSymbol("{", false)) {
|
|
return AdvancedSyntaxNode::Create(
|
|
FunctionStatement, false,
|
|
{nameAndArgs,
|
|
AdvancedSyntaxNode::Create(
|
|
ReturnStatement, false,
|
|
{AdvancedSyntaxNode::Create(
|
|
FunctionCallExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
GetFieldExpression, true,
|
|
{AdvancedSyntaxNode::Create(GetVariableExpression,
|
|
true, {"Task"}),
|
|
"AsyncClosure"}),
|
|
AdvancedSyntaxNode::Create(
|
|
ClosureExpression, true,
|
|
{AdvancedSyntaxNode::Create(ParenthesesExpression,
|
|
true, {}),
|
|
ParseNode()})})})});
|
|
} else {
|
|
auto v = ParseExpression();
|
|
|
|
EnsureSymbol(";");
|
|
return AdvancedSyntaxNode::Create(
|
|
FunctionStatement, false,
|
|
{nameAndArgs,
|
|
AdvancedSyntaxNode::Create(
|
|
ReturnStatement, false,
|
|
{AdvancedSyntaxNode::Create(
|
|
FunctionCallExpression, true,
|
|
{AdvancedSyntaxNode::Create(
|
|
GetFieldExpression, true,
|
|
{AdvancedSyntaxNode::Create(GetVariableExpression,
|
|
true, {"Task"}),
|
|
"AsyncClosure"}),
|
|
AdvancedSyntaxNode::Create(
|
|
ClosureExpression, true,
|
|
{AdvancedSyntaxNode::Create(ParenthesesExpression,
|
|
true, {}),
|
|
AdvancedSyntaxNode::Create(ReturnStatement,
|
|
false, {v})})})})});
|
|
}
|
|
}
|
|
if (IsIdentifier("meta")) {
|
|
if (i >= tokens.size() || tokens[i].type != LexTokenType::String) {
|
|
std::cout
|
|
<< "WARN: meta is a conditional keyword,\nif you suffix it "
|
|
"with a string, it will be assumed to be a metadata tag"
|
|
<< std::endl;
|
|
i--;
|
|
} else {
|
|
std::string name = tokens[i++].text;
|
|
EnsureSymbol("{");
|
|
auto expr = ParseExpression();
|
|
|
|
EnsureSymbol("}");
|
|
|
|
return AdvancedSyntaxNode::Create(
|
|
MetadataStatement, false,
|
|
{name, AdvancedSyntaxNode::Create(DictionaryExpression, true,
|
|
{expr})});
|
|
}
|
|
}
|
|
if (IsIdentifier("func")) {
|
|
|
|
auto nameAndArgs = ParseExpression();
|
|
|
|
if (IsSymbol("{", false)) {
|
|
return AdvancedSyntaxNode::Create(FunctionStatement, false,
|
|
{nameAndArgs, ParseNode()});
|
|
} else {
|
|
auto v = ParseExpression();
|
|
|
|
EnsureSymbol(";");
|
|
return AdvancedSyntaxNode::Create(
|
|
FunctionStatement, false,
|
|
{nameAndArgs,
|
|
AdvancedSyntaxNode::Create(ReturnStatement, false, {v})});
|
|
}
|
|
}
|
|
if (IsIdentifier("break")) {
|
|
EnsureSymbol(";");
|
|
return AdvancedSyntaxNode::Create(BreakStatement, false, {});
|
|
}
|
|
if (IsIdentifier("continue")) {
|
|
EnsureSymbol(";");
|
|
return AdvancedSyntaxNode::Create(ContinueStatement, false, {});
|
|
}
|
|
if (IsIdentifier("case")) {
|
|
auto r = AdvancedSyntaxNode::Create(CaseStatement, false,
|
|
{ParseExpression()});
|
|
EnsureSymbol(":");
|
|
return r;
|
|
}
|
|
if (IsIdentifier("default")) {
|
|
auto r = AdvancedSyntaxNode::Create(DefaultStatement, false, {});
|
|
EnsureSymbol(":");
|
|
return r;
|
|
}
|
|
|
|
if (IsIdentifier("return")) {
|
|
SyntaxNode v = Undefined();
|
|
if (!IsSymbol(";", true)) {
|
|
v = ParseExpression();
|
|
EnsureSymbol(";");
|
|
}
|
|
return AdvancedSyntaxNode::Create(ReturnStatement, false, {v});
|
|
}
|
|
if (IsSymbol("<", false) && this->i + 1 < this->tokens.size() &&
|
|
this->tokens[this->i + 1].type == LexTokenType::Identifier &&
|
|
this->tokens[this->i + 1].text == "return") {
|
|
this->i++;
|
|
uint32_t htmlId = NewId();
|
|
std::string compHtml = "__compGenHtml";
|
|
compHtml.append(std::to_string(htmlId));
|
|
std::vector<SyntaxNode> syntaxNode = {compHtml};
|
|
ParseHtml(syntaxNode, compHtml);
|
|
|
|
auto thytoken =
|
|
AdvancedSyntaxNode::Create(HtmlRootExpression, true, syntaxNode);
|
|
|
|
return AdvancedSyntaxNode::Create(ReturnStatement, false, {thytoken});
|
|
}
|
|
|
|
if (IsIdentifier("yield")) {
|
|
SyntaxNode v = Undefined();
|
|
if (!IsSymbol(";", true)) {
|
|
v = ParseExpression();
|
|
EnsureSymbol(";");
|
|
}
|
|
return AdvancedSyntaxNode::Create(YieldStatement, false, {v});
|
|
}
|
|
if (IsIdentifier("throw")) {
|
|
auto tkn2 = tkn;
|
|
|
|
auto v = ParseExpression();
|
|
EnsureSymbol(";");
|
|
return AdvancedSyntaxNode::Create(
|
|
ThrowStatement, false,
|
|
{v, tkn2.lineInfo.filename, (int64_t)tkn2.lineInfo.line,
|
|
(int64_t)tkn2.lineInfo.column, (int64_t)tkn.lineInfo.offset});
|
|
}
|
|
if (IsIdentifier("breakpoint")) {
|
|
auto tkn2 = tkn;
|
|
|
|
auto v = ParseExpression();
|
|
EnsureSymbol(";");
|
|
return AdvancedSyntaxNode::Create(
|
|
BreakpointStatement, false,
|
|
{v, tkn2.lineInfo.filename, (int64_t)tkn2.lineInfo.line,
|
|
(int64_t)tkn2.lineInfo.column, (int64_t)tkn.lineInfo.offset});
|
|
}
|
|
if (IsIdentifier("try")) {
|
|
auto tryBody = ParseNode();
|
|
SyntaxNode catchNode = nullptr;
|
|
SyntaxNode catchEx = nullptr;
|
|
SyntaxNode finally = nullptr;
|
|
if (IsIdentifier("catch")) {
|
|
EnsureSymbol("(");
|
|
catchEx = ParseExpression();
|
|
EnsureSymbol(")");
|
|
catchNode = ParseNode();
|
|
}
|
|
if (IsIdentifier("finally")) {
|
|
finally = ParseNode();
|
|
}
|
|
|
|
return AdvancedSyntaxNode::Create(
|
|
TryStatement, false, {tryBody, catchNode, catchEx, finally});
|
|
}
|
|
if (IsIdentifier("defer")) {
|
|
if (IsSymbol("{", false)) {
|
|
return AdvancedSyntaxNode::Create(DeferStatement, false,
|
|
{ParseNode()});
|
|
} else {
|
|
auto v = ParseExpression();
|
|
|
|
EnsureSymbol(";");
|
|
return AdvancedSyntaxNode::Create(
|
|
DeferStatement, false,
|
|
{AdvancedSyntaxNode::Create(ReturnStatement, false, {v})});
|
|
}
|
|
}
|
|
auto v = ParseExpression();
|
|
EnsureSymbol(";");
|
|
return v;
|
|
}
|
|
SyntaxNode Parser::ParseNullCoalescing() {
|
|
SyntaxNode expr = ParseLOr();
|
|
while (IsSymbol("?\?")) {
|
|
expr = AdvancedSyntaxNode::Create(NullCoalescingExpression, true,
|
|
{expr, ParseLOr()});
|
|
}
|
|
return expr;
|
|
}
|
|
SyntaxNode Parser::ParseTernary() {
|
|
SyntaxNode node = ParseNullCoalescing();
|
|
if (IsSymbol("?")) {
|
|
auto yes = ParseTernary();
|
|
EnsureSymbol(":");
|
|
auto no = ParseTernary();
|
|
|
|
return AdvancedSyntaxNode::Create(TernaryExpression, true,
|
|
{node, yes, no});
|
|
}
|
|
return node;
|
|
}
|
|
SyntaxNode Parser::ParseShift() {
|
|
SyntaxNode expr = ParseSum();
|
|
while (IsAnySymbol({"<<", ">>"}, true)) {
|
|
if (tkn.text == "<<") {
|
|
expr = AdvancedSyntaxNode::Create(LeftShiftExpression, true,
|
|
{expr, ParseSum()});
|
|
} else if (tkn.text == ">>") {
|
|
expr = AdvancedSyntaxNode::Create(RightShiftExpression, true,
|
|
{expr, ParseSum()});
|
|
}
|
|
}
|
|
return expr;
|
|
}
|
|
|
|
SyntaxNode Parser::ParseRel() {
|
|
SyntaxNode expr = ParseShift();
|
|
while (IsAnySymbol({"<", ">", "<=", ">="}, true)) {
|
|
if (tkn.text == "<") {
|
|
expr = AdvancedSyntaxNode::Create(LessThanExpression, true,
|
|
{expr, ParseShift()});
|
|
} else if (tkn.text == ">") {
|
|
expr = AdvancedSyntaxNode::Create(GreaterThanExpression, true,
|
|
{expr, ParseShift()});
|
|
} else if (tkn.text == "<=") {
|
|
expr = AdvancedSyntaxNode::Create(LessThanEqualsExpression, true,
|
|
{expr, ParseShift()});
|
|
} else if (tkn.text == ">=") {
|
|
expr = AdvancedSyntaxNode::Create(GreaterThanEqualsExpression, true,
|
|
{expr, ParseShift()});
|
|
}
|
|
}
|
|
return expr;
|
|
}
|
|
SyntaxNode Parser::ParseEq() {
|
|
SyntaxNode expr = ParseRel();
|
|
while (IsAnySymbol({"==", "!="}, true)) {
|
|
if (tkn.text == "==") {
|
|
expr = AdvancedSyntaxNode::Create(EqualsExpression, true,
|
|
{expr, ParseRel()});
|
|
} else if (tkn.text == "!=") {
|
|
expr = AdvancedSyntaxNode::Create(NotEqualsExpression, true,
|
|
{expr, ParseRel()});
|
|
}
|
|
}
|
|
return expr;
|
|
}
|
|
SyntaxNode Parser::ParseBAnd() {
|
|
SyntaxNode expr = ParseEq();
|
|
while (IsSymbol("&")) {
|
|
expr = AdvancedSyntaxNode::Create(BitwiseAndExpression, true,
|
|
{expr, ParseEq()});
|
|
}
|
|
return expr;
|
|
}
|
|
SyntaxNode Parser::ParseExpression() {
|
|
SyntaxNode expr = ParseAssignment();
|
|
while (IsSymbol(",")) {
|
|
expr = AdvancedSyntaxNode::Create(CommaExpression, true,
|
|
{expr, ParseAssignment()});
|
|
}
|
|
return expr;
|
|
}
|
|
SyntaxNode Parser::ParseXOr() {
|
|
SyntaxNode expr = ParseBAnd();
|
|
while (IsSymbol("^")) {
|
|
expr = AdvancedSyntaxNode::Create(XOrExpression, true,
|
|
{expr, ParseBAnd()});
|
|
}
|
|
return expr;
|
|
}
|
|
SyntaxNode Parser::ParseBOr() {
|
|
SyntaxNode expr = ParseXOr();
|
|
while (IsSymbol("|")) {
|
|
expr = AdvancedSyntaxNode::Create(BitwiseOrExpression, true,
|
|
{expr, ParseXOr()});
|
|
}
|
|
return expr;
|
|
}
|
|
SyntaxNode Parser::ParseLAnd() {
|
|
SyntaxNode expr = ParseBOr();
|
|
while (IsSymbol("&&")) {
|
|
expr = AdvancedSyntaxNode::Create(LogicalAndExpression, true,
|
|
{expr, ParseBOr()});
|
|
}
|
|
return expr;
|
|
}
|
|
SyntaxNode Parser::ParseLOr() {
|
|
SyntaxNode expr = ParseLAnd();
|
|
while (IsSymbol("||")) {
|
|
expr = AdvancedSyntaxNode::Create(LogicalOrExpression, true,
|
|
{expr, ParseLAnd()});
|
|
}
|
|
return expr;
|
|
}
|
|
} // namespace Tesses::CrossLang
|