/* * 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 #include #include #include #include #include #include namespace AST { struct HighlightMetadata { bool is_first_in_list { true }; }; struct Position { size_t start_offset { 0 }; size_t end_offset { 0 }; bool contains(size_t offset) const { return start_offset <= offset && offset <= end_offset; } }; struct Rewiring : public RefCounted { int source_fd { -1 }; int dest_fd { -1 }; Rewiring* other_pipe_end { nullptr }; enum class Close { None, Source, Destination, RefreshDestination, ImmediatelyCloseDestination, } fd_action { Close::None }; Rewiring(int source, int dest, Close close = Close::None) : source_fd(source) , dest_fd(dest) , fd_action(close) { } Rewiring(int source, int dest, Rewiring* other_end, Close close) : source_fd(source) , dest_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 }; virtual Result, String> apply() const override; virtual ~PathRedirection(); PathRedirection(String path, int fd, decltype(direction) direction) : path(move(path)) , fd(fd) , direction(direction) { } private: virtual bool is_path_redirection() const override { return true; } }; struct FdRedirection : public Redirection , public Rewiring { virtual Result, String> apply() const override { return static_cast>(this); } virtual ~FdRedirection(); FdRedirection(int source, int dest, Rewiring::Close close) : Rewiring(source, dest, close) { } FdRedirection(int source, int dest, Rewiring* pipe_end, Rewiring::Close close) : Rewiring(source, dest, pipe_end, close) { } private: virtual bool is_fd_redirection() const override { return true; } }; struct Command { Vector argv; Vector> redirections; bool should_wait { true }; bool is_pipe_source { false }; bool should_notify_if_in_background { true }; }; 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 RefPtr 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 }) { } 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 RefPtr 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(values)) { } const Vector>& values() const { return m_contained_values; } private: Vector> 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(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(glob) { } private: String m_glob; }; class SimpleVariableValue final : public Value { public: virtual Vector resolve_as_list(RefPtr) override; RefPtr resolve_without_cast(RefPtr) override; virtual ~SimpleVariableValue(); SimpleVariableValue(String name) : m_name(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(name) { } private: String m_username; }; class Node : public RefCounted { public: virtual void dump(int level) const = 0; 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_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) { 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; } protected: Position m_position; bool m_is_syntax_error { false }; RefPtr m_syntax_error_node; }; class PathRedirectionNode : public Node { public: PathRedirectionNode(Position, int, RefPtr); 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; } protected: int m_fd { -1 }; RefPtr m_path; }; class And final : public Node { public: And(Position, RefPtr, RefPtr); virtual ~And(); 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 "And"; } virtual bool would_execute() const override { return true; } RefPtr m_left; RefPtr m_right; }; class ListConcatenate final : public Node { public: ListConcatenate(Position, Vector>); virtual ~ListConcatenate(); 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 "ListConcatenate"; } 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, RefPtr); virtual ~Background(); 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 "Background"; } RefPtr m_command; }; class BarewordLiteral final : public Node { public: BarewordLiteral(Position, String); virtual ~BarewordLiteral(); const String& text() const { return m_text; } private: virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual String class_name() const override { return "BarewordLiteral"; } virtual bool is_bareword() const override { return true; } virtual RefPtr leftmost_trivial_literal() const override { return this; } String m_text; }; class CastToCommand final : public Node { public: CastToCommand(Position, RefPtr); virtual ~CastToCommand(); 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 Vector complete_for_editor(Shell&, size_t, const HitTestResult&) override; virtual String class_name() const override { return "CastToCommand"; } virtual bool is_command() const override { return true; } virtual bool is_list() const override { return true; } virtual RefPtr leftmost_trivial_literal() const override; RefPtr m_inner; }; class CastToList final : public Node { public: CastToList(Position, RefPtr); virtual ~CastToList(); 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 "CastToList"; } 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(); private: virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual String class_name() const override { return "CloseFdRedirection"; } virtual bool is_command() const override { return true; } int m_fd { -1 }; }; class CommandLiteral final : public Node { public: CommandLiteral(Position, Command); virtual ~CommandLiteral(); private: 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 String class_name() const override { return "CommandLiteral"; } 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(); const String& text() const { return m_text; } private: virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual String class_name() const override { return "Comment"; } String m_text; }; class DynamicEvaluate final : public Node { public: DynamicEvaluate(Position, RefPtr); virtual ~DynamicEvaluate(); 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 "DynamicEvaluate"; } 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. } RefPtr m_inner; }; class DoubleQuotedString final : public Node { public: DoubleQuotedString(Position, RefPtr); virtual ~DoubleQuotedString(); 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 "DoubleQuotedString"; } RefPtr m_inner; }; class Fd2FdRedirection final : public Node { public: Fd2FdRedirection(Position, int, int); virtual ~Fd2FdRedirection(); private: virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual String class_name() const override { return "Fd2FdRedirection"; } virtual bool is_command() const override { return true; } int source_fd { -1 }; int dest_fd { -1 }; }; class ForLoop final : public Node { public: ForLoop(Position, String variable_name, RefPtr iterated_expr, RefPtr block, Optional in_kw_position = {}); virtual ~ForLoop(); 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 "ForLoop"; } String m_variable_name; RefPtr m_iterated_expression; RefPtr m_block; Optional m_in_kw_position; }; class Glob final : public Node { public: Glob(Position, String); virtual ~Glob(); const String& text() const { return m_text; } private: virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual String class_name() const override { return "Glob"; } 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, RefPtr, bool capture_stdout = false); virtual ~Execute(); void capture_stdout() { m_capture_stdout = true; } RefPtr command() { return m_command; } 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 Vector complete_for_editor(Shell&, size_t, const HitTestResult&) override; virtual String class_name() const override { return "Execute"; } virtual bool is_execute() const override { return true; } virtual bool would_execute() const override { return true; } RefPtr m_command; bool m_capture_stdout { false }; }; class Join final : public Node { public: Join(Position, RefPtr, RefPtr); virtual ~Join(); 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 "Join"; } virtual bool is_command() const override { return true; } virtual bool is_list() const override { return true; } virtual RefPtr leftmost_trivial_literal() const override; RefPtr m_left; RefPtr m_right; }; class Or final : public Node { public: Or(Position, RefPtr, RefPtr); virtual ~Or(); 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 "Or"; } virtual bool would_execute() const override { return true; } RefPtr m_left; RefPtr m_right; }; class Pipe final : public Node { public: Pipe(Position, RefPtr, RefPtr); virtual ~Pipe(); 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 "Pipe"; } virtual bool is_list() const override { return true; } RefPtr m_left; RefPtr m_right; }; class ReadRedirection final : public PathRedirectionNode { public: ReadRedirection(Position, int, RefPtr); virtual ~ReadRedirection(); private: virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual String class_name() const override { return "ReadRedirection"; } }; class ReadWriteRedirection final : public PathRedirectionNode { public: ReadWriteRedirection(Position, int, RefPtr); virtual ~ReadWriteRedirection(); private: virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual String class_name() const override { return "ReadWriteRedirection"; } }; class Sequence final : public Node { public: Sequence(Position, RefPtr, RefPtr); virtual ~Sequence(); 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 "Sequence"; } virtual bool is_list() const override { return true; } virtual bool would_execute() const override { return m_left->would_execute() || m_right->would_execute(); } RefPtr m_left; RefPtr m_right; }; class SimpleVariable final : public Node { public: SimpleVariable(Position, String); virtual ~SimpleVariable(); private: 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 String class_name() const override { return "SimpleVariable"; } String m_name; }; class SpecialVariable final : public Node { public: SpecialVariable(Position, char); virtual ~SpecialVariable(); private: 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 String class_name() const override { return "SpecialVariable"; } char m_name { -1 }; }; class Juxtaposition final : public Node { public: Juxtaposition(Position, RefPtr, RefPtr); virtual ~Juxtaposition(); 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 Vector complete_for_editor(Shell&, size_t, const HitTestResult&) override; virtual String class_name() const override { return "Juxtaposition"; } RefPtr m_left; RefPtr m_right; }; class StringLiteral final : public Node { public: StringLiteral(Position, String); virtual ~StringLiteral(); const String& text() const { return m_text; } private: virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override; virtual String class_name() const override { return "StringLiteral"; } virtual RefPtr leftmost_trivial_literal() const override { return this; }; String m_text; }; class StringPartCompose final : public Node { public: StringPartCompose(Position, RefPtr, RefPtr); virtual ~StringPartCompose(); 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 "StringPartCompose"; } RefPtr m_left; RefPtr m_right; }; class SyntaxError final : public Node { public: SyntaxError(Position, String); virtual ~SyntaxError(); const String& error_text() const { return m_syntax_error_text; } 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 { return { nullptr, nullptr, nullptr }; } virtual String class_name() const override { return "SyntaxError"; } virtual bool is_syntax_error() const override { return true; } virtual const SyntaxError& syntax_error_node() const override; String m_syntax_error_text; }; class Tilde final : public Node { public: Tilde(Position, String); virtual ~Tilde(); String text() const; private: 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 String class_name() const override { return "Tilde"; } virtual bool is_tilde() const override { return true; } String m_username; }; class VariableDeclarations final : public Node { public: struct Variable { RefPtr name; RefPtr value; }; VariableDeclarations(Position, Vector variables); virtual ~VariableDeclarations(); const Vector& variables() const { return m_variables; } 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 "VariableDeclarations"; } virtual bool is_variable_decls() const override { return true; } Vector m_variables; }; class WriteAppendRedirection final : public PathRedirectionNode { public: WriteAppendRedirection(Position, int, RefPtr); virtual ~WriteAppendRedirection(); private: virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual String class_name() const override { return "WriteAppendRedirection"; } }; class WriteRedirection final : public PathRedirectionNode { public: WriteRedirection(Position, int, RefPtr); virtual ~WriteRedirection(); private: virtual void dump(int level) const override; virtual RefPtr run(RefPtr) override; virtual String class_name() const override { return "WriteRedirection"; } }; }