Parser.hpp: Add basic parsing of if/elseif/else statements

Signed-off-by: Username404 <w.iron.zombie@gmail.com>
This commit is contained in:
Username404 2023-08-06 19:49:35 +02:00
parent 164e5c5da3
commit 85a3582612
Signed by: Username404-59
GPG Key ID: 7AB361FBB257A5D1
8 changed files with 153 additions and 7 deletions

View File

@ -130,6 +130,42 @@ namespace StandardComponents {
struct Call: ParseTree, Reference { struct Call: ParseTree, Reference {
using Reference::Reference; using Reference::Reference;
}; };
struct Operator: ParseComponent { // TODO Parse operators in Parser.hpp
tok::type operator_type;
Operator(const convertible_to<tok::type> auto& operator_token): operator_type() {
using enum tok::type;
static_assert((operator_token == PLUS or operator_token == HYPHEN or operator_token == ASTERISK or operator_token == DIVIDE or operator_token == LCOMP or operator_token == RCOMP));
operator_type = operator_token;
}
};
struct Condition: ParseTree {
Condition(const ParseTree left, const ParseTree right, const Operator& operator_token) {
*this << left << operator_token << right;
}
explicit Condition(const derived_from<ParseComponent> auto condition) { *this << condition; }
struct Statement;
protected:
Condition() = default;
};
struct Condition::Statement: ParseTree {
struct Branch;
Condition condition;
ParseTree else_branches;
bool is_last_branch_conditional() const;
Statement(Condition _condition): ParseTree(), condition(move(_condition)), else_branches() {}
protected:
Statement(): condition(), else_branches() {}
};
struct Condition::Statement::Branch: Condition::Statement {
inline bool is_conditional() const { return not condition.empty(); };
using Condition::Statement::Statement; Branch(): Condition::Statement() {};
private:
using Condition::Statement::is_last_branch_conditional;
};
bool Condition::Statement::is_last_branch_conditional() const {
const auto* last = (not else_branches.empty()) ? dynamic_cast<const Branch*>(else_branches[else_branches.size() - 1].get()) : nullptr;
return (last == nullptr and (not this->condition.empty())) or (last != nullptr and not last->condition.empty());
}
struct Function: NamedIdentifier<true>, ParseTree { struct Function: NamedIdentifier<true>, ParseTree {
ParseTree parameters; ParseTree parameters;

View File

@ -88,11 +88,43 @@ namespace Parser {
} else { } else {
unsigned int parametersDistance = 0; unsigned int parametersDistance = 0;
if (next.toktype == LPAR) { if (next.toktype == LPAR) {
const auto closing = find_if(lexed.begin() + i, lexed.end(), [](const tok& token){ return token.toktype == RPAR; }); const auto closing = find_corresponding(lexed.begin() + i + 2, lexed.end(), LPAR, RPAR);
parametersDistance = distance(lexed.begin() + i, closing); parametersDistance = distance(lexed.begin() + i, closing);
i += parametersDistance; i += parametersDistance;
} }
if (nextAre({LCOMP, LCOMP, LBRACE})) { const bool is_branch = current.toktext == ID(CONDITION_STATEMENT_BRANCH);
const bool is_conditional_branch = (not is_branch) and current.toktext == ID(CONDITION_STATEMENT_CONDITIONAL_BRANCH);
if (current.toktext == ID(CONDITION_STATEMENT) or is_branch or is_conditional_branch) {
if (is_branch or is_conditional_branch) {
const auto& last_id = parseTree.at(parseTree.size() - 1)->getId();
if (last_id != typeid(Condition::Statement)) {
parsingError(current, "unexpected \"" + current.toktext + "\" without preceding if statement");
}
}
if (*(lexed.begin() + i + 1) != tok::LBRACE) parsingError(*(lexed.begin() + i), "missing statement body");
const auto body_end = find_corresponding(lexed.begin() + i + 2, lexed.end(), LBRACE, RBRACE);
auto* statement = (is_branch or is_conditional_branch) ? dynamic_cast<Condition::Statement*>(parseTree[parseTree.size() - 1].get()) : nullptr;
auto& else_branches = statement->else_branches;
if ((is_conditional_branch or is_branch) and not statement->is_last_branch_conditional())
parsingError(current, "<- unexpected branch", true);
optional<Condition> condition;
// TODO Check that the condition is valid
if (next.toktype == LPAR and ((lexed.begin() + i - parametersDistance) + 2) < lexed.begin() + i)
condition.emplace(parse((lexed.begin() + i - parametersDistance) + 2, lexed.begin() + i));
if (condition.has_value() or is_branch) {
if (is_conditional_branch or is_branch) {
auto branch = (condition.has_value() ? (Condition::Statement::Branch(move(condition.value()))) : Condition::Statement::Branch());
branch.ParseTree::operator=(parse(lexed.begin() + i + 2, body_end));
else_branches << branch;
} else {
Condition::Statement new_statement (move(condition.value()));
new_statement.ParseTree::operator=(parse(lexed.begin() + i + 2, body_end));
parseTree << new_statement;
}
i += distance(lexed.begin() + i, body_end);
} else if (not is_branch) parsingError(current, "missing condition after an \"" + current.toktext + "\" statement");
continue;
} else if (nextAre({LCOMP, LCOMP, LBRACE})) {
Function function(current.toktext); Function function(current.toktext);
if (parametersDistance > 2) if (parametersDistance > 2)
function.parameters = parse(filter_comma_list(lexed.begin() + ((i + 2) - parametersDistance), lexed.begin() + i)); // TODO Parse parameters correctly function.parameters = parse(filter_comma_list(lexed.begin() + ((i + 2) - parametersDistance), lexed.begin() + i)); // TODO Parse parameters correctly

View File

@ -7,11 +7,11 @@
#include <string_view> #include <string_view>
static constinit const array identifiers { static constinit const array identifiers {
"class", "structure", "print", "print_line" "class", "structure", "print", "print_line", "if", "else", "elseif"
}; };
enum class ReservedIdentifier: size_t { enum class ReservedIdentifier: size_t {
CLASS, STRUCT, PRINT_FUNCTION, PRINT_LINE_FUNCTION CLASS, STRUCT, PRINT_FUNCTION, PRINT_LINE_FUNCTION, CONDITION_STATEMENT, CONDITION_STATEMENT_BRANCH, CONDITION_STATEMENT_CONDITIONAL_BRANCH
}; };
inline const char* ID(const ReservedIdentifier& identifier) { inline const char* ID(const ReservedIdentifier& identifier) {

View File

@ -108,13 +108,13 @@ protected:
void separate_transpileTree(const T& parseTree, const unsigned short& indentationLevel = 0) { void separate_transpileTree(const T& parseTree, const unsigned short& indentationLevel = 0) {
transpileTree(parseTree, indentationLevel, [this, &parseTree](const auto& iterator){ transpileTree(parseTree, indentationLevel, [this, &parseTree](const auto& iterator){
if ((newLines || iterator + 1 == parseTree.cend()) && use_uniqueLineSeparator()) output << uniqueLineSeparator().value(); if ((newLines || iterator + 1 == parseTree.cend()) && use_uniqueLineSeparator()) output << uniqueLineSeparator().value();
if (iterator + 1 != parseTree.cend()) output << separator; if (iterator + 1 < parseTree.cend()) output << separator;
}); });
} }
IS(ParseTree) IS(ParseTree)
void separate_transpileTree(const T& parseTree, const string_view separation_characters) { void separate_transpileTree(const T& parseTree, const string_view separation_characters) {
transpileTree(parseTree, 0, [this, &parseTree, &separation_characters](const auto& iterator){ transpileTree(parseTree, 0, [this, &parseTree, &separation_characters](const auto& iterator){
if (iterator + 1 != parseTree.cend()) { output << separation_characters; } if (iterator + 1 < parseTree.cend()) { output << separation_characters; }
}); });
} }
typedef optional<const char*> optional_string; typedef optional<const char*> optional_string;
@ -137,7 +137,8 @@ public:
separate_transpileTree(parseComponent, ", "); separate_transpileTree(parseComponent, ", ");
output << ')'; output << ')';
), ),
make_task(StandardComponents::types::Integer, output << setprecision(parseComponent.precision) << fixed << parseComponent.value;) make_task(StandardComponents::types::Integer, output << setprecision(parseComponent.precision) << fixed << parseComponent.value;),
make_task(StandardComponents::Condition, output << '('; transpileTree(parseComponent); output << ')';)
})); }));
return fullMap; return fullMap;
}; };

