Sfoglia il codice sorgente

Shell: Add the (now) free subshell support

AnotherTest 4 anni fa
parent
commit
b194d79c53
4 ha cambiato i file con 92 aggiunte e 0 eliminazioni
  1. 45 0
      Shell/AST.cpp
  2. 16 0
      Shell/AST.h
  3. 26 0
      Shell/Parser.cpp
  4. 5 0
      Shell/Parser.h

+ 45 - 0
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<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);

+ 16 - 0
Shell/AST.h

@@ -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);

+ 26 - 0
Shell/Parser.cpp

@@ -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();

+ 5 - 0
Shell/Parser.h

@@ -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?