/* * Copyright (c) 2020, the SerenityOS developers. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include "Forward.h" #include "Job.h" #include "NodeVisitor.h" #include #include #include #include #include #include #include #include #include namespace Shell::AST { struct HighlightMetadata { bool is_first_in_list { true }; }; struct Position { size_t start_offset { 0 }; size_t end_offset { 0 }; struct Line { size_t line_number { 0 }; size_t line_column { 0 }; bool operator==(const Line& other) const { return line_number == other.line_number && line_column == other.line_column; } } start_line, end_line; bool contains(size_t offset) const { return start_offset <= offset && offset <= end_offset; } }; struct FdRedirection; struct Rewiring : public RefCounted { int old_fd { -1 }; int new_fd { -1 }; FdRedirection* other_pipe_end { nullptr }; enum class Close { None, Old, New, RefreshNew, RefreshOld, ImmediatelyCloseNew, } fd_action { Close::None }; Rewiring(int source, int dest, Close close = Close::None) : old_fd(source) , new_fd(dest) , fd_action(close) { } Rewiring(int source, int dest, FdRedirection* other_end, Close close) : old_fd(source) , new_fd(dest) , other_pipe_end(other_end) , fd_action(close) { } }; struct Redirection : public RefCounted { virtual Result, String> apply() const = 0; virtual ~Redirection(); virtual bool is_path_redirection() const { return false; } virtual bool is_fd_redirection() const { return false; } virtual bool is_close_redirection() const { return false; } }; struct CloseRedirection : public Redirection { int fd { -1 }; virtual Result, String> apply() const override; virtual ~CloseRedirection(); CloseRedirection(int fd) : fd(fd) { } private: virtual bool is_close_redirection() const override { return true; } }; struct PathRedirection : public Redirection { String path; int fd { -1 }; enum { Read, Write, WriteAppend, ReadWrite, } direction { Read }; static NonnullRefPtr create(String path, int fd, decltype(direction) direction) { return adopt(*new PathRedirection(move(path), fd, direction)); } virtual Result, String> apply() const override; virtual ~PathRedirection(); private: PathRedirection(String path, int fd, decltype(direction) direction) : path(move(path)) , fd(fd) , direction(direction) { } virtual bool is_path_redirection() const override { return true; } }; struct FdRedirection : public Redirection { public: static NonnullRefPtr create(int old_fd, int new_fd, Rewiring::Close close) { return adopt(*new FdRedirection(old_fd, new_fd, close)); } static NonnullRefPtr create(int old_fd, int new_fd, FdRedirection* pipe_end, Rewiring::Close close) { return adopt(*new FdRedirection(old_fd, new_fd, pipe_end, close)); } virtual ~FdRedirection(); virtual Result, String> apply() const override { return adopt(*new Rewiring(old_fd, new_fd, other_pipe_end, action)); } int old_fd { -1 }; int new_fd { -1 }; FdRedirection* other_pipe_end { nullptr }; Rewiring::Close action { Rewiring::Close::None }; private: FdRedirection(int source, int dest, Rewiring::Close close) : FdRedirection(source, dest, nullptr, close) { } FdRedirection(int old_fd, int new_fd, FdRedirection* pipe_end, Rewiring::Close close) : old_fd(old_fd) , new_fd(new_fd) , other_pipe_end(pipe_end) , action(close) { } virtual bool is_fd_redirection() const override { return true; } }; class Pipeline : public RefCounted { public: pid_t pgid { -1 }; }; struct NodeWithAction { mutable NonnullRefPtr node; enum Action { And, Or, Sequence, } action; NodeWithAction(Node& node, Action action) : node(node) , action(action) { } }; struct Command { Vector argv; NonnullRefPtrVector redirections; bool should_wait { true }; bool is_pipe_source { false }; bool should_notify_if_in_background { true }; bool should_immediately_execute_next { false }; mutable RefPtr pipeline; Vector next_chain; }; struct HitTestResult { RefPtr matching_node; RefPtr closest_node_with_semantic_meaning; // This is used if matching_node is a bareword RefPtr closest_command_node; // This is used if matching_node is a bareword, and it is not the first in a list }; class Value : public RefCounted { public: virtual Vector resolve_as_list(RefPtr) = 0; virtual Vector resolve_as_commands(RefPtr); virtual NonnullRefPtr resolve_without_cast(RefPtr) { return *this; } virtual ~Value(); virtual bool is_command() const { return false; } virtual bool is_glob() const { return false; } virtual bool is_job() const { return false; } virtual bool is_list() const { return false; } virtual bool is_string() const { return false; } virtual bool is_list_without_resolution() const { return false; } }; class CommandValue final : public Value { public: virtual Vector resolve_as_list(RefPtr) override; virtual Vector resolve_as_commands(RefPtr) override; virtual ~CommandValue(); virtual bool is_command() const override { return true; } CommandValue(Command command) : m_command(move(command)) { } CommandValue(Vector argv) : m_command({ move(argv), {}, true, false, true, false, nullptr, {} }) { } private: Command m_command; }; class CommandSequenceValue final : public Value { public: virtual Vector resolve_as_list(RefPtr) override; virtual Vector resolve_as_commands(RefPtr) override; virtual ~CommandSequenceValue(); virtual bool is_command() const override { return true; } CommandSequenceValue(Vector commands) : m_contained_values(move(commands)) { } private: Vector m_contained_values; }; class JobValue final : public Value { public: virtual Vector resolve_as_list(RefPtr) override { ASSERT_NOT_REACHED(); } virtual Vector resolve_as_commands(RefPtr) override { ASSERT_NOT_REACHED(); } virtual ~JobValue(); virtual bool is_job() const override { return true; } JobValue(RefPtr job) : m_job(move(job)) { } const RefPtr job() const { return m_job; } private: RefPtr m_job; }; class ListValue final : public Value { public: virtual Vector resolve_as_list(RefPtr) override; virtual NonnullRefPtr resolve_without_cast(RefPtr) override; virtual ~ListValue(); virtual bool is_list() const override { return true; } virtual bool is_list_without_resolution() const override { return true; } ListValue(Vector values); ListValue(Vector> values) : m_contained_values(move(static_cast&>(values))) { } ListValue(NonnullRefPtrVector values) : m_contained_values(move(values)) { } const NonnullRefPtrVector& values() const { return m_contained_values; } NonnullRefPtrVector& values() { return m_contained_values; } private: NonnullRefPtrVector m_contained_values; }; class StringValue final : public Value { public: virtual Vector resolve_as_list(RefPtr) override; virtual ~StringValue(); virtual bool is_string() const override { return m_split.is_null(); } virtual bool is_list() const override { return !m_split.is_null(); } StringValue(String string, String split_by = {}, bool keep_empty = false) : m_string(move(string)) , m_split(move(split_by)) , m_keep_empty(keep_empty) { } private: String m_string; String m_split; bool m_keep_empty { false }; }; class GlobValue final : public Value { public: virtual Vector resolve_as_list(RefPtr) override; virtual ~GlobValue(); virtual bool is_glob() const override { return true; } GlobValue(String glob) : m_glob(move(glob)) { } private: String m_glob; }; class SimpleVariableValue final : public Value { public: virtual Vector resolve_as_list(RefPtr) override; virtual NonnullRefPtr resolve_without_cast(RefPtr) override; virtual ~SimpleVariableValue(); SimpleVariableValue(String name) : m_name(move(name)) { } private: String m_name; }; class SpecialVariableValue final : public Value { public: virtual Vector resolve_as_list(RefPtr) override; virtual ~SpecialVariableValue(); SpecialVariableValue(char name) : m_name(name) { } private: char m_name { -1 }; }; class TildeValue final : public Value { public: virtual Vector resolve_as_list(RefPtr) override; virtual ~TildeValue(); virtual bool is_string() const override { return true; } TildeValue(String name) : m_username(move(name)) { } private: String m_username; }; class Node : public RefCounted { public: virtual void dump(int level) const = 0; virtual void for_each_entry(RefPtr shell, Function)> callback); virtual RefPtr run(RefPtr) = 0; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) = 0; virtual Vector complete_for_editor(Shell&, size_t, const HitTestResult&); Vector complete_for_editor(Shell& shell, size_t offset); virtual HitTestResult hit_test_position(size_t offset) { if (m_position.contains(offset)) return { this, nullptr, nullptr }; return { nullptr, nullptr, nullptr }; } virtual String class_name() const { return "Node"; } Node(Position); virtual ~Node(); virtual bool is_bareword() const { return false; } virtual bool is_command() const { return false; } virtual bool is_execute() const { return false; } virtual bool is_glob() const { return false; } virtual bool is_tilde() const { return false; } virtual bool is_variable_decls() const { return false; } virtual bool is_simple_variable() const { return false; } virtual bool is_syntax_error() const { return m_is_syntax_error; } virtual bool is_list() const { return false; } virtual bool would_execute() const { return false; } const Position& position() const { return m_position; } void set_is_syntax_error(const SyntaxError& error_node) { if (!m_is_syntax_error) { m_is_syntax_error = true; m_syntax_error_node = error_node; } } virtual const SyntaxError& syntax_error_node() const { ASSERT(is_syntax_error()); return *m_syntax_error_node; } virtual RefPtr leftmost_trivial_literal() const { return nullptr; } Vector to_lazy_evaluated_commands(RefPtr shell); virtual void visit(NodeVisitor&) { ASSERT_NOT_REACHED(); } virtual void visit(NodeVisitor& visitor) const { const_cast(this)->visit(visitor); } enum class Kind : u32 { And, ListConcatenate, Background, BarewordLiteral, BraceExpansion, CastToCommand, CastToList, CloseFdRedirection, CommandLiteral, Comment, DynamicEvaluate, DoubleQuotedString, Fd2FdRedirection, FunctionDeclaration, ForLoop, Glob, Execute, IfCond, Join, MatchExpr, Or, Pipe, Range, ReadRedirection, ReadWriteRedirection, Sequence, Subshell, SimpleVariable, SpecialVariable, Juxtaposition, StringLiteral, StringPartCompose, SyntaxError, Tilde, VariableDeclarations, WriteAppendRedirection, WriteRedirection, __Count, }; virtual Kind kind() const = 0; protected: Position m_position; bool m_is_syntax_error { false }; RefPtr m_syntax_error_node; }; #define NODE(name) \ virtual String class_name() const override { return #name; } \ virtual Kind kind() const override { return Kind::name; } class PathRedirectionNode : public Node { public: PathRedirectionNode(Position, int, NonnullRefPtr); virtual ~PathRedirectionNode(); virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual Vector complete_for_editor(Shell&, size_t, const HitTestResult&) override; virtual HitTestResult hit_test_position(size_t offset) override; virtual bool is_command() const override { return true; } virtual bool is_list() const override { return true; } virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& path() const { return m_path; } int fd() const { return m_fd; } protected: int m_fd { -1 }; NonnullRefPtr m_path; }; class And final : public Node { public: And(Position, NonnullRefPtr, NonnullRefPtr, Position and_position); virtual ~And(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& left() const { return m_left; } const NonnullRefPtr& right() const { return m_right; } const Position& and_position() const { return m_and_position; } private: NODE(And); 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; NonnullRefPtr m_left; NonnullRefPtr m_right; Position m_and_position; }; class ListConcatenate final : public Node { public: ListConcatenate(Position, Vector>); virtual ~ListConcatenate(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const Vector> list() const { return m_list; } private: NODE(ListConcatenate); 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 bool is_list() const override { return true; } virtual RefPtr leftmost_trivial_literal() const override; Vector> m_list; }; class Background final : public Node { public: Background(Position, NonnullRefPtr); virtual ~Background(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& command() const { return m_command; } private: NODE(Background); 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; NonnullRefPtr m_command; }; class BarewordLiteral final : public Node { public: BarewordLiteral(Position, String); virtual ~BarewordLiteral(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const String& text() const { return m_text; } private: NODE(BarewordLiteral); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual bool is_bareword() const override { return true; } virtual RefPtr leftmost_trivial_literal() const override { return this; } String m_text; }; class BraceExpansion final : public Node { public: BraceExpansion(Position, NonnullRefPtrVector); virtual ~BraceExpansion(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtrVector& entries() const { return m_entries; } private: NODE(BraceExpansion); 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; NonnullRefPtrVector m_entries; }; class CastToCommand final : public Node { public: CastToCommand(Position, NonnullRefPtr); virtual ~CastToCommand(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& inner() const { return m_inner; } private: NODE(CastToCommand); 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 Vector complete_for_editor(Shell&, size_t, const HitTestResult&) override; virtual bool is_command() const override { return true; } virtual bool is_list() const override { return true; } virtual RefPtr leftmost_trivial_literal() const override; NonnullRefPtr m_inner; }; class CastToList final : public Node { public: CastToList(Position, RefPtr); virtual ~CastToList(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const RefPtr& inner() const { return m_inner; } private: NODE(CastToList); 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 bool is_list() const override { return true; } virtual RefPtr leftmost_trivial_literal() const override; RefPtr m_inner; }; class CloseFdRedirection final : public Node { public: CloseFdRedirection(Position, int); virtual ~CloseFdRedirection(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } int fd() const { return m_fd; } private: NODE(CloseFdRedirection); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual bool is_command() const override { return true; } int m_fd { -1 }; }; class CommandLiteral final : public Node { public: CommandLiteral(Position, Command); virtual ~CommandLiteral(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const Command& command() const { return m_command; } private: NODE(CommandLiteral); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override { ASSERT_NOT_REACHED(); } virtual bool is_command() const override { return true; } virtual bool is_list() const override { return true; } Command m_command; }; class Comment : public Node { public: Comment(Position, String); virtual ~Comment(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const String& text() const { return m_text; } private: NODE(Comment); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; String m_text; }; class DynamicEvaluate final : public Node { public: DynamicEvaluate(Position, NonnullRefPtr); virtual ~DynamicEvaluate(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& inner() const { return m_inner; } private: NODE(DynamicEvaluate); 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 bool is_bareword() const override { return m_inner->is_bareword(); } virtual bool is_command() const override { return is_list(); } virtual bool is_execute() const override { return true; } virtual bool is_glob() const override { return m_inner->is_glob(); } virtual bool is_list() const override { return m_inner->is_list() || m_inner->is_command() || m_inner->is_glob(); // Anything that generates a list. } NonnullRefPtr m_inner; }; class DoubleQuotedString final : public Node { public: DoubleQuotedString(Position, RefPtr); virtual ~DoubleQuotedString(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const RefPtr& inner() const { return m_inner; } private: NODE(DoubleQuotedString); 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; RefPtr m_inner; }; class Fd2FdRedirection final : public Node { public: Fd2FdRedirection(Position, int, int); virtual ~Fd2FdRedirection(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } int source_fd() const { return m_old_fd; } int dest_fd() const { return m_new_fd; } private: NODE(Fd2FdRedirection); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual bool is_command() const override { return true; } int m_old_fd { -1 }; int m_new_fd { -1 }; }; class FunctionDeclaration final : public Node { public: struct NameWithPosition { String name; Position position; }; FunctionDeclaration(Position, NameWithPosition name, Vector argument_names, RefPtr body); virtual ~FunctionDeclaration(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NameWithPosition& name() const { return m_name; } const Vector arguments() const { return m_arguments; } const RefPtr& block() const { return m_block; } private: NODE(FunctionDeclaration); 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 Vector complete_for_editor(Shell&, size_t, const HitTestResult&) override; virtual bool would_execute() const override { return true; } NameWithPosition m_name; Vector m_arguments; RefPtr m_block; }; class ForLoop final : public Node { public: ForLoop(Position, String variable_name, NonnullRefPtr iterated_expr, RefPtr block, Optional in_kw_position = {}); virtual ~ForLoop(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const String& variable_name() const { return m_variable_name; } const NonnullRefPtr& iterated_expression() const { return m_iterated_expression; } const RefPtr& block() const { return m_block; } const Optional in_keyword_position() const { return m_in_kw_position; } private: NODE(ForLoop); 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 bool would_execute() const override { return true; } String m_variable_name; NonnullRefPtr m_iterated_expression; RefPtr m_block; Optional m_in_kw_position; }; class Glob final : public Node { public: Glob(Position, String); virtual ~Glob(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const String& text() const { return m_text; } private: NODE(Glob); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual bool is_glob() const override { return true; } virtual bool is_list() const override { return true; } String m_text; }; class Execute final : public Node { public: Execute(Position, NonnullRefPtr, bool capture_stdout = false); virtual ~Execute(); void capture_stdout() { m_capture_stdout = true; } NonnullRefPtr& command() { return m_command; } virtual void for_each_entry(RefPtr shell, Function)> callback) override; virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& command() const { return m_command; } bool does_capture_stdout() const { return m_capture_stdout; } private: NODE(Execute); 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 Vector complete_for_editor(Shell&, size_t, const HitTestResult&) override; virtual bool is_execute() const override { return true; } virtual bool would_execute() const override { return true; } NonnullRefPtr m_command; bool m_capture_stdout { false }; }; class IfCond final : public Node { public: IfCond(Position, Optional else_position, NonnullRefPtr cond_expr, RefPtr true_branch, RefPtr false_branch); virtual ~IfCond(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& condition() const { return m_condition; } const RefPtr& true_branch() const { return m_true_branch; } const RefPtr& false_branch() const { return m_false_branch; } const Optional else_position() const { return m_else_position; } private: NODE(IfCond); 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 bool would_execute() const override { return true; } NonnullRefPtr m_condition; RefPtr m_true_branch; RefPtr m_false_branch; Optional m_else_position; }; class Join final : public Node { public: Join(Position, NonnullRefPtr, NonnullRefPtr); virtual ~Join(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& left() const { return m_left; } const NonnullRefPtr& right() const { return m_right; } private: NODE(Join); 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 bool is_command() const override { return true; } virtual bool is_list() const override { return true; } virtual RefPtr leftmost_trivial_literal() const override; NonnullRefPtr m_left; NonnullRefPtr m_right; }; struct MatchEntry { NonnullRefPtrVector options; Optional> match_names; Optional match_as_position; Vector pipe_positions; RefPtr body; }; class MatchExpr final : public Node { public: MatchExpr(Position, NonnullRefPtr expr, String name, Optional as_position, Vector entries); virtual ~MatchExpr(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& matched_expr() const { return m_matched_expr; } const String& expr_name() const { return m_expr_name; } const Vector& entries() const { return m_entries; } const Optional& as_position() const { return m_as_position; } private: NODE(MatchExpr); 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 bool would_execute() const override { return true; } NonnullRefPtr m_matched_expr; String m_expr_name; Optional m_as_position; Vector m_entries; }; class Or final : public Node { public: Or(Position, NonnullRefPtr, NonnullRefPtr, Position or_position); virtual ~Or(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& left() const { return m_left; } const NonnullRefPtr& right() const { return m_right; } const Position& or_position() const { return m_or_position; } private: NODE(Or); 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; NonnullRefPtr m_left; NonnullRefPtr m_right; Position m_or_position; }; class Pipe final : public Node { public: Pipe(Position, NonnullRefPtr, NonnullRefPtr); virtual ~Pipe(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& left() const { return m_left; } const NonnullRefPtr& right() const { return m_right; } private: NODE(Pipe); 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 bool is_command() const override { return true; } NonnullRefPtr m_left; NonnullRefPtr m_right; }; class Range final : public Node { public: Range(Position, NonnullRefPtr, NonnullRefPtr); virtual ~Range(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& start() const { return m_start; } const NonnullRefPtr& end() const { return m_end; } private: NODE(Range); 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; NonnullRefPtr m_start; NonnullRefPtr m_end; }; class ReadRedirection final : public PathRedirectionNode { public: ReadRedirection(Position, int, NonnullRefPtr); virtual ~ReadRedirection(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } private: NODE(ReadRedirection); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; }; class ReadWriteRedirection final : public PathRedirectionNode { public: ReadWriteRedirection(Position, int, NonnullRefPtr); virtual ~ReadWriteRedirection(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } private: NODE(ReadWriteRedirection); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; }; class Sequence final : public Node { public: Sequence(Position, NonnullRefPtr, NonnullRefPtr, Position separator_position); virtual ~Sequence(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& left() const { return m_left; } const NonnullRefPtr& right() const { return m_right; } const Position& separator_position() const { return m_separator_position; } private: NODE(Sequence); 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 bool is_list() const override { return true; } virtual bool would_execute() const override { return m_left->would_execute() || m_right->would_execute(); } NonnullRefPtr m_left; NonnullRefPtr m_right; Position m_separator_position; }; class Subshell final : public Node { public: Subshell(Position, RefPtr block); virtual ~Subshell(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const RefPtr& block() const { return m_block; } private: NODE(Subshell); 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 bool would_execute() const override { return true; } RefPtr m_block; }; class SimpleVariable final : public Node { public: SimpleVariable(Position, String); virtual ~SimpleVariable(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const String& name() const { return m_name; } private: NODE(SimpleVariable); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual Vector complete_for_editor(Shell&, size_t, const HitTestResult&) override; virtual HitTestResult hit_test_position(size_t) override; virtual bool is_simple_variable() const override { return true; } String m_name; }; class SpecialVariable final : public Node { public: SpecialVariable(Position, char); virtual ~SpecialVariable(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } char name() const { return m_name; } private: NODE(SpecialVariable); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual Vector complete_for_editor(Shell&, size_t, const HitTestResult&) override; virtual HitTestResult hit_test_position(size_t) override; char m_name { -1 }; }; class Juxtaposition final : public Node { public: Juxtaposition(Position, NonnullRefPtr, NonnullRefPtr); virtual ~Juxtaposition(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& left() const { return m_left; } const NonnullRefPtr& right() const { return m_right; } private: NODE(Juxtaposition); 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 Vector complete_for_editor(Shell&, size_t, const HitTestResult&) override; NonnullRefPtr m_left; NonnullRefPtr m_right; }; class StringLiteral final : public Node { public: StringLiteral(Position, String); virtual ~StringLiteral(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const String& text() const { return m_text; } private: NODE(StringLiteral); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual RefPtr leftmost_trivial_literal() const override { return this; }; String m_text; }; class StringPartCompose final : public Node { public: StringPartCompose(Position, NonnullRefPtr, NonnullRefPtr); virtual ~StringPartCompose(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const NonnullRefPtr& left() const { return m_left; } const NonnullRefPtr& right() const { return m_right; } private: NODE(StringPartCompose); 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; NonnullRefPtr m_left; NonnullRefPtr m_right; }; class SyntaxError final : public Node { public: SyntaxError(Position, String, bool is_continuable = false); virtual ~SyntaxError(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const String& error_text() const { return m_syntax_error_text; } bool is_continuable() const { return m_is_continuable; } private: NODE(SyntaxError); 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 { return { nullptr, nullptr, nullptr }; } virtual bool is_syntax_error() const override { return true; } virtual const SyntaxError& syntax_error_node() const override; String m_syntax_error_text; bool m_is_continuable { false }; }; class Tilde final : public Node { public: Tilde(Position, String); virtual ~Tilde(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } String text() const; private: NODE(Tilde); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual Vector complete_for_editor(Shell&, size_t, const HitTestResult&) override; virtual HitTestResult hit_test_position(size_t) override; virtual bool is_tilde() const override { return true; } String m_username; }; class VariableDeclarations final : public Node { public: struct Variable { NonnullRefPtr name; NonnullRefPtr value; }; VariableDeclarations(Position, Vector variables); virtual ~VariableDeclarations(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } const Vector& variables() const { return m_variables; } private: NODE(VariableDeclarations); 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 bool is_variable_decls() const override { return true; } Vector m_variables; }; class WriteAppendRedirection final : public PathRedirectionNode { public: WriteAppendRedirection(Position, int, NonnullRefPtr); virtual ~WriteAppendRedirection(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } private: NODE(WriteAppendRedirection); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; }; class WriteRedirection final : public PathRedirectionNode { public: WriteRedirection(Position, int, NonnullRefPtr); virtual ~WriteRedirection(); virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); } private: NODE(WriteRedirection); virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; }; } namespace AK { template<> struct Formatter : StandardFormatter { Formatter() { } explicit Formatter(StandardFormatter formatter) : StandardFormatter(formatter) { } void format(TypeErasedFormatParams&, FormatBuilder&, const Shell::AST::Command& value); }; }