Parser.hpp: Add basic parsing of if/elseif/else statements
Signed-off-by: Username404 <w.iron.zombie@gmail.com>
This commit is contained in:
parent
164e5c5da3
commit
85a3582612
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue