1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-18 21:25:07 +00:00

Shell: Add 'if' expressions

```sh
if foo bar baz {
    quux
} else if foobar || whatever {
    echo I ran out of example words
} else {
    exit 2
}
```
This commit is contained in:
AnotherTest 2020-08-11 12:05:46 +04:30 committed by Andreas Kling
parent c2be38e50f
commit b90eb5c9ba
4 changed files with 210 additions and 2 deletions

View file

@ -364,6 +364,9 @@ RefPtr<AST::Node> Parser::parse_control_structure()
if (auto for_loop = parse_for_loop())
return for_loop;
if (auto if_expr = parse_if_expr())
return if_expr;
return nullptr;
}
@ -431,6 +434,83 @@ RefPtr<AST::Node> Parser::parse_for_loop()
return create<AST::ForLoop>(move(variable_name), move(iterated_expression), move(body), move(in_start_position)); // ForLoop Var Iterated Block
}
RefPtr<AST::Node> Parser::parse_if_expr()
{
auto rule_start = push_start();
if (!expect("if")) {
m_offset = rule_start->offset;
return nullptr;
}
if (consume_while(is_any_of(" \t\n")).is_empty()) {
m_offset = rule_start->offset;
return nullptr;
}
RefPtr<AST::Node> condition;
{
auto cond_error_start = push_start();
condition = parse_or_logical_sequence();
if (!condition) {
auto syntax_error = create<AST::SyntaxError>("Expected a logical sequence after 'if'");
return create<AST::IfCond>(Optional<AST::Position> {}, move(syntax_error), nullptr, nullptr);
}
}
auto parse_braced_toplevel = [&]() -> RefPtr<AST::Node> {
{
auto obrace_error_start = push_start();
if (!expect('{')) {
auto syntax_error = create<AST::SyntaxError>("Expected an open brace '{' to start an 'if' true branch");
return syntax_error;
}
}
auto body = parse_toplevel();
{
auto cbrace_error_start = push_start();
if (!expect('}')) {
auto error_start = push_start();
RefPtr<AST::SyntaxError> syntax_error = create<AST::SyntaxError>("Expected a close brace '}' to end an 'if' true branch");
if (body)
body->set_is_syntax_error(*syntax_error);
else
body = syntax_error;
}
}
return body;
};
consume_while(is_whitespace);
auto true_branch = parse_braced_toplevel();
if (true_branch && true_branch->is_syntax_error())
return create<AST::IfCond>(Optional<AST::Position> {}, move(condition), move(true_branch), nullptr); // If expr syntax_error
consume_while(is_whitespace);
Optional<AST::Position> else_position;
{
auto else_start = push_start();
if (expect("else"))
else_position = AST::Position { else_start->offset, m_offset };
}
if (else_position.has_value()) {
consume_while(is_whitespace);
if (peek() == '{') {
auto false_branch = parse_braced_toplevel();
return create<AST::IfCond>(else_position, move(condition), move(true_branch), move(false_branch)); // If expr true_branch Else false_branch
}
auto else_if_branch = parse_if_expr();
return create<AST::IfCond>(else_position, move(condition), move(true_branch), move(else_if_branch)); // If expr true_branch Else If ...
}
return create<AST::IfCond>(else_position, move(condition), move(true_branch), nullptr); // If expr true_branch
}
RefPtr<AST::Node> Parser::parse_redirection()
{
auto rule_start = push_start();