View File

@ -16,6 +16,22 @@ struct GsTarget: Target {
output << "):" << separator << indentation; output << "):" << separator << indentation;
if (parseComponent.empty()) output << "pass"; if (parseComponent.empty()) output << "pass";
separate_transpileTree(parseComponent, 1); separate_transpileTree(parseComponent, 1);
),
make_task(Condition::Statement,
output << "if ("; transpileTree(parseComponent.condition); output << "):" << separator << indentation;
if (parseComponent.empty()) output << "pass";
separate_transpileTree(parseComponent, 1);
if (not parseComponent.else_branches.empty()) {
output << separator;
separate_transpileTree(parseComponent.else_branches);
}
),
make_task(Condition::Statement::Branch,
if (parseComponent.is_conditional()) {
output << "elif ("; transpileTree(parseComponent.condition); output << ")";
} else output << "else";
output << ':' << separator << indentation;
separate_transpileTree(parseComponent, 1);
) )
}; };
} }

View File

@ -20,6 +20,27 @@ struct JsTarget: Target {
separate_transpileTree(parseComponent, 1); separate_transpileTree(parseComponent, 1);
if (newLines and not parseComponent.empty()) output << separator; if (newLines and not parseComponent.empty()) output << separator;
output << '}'; output << '}';
),
make_task(Condition::Statement,
output << "if ("; transpileTree(parseComponent.condition); output << ") {";
if (not parseComponent.empty()) {
if (newLines) output << separator << indentation; }
separate_transpileTree(parseComponent, 1);
if (not parseComponent.else_branches.empty()) {
if (newLines) output << separator;
output << '}';
separate_transpileTree(parseComponent.else_branches, string((newLines) ? separator : "") + '}');
}
if (newLines) output << separator;
output << '}';
),
make_task(Condition::Statement::Branch,
if (parseComponent.is_conditional()) {
output << " else if ("; transpileTree(parseComponent.condition); output << ')';
} else output << " else";
output << " {";
if (newLines) output << separator << indentation;
separate_transpileTree(parseComponent, 1);
) )
}; };
} }

