mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 04:58:13 +00:00
Shell: Track line numbers and the positions of some keywords
This commit is contained in:
parent
b91be8b9fd
commit
a10cfee0d4
4 changed files with 251 additions and 107 deletions
|
@ -121,7 +121,15 @@ Vector<Command> Node::to_lazy_evaluated_commands(RefPtr<Shell> shell)
|
||||||
|
|
||||||
void Node::dump(int level) const
|
void Node::dump(int level) const
|
||||||
{
|
{
|
||||||
print_indented(String::format("%s at %d:%d", class_name().characters(), m_position.start_offset, m_position.end_offset), level);
|
print_indented(String::format("%s at %d:%d (from %d.%d to %d.%d)",
|
||||||
|
class_name().characters(),
|
||||||
|
m_position.start_offset,
|
||||||
|
m_position.end_offset,
|
||||||
|
m_position.start_line.line_number,
|
||||||
|
m_position.start_line.line_column,
|
||||||
|
m_position.end_line.line_number,
|
||||||
|
m_position.end_line.line_column),
|
||||||
|
level);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node::Node(Position position)
|
Node::Node(Position position)
|
||||||
|
@ -226,10 +234,11 @@ HitTestResult And::hit_test_position(size_t offset)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
And::And(Position position, NonnullRefPtr<Node> left, NonnullRefPtr<Node> right)
|
And::And(Position position, NonnullRefPtr<Node> left, NonnullRefPtr<Node> right, Position and_position)
|
||||||
: Node(move(position))
|
: Node(move(position))
|
||||||
, m_left(move(left))
|
, m_left(move(left))
|
||||||
, m_right(move(right))
|
, m_right(move(right))
|
||||||
|
, m_and_position(and_position)
|
||||||
{
|
{
|
||||||
if (m_left->is_syntax_error())
|
if (m_left->is_syntax_error())
|
||||||
set_is_syntax_error(m_left->syntax_error_node());
|
set_is_syntax_error(m_left->syntax_error_node());
|
||||||
|
@ -913,7 +922,7 @@ void ForLoop::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightM
|
||||||
{
|
{
|
||||||
editor.stylize({ m_position.start_offset, m_position.start_offset + 3 }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
|
editor.stylize({ m_position.start_offset, m_position.start_offset + 3 }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
|
||||||
if (m_in_kw_position.has_value())
|
if (m_in_kw_position.has_value())
|
||||||
editor.stylize({ m_in_kw_position.value(), m_in_kw_position.value() + 2 }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
|
editor.stylize({ m_in_kw_position.value().start_offset, m_in_kw_position.value().end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Yellow) });
|
||||||
|
|
||||||
metadata.is_first_in_list = false;
|
metadata.is_first_in_list = false;
|
||||||
m_iterated_expression->highlight_in_editor(editor, shell, metadata);
|
m_iterated_expression->highlight_in_editor(editor, shell, metadata);
|
||||||
|
@ -937,7 +946,7 @@ HitTestResult ForLoop::hit_test_position(size_t offset)
|
||||||
return m_block->hit_test_position(offset);
|
return m_block->hit_test_position(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
ForLoop::ForLoop(Position position, String variable_name, NonnullRefPtr<AST::Node> iterated_expr, RefPtr<AST::Node> block, Optional<size_t> in_kw_position)
|
ForLoop::ForLoop(Position position, String variable_name, NonnullRefPtr<AST::Node> iterated_expr, RefPtr<AST::Node> block, Optional<Position> in_kw_position)
|
||||||
: Node(move(position))
|
: Node(move(position))
|
||||||
, m_variable_name(move(variable_name))
|
, m_variable_name(move(variable_name))
|
||||||
, m_iterated_expression(move(iterated_expr))
|
, m_iterated_expression(move(iterated_expr))
|
||||||
|
@ -1541,10 +1550,11 @@ HitTestResult Or::hit_test_position(size_t offset)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Or::Or(Position position, NonnullRefPtr<Node> left, NonnullRefPtr<Node> right)
|
Or::Or(Position position, NonnullRefPtr<Node> left, NonnullRefPtr<Node> right, Position or_position)
|
||||||
: Node(move(position))
|
: Node(move(position))
|
||||||
, m_left(move(left))
|
, m_left(move(left))
|
||||||
, m_right(move(right))
|
, m_right(move(right))
|
||||||
|
, m_or_position(or_position)
|
||||||
{
|
{
|
||||||
if (m_left->is_syntax_error())
|
if (m_left->is_syntax_error())
|
||||||
set_is_syntax_error(m_left->syntax_error_node());
|
set_is_syntax_error(m_left->syntax_error_node());
|
||||||
|
@ -1796,10 +1806,11 @@ HitTestResult Sequence::hit_test_position(size_t offset)
|
||||||
return m_right->hit_test_position(offset);
|
return m_right->hit_test_position(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequence::Sequence(Position position, NonnullRefPtr<Node> left, NonnullRefPtr<Node> right)
|
Sequence::Sequence(Position position, NonnullRefPtr<Node> left, NonnullRefPtr<Node> right, Position separator_position)
|
||||||
: Node(move(position))
|
: Node(move(position))
|
||||||
, m_left(move(left))
|
, m_left(move(left))
|
||||||
, m_right(move(right))
|
, m_right(move(right))
|
||||||
|
, m_separator_position(separator_position)
|
||||||
{
|
{
|
||||||
if (m_left->is_syntax_error())
|
if (m_left->is_syntax_error())
|
||||||
set_is_syntax_error(m_left->syntax_error_node());
|
set_is_syntax_error(m_left->syntax_error_node());
|
||||||
|
|
144
Shell/AST.h
144
Shell/AST.h
|
@ -47,6 +47,16 @@ struct HighlightMetadata {
|
||||||
struct Position {
|
struct Position {
|
||||||
size_t start_offset { 0 };
|
size_t start_offset { 0 };
|
||||||
size_t end_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; }
|
bool contains(size_t offset) const { return start_offset <= offset && offset <= end_offset; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -418,12 +428,57 @@ public:
|
||||||
virtual void visit(NodeVisitor&) { ASSERT_NOT_REACHED(); }
|
virtual void visit(NodeVisitor&) { ASSERT_NOT_REACHED(); }
|
||||||
virtual void visit(NodeVisitor& visitor) const { const_cast<Node*>(this)->visit(visitor); }
|
virtual void visit(NodeVisitor& visitor) const { const_cast<Node*>(this)->visit(visitor); }
|
||||||
|
|
||||||
|
enum class Kind : u32 {
|
||||||
|
And,
|
||||||
|
ListConcatenate,
|
||||||
|
Background,
|
||||||
|
BarewordLiteral,
|
||||||
|
CastToCommand,
|
||||||
|
CastToList,
|
||||||
|
CloseFdRedirection,
|
||||||
|
CommandLiteral,
|
||||||
|
Comment,
|
||||||
|
DynamicEvaluate,
|
||||||
|
DoubleQuotedString,
|
||||||
|
Fd2FdRedirection,
|
||||||
|
FunctionDeclaration,
|
||||||
|
ForLoop,
|
||||||
|
Glob,
|
||||||
|
Execute,
|
||||||
|
IfCond,
|
||||||
|
Join,
|
||||||
|
MatchExpr,
|
||||||
|
Or,
|
||||||
|
Pipe,
|
||||||
|
ReadRedirection,
|
||||||
|
ReadWriteRedirection,
|
||||||
|
Sequence,
|
||||||
|
Subshell,
|
||||||
|
SimpleVariable,
|
||||||
|
SpecialVariable,
|
||||||
|
Juxtaposition,
|
||||||
|
StringLiteral,
|
||||||
|
StringPartCompose,
|
||||||
|
SyntaxError,
|
||||||
|
Tilde,
|
||||||
|
VariableDeclarations,
|
||||||
|
WriteAppendRedirection,
|
||||||
|
WriteRedirection,
|
||||||
|
__Count,
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual Kind kind() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Position m_position;
|
Position m_position;
|
||||||
bool m_is_syntax_error { false };
|
bool m_is_syntax_error { false };
|
||||||
RefPtr<const SyntaxError> m_syntax_error_node;
|
RefPtr<const 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 {
|
class PathRedirectionNode : public Node {
|
||||||
public:
|
public:
|
||||||
PathRedirectionNode(Position, int, NonnullRefPtr<Node>);
|
PathRedirectionNode(Position, int, NonnullRefPtr<Node>);
|
||||||
|
@ -445,22 +500,24 @@ protected:
|
||||||
|
|
||||||
class And final : public Node {
|
class And final : public Node {
|
||||||
public:
|
public:
|
||||||
And(Position, NonnullRefPtr<Node>, NonnullRefPtr<Node>);
|
And(Position, NonnullRefPtr<Node>, NonnullRefPtr<Node>, Position and_position);
|
||||||
virtual ~And();
|
virtual ~And();
|
||||||
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
||||||
|
|
||||||
const NonnullRefPtr<Node>& left() const { return m_left; }
|
const NonnullRefPtr<Node>& left() const { return m_left; }
|
||||||
const NonnullRefPtr<Node>& right() const { return m_right; }
|
const NonnullRefPtr<Node>& right() const { return m_right; }
|
||||||
|
const Position& and_position() const { return m_and_position; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(And);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual String class_name() const override { return "And"; }
|
|
||||||
|
|
||||||
NonnullRefPtr<Node> m_left;
|
NonnullRefPtr<Node> m_left;
|
||||||
NonnullRefPtr<Node> m_right;
|
NonnullRefPtr<Node> m_right;
|
||||||
|
Position m_and_position;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ListConcatenate final : public Node {
|
class ListConcatenate final : public Node {
|
||||||
|
@ -471,11 +528,11 @@ public:
|
||||||
const Vector<NonnullRefPtr<Node>> list() const { return m_list; }
|
const Vector<NonnullRefPtr<Node>> list() const { return m_list; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(ListConcatenate);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) 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 bool is_list() const override { return true; }
|
||||||
virtual RefPtr<Node> leftmost_trivial_literal() const override;
|
virtual RefPtr<Node> leftmost_trivial_literal() const override;
|
||||||
|
|
||||||
|
@ -491,11 +548,11 @@ public:
|
||||||
const NonnullRefPtr<Node>& command() const { return m_command; }
|
const NonnullRefPtr<Node>& command() const { return m_command; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(Background);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual String class_name() const override { return "Background"; }
|
|
||||||
|
|
||||||
NonnullRefPtr<Node> m_command;
|
NonnullRefPtr<Node> m_command;
|
||||||
};
|
};
|
||||||
|
@ -509,10 +566,10 @@ public:
|
||||||
const String& text() const { return m_text; }
|
const String& text() const { return m_text; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(BarewordLiteral);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) 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 bool is_bareword() const override { return true; }
|
||||||
virtual RefPtr<Node> leftmost_trivial_literal() const override { return this; }
|
virtual RefPtr<Node> leftmost_trivial_literal() const override { return this; }
|
||||||
|
|
||||||
|
@ -528,12 +585,12 @@ public:
|
||||||
const NonnullRefPtr<Node>& inner() const { return m_inner; }
|
const NonnullRefPtr<Node>& inner() const { return m_inner; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(CastToCommand);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, const HitTestResult&) override;
|
virtual Vector<Line::CompletionSuggestion> 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_command() const override { return true; }
|
||||||
virtual bool is_list() const override { return true; }
|
virtual bool is_list() const override { return true; }
|
||||||
virtual RefPtr<Node> leftmost_trivial_literal() const override;
|
virtual RefPtr<Node> leftmost_trivial_literal() const override;
|
||||||
|
@ -550,11 +607,11 @@ public:
|
||||||
const RefPtr<Node>& inner() const { return m_inner; }
|
const RefPtr<Node>& inner() const { return m_inner; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(CastToList);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) 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 bool is_list() const override { return true; }
|
||||||
virtual RefPtr<Node> leftmost_trivial_literal() const override;
|
virtual RefPtr<Node> leftmost_trivial_literal() const override;
|
||||||
|
|
||||||
|
@ -570,10 +627,10 @@ public:
|
||||||
int fd() const { return m_fd; }
|
int fd() const { return m_fd; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(CloseFdRedirection);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) 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; }
|
virtual bool is_command() const override { return true; }
|
||||||
|
|
||||||
int m_fd { -1 };
|
int m_fd { -1 };
|
||||||
|
@ -588,10 +645,10 @@ public:
|
||||||
const Command& command() const { return m_command; }
|
const Command& command() const { return m_command; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(CommandLiteral);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override { ASSERT_NOT_REACHED(); }
|
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_command() const override { return true; }
|
||||||
virtual bool is_list() const override { return true; }
|
virtual bool is_list() const override { return true; }
|
||||||
|
|
||||||
|
@ -607,10 +664,10 @@ public:
|
||||||
const String& text() const { return m_text; }
|
const String& text() const { return m_text; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(Comment);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual String class_name() const override { return "Comment"; }
|
|
||||||
|
|
||||||
String m_text;
|
String m_text;
|
||||||
};
|
};
|
||||||
|
@ -624,11 +681,11 @@ public:
|
||||||
const NonnullRefPtr<Node>& inner() const { return m_inner; }
|
const NonnullRefPtr<Node>& inner() const { return m_inner; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(DynamicEvaluate);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) 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_bareword() const override { return m_inner->is_bareword(); }
|
||||||
virtual bool is_command() const override { return is_list(); }
|
virtual bool is_command() const override { return is_list(); }
|
||||||
|
@ -651,11 +708,11 @@ public:
|
||||||
const RefPtr<Node>& inner() const { return m_inner; }
|
const RefPtr<Node>& inner() const { return m_inner; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(DoubleQuotedString);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual String class_name() const override { return "DoubleQuotedString"; }
|
|
||||||
|
|
||||||
RefPtr<Node> m_inner;
|
RefPtr<Node> m_inner;
|
||||||
};
|
};
|
||||||
|
@ -670,10 +727,10 @@ public:
|
||||||
int dest_fd() const { return m_dest_fd; }
|
int dest_fd() const { return m_dest_fd; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(Fd2FdRedirection);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) 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; }
|
virtual bool is_command() const override { return true; }
|
||||||
|
|
||||||
int m_source_fd { -1 };
|
int m_source_fd { -1 };
|
||||||
|
@ -695,12 +752,12 @@ public:
|
||||||
const RefPtr<Node>& block() const { return m_block; }
|
const RefPtr<Node>& block() const { return m_block; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(FunctionDeclaration);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, const HitTestResult&) override;
|
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, const HitTestResult&) override;
|
||||||
virtual String class_name() const override { return "FunctionDeclaration"; }
|
|
||||||
virtual bool would_execute() const override { return true; }
|
virtual bool would_execute() const override { return true; }
|
||||||
|
|
||||||
NameWithPosition m_name;
|
NameWithPosition m_name;
|
||||||
|
@ -710,26 +767,27 @@ private:
|
||||||
|
|
||||||
class ForLoop final : public Node {
|
class ForLoop final : public Node {
|
||||||
public:
|
public:
|
||||||
ForLoop(Position, String variable_name, NonnullRefPtr<AST::Node> iterated_expr, RefPtr<AST::Node> block, Optional<size_t> in_kw_position = {});
|
ForLoop(Position, String variable_name, NonnullRefPtr<AST::Node> iterated_expr, RefPtr<AST::Node> block, Optional<Position> in_kw_position = {});
|
||||||
virtual ~ForLoop();
|
virtual ~ForLoop();
|
||||||
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
||||||
|
|
||||||
const String& variable_name() const { return m_variable_name; }
|
const String& variable_name() const { return m_variable_name; }
|
||||||
const NonnullRefPtr<Node>& iterated_expression() const { return m_iterated_expression; }
|
const NonnullRefPtr<Node>& iterated_expression() const { return m_iterated_expression; }
|
||||||
const RefPtr<Node>& block() const { return m_block; }
|
const RefPtr<Node>& block() const { return m_block; }
|
||||||
|
const Optional<Position> in_keyword_position() const { return m_in_kw_position; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(ForLoop);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual String class_name() const override { return "ForLoop"; }
|
|
||||||
virtual bool would_execute() const override { return true; }
|
virtual bool would_execute() const override { return true; }
|
||||||
|
|
||||||
String m_variable_name;
|
String m_variable_name;
|
||||||
NonnullRefPtr<AST::Node> m_iterated_expression;
|
NonnullRefPtr<AST::Node> m_iterated_expression;
|
||||||
RefPtr<AST::Node> m_block;
|
RefPtr<AST::Node> m_block;
|
||||||
Optional<size_t> m_in_kw_position;
|
Optional<Position> m_in_kw_position;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Glob final : public Node {
|
class Glob final : public Node {
|
||||||
|
@ -741,10 +799,10 @@ public:
|
||||||
const String& text() const { return m_text; }
|
const String& text() const { return m_text; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(Glob);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) 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_glob() const override { return true; }
|
||||||
virtual bool is_list() const override { return true; }
|
virtual bool is_list() const override { return true; }
|
||||||
|
|
||||||
|
@ -764,12 +822,12 @@ public:
|
||||||
bool does_capture_stdout() const { return m_capture_stdout; }
|
bool does_capture_stdout() const { return m_capture_stdout; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(Execute);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, const HitTestResult&) override;
|
virtual Vector<Line::CompletionSuggestion> 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 is_execute() const override { return true; }
|
||||||
virtual bool would_execute() const override { return true; }
|
virtual bool would_execute() const override { return true; }
|
||||||
|
|
||||||
|
@ -789,11 +847,11 @@ public:
|
||||||
const Optional<Position> else_position() const { return m_else_position; }
|
const Optional<Position> else_position() const { return m_else_position; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(IfCond);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual String class_name() const override { return "IfCond"; }
|
|
||||||
virtual bool would_execute() const override { return true; }
|
virtual bool would_execute() const override { return true; }
|
||||||
|
|
||||||
NonnullRefPtr<AST::Node> m_condition;
|
NonnullRefPtr<AST::Node> m_condition;
|
||||||
|
@ -813,11 +871,11 @@ public:
|
||||||
const NonnullRefPtr<Node>& right() const { return m_right; }
|
const NonnullRefPtr<Node>& right() const { return m_right; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(Join);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) 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_command() const override { return true; }
|
||||||
virtual bool is_list() const override { return true; }
|
virtual bool is_list() const override { return true; }
|
||||||
virtual RefPtr<Node> leftmost_trivial_literal() const override;
|
virtual RefPtr<Node> leftmost_trivial_literal() const override;
|
||||||
|
@ -841,13 +899,14 @@ public:
|
||||||
const NonnullRefPtr<Node>& matched_expr() const { return m_matched_expr; }
|
const NonnullRefPtr<Node>& matched_expr() const { return m_matched_expr; }
|
||||||
const String& expr_name() const { return m_expr_name; }
|
const String& expr_name() const { return m_expr_name; }
|
||||||
const Vector<MatchEntry>& entries() const { return m_entries; }
|
const Vector<MatchEntry>& entries() const { return m_entries; }
|
||||||
|
const Optional<Position>& as_position() const { return m_as_position; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(MatchExpr);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual String class_name() const override { return "MatchExpr"; }
|
|
||||||
virtual bool would_execute() const override { return true; }
|
virtual bool would_execute() const override { return true; }
|
||||||
|
|
||||||
NonnullRefPtr<Node> m_matched_expr;
|
NonnullRefPtr<Node> m_matched_expr;
|
||||||
|
@ -858,22 +917,24 @@ private:
|
||||||
|
|
||||||
class Or final : public Node {
|
class Or final : public Node {
|
||||||
public:
|
public:
|
||||||
Or(Position, NonnullRefPtr<Node>, NonnullRefPtr<Node>);
|
Or(Position, NonnullRefPtr<Node>, NonnullRefPtr<Node>, Position or_position);
|
||||||
virtual ~Or();
|
virtual ~Or();
|
||||||
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
||||||
|
|
||||||
const NonnullRefPtr<Node>& left() const { return m_left; }
|
const NonnullRefPtr<Node>& left() const { return m_left; }
|
||||||
const NonnullRefPtr<Node>& right() const { return m_right; }
|
const NonnullRefPtr<Node>& right() const { return m_right; }
|
||||||
|
const Position& or_position() const { return m_or_position; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(Or);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual String class_name() const override { return "Or"; }
|
|
||||||
|
|
||||||
NonnullRefPtr<Node> m_left;
|
NonnullRefPtr<Node> m_left;
|
||||||
NonnullRefPtr<Node> m_right;
|
NonnullRefPtr<Node> m_right;
|
||||||
|
Position m_or_position;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Pipe final : public Node {
|
class Pipe final : public Node {
|
||||||
|
@ -886,11 +947,11 @@ public:
|
||||||
const NonnullRefPtr<Node>& right() const { return m_right; }
|
const NonnullRefPtr<Node>& right() const { return m_right; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(Pipe);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual String class_name() const override { return "Pipe"; }
|
|
||||||
virtual bool is_command() const override { return true; }
|
virtual bool is_command() const override { return true; }
|
||||||
|
|
||||||
NonnullRefPtr<Node> m_left;
|
NonnullRefPtr<Node> m_left;
|
||||||
|
@ -904,9 +965,9 @@ public:
|
||||||
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(ReadRedirection);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual String class_name() const override { return "ReadRedirection"; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ReadWriteRedirection final : public PathRedirectionNode {
|
class ReadWriteRedirection final : public PathRedirectionNode {
|
||||||
|
@ -916,31 +977,34 @@ public:
|
||||||
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(ReadWriteRedirection);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual String class_name() const override { return "ReadWriteRedirection"; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Sequence final : public Node {
|
class Sequence final : public Node {
|
||||||
public:
|
public:
|
||||||
Sequence(Position, NonnullRefPtr<Node>, NonnullRefPtr<Node>);
|
Sequence(Position, NonnullRefPtr<Node>, NonnullRefPtr<Node>, Position separator_position);
|
||||||
virtual ~Sequence();
|
virtual ~Sequence();
|
||||||
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
||||||
|
|
||||||
const NonnullRefPtr<Node>& left() const { return m_left; }
|
const NonnullRefPtr<Node>& left() const { return m_left; }
|
||||||
const NonnullRefPtr<Node>& right() const { return m_right; }
|
const NonnullRefPtr<Node>& right() const { return m_right; }
|
||||||
|
|
||||||
|
const Position& separator_position() const { return m_separator_position; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(Sequence);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) 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 is_list() const override { return true; }
|
||||||
virtual bool would_execute() const override { return m_left->would_execute() || m_right->would_execute(); }
|
virtual bool would_execute() const override { return m_left->would_execute() || m_right->would_execute(); }
|
||||||
|
|
||||||
NonnullRefPtr<Node> m_left;
|
NonnullRefPtr<Node> m_left;
|
||||||
NonnullRefPtr<Node> m_right;
|
NonnullRefPtr<Node> m_right;
|
||||||
|
Position m_separator_position;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Subshell final : public Node {
|
class Subshell final : public Node {
|
||||||
|
@ -952,11 +1016,11 @@ public:
|
||||||
const RefPtr<Node>& block() const { return m_block; }
|
const RefPtr<Node>& block() const { return m_block; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(Subshell);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual String class_name() const override { return "Subshell"; }
|
|
||||||
virtual bool would_execute() const override { return true; }
|
virtual bool would_execute() const override { return true; }
|
||||||
|
|
||||||
RefPtr<AST::Node> m_block;
|
RefPtr<AST::Node> m_block;
|
||||||
|
@ -971,12 +1035,12 @@ public:
|
||||||
const String& name() const { return m_name; }
|
const String& name() const { return m_name; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(SimpleVariable);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, const HitTestResult&) override;
|
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, const HitTestResult&) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual String class_name() const override { return "SimpleVariable"; }
|
|
||||||
virtual bool is_simple_variable() const override { return true; }
|
virtual bool is_simple_variable() const override { return true; }
|
||||||
|
|
||||||
String m_name;
|
String m_name;
|
||||||
|
@ -991,12 +1055,12 @@ public:
|
||||||
char name() const { return m_name; }
|
char name() const { return m_name; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(SpecialVariable);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, const HitTestResult&) override;
|
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, const HitTestResult&) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual String class_name() const override { return "SpecialVariable"; }
|
|
||||||
|
|
||||||
char m_name { -1 };
|
char m_name { -1 };
|
||||||
};
|
};
|
||||||
|
@ -1011,12 +1075,12 @@ public:
|
||||||
const NonnullRefPtr<Node>& right() const { return m_right; }
|
const NonnullRefPtr<Node>& right() const { return m_right; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(Juxtaposition);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, const HitTestResult&) override;
|
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, const HitTestResult&) override;
|
||||||
virtual String class_name() const override { return "Juxtaposition"; }
|
|
||||||
|
|
||||||
NonnullRefPtr<Node> m_left;
|
NonnullRefPtr<Node> m_left;
|
||||||
NonnullRefPtr<Node> m_right;
|
NonnullRefPtr<Node> m_right;
|
||||||
|
@ -1031,10 +1095,10 @@ public:
|
||||||
const String& text() const { return m_text; }
|
const String& text() const { return m_text; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(StringLiteral);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual String class_name() const override { return "StringLiteral"; }
|
|
||||||
virtual RefPtr<Node> leftmost_trivial_literal() const override { return this; };
|
virtual RefPtr<Node> leftmost_trivial_literal() const override { return this; };
|
||||||
|
|
||||||
String m_text;
|
String m_text;
|
||||||
|
@ -1050,11 +1114,11 @@ public:
|
||||||
const NonnullRefPtr<Node>& right() const { return m_right; }
|
const NonnullRefPtr<Node>& right() const { return m_right; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(StringPartCompose);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override;
|
virtual HitTestResult hit_test_position(size_t) override;
|
||||||
virtual String class_name() const override { return "StringPartCompose"; }
|
|
||||||
|
|
||||||
NonnullRefPtr<Node> m_left;
|
NonnullRefPtr<Node> m_left;
|
||||||
NonnullRefPtr<Node> m_right;
|
NonnullRefPtr<Node> m_right;
|
||||||
|
@ -1069,11 +1133,11 @@ public:
|
||||||
const String& error_text() const { return m_syntax_error_text; }
|
const String& error_text() const { return m_syntax_error_text; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(SyntaxError);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) override { return { nullptr, nullptr, nullptr }; }
|
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 bool is_syntax_error() const override { return true; }
|
||||||
virtual const SyntaxError& syntax_error_node() const override;
|
virtual const SyntaxError& syntax_error_node() const override;
|
||||||
|
|
||||||
|
@ -1089,12 +1153,12 @@ public:
|
||||||
String text() const;
|
String text() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(Tilde);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, const HitTestResult&) override;
|
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, const HitTestResult&) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) 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; }
|
virtual bool is_tilde() const override { return true; }
|
||||||
|
|
||||||
String m_username;
|
String m_username;
|
||||||
|
@ -1113,11 +1177,11 @@ public:
|
||||||
const Vector<Variable>& variables() const { return m_variables; }
|
const Vector<Variable>& variables() const { return m_variables; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(VariableDeclarations);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
|
||||||
virtual HitTestResult hit_test_position(size_t) 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; }
|
virtual bool is_variable_decls() const override { return true; }
|
||||||
|
|
||||||
Vector<Variable> m_variables;
|
Vector<Variable> m_variables;
|
||||||
|
@ -1130,9 +1194,9 @@ public:
|
||||||
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(WriteAppendRedirection);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual String class_name() const override { return "WriteAppendRedirection"; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class WriteRedirection final : public PathRedirectionNode {
|
class WriteRedirection final : public PathRedirectionNode {
|
||||||
|
@ -1142,9 +1206,9 @@ public:
|
||||||
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NODE(WriteRedirection);
|
||||||
virtual void dump(int level) const override;
|
virtual void dump(int level) const override;
|
||||||
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
virtual RefPtr<Value> run(RefPtr<Shell>) override;
|
||||||
virtual String class_name() const override { return "WriteRedirection"; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
160
Shell/Parser.cpp
160
Shell/Parser.cpp
|
@ -29,6 +29,11 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
Parser::SavedOffset Parser::save_offset() const
|
||||||
|
{
|
||||||
|
return { m_offset, m_line };
|
||||||
|
}
|
||||||
|
|
||||||
char Parser::peek()
|
char Parser::peek()
|
||||||
{
|
{
|
||||||
if (m_offset == m_input.length())
|
if (m_offset == m_input.length())
|
||||||
|
@ -39,6 +44,8 @@ char Parser::peek()
|
||||||
auto ch = m_input[m_offset];
|
auto ch = m_input[m_offset];
|
||||||
if (ch == '\\' && m_input.length() > m_offset + 1 && m_input[m_offset + 1] == '\n') {
|
if (ch == '\\' && m_input.length() > m_offset + 1 && m_input[m_offset + 1] == '\n') {
|
||||||
m_offset += 2;
|
m_offset += 2;
|
||||||
|
++m_line.line_number;
|
||||||
|
m_line.line_column = 0;
|
||||||
return peek();
|
return peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,13 +57,14 @@ char Parser::consume()
|
||||||
auto ch = peek();
|
auto ch = peek();
|
||||||
++m_offset;
|
++m_offset;
|
||||||
|
|
||||||
return ch;
|
if (ch == '\n') {
|
||||||
}
|
++m_line.line_number;
|
||||||
|
m_line.line_column = 0;
|
||||||
|
} else {
|
||||||
|
++m_line.line_column;
|
||||||
|
}
|
||||||
|
|
||||||
void Parser::putback()
|
return ch;
|
||||||
{
|
|
||||||
ASSERT(m_offset > 0);
|
|
||||||
--m_offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Parser::expect(char ch)
|
bool Parser::expect(char ch)
|
||||||
|
@ -67,13 +75,14 @@ bool Parser::expect(char ch)
|
||||||
bool Parser::expect(const StringView& expected)
|
bool Parser::expect(const StringView& expected)
|
||||||
{
|
{
|
||||||
auto offset_at_start = m_offset;
|
auto offset_at_start = m_offset;
|
||||||
|
auto line_at_start = line();
|
||||||
|
|
||||||
if (expected.length() + m_offset > m_input.length())
|
if (expected.length() + m_offset > m_input.length())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (size_t i = 0; i < expected.length(); ++i) {
|
for (size_t i = 0; i < expected.length(); ++i) {
|
||||||
if (peek() != expected[i]) {
|
if (peek() != expected[i]) {
|
||||||
m_offset = offset_at_start;
|
restore_to(offset_at_start, line_at_start);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,12 +95,12 @@ bool Parser::expect(const StringView& expected)
|
||||||
template<typename A, typename... Args>
|
template<typename A, typename... Args>
|
||||||
NonnullRefPtr<A> Parser::create(Args... args)
|
NonnullRefPtr<A> Parser::create(Args... args)
|
||||||
{
|
{
|
||||||
return adopt(*new A(AST::Position { m_rule_start_offsets.last(), m_offset }, args...));
|
return adopt(*new A(AST::Position { m_rule_start_offsets.last(), m_offset, m_rule_start_lines.last(), line() }, args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] OwnPtr<Parser::ScopedOffset> Parser::push_start()
|
[[nodiscard]] OwnPtr<Parser::ScopedOffset> Parser::push_start()
|
||||||
{
|
{
|
||||||
return make<ScopedOffset>(m_rule_start_offsets, m_offset);
|
return make<ScopedOffset>(m_rule_start_offsets, m_rule_start_lines, m_offset, m_line.line_number, m_line.line_column);
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr bool is_whitespace(char c)
|
static constexpr bool is_whitespace(char c)
|
||||||
|
@ -128,13 +137,14 @@ static inline char to_byte(char a, char b)
|
||||||
RefPtr<AST::Node> Parser::parse()
|
RefPtr<AST::Node> Parser::parse()
|
||||||
{
|
{
|
||||||
m_offset = 0;
|
m_offset = 0;
|
||||||
|
m_line = { 0, 0 };
|
||||||
|
|
||||||
auto toplevel = parse_toplevel();
|
auto toplevel = parse_toplevel();
|
||||||
|
|
||||||
if (m_offset < m_input.length()) {
|
if (m_offset < m_input.length()) {
|
||||||
// Parsing stopped midway, this is a syntax error.
|
// Parsing stopped midway, this is a syntax error.
|
||||||
auto error_start = push_start();
|
auto error_start = push_start();
|
||||||
m_offset = m_input.length();
|
consume_while([](auto) { return true; });
|
||||||
auto syntax_error_node = create<AST::SyntaxError>("Unexpected tokens past the end");
|
auto syntax_error_node = create<AST::SyntaxError>("Unexpected tokens past the end");
|
||||||
if (!toplevel)
|
if (!toplevel)
|
||||||
toplevel = move(syntax_error_node);
|
toplevel = move(syntax_error_node);
|
||||||
|
@ -162,6 +172,8 @@ RefPtr<AST::Node> Parser::parse_sequence()
|
||||||
auto rule_start = push_start();
|
auto rule_start = push_start();
|
||||||
auto var_decls = parse_variable_decls();
|
auto var_decls = parse_variable_decls();
|
||||||
|
|
||||||
|
auto pos_before_seps = save_offset();
|
||||||
|
|
||||||
switch (peek()) {
|
switch (peek()) {
|
||||||
case '}':
|
case '}':
|
||||||
return var_decls;
|
return var_decls;
|
||||||
|
@ -171,9 +183,15 @@ RefPtr<AST::Node> Parser::parse_sequence()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
consume_while(is_any_of("\n;"));
|
consume_while(is_any_of("\n;"));
|
||||||
|
|
||||||
|
auto pos_after_seps = save_offset();
|
||||||
|
|
||||||
auto rest = parse_sequence();
|
auto rest = parse_sequence();
|
||||||
if (rest)
|
if (rest)
|
||||||
return create<AST::Sequence>(var_decls.release_nonnull(), rest.release_nonnull());
|
return create<AST::Sequence>(
|
||||||
|
var_decls.release_nonnull(),
|
||||||
|
rest.release_nonnull(),
|
||||||
|
AST::Position { pos_before_seps.offset, pos_after_seps.offset, pos_before_seps.line, pos_after_seps.line });
|
||||||
return var_decls;
|
return var_decls;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -189,24 +207,38 @@ RefPtr<AST::Node> Parser::parse_sequence()
|
||||||
return var_decls;
|
return var_decls;
|
||||||
|
|
||||||
if (var_decls)
|
if (var_decls)
|
||||||
first = create<AST::Sequence>(var_decls.release_nonnull(), first.release_nonnull());
|
first = create<AST::Sequence>(
|
||||||
|
var_decls.release_nonnull(),
|
||||||
|
first.release_nonnull(),
|
||||||
|
AST::Position { pos_before_seps.offset, pos_before_seps.offset, pos_before_seps.line, pos_before_seps.line });
|
||||||
|
|
||||||
consume_while(is_whitespace);
|
consume_while(is_whitespace);
|
||||||
|
|
||||||
|
pos_before_seps = save_offset();
|
||||||
switch (peek()) {
|
switch (peek()) {
|
||||||
case ';':
|
case ';':
|
||||||
case '\n':
|
case '\n': {
|
||||||
consume_while(is_any_of("\n;"));
|
consume_while(is_any_of("\n;"));
|
||||||
|
auto pos_after_seps = save_offset();
|
||||||
|
|
||||||
if (auto expr = parse_sequence()) {
|
if (auto expr = parse_sequence()) {
|
||||||
return create<AST::Sequence>(first.release_nonnull(), expr.release_nonnull()); // Sequence
|
return create<AST::Sequence>(
|
||||||
|
first.release_nonnull(),
|
||||||
|
expr.release_nonnull(),
|
||||||
|
AST::Position { pos_before_seps.offset, pos_after_seps.offset, pos_before_seps.line, pos_after_seps.line }); // Sequence
|
||||||
}
|
}
|
||||||
return first;
|
return first;
|
||||||
|
}
|
||||||
case '&': {
|
case '&': {
|
||||||
auto execute_pipe_seq = first->would_execute() ? first.release_nonnull() : static_cast<NonnullRefPtr<AST::Node>>(create<AST::Execute>(first.release_nonnull()));
|
auto execute_pipe_seq = first->would_execute() ? first.release_nonnull() : static_cast<NonnullRefPtr<AST::Node>>(create<AST::Execute>(first.release_nonnull()));
|
||||||
consume();
|
consume();
|
||||||
|
auto pos_after_seps = save_offset();
|
||||||
auto bg = create<AST::Background>(execute_pipe_seq); // Execute Background
|
auto bg = create<AST::Background>(execute_pipe_seq); // Execute Background
|
||||||
if (auto rest = parse_sequence())
|
if (auto rest = parse_sequence())
|
||||||
return create<AST::Sequence>(move(bg), rest.release_nonnull()); // Sequence Background Sequence
|
return create<AST::Sequence>(
|
||||||
|
move(bg),
|
||||||
|
rest.release_nonnull(),
|
||||||
|
AST::Position { pos_before_seps.offset, pos_after_seps.offset, pos_before_seps.line, pos_before_seps.line }); // Sequence Background Sequence
|
||||||
|
|
||||||
return bg;
|
return bg;
|
||||||
}
|
}
|
||||||
|
@ -221,13 +253,13 @@ RefPtr<AST::Node> Parser::parse_variable_decls()
|
||||||
|
|
||||||
consume_while(is_whitespace);
|
consume_while(is_whitespace);
|
||||||
|
|
||||||
auto offset_before_name = m_offset;
|
auto pos_before_name = save_offset();
|
||||||
auto var_name = consume_while(is_word_character);
|
auto var_name = consume_while(is_word_character);
|
||||||
if (var_name.is_empty())
|
if (var_name.is_empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (!expect('=')) {
|
if (!expect('=')) {
|
||||||
m_offset = offset_before_name;
|
restore_to(pos_before_name.offset, pos_before_name.line);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,12 +268,12 @@ RefPtr<AST::Node> Parser::parse_variable_decls()
|
||||||
auto start = push_start();
|
auto start = push_start();
|
||||||
auto expression = parse_expression();
|
auto expression = parse_expression();
|
||||||
if (!expression || expression->is_syntax_error()) {
|
if (!expression || expression->is_syntax_error()) {
|
||||||
m_offset = start->offset;
|
restore_to(*start);
|
||||||
if (peek() == '(') {
|
if (peek() == '(') {
|
||||||
consume();
|
consume();
|
||||||
auto command = parse_pipe_sequence();
|
auto command = parse_pipe_sequence();
|
||||||
if (!command)
|
if (!command)
|
||||||
m_offset = start->offset;
|
restore_to(*start);
|
||||||
else if (!expect(')'))
|
else if (!expect(')'))
|
||||||
command->set_is_syntax_error(*create<AST::SyntaxError>("Expected a terminating close paren"));
|
command->set_is_syntax_error(*create<AST::SyntaxError>("Expected a terminating close paren"));
|
||||||
expression = command;
|
expression = command;
|
||||||
|
@ -252,7 +284,7 @@ RefPtr<AST::Node> Parser::parse_variable_decls()
|
||||||
auto string_start = push_start();
|
auto string_start = push_start();
|
||||||
expression = create<AST::StringLiteral>("");
|
expression = create<AST::StringLiteral>("");
|
||||||
} else {
|
} else {
|
||||||
m_offset = offset_before_name;
|
restore_to(pos_before_name.offset, pos_before_name.line);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,14 +312,14 @@ RefPtr<AST::Node> Parser::parse_function_decl()
|
||||||
auto rule_start = push_start();
|
auto rule_start = push_start();
|
||||||
|
|
||||||
auto restore = [&] {
|
auto restore = [&] {
|
||||||
m_offset = rule_start->offset;
|
restore_to(*rule_start);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
consume_while(is_whitespace);
|
consume_while(is_whitespace);
|
||||||
auto offset_before_name = m_offset;
|
auto pos_before_name = save_offset();
|
||||||
auto function_name = consume_while(is_word_character);
|
auto function_name = consume_while(is_word_character);
|
||||||
auto offset_after_name = m_offset;
|
auto pos_after_name = save_offset();
|
||||||
if (function_name.is_empty())
|
if (function_name.is_empty())
|
||||||
return restore();
|
return restore();
|
||||||
|
|
||||||
|
@ -302,12 +334,13 @@ RefPtr<AST::Node> Parser::parse_function_decl()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
auto name_offset = m_offset;
|
auto name_offset = m_offset;
|
||||||
|
auto start_line = line();
|
||||||
auto arg_name = consume_while(is_word_character);
|
auto arg_name = consume_while(is_word_character);
|
||||||
if (arg_name.is_empty()) {
|
if (arg_name.is_empty()) {
|
||||||
// FIXME: Should this be a syntax error, or just return?
|
// FIXME: Should this be a syntax error, or just return?
|
||||||
return restore();
|
return restore();
|
||||||
}
|
}
|
||||||
arguments.append({ arg_name, { name_offset, m_offset } });
|
arguments.append({ arg_name, { name_offset, m_offset, start_line, line() } });
|
||||||
}
|
}
|
||||||
|
|
||||||
consume_while(is_whitespace);
|
consume_while(is_whitespace);
|
||||||
|
@ -322,7 +355,7 @@ RefPtr<AST::Node> Parser::parse_function_decl()
|
||||||
return create<AST::FunctionDeclaration>(
|
return create<AST::FunctionDeclaration>(
|
||||||
AST::FunctionDeclaration::NameWithPosition {
|
AST::FunctionDeclaration::NameWithPosition {
|
||||||
move(function_name),
|
move(function_name),
|
||||||
{ offset_before_name, offset_after_name } },
|
{ pos_before_name.offset, pos_after_name.offset, pos_before_name.line, pos_after_name.line } },
|
||||||
move(arguments),
|
move(arguments),
|
||||||
move(syntax_error));
|
move(syntax_error));
|
||||||
}
|
}
|
||||||
|
@ -345,7 +378,7 @@ RefPtr<AST::Node> Parser::parse_function_decl()
|
||||||
return create<AST::FunctionDeclaration>(
|
return create<AST::FunctionDeclaration>(
|
||||||
AST::FunctionDeclaration::NameWithPosition {
|
AST::FunctionDeclaration::NameWithPosition {
|
||||||
move(function_name),
|
move(function_name),
|
||||||
{ offset_before_name, offset_after_name } },
|
{ pos_before_name.offset, pos_after_name.offset, pos_before_name.line, pos_after_name.line } },
|
||||||
move(arguments),
|
move(arguments),
|
||||||
move(body));
|
move(body));
|
||||||
}
|
}
|
||||||
|
@ -354,7 +387,7 @@ RefPtr<AST::Node> Parser::parse_function_decl()
|
||||||
return create<AST::FunctionDeclaration>(
|
return create<AST::FunctionDeclaration>(
|
||||||
AST::FunctionDeclaration::NameWithPosition {
|
AST::FunctionDeclaration::NameWithPosition {
|
||||||
move(function_name),
|
move(function_name),
|
||||||
{ offset_before_name, offset_after_name } },
|
{ pos_before_name.offset, pos_after_name.offset, pos_before_name.line, pos_after_name.line } },
|
||||||
move(arguments),
|
move(arguments),
|
||||||
move(body));
|
move(body));
|
||||||
}
|
}
|
||||||
|
@ -368,17 +401,19 @@ RefPtr<AST::Node> Parser::parse_or_logical_sequence()
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
consume_while(is_whitespace);
|
consume_while(is_whitespace);
|
||||||
auto saved_offset = m_offset;
|
auto pos_before_or = save_offset();
|
||||||
if (!expect("||")) {
|
if (!expect("||"))
|
||||||
m_offset = saved_offset;
|
|
||||||
return and_sequence;
|
return and_sequence;
|
||||||
}
|
auto pos_after_or = save_offset();
|
||||||
|
|
||||||
auto right_and_sequence = parse_and_logical_sequence();
|
auto right_and_sequence = parse_and_logical_sequence();
|
||||||
if (!right_and_sequence)
|
if (!right_and_sequence)
|
||||||
right_and_sequence = create<AST::SyntaxError>("Expected an expression after '||'");
|
right_and_sequence = create<AST::SyntaxError>("Expected an expression after '||'");
|
||||||
|
|
||||||
return create<AST::Or>(and_sequence.release_nonnull(), right_and_sequence.release_nonnull());
|
return create<AST::Or>(
|
||||||
|
and_sequence.release_nonnull(),
|
||||||
|
right_and_sequence.release_nonnull(),
|
||||||
|
AST::Position { pos_before_or.offset, pos_after_or.offset, pos_before_or.line, pos_after_or.line });
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<AST::Node> Parser::parse_and_logical_sequence()
|
RefPtr<AST::Node> Parser::parse_and_logical_sequence()
|
||||||
|
@ -390,17 +425,19 @@ RefPtr<AST::Node> Parser::parse_and_logical_sequence()
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
consume_while(is_whitespace);
|
consume_while(is_whitespace);
|
||||||
auto saved_offset = m_offset;
|
auto pos_before_and = save_offset();
|
||||||
if (!expect("&&")) {
|
if (!expect("&&"))
|
||||||
m_offset = saved_offset;
|
|
||||||
return pipe_sequence;
|
return pipe_sequence;
|
||||||
}
|
auto pos_after_end = save_offset();
|
||||||
|
|
||||||
auto right_and_sequence = parse_and_logical_sequence();
|
auto right_and_sequence = parse_and_logical_sequence();
|
||||||
if (!right_and_sequence)
|
if (!right_and_sequence)
|
||||||
right_and_sequence = create<AST::SyntaxError>("Expected an expression after '&&'");
|
right_and_sequence = create<AST::SyntaxError>("Expected an expression after '&&'");
|
||||||
|
|
||||||
return create<AST::And>(pipe_sequence.release_nonnull(), right_and_sequence.release_nonnull());
|
return create<AST::And>(
|
||||||
|
pipe_sequence.release_nonnull(),
|
||||||
|
right_and_sequence.release_nonnull(),
|
||||||
|
AST::Position { pos_before_and.offset, pos_after_end.offset, pos_before_and.line, pos_after_end.line });
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<AST::Node> Parser::parse_pipe_sequence()
|
RefPtr<AST::Node> Parser::parse_pipe_sequence()
|
||||||
|
@ -419,13 +456,14 @@ RefPtr<AST::Node> Parser::parse_pipe_sequence()
|
||||||
if (peek() != '|')
|
if (peek() != '|')
|
||||||
return left;
|
return left;
|
||||||
|
|
||||||
|
auto before_pipe = save_offset();
|
||||||
consume();
|
consume();
|
||||||
|
|
||||||
if (auto pipe_seq = parse_pipe_sequence()) {
|
if (auto pipe_seq = parse_pipe_sequence()) {
|
||||||
return create<AST::Pipe>(left.release_nonnull(), pipe_seq.release_nonnull()); // Pipe
|
return create<AST::Pipe>(left.release_nonnull(), pipe_seq.release_nonnull()); // Pipe
|
||||||
}
|
}
|
||||||
|
|
||||||
putback();
|
restore_to(before_pipe.offset, before_pipe.line);
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,28 +516,26 @@ RefPtr<AST::Node> Parser::parse_control_structure()
|
||||||
RefPtr<AST::Node> Parser::parse_for_loop()
|
RefPtr<AST::Node> Parser::parse_for_loop()
|
||||||
{
|
{
|
||||||
auto rule_start = push_start();
|
auto rule_start = push_start();
|
||||||
if (!expect("for")) {
|
if (!expect("for"))
|
||||||
m_offset = rule_start->offset;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
if (consume_while(is_any_of(" \t\n")).is_empty()) {
|
if (consume_while(is_any_of(" \t\n")).is_empty()) {
|
||||||
m_offset = rule_start->offset;
|
restore_to(*rule_start);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto variable_name = consume_while(is_word_character);
|
auto variable_name = consume_while(is_word_character);
|
||||||
Optional<size_t> in_start_position;
|
Optional<AST::Position> in_start_position;
|
||||||
if (variable_name.is_empty()) {
|
if (variable_name.is_empty()) {
|
||||||
variable_name = "it";
|
variable_name = "it";
|
||||||
} else {
|
} else {
|
||||||
consume_while(is_whitespace);
|
consume_while(is_whitespace);
|
||||||
auto in_error_start = push_start();
|
auto in_error_start = push_start();
|
||||||
in_start_position = in_error_start->offset;
|
|
||||||
if (!expect("in")) {
|
if (!expect("in")) {
|
||||||
auto syntax_error = create<AST::SyntaxError>("Expected 'in' after a variable name in a 'for' loop");
|
auto syntax_error = create<AST::SyntaxError>("Expected 'in' after a variable name in a 'for' loop");
|
||||||
return create<AST::ForLoop>(move(variable_name), move(syntax_error), nullptr); // ForLoop Var Iterated Block
|
return create<AST::ForLoop>(move(variable_name), move(syntax_error), nullptr); // ForLoop Var Iterated Block
|
||||||
}
|
}
|
||||||
|
in_start_position = AST::Position { in_error_start->offset, m_offset, in_error_start->line, line() };
|
||||||
}
|
}
|
||||||
|
|
||||||
consume_while(is_whitespace);
|
consume_while(is_whitespace);
|
||||||
|
@ -542,13 +578,11 @@ RefPtr<AST::Node> Parser::parse_for_loop()
|
||||||
RefPtr<AST::Node> Parser::parse_if_expr()
|
RefPtr<AST::Node> Parser::parse_if_expr()
|
||||||
{
|
{
|
||||||
auto rule_start = push_start();
|
auto rule_start = push_start();
|
||||||
if (!expect("if")) {
|
if (!expect("if"))
|
||||||
m_offset = rule_start->offset;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
if (consume_while(is_any_of(" \t\n")).is_empty()) {
|
if (consume_while(is_any_of(" \t\n")).is_empty()) {
|
||||||
m_offset = rule_start->offset;
|
restore_to(*rule_start);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,7 +629,7 @@ RefPtr<AST::Node> Parser::parse_if_expr()
|
||||||
{
|
{
|
||||||
auto else_start = push_start();
|
auto else_start = push_start();
|
||||||
if (expect("else"))
|
if (expect("else"))
|
||||||
else_position = AST::Position { else_start->offset, m_offset };
|
else_position = AST::Position { else_start->offset, m_offset, else_start->line, line() };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (else_position.has_value()) {
|
if (else_position.has_value()) {
|
||||||
|
@ -642,7 +676,7 @@ RefPtr<AST::Node> Parser::parse_match_expr()
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (consume_while(is_whitespace).is_empty()) {
|
if (consume_while(is_whitespace).is_empty()) {
|
||||||
m_offset = rule_start->offset;
|
restore_to(*rule_start);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,8 +692,9 @@ RefPtr<AST::Node> Parser::parse_match_expr()
|
||||||
String match_name;
|
String match_name;
|
||||||
Optional<AST::Position> as_position;
|
Optional<AST::Position> as_position;
|
||||||
auto as_start = m_offset;
|
auto as_start = m_offset;
|
||||||
|
auto as_line = line();
|
||||||
if (expect("as")) {
|
if (expect("as")) {
|
||||||
as_position = AST::Position { as_start, m_offset };
|
as_position = AST::Position { as_start, m_offset, as_line, line() };
|
||||||
|
|
||||||
if (consume_while(is_any_of(" \t\n")).is_empty()) {
|
if (consume_while(is_any_of(" \t\n")).is_empty()) {
|
||||||
auto node = create<AST::MatchExpr>(
|
auto node = create<AST::MatchExpr>(
|
||||||
|
@ -730,9 +765,10 @@ AST::MatchEntry Parser::parse_match_entry()
|
||||||
consume_while(is_any_of(" \t\n"));
|
consume_while(is_any_of(" \t\n"));
|
||||||
|
|
||||||
auto previous_pipe_start_position = m_offset;
|
auto previous_pipe_start_position = m_offset;
|
||||||
|
auto previous_pipe_start_line = line();
|
||||||
RefPtr<AST::SyntaxError> error;
|
RefPtr<AST::SyntaxError> error;
|
||||||
while (expect('|')) {
|
while (expect('|')) {
|
||||||
pipe_positions.append({ previous_pipe_start_position, m_offset });
|
pipe_positions.append({ previous_pipe_start_position, m_offset, previous_pipe_start_line, line() });
|
||||||
consume_while(is_any_of(" \t\n"));
|
consume_while(is_any_of(" \t\n"));
|
||||||
auto pattern = parse_match_pattern();
|
auto pattern = parse_match_pattern();
|
||||||
if (!pattern) {
|
if (!pattern) {
|
||||||
|
@ -742,6 +778,9 @@ AST::MatchEntry Parser::parse_match_entry()
|
||||||
consume_while(is_any_of(" \t\n"));
|
consume_while(is_any_of(" \t\n"));
|
||||||
|
|
||||||
patterns.append(pattern.release_nonnull());
|
patterns.append(pattern.release_nonnull());
|
||||||
|
|
||||||
|
previous_pipe_start_line = line();
|
||||||
|
previous_pipe_start_position = m_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
consume_while(is_any_of(" \t\n"));
|
consume_while(is_any_of(" \t\n"));
|
||||||
|
@ -864,7 +903,7 @@ RefPtr<AST::Node> Parser::parse_redirection()
|
||||||
return create<AST::ReadWriteRedirection>(pipe_fd, path.release_nonnull()); // Redirection ReadWrite
|
return create<AST::ReadWriteRedirection>(pipe_fd, path.release_nonnull()); // Redirection ReadWrite
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
m_offset = rule_start->offset;
|
restore_to(*rule_start);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -930,7 +969,7 @@ RefPtr<AST::Node> Parser::parse_expression()
|
||||||
consume();
|
consume();
|
||||||
auto list = parse_list_expression();
|
auto list = parse_list_expression();
|
||||||
if (!expect(')')) {
|
if (!expect(')')) {
|
||||||
m_offset = rule_start->offset;
|
restore_to(*rule_start);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return read_concat(create<AST::CastToList>(move(list))); // Cast To List
|
return read_concat(create<AST::CastToList>(move(list))); // Cast To List
|
||||||
|
@ -1126,7 +1165,7 @@ RefPtr<AST::Node> Parser::parse_variable()
|
||||||
auto name = consume_while(is_word_character);
|
auto name = consume_while(is_word_character);
|
||||||
|
|
||||||
if (name.length() == 0) {
|
if (name.length() == 0) {
|
||||||
putback();
|
restore_to(rule_start->offset, rule_start->line);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1215,6 +1254,7 @@ RefPtr<AST::Node> Parser::parse_bareword()
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto current_end = m_offset;
|
auto current_end = m_offset;
|
||||||
|
auto current_line = line();
|
||||||
auto string = builder.to_string();
|
auto string = builder.to_string();
|
||||||
if (string.starts_with('~')) {
|
if (string.starts_with('~')) {
|
||||||
String username;
|
String username;
|
||||||
|
@ -1231,7 +1271,9 @@ RefPtr<AST::Node> Parser::parse_bareword()
|
||||||
|
|
||||||
// Synthesize a Tilde Node with the correct positioning information.
|
// Synthesize a Tilde Node with the correct positioning information.
|
||||||
{
|
{
|
||||||
m_offset -= string.length();
|
restore_to(rule_start->offset, rule_start->line);
|
||||||
|
auto ch = consume();
|
||||||
|
ASSERT(ch == '~');
|
||||||
tilde = create<AST::Tilde>(move(username));
|
tilde = create<AST::Tilde>(move(username));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1240,9 +1282,8 @@ RefPtr<AST::Node> Parser::parse_bareword()
|
||||||
|
|
||||||
// Synthesize a BarewordLiteral Node with the correct positioning information.
|
// Synthesize a BarewordLiteral Node with the correct positioning information.
|
||||||
{
|
{
|
||||||
m_offset = tilde->position().end_offset;
|
|
||||||
auto text_start = push_start();
|
auto text_start = push_start();
|
||||||
m_offset = current_end;
|
restore_to(current_end, current_line);
|
||||||
text = create<AST::BarewordLiteral>(move(string));
|
text = create<AST::BarewordLiteral>(move(string));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1267,6 +1308,7 @@ RefPtr<AST::Node> Parser::parse_glob()
|
||||||
|
|
||||||
char ch = peek();
|
char ch = peek();
|
||||||
if (ch == '*' || ch == '?') {
|
if (ch == '*' || ch == '?') {
|
||||||
|
auto saved_offset = save_offset();
|
||||||
consume();
|
consume();
|
||||||
StringBuilder textbuilder;
|
StringBuilder textbuilder;
|
||||||
if (bareword_part) {
|
if (bareword_part) {
|
||||||
|
@ -1276,7 +1318,7 @@ RefPtr<AST::Node> Parser::parse_glob()
|
||||||
text = bareword->text();
|
text = bareword->text();
|
||||||
} else {
|
} else {
|
||||||
// FIXME: Allow composition of tilde+bareword with globs: '~/foo/bar/baz*'
|
// FIXME: Allow composition of tilde+bareword with globs: '~/foo/bar/baz*'
|
||||||
putback();
|
restore_to(saved_offset.offset, saved_offset.line);
|
||||||
bareword_part->set_is_syntax_error(*create<AST::SyntaxError>(String::format("Unexpected %s inside a glob", bareword_part->class_name().characters())));
|
bareword_part->set_is_syntax_error(*create<AST::SyntaxError>(String::format("Unexpected %s inside a glob", bareword_part->class_name().characters())));
|
||||||
return bareword_part;
|
return bareword_part;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,12 @@ public:
|
||||||
|
|
||||||
RefPtr<AST::Node> parse();
|
RefPtr<AST::Node> parse();
|
||||||
|
|
||||||
|
struct SavedOffset {
|
||||||
|
size_t offset;
|
||||||
|
AST::Position::Line line;
|
||||||
|
};
|
||||||
|
SavedOffset save_offset() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RefPtr<AST::Node> parse_toplevel();
|
RefPtr<AST::Node> parse_toplevel();
|
||||||
RefPtr<AST::Node> parse_sequence();
|
RefPtr<AST::Node> parse_sequence();
|
||||||
|
@ -76,34 +82,55 @@ private:
|
||||||
bool at_end() const { return m_input.length() <= m_offset; }
|
bool at_end() const { return m_input.length() <= m_offset; }
|
||||||
char peek();
|
char peek();
|
||||||
char consume();
|
char consume();
|
||||||
void putback();
|
|
||||||
bool expect(char);
|
bool expect(char);
|
||||||
bool expect(const StringView&);
|
bool expect(const StringView&);
|
||||||
|
|
||||||
|
void restore_to(size_t offset, AST::Position::Line line)
|
||||||
|
{
|
||||||
|
m_offset = offset;
|
||||||
|
m_line = move(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
AST::Position::Line line() const { return m_line; }
|
||||||
|
|
||||||
StringView consume_while(Function<bool(char)>);
|
StringView consume_while(Function<bool(char)>);
|
||||||
|
|
||||||
struct ScopedOffset {
|
struct ScopedOffset {
|
||||||
ScopedOffset(Vector<size_t>& offsets, size_t offset)
|
ScopedOffset(Vector<size_t>& offsets, Vector<AST::Position::Line>& lines, size_t offset, size_t lineno, size_t linecol)
|
||||||
: offsets(offsets)
|
: offsets(offsets)
|
||||||
|
, lines(lines)
|
||||||
, offset(offset)
|
, offset(offset)
|
||||||
|
, line({ lineno, linecol })
|
||||||
{
|
{
|
||||||
offsets.append(offset);
|
offsets.append(offset);
|
||||||
|
lines.append(line);
|
||||||
}
|
}
|
||||||
~ScopedOffset()
|
~ScopedOffset()
|
||||||
{
|
{
|
||||||
auto last = offsets.take_last();
|
auto last = offsets.take_last();
|
||||||
ASSERT(last == offset);
|
ASSERT(last == offset);
|
||||||
|
|
||||||
|
auto last_line = lines.take_last();
|
||||||
|
ASSERT(last_line == line);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<size_t>& offsets;
|
Vector<size_t>& offsets;
|
||||||
|
Vector<AST::Position::Line>& lines;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
|
AST::Position::Line line;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void restore_to(const ScopedOffset& offset) { restore_to(offset.offset, offset.line); }
|
||||||
|
|
||||||
OwnPtr<ScopedOffset> push_start();
|
OwnPtr<ScopedOffset> push_start();
|
||||||
|
|
||||||
StringView m_input;
|
StringView m_input;
|
||||||
size_t m_offset { 0 };
|
size_t m_offset { 0 };
|
||||||
|
|
||||||
|
AST::Position::Line m_line { 0, 0 };
|
||||||
|
|
||||||
Vector<size_t> m_rule_start_offsets;
|
Vector<size_t> m_rule_start_offsets;
|
||||||
|
Vector<AST::Position::Line> m_rule_start_lines;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue