From b194d79c53b668bcdb8a2f47b4ac4c6651003060 Mon Sep 17 00:00:00 2001 From: AnotherTest Date: Tue, 8 Sep 2020 15:59:07 +0430 Subject: [PATCH] Shell: Add the (now) free subshell support --- Shell/AST.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ Shell/AST.h | 16 ++++++++++++++++ Shell/Parser.cpp | 26 ++++++++++++++++++++++++++ Shell/Parser.h | 5 +++++ 4 files changed, 92 insertions(+) diff --git a/Shell/AST.cpp b/Shell/AST.cpp index 2dca0594b6..2b0a45d87a 100644 --- a/Shell/AST.cpp +++ b/Shell/AST.cpp @@ -1569,6 +1569,51 @@ Sequence::~Sequence() { } +void Subshell::dump(int level) const +{ + Node::dump(level); + if (m_block) + m_block->dump(level + 1); +} + +RefPtr Subshell::run(RefPtr shell) +{ + if (!m_block) + return create({}); + + 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 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); diff --git a/Shell/AST.h b/Shell/AST.h index f336b819d9..e180aa3594 100644 --- a/Shell/AST.h +++ b/Shell/AST.h @@ -806,6 +806,22 @@ private: RefPtr m_right; }; +class Subshell final : public Node { +public: + Subshell(Position, RefPtr block); + virtual ~Subshell(); + +private: + virtual void dump(int level) const override; + virtual RefPtr run(RefPtr) 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 m_block; +}; + class SimpleVariable final : public Node { public: SimpleVariable(Position, String); diff --git a/Shell/Parser.cpp b/Shell/Parser.cpp index c40944ca47..98ea06f5f7 100644 --- a/Shell/Parser.cpp +++ b/Shell/Parser.cpp @@ -366,6 +366,9 @@ RefPtr 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 Parser::parse_if_expr() return create(else_position, move(condition), move(true_branch), nullptr); // If expr true_branch } +RefPtr 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 syntax_error = create("Expected a close brace '}' to end a subshell"); + if (body) + body->set_is_syntax_error(*syntax_error); + else + body = syntax_error; + } + } + + return create(move(body)); +} + RefPtr Parser::parse_redirection() { auto rule_start = push_start(); diff --git a/Shell/Parser.h b/Shell/Parser.h index 4d20a200d4..375ea71c09 100644 --- a/Shell/Parser.h +++ b/Shell/Parser.h @@ -53,6 +53,7 @@ private: RefPtr parse_control_structure(); RefPtr parse_for_loop(); RefPtr parse_if_expr(); + RefPtr parse_subshell(); RefPtr parse_redirection(); RefPtr parse_list_expression(); RefPtr 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?