View File

@ -26,6 +26,25 @@ struct LuaTarget: Target {
separate_transpileTree(parseComponent, 1); separate_transpileTree(parseComponent, 1);
if (not parseComponent.empty()) output << separator; if (not parseComponent.empty()) output << separator;
output << "end"; output << "end";
),
make_task(Condition::Statement,
output << "if ("; transpileTree(parseComponent.condition); output << ") then";
if (not parseComponent.empty()) {
output << separator; if (newLines) output << indentation; }
separate_transpileTree(parseComponent, 1);
if (not parseComponent.else_branches.empty()) {
output << separator;
separate_transpileTree(parseComponent.else_branches);
}
output << separator << "end";
),
make_task(Condition::Statement::Branch,
if (parseComponent.is_conditional()) {
output << "elseif ("; transpileTree(parseComponent.condition); output << ") then";
} else output << "else ";
output << separator;
if (newLines) output << indentation;
separate_transpileTree(parseComponent, 1);
) )
}; };
} }

View File

@ -16,6 +16,27 @@ struct PyTarget: Target {
if (parseComponent.empty()) output << "pass"; if (parseComponent.empty()) output << "pass";
separate_transpileTree(parseComponent, 1); separate_transpileTree(parseComponent, 1);
), ),
make_task(Condition::Statement,
output << "if ("; transpileTree(parseComponent.condition); output << "):" << separator << indentation;
if (parseComponent.empty()) output << "pass";
separate_transpileTree(parseComponent, 1);
if (not parseComponent.else_branches.empty()) {
output << separator;
separate_transpileTree(parseComponent.else_branches);
}
),
make_task(Condition::Statement::Branch,
if (parseComponent.is_conditional()) {
output << "elif ("; transpileTree(parseComponent.condition); output << ")";
} else output << "else";
output << ':' << separator << indentation;
separate_transpileTree(parseComponent, 1);
),
make_task(StandardComponents::Reference,
if (parseComponent.name == "true" or parseComponent.name == "false") {
output << (char) toupper(parseComponent.name.front()) << parseComponent.name.substr(1);
} else output << parseComponent.name;
)
}; };
} }
using Target::Target; using Target::Target;