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 {
|
||||
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 {
|
||||
ParseTree parameters;
|
||||
|
|
|
@ -88,11 +88,43 @@ namespace Parser {
|
|||
} else {
|
||||
unsigned int parametersDistance = 0;
|
||||
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);
|
||||
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);
|
||||
if (parametersDistance > 2)
|
||||
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>
|
||||
|
||||
static constinit const array identifiers {
|
||||
"class", "structure", "print", "print_line"
|
||||
"class", "structure", "print", "print_line", "if", "else", "elseif"
|
||||
};
|
||||
|
||||
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) {
|
||||
|
|
|
@ -108,13 +108,13 @@ protected:
|
|||
void separate_transpileTree(const T& parseTree, const unsigned short& indentationLevel = 0) {
|
||||
transpileTree(parseTree, indentationLevel, [this, &parseTree](const auto& iterator){
|
||||
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)
|
||||
void separate_transpileTree(const T& parseTree, const string_view separation_characters) {
|
||||
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;
|
||||
|
@ -137,7 +137,8 @@ public:
|
|||
separate_transpileTree(parseComponent, ", ");
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -16,6 +16,22 @@ struct GsTarget: Target {
|
|||
output << "):" << separator << indentation;
|
||||
if (parseComponent.empty()) output << "pass";
|
||||
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);
|
||||
if (newLines and not parseComponent.empty()) output << separator;
|
||||
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);
|
||||
if (not parseComponent.empty()) output << separator;
|
||||
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";
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue