Shell: Add the (now) free subshell support

This commit is contained in:
AnotherTest 2020-09-08 15:59:07 +04:30 committed by Andreas Kling
parent 0fd8d5ad3d
commit b194d79c53
4 changed files with 92 additions and 0 deletions

View file

@ -1569,6 +1569,51 @@ Sequence::~Sequence()
{
}
void Subshell::dump(int level) const
{
Node::dump(level);
if (m_block)
m_block->dump(level + 1);
}
RefPtr<Value> Subshell::run(RefPtr<Shell> shell)
{
if (!m_block)
return create<ListValue>({});
return m_block->run(shell);
}
void Subshell::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
{
metadata.is_first_in_list = true;
if (m_block)
m_block->highlight_in_editor(editor, shell, metadata);
}
HitTestResult Subshell::hit_test_position(size_t offset)
{
if (!position().contains(offset))
return {};
if (m_block)
return m_block->hit_test_position(offset);
return {};
}
Subshell::Subshell(Position position, RefPtr<Node> block)
: Node(move(position))
, m_block(block)
{
if (m_block && m_block->is_syntax_error())
set_is_syntax_error(m_block->syntax_error_node());
}
Subshell::~Subshell()
{
}
void SimpleVariable::dump(int level) const
{
Node::dump(level);

View file

@ -806,6 +806,22 @@ private:
RefPtr<Node> m_right;
};
class Subshell final : public Node {
public:
Subshell(Position, RefPtr<Node> block);
virtual ~Subshell();
private:
virtual void dump(int level) const override;
virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual String class_name() const override { return "Subshell"; }
virtual bool would_execute() const override { return true; }
RefPtr<AST::Node> m_block;
};
class SimpleVariable final : public Node {
public:
SimpleVariable(Position, String);

View file

@ -366,6 +366,9 @@ RefPtr<AST::Node> Parser::parse_control_structure()
if (auto if_expr = parse_if_expr())
return if_expr;
if (auto subshell = parse_subshell())
return subshell;
return nullptr;
}
@ -510,6 +513,29 @@ RefPtr<AST::Node> Parser::parse_if_expr()
return create<AST::IfCond>(else_position, move(condition), move(true_branch), nullptr); // If expr true_branch
}
RefPtr<AST::Node> Parser::parse_subshell()
{
auto rule_start = push_start();
if (!expect('{'))
return nullptr;
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 a subshell");
if (body)
body->set_is_syntax_error(*syntax_error);
else
body = syntax_error;
}
}
return create<AST::Subshell>(move(body));
}
RefPtr<AST::Node> Parser::parse_redirection()
{
auto rule_start = push_start();

View file

@ -53,6 +53,7 @@ private:
RefPtr<AST::Node> parse_control_structure();
RefPtr<AST::Node> parse_for_loop();
RefPtr<AST::Node> parse_if_expr();
RefPtr<AST::Node> parse_subshell();
RefPtr<AST::Node> parse_redirection();
RefPtr<AST::Node> parse_list_expression();
RefPtr<AST::Node> parse_expression();
@ -129,6 +130,8 @@ pipe_sequence :: command '|' pipe_sequence
control_structure :: for_expr
| if_expr
| subshell
for_expr :: 'for' ws+ (identifier ' '+ 'in' ws*)? expression ws+ '{' toplevel '}'
if_expr :: 'if' ws+ or_logical_sequence ws+ '{' toplevel '}' else_clause?
@ -136,6 +139,8 @@ if_expr :: 'if' ws+ or_logical_sequence ws+ '{' toplevel '}' else_clause?
else_clause :: else '{' toplevel '}'
| else if_expr
subshell :: '{' toplevel '}'
command :: redirection command
| list_expression command?