mirror of
https://github.com/RGBCube/serenity
synced 2025-05-17 14:05:07 +00:00

We previously allowed globs as match pattern, but for more complex matching needs, it's nice to have regular expressions. And as the existing "name a part of the match" concept maps nicely to named capture groups, we can simply reuse the same code and make groups with names available in the match body.
1534 lines
52 KiB
C++
1534 lines
52 KiB
C++
/*
|
|
* Copyright (c) 2020, the SerenityOS developers.
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "Forward.h"
|
|
#include "Job.h"
|
|
#include "NodeVisitor.h"
|
|
#include <AK/Format.h>
|
|
#include <AK/NonnullRefPtr.h>
|
|
#include <AK/RefCounted.h>
|
|
#include <AK/RefPtr.h>
|
|
#include <AK/String.h>
|
|
#include <AK/Types.h>
|
|
#include <AK/Vector.h>
|
|
#include <LibLine/Editor.h>
|
|
#include <LibRegex/Regex.h>
|
|
|
|
namespace Shell::AST {
|
|
|
|
using AK::make_ref_counted;
|
|
|
|
template<typename T>
|
|
static inline NonnullRefPtr<T> make_ref_counted(std::initializer_list<NonnullRefPtr<Value>> arg)
|
|
{
|
|
return adopt_ref(*new T(arg));
|
|
}
|
|
|
|
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==(Line const& 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 NameWithPosition {
|
|
String name;
|
|
Position position;
|
|
};
|
|
|
|
struct FdRedirection;
|
|
struct Rewiring : public RefCounted<Rewiring> {
|
|
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<Redirection> {
|
|
virtual ErrorOr<NonnullRefPtr<Rewiring>> 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 ErrorOr<NonnullRefPtr<Rewiring>> 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<PathRedirection> create(String path, int fd, decltype(direction) direction)
|
|
{
|
|
return adopt_ref(*new PathRedirection(move(path), fd, direction));
|
|
}
|
|
|
|
virtual ErrorOr<NonnullRefPtr<Rewiring>> 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<FdRedirection> create(int old_fd, int new_fd, Rewiring::Close close)
|
|
{
|
|
return adopt_ref(*new FdRedirection(old_fd, new_fd, close));
|
|
}
|
|
|
|
static NonnullRefPtr<FdRedirection> create(int old_fd, int new_fd, FdRedirection* pipe_end, Rewiring::Close close)
|
|
{
|
|
return adopt_ref(*new FdRedirection(old_fd, new_fd, pipe_end, close));
|
|
}
|
|
|
|
virtual ~FdRedirection();
|
|
|
|
virtual ErrorOr<NonnullRefPtr<Rewiring>> apply() const override
|
|
{
|
|
return adopt_ref(*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<Pipeline> {
|
|
public:
|
|
pid_t pgid { -1 };
|
|
};
|
|
|
|
struct NodeWithAction {
|
|
mutable NonnullRefPtr<Node> node;
|
|
enum Action {
|
|
And,
|
|
Or,
|
|
Sequence,
|
|
} action;
|
|
|
|
NodeWithAction(Node& node, Action action)
|
|
: node(node)
|
|
, action(action)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct Command {
|
|
Vector<String> argv;
|
|
NonnullRefPtrVector<Redirection> 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> pipeline;
|
|
Vector<NodeWithAction> next_chain;
|
|
Optional<Position> position;
|
|
};
|
|
|
|
struct HitTestResult {
|
|
RefPtr<Node> matching_node;
|
|
RefPtr<Node> closest_node_with_semantic_meaning; // This is used if matching_node is a bareword
|
|
RefPtr<Node> 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<Value> {
|
|
public:
|
|
virtual Vector<String> resolve_as_list(RefPtr<Shell>) = 0;
|
|
virtual String resolve_as_string(RefPtr<Shell> shell);
|
|
virtual Vector<Command> resolve_as_commands(RefPtr<Shell>);
|
|
virtual NonnullRefPtr<Value> resolve_without_cast(RefPtr<Shell>) { return *this; }
|
|
virtual NonnullRefPtr<Value> clone() const = 0;
|
|
virtual NonnullRefPtr<Value> with_slices(NonnullRefPtr<Slice> slice) const&;
|
|
virtual NonnullRefPtr<Value> with_slices(NonnullRefPtrVector<Slice> slices) const&;
|
|
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; }
|
|
|
|
protected:
|
|
Value& set_slices(NonnullRefPtrVector<Slice> slices)
|
|
{
|
|
m_slices = move(slices);
|
|
return *this;
|
|
}
|
|
NonnullRefPtrVector<Slice> m_slices;
|
|
};
|
|
|
|
class CommandValue final : public Value {
|
|
public:
|
|
virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
|
|
virtual Vector<Command> resolve_as_commands(RefPtr<Shell>) override;
|
|
virtual NonnullRefPtr<Value> clone() const override { return make_ref_counted<CommandValue>(m_command)->set_slices(m_slices); }
|
|
virtual ~CommandValue();
|
|
virtual bool is_command() const override { return true; }
|
|
CommandValue(Command command)
|
|
: m_command(move(command))
|
|
{
|
|
}
|
|
|
|
CommandValue(Vector<String> argv, Position position)
|
|
: m_command({ move(argv), {}, true, false, true, false, nullptr, {}, move(position) })
|
|
{
|
|
}
|
|
|
|
private:
|
|
Command m_command;
|
|
};
|
|
|
|
class CommandSequenceValue final : public Value {
|
|
public:
|
|
virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
|
|
virtual Vector<Command> resolve_as_commands(RefPtr<Shell>) override;
|
|
virtual NonnullRefPtr<Value> clone() const override { return make_ref_counted<CommandSequenceValue>(m_contained_values)->set_slices(m_slices); }
|
|
virtual ~CommandSequenceValue();
|
|
virtual bool is_command() const override { return true; }
|
|
CommandSequenceValue(Vector<Command> commands)
|
|
: m_contained_values(move(commands))
|
|
{
|
|
}
|
|
|
|
private:
|
|
Vector<Command> m_contained_values;
|
|
};
|
|
|
|
class JobValue final : public Value {
|
|
public:
|
|
virtual Vector<String> resolve_as_list(RefPtr<Shell>) override { VERIFY_NOT_REACHED(); }
|
|
virtual String resolve_as_string(RefPtr<Shell>) override { return String::formatted("%{}", m_job->job_id()); }
|
|
virtual Vector<Command> resolve_as_commands(RefPtr<Shell>) override { VERIFY_NOT_REACHED(); }
|
|
virtual NonnullRefPtr<Value> clone() const override { return make_ref_counted<JobValue>(m_job)->set_slices(m_slices); }
|
|
virtual ~JobValue();
|
|
virtual bool is_job() const override { return true; }
|
|
JobValue(RefPtr<Job> job)
|
|
: m_job(move(job))
|
|
{
|
|
}
|
|
|
|
RefPtr<Job> const job() const { return m_job; }
|
|
|
|
private:
|
|
RefPtr<Job> m_job;
|
|
};
|
|
|
|
class ListValue final : public Value {
|
|
public:
|
|
virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
|
|
virtual NonnullRefPtr<Value> resolve_without_cast(RefPtr<Shell>) override;
|
|
virtual NonnullRefPtr<Value> clone() const override { return make_ref_counted<ListValue>(m_contained_values)->set_slices(m_slices); }
|
|
virtual ~ListValue();
|
|
virtual bool is_list() const override { return true; }
|
|
virtual bool is_list_without_resolution() const override { return true; }
|
|
ListValue(Vector<String> values);
|
|
ListValue(Vector<NonnullRefPtr<Value>> values)
|
|
: m_contained_values(move(static_cast<NonnullRefPtrVector<Value>&>(values)))
|
|
{
|
|
}
|
|
ListValue(NonnullRefPtrVector<Value> values)
|
|
: m_contained_values(move(values))
|
|
{
|
|
}
|
|
|
|
NonnullRefPtrVector<Value> const& values() const { return m_contained_values; }
|
|
NonnullRefPtrVector<Value>& values() { return m_contained_values; }
|
|
|
|
private:
|
|
NonnullRefPtrVector<Value> m_contained_values;
|
|
};
|
|
|
|
class StringValue final : public Value {
|
|
public:
|
|
virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
|
|
virtual String resolve_as_string(RefPtr<Shell> shell) override;
|
|
virtual NonnullRefPtr<Value> clone() const override { return make_ref_counted<StringValue>(m_string, m_split, m_keep_empty)->set_slices(m_slices); }
|
|
virtual ~StringValue();
|
|
virtual bool is_string() const override { return m_split.is_null(); }
|
|
virtual bool is_list() const override { return !m_split.is_null(); }
|
|
NonnullRefPtr<Value> resolve_without_cast(RefPtr<Shell>) override;
|
|
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<String> resolve_as_list(RefPtr<Shell>) override;
|
|
virtual NonnullRefPtr<Value> clone() const override { return make_ref_counted<GlobValue>(m_glob, m_generation_position)->set_slices(m_slices); }
|
|
virtual ~GlobValue();
|
|
virtual bool is_glob() const override { return true; }
|
|
GlobValue(String glob, Position position)
|
|
: m_glob(move(glob))
|
|
, m_generation_position(move(position))
|
|
{
|
|
}
|
|
|
|
private:
|
|
String m_glob;
|
|
Position m_generation_position;
|
|
};
|
|
|
|
class SimpleVariableValue final : public Value {
|
|
public:
|
|
virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
|
|
virtual String resolve_as_string(RefPtr<Shell>) override;
|
|
virtual NonnullRefPtr<Value> resolve_without_cast(RefPtr<Shell>) override;
|
|
virtual NonnullRefPtr<Value> clone() const override { return make_ref_counted<SimpleVariableValue>(m_name)->set_slices(m_slices); }
|
|
virtual ~SimpleVariableValue();
|
|
SimpleVariableValue(String name)
|
|
: m_name(move(name))
|
|
{
|
|
}
|
|
|
|
private:
|
|
String m_name;
|
|
};
|
|
|
|
class SpecialVariableValue final : public Value {
|
|
public:
|
|
virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
|
|
virtual String resolve_as_string(RefPtr<Shell>) override;
|
|
virtual NonnullRefPtr<Value> clone() const override { return make_ref_counted<SpecialVariableValue>(m_name)->set_slices(m_slices); }
|
|
virtual ~SpecialVariableValue();
|
|
SpecialVariableValue(char name)
|
|
: m_name(name)
|
|
{
|
|
}
|
|
|
|
private:
|
|
char m_name { 0 };
|
|
};
|
|
|
|
class TildeValue final : public Value {
|
|
public:
|
|
virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
|
|
virtual String resolve_as_string(RefPtr<Shell>) override;
|
|
virtual NonnullRefPtr<Value> clone() const override { return make_ref_counted<TildeValue>(m_username)->set_slices(m_slices); }
|
|
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<Node> {
|
|
AK_MAKE_NONCOPYABLE(Node);
|
|
AK_MAKE_NONMOVABLE(Node);
|
|
|
|
public:
|
|
virtual void dump(int level) const = 0;
|
|
virtual void for_each_entry(RefPtr<Shell> shell, Function<IterationDecision(NonnullRefPtr<Value>)> callback);
|
|
virtual RefPtr<Value> run(RefPtr<Shell>) = 0;
|
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) = 0;
|
|
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, HitTestResult const&);
|
|
Vector<Line::CompletionSuggestion> complete_for_editor(Shell& shell, size_t offset);
|
|
virtual HitTestResult hit_test_position(size_t offset) const
|
|
{
|
|
if (m_position.contains(offset))
|
|
return { this, nullptr, nullptr };
|
|
return { nullptr, nullptr, nullptr };
|
|
}
|
|
virtual String class_name() const { return "Node"; }
|
|
Node(Position);
|
|
virtual ~Node() = default;
|
|
|
|
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;
|
|
|
|
virtual bool is_list() const { return false; }
|
|
virtual bool would_execute() const { return false; }
|
|
virtual bool should_override_execution_in_current_process() const { return false; }
|
|
|
|
Position const& position() const { return m_position; }
|
|
virtual void clear_syntax_error();
|
|
virtual void set_is_syntax_error(SyntaxError const& error_node);
|
|
virtual SyntaxError const& syntax_error_node() const
|
|
{
|
|
VERIFY(is_syntax_error());
|
|
return *m_syntax_error_node;
|
|
}
|
|
|
|
virtual RefPtr<Node> leftmost_trivial_literal() const { return nullptr; }
|
|
|
|
Vector<Command> to_lazy_evaluated_commands(RefPtr<Shell> shell);
|
|
|
|
virtual void visit(NodeVisitor&) { VERIFY_NOT_REACHED(); }
|
|
virtual void visit(NodeVisitor& visitor) const { const_cast<Node*>(this)->visit(visitor); }
|
|
|
|
enum class Kind : u32 {
|
|
And,
|
|
Background,
|
|
BarewordLiteral,
|
|
BraceExpansion,
|
|
CastToCommand,
|
|
CastToList,
|
|
CloseFdRedirection,
|
|
CommandLiteral,
|
|
Comment,
|
|
ContinuationControl,
|
|
DoubleQuotedString,
|
|
DynamicEvaluate,
|
|
Execute,
|
|
Fd2FdRedirection,
|
|
ForLoop,
|
|
FunctionDeclaration,
|
|
Glob,
|
|
Heredoc,
|
|
HistoryEvent,
|
|
IfCond,
|
|
ImmediateExpression,
|
|
Join,
|
|
Juxtaposition,
|
|
ListConcatenate,
|
|
MatchExpr,
|
|
Or,
|
|
Pipe,
|
|
Range,
|
|
ReadRedirection,
|
|
ReadWriteRedirection,
|
|
Sequence,
|
|
Slice,
|
|
SimpleVariable,
|
|
SpecialVariable,
|
|
StringLiteral,
|
|
StringPartCompose,
|
|
Subshell,
|
|
SyntaxError,
|
|
SyntheticValue,
|
|
Tilde,
|
|
VariableDeclarations,
|
|
WriteAppendRedirection,
|
|
WriteRedirection,
|
|
__Count,
|
|
};
|
|
|
|
virtual Kind kind() const = 0;
|
|
|
|
protected:
|
|
Position m_position;
|
|
RefPtr<SyntaxError> 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<Node>);
|
|
virtual ~PathRedirectionNode();
|
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
|
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, HitTestResult const&) override;
|
|
virtual HitTestResult hit_test_position(size_t offset) const 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); }
|
|
|
|
NonnullRefPtr<Node> const& path() const { return m_path; }
|
|
int fd() const { return m_fd; }
|
|
|
|
protected:
|
|
int m_fd { -1 };
|
|
NonnullRefPtr<Node> m_path;
|
|
};
|
|
|
|
class And final : public Node {
|
|
public:
|
|
And(Position, NonnullRefPtr<Node>, NonnullRefPtr<Node>, Position and_position);
|
|
virtual ~And() = default;
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtr<Node> const& left() const { return m_left; }
|
|
NonnullRefPtr<Node> const& right() const { return m_right; }
|
|
Position const& and_position() const { return m_and_position; }
|
|
|
|
private:
|
|
NODE(And);
|
|
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) const override;
|
|
|
|
NonnullRefPtr<Node> m_left;
|
|
NonnullRefPtr<Node> m_right;
|
|
Position m_and_position;
|
|
};
|
|
|
|
class ListConcatenate final : public Node {
|
|
public:
|
|
ListConcatenate(Position, Vector<NonnullRefPtr<Node>>);
|
|
virtual ~ListConcatenate() = default;
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
Vector<NonnullRefPtr<Node>> const list() const { return m_list; }
|
|
|
|
private:
|
|
NODE(ListConcatenate);
|
|
virtual void dump(int level) const override;
|
|
virtual void for_each_entry(RefPtr<Shell> shell, Function<IterationDecision(NonnullRefPtr<Value>)> callback) 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) const override;
|
|
virtual bool is_list() const override { return true; }
|
|
virtual RefPtr<Node> leftmost_trivial_literal() const override;
|
|
|
|
Vector<NonnullRefPtr<Node>> m_list;
|
|
};
|
|
|
|
class Background final : public Node {
|
|
public:
|
|
Background(Position, NonnullRefPtr<Node>);
|
|
virtual ~Background() = default;
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtr<Node> const& command() const { return m_command; }
|
|
|
|
private:
|
|
NODE(Background);
|
|
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) const override;
|
|
|
|
NonnullRefPtr<Node> m_command;
|
|
};
|
|
|
|
class BarewordLiteral final : public Node {
|
|
public:
|
|
BarewordLiteral(Position, String);
|
|
virtual ~BarewordLiteral() = default;
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
String const& text() const { return m_text; }
|
|
|
|
private:
|
|
NODE(BarewordLiteral);
|
|
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 bool is_bareword() const override { return true; }
|
|
virtual RefPtr<Node> leftmost_trivial_literal() const override { return this; }
|
|
|
|
String m_text;
|
|
};
|
|
|
|
class BraceExpansion final : public Node {
|
|
public:
|
|
BraceExpansion(Position, NonnullRefPtrVector<Node>);
|
|
virtual ~BraceExpansion() = default;
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtrVector<Node> const& entries() const { return m_entries; }
|
|
|
|
private:
|
|
NODE(BraceExpansion);
|
|
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) const override;
|
|
|
|
NonnullRefPtrVector<Node> m_entries;
|
|
};
|
|
|
|
class CastToCommand final : public Node {
|
|
public:
|
|
CastToCommand(Position, NonnullRefPtr<Node>);
|
|
virtual ~CastToCommand() = default;
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtr<Node> const& inner() const { return m_inner; }
|
|
|
|
private:
|
|
NODE(CastToCommand);
|
|
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) const override;
|
|
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, HitTestResult const&) override;
|
|
virtual bool is_command() const override { return true; }
|
|
virtual bool is_list() const override { return true; }
|
|
virtual RefPtr<Node> leftmost_trivial_literal() const override;
|
|
|
|
NonnullRefPtr<Node> m_inner;
|
|
};
|
|
|
|
class CastToList final : public Node {
|
|
public:
|
|
CastToList(Position, RefPtr<Node>);
|
|
virtual ~CastToList() = default;
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
RefPtr<Node> const& inner() const { return m_inner; }
|
|
|
|
private:
|
|
NODE(CastToList);
|
|
virtual void dump(int level) const override;
|
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
|
virtual void for_each_entry(RefPtr<Shell> shell, Function<IterationDecision(NonnullRefPtr<Value>)> callback) override;
|
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
|
virtual HitTestResult hit_test_position(size_t) const override;
|
|
virtual bool is_list() const override { return true; }
|
|
virtual RefPtr<Node> leftmost_trivial_literal() const override;
|
|
|
|
RefPtr<Node> 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<Value> run(RefPtr<Shell>) 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); }
|
|
|
|
Command const& command() const { return m_command; }
|
|
|
|
private:
|
|
NODE(CommandLiteral);
|
|
virtual void dump(int level) const override;
|
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override { VERIFY_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); }
|
|
|
|
String const& text() const { return m_text; }
|
|
|
|
private:
|
|
NODE(Comment);
|
|
virtual void dump(int level) const override;
|
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
|
|
|
String m_text;
|
|
};
|
|
|
|
class ContinuationControl final : public Node {
|
|
public:
|
|
enum ContinuationKind {
|
|
Break,
|
|
Continue,
|
|
};
|
|
ContinuationControl(Position position, ContinuationKind kind)
|
|
: Node(move(position))
|
|
, m_kind(kind)
|
|
{
|
|
}
|
|
virtual ~ContinuationControl() = default;
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
ContinuationKind continuation_kind() const { return m_kind; }
|
|
|
|
private:
|
|
NODE(ContinuationControl);
|
|
|
|
virtual void dump(int level) const override;
|
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
|
|
|
ContinuationKind m_kind { ContinuationKind::Break };
|
|
};
|
|
|
|
class DynamicEvaluate final : public Node {
|
|
public:
|
|
DynamicEvaluate(Position, NonnullRefPtr<Node>);
|
|
virtual ~DynamicEvaluate();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtr<Node> const& inner() const { return m_inner; }
|
|
|
|
private:
|
|
NODE(DynamicEvaluate);
|
|
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) const 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<Node> m_inner;
|
|
};
|
|
|
|
class DoubleQuotedString final : public Node {
|
|
public:
|
|
DoubleQuotedString(Position, RefPtr<Node>);
|
|
virtual ~DoubleQuotedString();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
RefPtr<Node> const& inner() const { return m_inner; }
|
|
|
|
private:
|
|
NODE(DoubleQuotedString);
|
|
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) const override;
|
|
|
|
RefPtr<Node> 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<Value> run(RefPtr<Shell>) 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:
|
|
FunctionDeclaration(Position, NameWithPosition name, Vector<NameWithPosition> argument_names, RefPtr<AST::Node> body);
|
|
virtual ~FunctionDeclaration();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NameWithPosition const& name() const { return m_name; }
|
|
Vector<NameWithPosition> const arguments() const { return m_arguments; }
|
|
RefPtr<Node> const& block() const { return m_block; }
|
|
|
|
private:
|
|
NODE(FunctionDeclaration);
|
|
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) const override;
|
|
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, HitTestResult const&) override;
|
|
virtual bool would_execute() const override { return true; }
|
|
virtual bool should_override_execution_in_current_process() const override { return true; }
|
|
|
|
NameWithPosition m_name;
|
|
Vector<NameWithPosition> m_arguments;
|
|
RefPtr<AST::Node> m_block;
|
|
};
|
|
|
|
class ForLoop final : public Node {
|
|
public:
|
|
ForLoop(Position, Optional<NameWithPosition> variable, Optional<NameWithPosition> index_variable, RefPtr<AST::Node> iterated_expr, RefPtr<AST::Node> block, Optional<Position> in_kw_position = {}, Optional<Position> index_kw_position = {});
|
|
virtual ~ForLoop();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
Optional<NameWithPosition> const& variable() const { return m_variable; }
|
|
Optional<NameWithPosition> const& index_variable() const { return m_index_variable; }
|
|
RefPtr<Node> const& iterated_expression() const { return m_iterated_expression; }
|
|
RefPtr<Node> const& block() const { return m_block; }
|
|
Optional<Position> const index_keyword_position() const { return m_index_kw_position; }
|
|
Optional<Position> const in_keyword_position() const { return m_in_kw_position; }
|
|
|
|
private:
|
|
NODE(ForLoop);
|
|
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) const override;
|
|
virtual bool would_execute() const override { return true; }
|
|
virtual bool should_override_execution_in_current_process() const override { return true; }
|
|
|
|
Optional<NameWithPosition> m_variable;
|
|
Optional<NameWithPosition> m_index_variable;
|
|
RefPtr<AST::Node> m_iterated_expression;
|
|
RefPtr<AST::Node> m_block;
|
|
Optional<Position> m_in_kw_position;
|
|
Optional<Position> m_index_kw_position;
|
|
};
|
|
|
|
class Glob final : public Node {
|
|
public:
|
|
Glob(Position, String);
|
|
virtual ~Glob();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
String const& text() const { return m_text; }
|
|
|
|
private:
|
|
NODE(Glob);
|
|
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 bool is_glob() const override { return true; }
|
|
virtual bool is_list() const override { return true; }
|
|
|
|
String m_text;
|
|
};
|
|
|
|
struct HistorySelector {
|
|
enum EventKind {
|
|
IndexFromStart,
|
|
IndexFromEnd,
|
|
StartingStringLookup,
|
|
ContainingStringLookup,
|
|
};
|
|
enum WordSelectorKind {
|
|
Index,
|
|
Last,
|
|
};
|
|
|
|
struct {
|
|
EventKind kind { IndexFromStart };
|
|
size_t index { 0 };
|
|
Position text_position;
|
|
String text;
|
|
} event;
|
|
|
|
struct WordSelector {
|
|
WordSelectorKind kind { Index };
|
|
size_t selector { 0 };
|
|
Position position;
|
|
RefPtr<AST::SyntaxError> syntax_error_node;
|
|
|
|
size_t resolve(size_t size) const
|
|
{
|
|
if (kind == Index)
|
|
return selector;
|
|
if (kind == Last)
|
|
return size - selector - 1;
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
};
|
|
struct {
|
|
WordSelector start;
|
|
Optional<WordSelector> end;
|
|
} word_selector_range;
|
|
};
|
|
|
|
class HistoryEvent final : public Node {
|
|
public:
|
|
HistoryEvent(Position, HistorySelector);
|
|
virtual ~HistoryEvent();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
HistorySelector const& selector() const { return m_selector; }
|
|
|
|
private:
|
|
NODE(HistoryEvent);
|
|
virtual void dump(int level) const override;
|
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
|
|
|
HistorySelector m_selector;
|
|
};
|
|
|
|
class Execute final : public Node {
|
|
public:
|
|
Execute(Position, NonnullRefPtr<Node>, bool capture_stdout = false);
|
|
virtual ~Execute();
|
|
void capture_stdout() { m_capture_stdout = true; }
|
|
NonnullRefPtr<Node>& command() { return m_command; }
|
|
virtual void for_each_entry(RefPtr<Shell> shell, Function<IterationDecision(NonnullRefPtr<Value>)> callback) override;
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtr<Node> const& 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<Value> run(RefPtr<Shell>) override;
|
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
|
virtual HitTestResult hit_test_position(size_t) const override;
|
|
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, HitTestResult const&) override;
|
|
virtual bool is_execute() const override { return true; }
|
|
virtual bool would_execute() const override { return true; }
|
|
|
|
NonnullRefPtr<Node> m_command;
|
|
bool m_capture_stdout { false };
|
|
};
|
|
|
|
class IfCond final : public Node {
|
|
public:
|
|
IfCond(Position, Optional<Position> else_position, NonnullRefPtr<AST::Node> cond_expr, RefPtr<AST::Node> true_branch, RefPtr<AST::Node> false_branch);
|
|
virtual ~IfCond();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtr<Node> const& condition() const { return m_condition; }
|
|
RefPtr<Node> const& true_branch() const { return m_true_branch; }
|
|
RefPtr<Node> const& false_branch() const { return m_false_branch; }
|
|
Optional<Position> const else_position() const { return m_else_position; }
|
|
|
|
private:
|
|
NODE(IfCond);
|
|
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) const override;
|
|
virtual bool should_override_execution_in_current_process() const override { return true; }
|
|
|
|
NonnullRefPtr<AST::Node> m_condition;
|
|
RefPtr<AST::Node> m_true_branch;
|
|
RefPtr<AST::Node> m_false_branch;
|
|
|
|
Optional<Position> m_else_position;
|
|
};
|
|
|
|
class ImmediateExpression final : public Node {
|
|
public:
|
|
ImmediateExpression(Position, NameWithPosition function, NonnullRefPtrVector<AST::Node> arguments, Optional<Position> closing_brace_position);
|
|
virtual ~ImmediateExpression();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtrVector<Node> const& arguments() const { return m_arguments; }
|
|
auto const& function() const { return m_function; }
|
|
String const& function_name() const { return m_function.name; }
|
|
Position const& function_position() const { return m_function.position; }
|
|
bool has_closing_brace() const { return m_closing_brace_position.has_value(); }
|
|
|
|
private:
|
|
NODE(ImmediateExpression);
|
|
virtual void dump(int level) const override;
|
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
|
Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, HitTestResult const&) override;
|
|
virtual HitTestResult hit_test_position(size_t) const override;
|
|
|
|
NonnullRefPtrVector<AST::Node> m_arguments;
|
|
NameWithPosition m_function;
|
|
Optional<Position> m_closing_brace_position;
|
|
};
|
|
|
|
class Join final : public Node {
|
|
public:
|
|
Join(Position, NonnullRefPtr<Node>, NonnullRefPtr<Node>);
|
|
virtual ~Join();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtr<Node> const& left() const { return m_left; }
|
|
NonnullRefPtr<Node> const& right() const { return m_right; }
|
|
|
|
private:
|
|
NODE(Join);
|
|
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) const override;
|
|
virtual bool is_command() const override { return true; }
|
|
virtual bool is_list() const override { return true; }
|
|
virtual RefPtr<Node> leftmost_trivial_literal() const override;
|
|
|
|
NonnullRefPtr<Node> m_left;
|
|
NonnullRefPtr<Node> m_right;
|
|
};
|
|
|
|
struct MatchEntry {
|
|
Variant<NonnullRefPtrVector<Node>, Vector<Regex<ECMA262>>> options;
|
|
Optional<Vector<String>> match_names;
|
|
Optional<Position> match_as_position;
|
|
Vector<Position> pipe_positions;
|
|
RefPtr<Node> body;
|
|
};
|
|
|
|
class MatchExpr final : public Node {
|
|
public:
|
|
MatchExpr(Position, NonnullRefPtr<Node> expr, String name, Optional<Position> as_position, Vector<MatchEntry> entries);
|
|
virtual ~MatchExpr();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtr<Node> const& matched_expr() const { return m_matched_expr; }
|
|
String const& expr_name() const { return m_expr_name; }
|
|
Vector<MatchEntry> const& entries() const { return m_entries; }
|
|
Optional<Position> const& as_position() const { return m_as_position; }
|
|
|
|
private:
|
|
NODE(MatchExpr);
|
|
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) const override;
|
|
virtual bool would_execute() const override { return true; }
|
|
virtual bool should_override_execution_in_current_process() const override { return true; }
|
|
|
|
NonnullRefPtr<Node> m_matched_expr;
|
|
String m_expr_name;
|
|
Optional<Position> m_as_position;
|
|
Vector<MatchEntry> m_entries;
|
|
};
|
|
|
|
class Or final : public Node {
|
|
public:
|
|
Or(Position, NonnullRefPtr<Node>, NonnullRefPtr<Node>, Position or_position);
|
|
virtual ~Or();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtr<Node> const& left() const { return m_left; }
|
|
NonnullRefPtr<Node> const& right() const { return m_right; }
|
|
Position const& or_position() const { return m_or_position; }
|
|
|
|
private:
|
|
NODE(Or);
|
|
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) const override;
|
|
|
|
NonnullRefPtr<Node> m_left;
|
|
NonnullRefPtr<Node> m_right;
|
|
Position m_or_position;
|
|
};
|
|
|
|
class Pipe final : public Node {
|
|
public:
|
|
Pipe(Position, NonnullRefPtr<Node>, NonnullRefPtr<Node>);
|
|
virtual ~Pipe();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtr<Node> const& left() const { return m_left; }
|
|
NonnullRefPtr<Node> const& right() const { return m_right; }
|
|
|
|
private:
|
|
NODE(Pipe);
|
|
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) const override;
|
|
virtual bool is_command() const override { return true; }
|
|
|
|
NonnullRefPtr<Node> m_left;
|
|
NonnullRefPtr<Node> m_right;
|
|
};
|
|
|
|
class Range final : public Node {
|
|
public:
|
|
Range(Position, NonnullRefPtr<Node>, NonnullRefPtr<Node>);
|
|
virtual ~Range();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtr<Node> const& start() const { return m_start; }
|
|
NonnullRefPtr<Node> const& end() const { return m_end; }
|
|
|
|
private:
|
|
NODE(Range);
|
|
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) const override;
|
|
|
|
NonnullRefPtr<Node> m_start;
|
|
NonnullRefPtr<Node> m_end;
|
|
};
|
|
|
|
class ReadRedirection final : public PathRedirectionNode {
|
|
public:
|
|
ReadRedirection(Position, int, NonnullRefPtr<Node>);
|
|
virtual ~ReadRedirection();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
private:
|
|
NODE(ReadRedirection);
|
|
virtual void dump(int level) const override;
|
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
|
};
|
|
|
|
class ReadWriteRedirection final : public PathRedirectionNode {
|
|
public:
|
|
ReadWriteRedirection(Position, int, NonnullRefPtr<Node>);
|
|
virtual ~ReadWriteRedirection();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
private:
|
|
NODE(ReadWriteRedirection);
|
|
virtual void dump(int level) const override;
|
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
|
};
|
|
|
|
class Sequence final : public Node {
|
|
public:
|
|
Sequence(Position, NonnullRefPtrVector<Node>, Vector<Position> separator_positions);
|
|
virtual ~Sequence();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtrVector<Node> const& entries() const { return m_entries; }
|
|
|
|
Vector<Position> const& separator_positions() const { return m_separator_positions; }
|
|
|
|
private:
|
|
NODE(Sequence);
|
|
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) const override;
|
|
virtual bool is_list() const override { return true; }
|
|
virtual bool should_override_execution_in_current_process() const override { return true; }
|
|
virtual RefPtr<Node> leftmost_trivial_literal() const override;
|
|
|
|
NonnullRefPtrVector<Node> m_entries;
|
|
Vector<Position> m_separator_positions;
|
|
};
|
|
|
|
class Subshell final : public Node {
|
|
public:
|
|
Subshell(Position, RefPtr<Node> block);
|
|
virtual ~Subshell();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
RefPtr<Node> const& block() const { return m_block; }
|
|
|
|
private:
|
|
NODE(Subshell);
|
|
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) const override;
|
|
virtual bool would_execute() const override { return false; }
|
|
virtual bool should_override_execution_in_current_process() const override { return true; }
|
|
|
|
RefPtr<AST::Node> m_block;
|
|
};
|
|
|
|
class Slice final : public Node {
|
|
public:
|
|
Slice(Position, NonnullRefPtr<AST::Node>);
|
|
virtual ~Slice() override;
|
|
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtr<AST::Node> selector() const { return m_selector; }
|
|
|
|
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 Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, HitTestResult const&) override;
|
|
virtual HitTestResult hit_test_position(size_t) const override;
|
|
|
|
protected:
|
|
NODE(Slice);
|
|
NonnullRefPtr<AST::Node> m_selector;
|
|
};
|
|
|
|
class VariableNode : public Node {
|
|
public:
|
|
VariableNode(Position position)
|
|
: Node(move(position))
|
|
{
|
|
}
|
|
|
|
void set_slice(NonnullRefPtr<Slice>&& slice)
|
|
{
|
|
VERIFY(!m_slice);
|
|
m_slice = move(slice);
|
|
if (m_slice->is_syntax_error())
|
|
set_is_syntax_error(m_slice->syntax_error_node());
|
|
}
|
|
|
|
Slice const* slice() const { return m_slice.ptr(); }
|
|
|
|
protected:
|
|
RefPtr<Slice> m_slice;
|
|
};
|
|
|
|
class SimpleVariable final : public VariableNode {
|
|
public:
|
|
SimpleVariable(Position, String);
|
|
virtual ~SimpleVariable();
|
|
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
String const& name() const { return m_name; }
|
|
|
|
private:
|
|
NODE(SimpleVariable);
|
|
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 Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, HitTestResult const&) override;
|
|
virtual HitTestResult hit_test_position(size_t) const override;
|
|
virtual bool is_simple_variable() const override { return true; }
|
|
|
|
String m_name;
|
|
};
|
|
|
|
class SpecialVariable final : public VariableNode {
|
|
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<Value> run(RefPtr<Shell>) override;
|
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
|
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, HitTestResult const&) override;
|
|
virtual HitTestResult hit_test_position(size_t) const override;
|
|
|
|
char m_name { 0 };
|
|
};
|
|
|
|
class Juxtaposition final : public Node {
|
|
public:
|
|
Juxtaposition(Position, NonnullRefPtr<Node>, NonnullRefPtr<Node>);
|
|
virtual ~Juxtaposition();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtr<Node> const& left() const { return m_left; }
|
|
NonnullRefPtr<Node> const& right() const { return m_right; }
|
|
|
|
private:
|
|
NODE(Juxtaposition);
|
|
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) const override;
|
|
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, HitTestResult const&) override;
|
|
|
|
NonnullRefPtr<Node> m_left;
|
|
NonnullRefPtr<Node> m_right;
|
|
};
|
|
|
|
class Heredoc final : public Node {
|
|
public:
|
|
Heredoc(Position, String end, bool allow_interpolation, bool deindent);
|
|
virtual ~Heredoc();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
String const& end() const { return m_end; }
|
|
bool allow_interpolation() const { return m_allows_interpolation; }
|
|
bool deindent() const { return m_deindent; }
|
|
RefPtr<AST::Node> const& contents() const { return m_contents; }
|
|
void set_contents(RefPtr<AST::Node> contents)
|
|
{
|
|
m_contents = move(contents);
|
|
if (m_contents->is_syntax_error())
|
|
set_is_syntax_error(m_contents->syntax_error_node());
|
|
else
|
|
clear_syntax_error();
|
|
}
|
|
|
|
private:
|
|
NODE(Heredoc);
|
|
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) const override;
|
|
virtual RefPtr<Node> leftmost_trivial_literal() const override { return this; };
|
|
|
|
String m_end;
|
|
bool m_allows_interpolation { false };
|
|
bool m_deindent { false };
|
|
RefPtr<AST::Node> m_contents;
|
|
};
|
|
|
|
class StringLiteral final : public Node {
|
|
public:
|
|
enum class EnclosureType {
|
|
None,
|
|
SingleQuotes,
|
|
DoubleQuotes,
|
|
};
|
|
|
|
StringLiteral(Position, String, EnclosureType);
|
|
virtual ~StringLiteral();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
String const& text() const { return m_text; }
|
|
EnclosureType enclosure_type() const { return m_enclosure_type; }
|
|
|
|
private:
|
|
NODE(StringLiteral);
|
|
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 RefPtr<Node> leftmost_trivial_literal() const override { return this; };
|
|
|
|
String m_text;
|
|
EnclosureType m_enclosure_type;
|
|
};
|
|
|
|
class StringPartCompose final : public Node {
|
|
public:
|
|
StringPartCompose(Position, NonnullRefPtr<Node>, NonnullRefPtr<Node>);
|
|
virtual ~StringPartCompose();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
NonnullRefPtr<Node> const& left() const { return m_left; }
|
|
NonnullRefPtr<Node> const& right() const { return m_right; }
|
|
|
|
private:
|
|
NODE(StringPartCompose);
|
|
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) const override;
|
|
|
|
NonnullRefPtr<Node> m_left;
|
|
NonnullRefPtr<Node> 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); }
|
|
|
|
String const& error_text() const { return m_syntax_error_text; }
|
|
bool is_continuable() const { return m_is_continuable; }
|
|
|
|
virtual void clear_syntax_error() override
|
|
{
|
|
m_is_cleared = true;
|
|
}
|
|
virtual void set_is_syntax_error(SyntaxError const& error) override
|
|
{
|
|
m_position = error.position();
|
|
m_is_cleared = error.m_is_cleared;
|
|
m_is_continuable = error.m_is_continuable;
|
|
m_syntax_error_text = error.error_text();
|
|
}
|
|
|
|
virtual bool is_syntax_error() const override { return !m_is_cleared; }
|
|
|
|
private:
|
|
NODE(SyntaxError);
|
|
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) const override { return { nullptr, nullptr, nullptr }; }
|
|
virtual SyntaxError const& syntax_error_node() const override;
|
|
|
|
String m_syntax_error_text;
|
|
bool m_is_continuable { false };
|
|
bool m_is_cleared { false };
|
|
};
|
|
|
|
class SyntheticNode final : public Node {
|
|
public:
|
|
SyntheticNode(Position, NonnullRefPtr<Value>);
|
|
virtual ~SyntheticNode() = default;
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
Value const& value() const { return m_value; }
|
|
|
|
private:
|
|
NODE(SyntheticValue);
|
|
virtual void dump(int level) const override;
|
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
|
|
|
NonnullRefPtr<Value> m_value;
|
|
};
|
|
|
|
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<Value> run(RefPtr<Shell>) override;
|
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
|
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, HitTestResult const&) override;
|
|
virtual HitTestResult hit_test_position(size_t) const override;
|
|
virtual bool is_tilde() const override { return true; }
|
|
|
|
String m_username;
|
|
};
|
|
|
|
class VariableDeclarations final : public Node {
|
|
public:
|
|
struct Variable {
|
|
NonnullRefPtr<Node> name;
|
|
NonnullRefPtr<Node> value;
|
|
};
|
|
VariableDeclarations(Position, Vector<Variable> variables);
|
|
virtual ~VariableDeclarations();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
Vector<Variable> const& variables() const { return m_variables; }
|
|
|
|
private:
|
|
NODE(VariableDeclarations);
|
|
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) const override;
|
|
virtual bool is_variable_decls() const override { return true; }
|
|
|
|
Vector<Variable> m_variables;
|
|
};
|
|
|
|
class WriteAppendRedirection final : public PathRedirectionNode {
|
|
public:
|
|
WriteAppendRedirection(Position, int, NonnullRefPtr<Node>);
|
|
virtual ~WriteAppendRedirection();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
private:
|
|
NODE(WriteAppendRedirection);
|
|
virtual void dump(int level) const override;
|
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
|
};
|
|
|
|
class WriteRedirection final : public PathRedirectionNode {
|
|
public:
|
|
WriteRedirection(Position, int, NonnullRefPtr<Node>);
|
|
virtual ~WriteRedirection();
|
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
|
|
|
private:
|
|
NODE(WriteRedirection);
|
|
virtual void dump(int level) const override;
|
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
|
};
|
|
|
|
}
|
|
|
|
namespace AK {
|
|
|
|
template<>
|
|
struct Formatter<Shell::AST::Command> : StandardFormatter {
|
|
Formatter() = default;
|
|
explicit Formatter(StandardFormatter formatter)
|
|
: StandardFormatter(formatter)
|
|
{
|
|
}
|
|
|
|
ErrorOr<void> format(FormatBuilder&, Shell::AST::Command const& value);
|
|
};
|
|
|
|
}
|