summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Shell/AST.cpp294
-rw-r--r--Shell/AST.h102
-rw-r--r--Shell/Parser.cpp79
-rw-r--r--Shell/Shell.cpp70
-rw-r--r--Shell/Shell.h3
5 files changed, 351 insertions, 197 deletions
diff --git a/Shell/AST.cpp b/Shell/AST.cpp
index eac2501ee4..9fd98a74fd 100644
--- a/Shell/AST.cpp
+++ b/Shell/AST.cpp
@@ -96,7 +96,7 @@ Vector<Line::CompletionSuggestion> Node::complete_for_editor(Shell& shell, size_
if (corrected_offset > node->text().length())
return {};
- return shell.complete_path(node->text(), corrected_offset);
+ return shell.complete_path("", node->text(), corrected_offset);
}
return {};
}
@@ -129,11 +129,9 @@ void And::dump(int level) const
m_right->dump(level + 1);
}
-RefPtr<Value> And::run(TheExecutionInputType input_value)
+RefPtr<Value> And::run(RefPtr<Shell> shell)
{
- auto shell = input_value;
-
- auto left = m_left->run(input_value);
+ auto left = m_left->run(shell);
ASSERT(left->is_job());
auto* job_value = static_cast<JobValue*>(left.ptr());
@@ -146,7 +144,7 @@ RefPtr<Value> And::run(TheExecutionInputType input_value)
shell->block_on_job(job);
if (job->exit_code() == 0)
- return m_right->run(input_value);
+ return m_right->run(shell);
return job_value;
}
@@ -174,6 +172,8 @@ And::And(Position position, RefPtr<Node> left, RefPtr<Node> right)
, m_left(move(left))
, m_right(move(right))
{
+ if (m_left->is_syntax_error() || m_right->is_syntax_error())
+ set_is_syntax_error();
}
And::~And()
@@ -187,13 +187,13 @@ void ListConcatenate::dump(int level) const
m_list->dump(level + 1);
}
-RefPtr<Value> ListConcatenate::run(TheExecutionInputType input_value)
+RefPtr<Value> ListConcatenate::run(RefPtr<Shell> shell)
{
- auto list = m_list->run(input_value)->resolve_without_cast(input_value);
- auto element = m_element->run(input_value)->resolve_without_cast(input_value);
+ auto list = m_list->run(shell)->resolve_without_cast(shell);
+ auto element = m_element->run(shell)->resolve_without_cast(shell);
if (list->is_command() || element->is_command()) {
- auto joined_commands = join_commands(element->resolve_as_commands(input_value), list->resolve_as_commands(input_value));
+ auto joined_commands = join_commands(element->resolve_as_commands(shell), list->resolve_as_commands(shell));
if (joined_commands.size() == 1)
return create<CommandValue>(joined_commands[0]);
@@ -231,6 +231,8 @@ ListConcatenate::ListConcatenate(Position position, RefPtr<Node> element, RefPtr
, m_element(move(element))
, m_list(move(list))
{
+ if (m_element->is_syntax_error() || m_list->is_syntax_error())
+ set_is_syntax_error();
}
ListConcatenate::~ListConcatenate()
@@ -243,9 +245,9 @@ void Background::dump(int level) const
m_command->dump(level + 1);
}
-RefPtr<Value> Background::run(TheExecutionInputType input_value)
+RefPtr<Value> Background::run(RefPtr<Shell> shell)
{
- auto commands = m_command->run(input_value)->resolve_as_commands(input_value);
+ auto commands = m_command->run(shell)->resolve_as_commands(shell);
auto& last = commands.last();
last.should_wait = false;
@@ -269,6 +271,8 @@ Background::Background(Position position, RefPtr<Node> command)
: Node(move(position))
, m_command(move(command))
{
+ if (m_command->is_syntax_error())
+ set_is_syntax_error();
}
Background::~Background()
@@ -281,7 +285,7 @@ void BarewordLiteral::dump(int level) const
print_indented(m_text, level + 1);
}
-RefPtr<Value> BarewordLiteral::run(TheExecutionInputType)
+RefPtr<Value> BarewordLiteral::run(RefPtr<Shell>)
{
return create<StringValue>(m_text);
}
@@ -331,17 +335,16 @@ void CastToCommand::dump(int level) const
m_inner->dump(level + 1);
}
-RefPtr<Value> CastToCommand::run(TheExecutionInputType input_value)
+RefPtr<Value> CastToCommand::run(RefPtr<Shell> shell)
{
if (m_inner->is_command())
- return m_inner->run(input_value);
+ return m_inner->run(shell);
- auto shell = input_value;
- auto value = m_inner->run(input_value)->resolve_without_cast(input_value);
+ auto value = m_inner->run(shell)->resolve_without_cast(shell);
if (value->is_command())
return value;
- auto argv = value->resolve_as_list(input_value);
+ auto argv = value->resolve_as_list(shell);
return create<CommandValue>(move(argv));
}
@@ -380,6 +383,8 @@ CastToCommand::CastToCommand(Position position, RefPtr<Node> inner)
: Node(move(position))
, m_inner(move(inner))
{
+ if (m_inner->is_syntax_error())
+ set_is_syntax_error();
}
CastToCommand::~CastToCommand()
@@ -395,18 +400,17 @@ void CastToList::dump(int level) const
print_indented("(empty)", level + 1);
}
-RefPtr<Value> CastToList::run(TheExecutionInputType input_value)
+RefPtr<Value> CastToList::run(RefPtr<Shell> shell)
{
if (!m_inner)
return create<ListValue>({});
- auto shell = input_value;
- auto inner_value = m_inner->run(input_value);
+ auto inner_value = m_inner->run(shell);
if (inner_value->is_command())
return inner_value;
- auto values = inner_value->resolve_as_list(input_value);
+ auto values = inner_value->resolve_as_list(shell);
Vector<RefPtr<Value>> cast_values;
for (auto& value : values)
cast_values.append(create<StringValue>(value));
@@ -435,6 +439,8 @@ CastToList::CastToList(Position position, RefPtr<Node> inner)
: Node(move(position))
, m_inner(move(inner))
{
+ if (m_inner && m_inner->is_syntax_error())
+ set_is_syntax_error();
}
CastToList::~CastToList()
@@ -447,7 +453,7 @@ void CloseFdRedirection::dump(int level) const
print_indented(String::format("%d -> Close", m_fd), level);
}
-RefPtr<Value> CloseFdRedirection::run(TheExecutionInputType)
+RefPtr<Value> CloseFdRedirection::run(RefPtr<Shell>)
{
Command command;
command.redirections.append(*new CloseRedirection(m_fd));
@@ -476,7 +482,7 @@ void CommandLiteral::dump(int level) const
print_indented("(Generated command literal)", level + 1);
}
-RefPtr<Value> CommandLiteral::run(TheExecutionInputType)
+RefPtr<Value> CommandLiteral::run(RefPtr<Shell>)
{
return create<CommandValue>(m_command);
}
@@ -497,7 +503,7 @@ void Comment::dump(int level) const
print_indented(m_text, level + 1);
}
-RefPtr<Value> Comment::run(TheExecutionInputType)
+RefPtr<Value> Comment::run(RefPtr<Shell>)
{
return create<StringValue>("");
}
@@ -523,11 +529,10 @@ void DoubleQuotedString::dump(int level) const
m_inner->dump(level + 1);
}
-RefPtr<Value> DoubleQuotedString::run(TheExecutionInputType input_value)
+RefPtr<Value> DoubleQuotedString::run(RefPtr<Shell> shell)
{
StringBuilder builder;
- auto shell = input_value;
- auto values = m_inner->run(input_value)->resolve_as_list(input_value);
+ auto values = m_inner->run(shell)->resolve_as_list(shell);
builder.join("", values);
@@ -557,6 +562,8 @@ DoubleQuotedString::DoubleQuotedString(Position position, RefPtr<Node> inner)
: Node(move(position))
, m_inner(move(inner))
{
+ if (m_inner->is_syntax_error())
+ set_is_syntax_error();
}
DoubleQuotedString::~DoubleQuotedString()
@@ -569,19 +576,19 @@ void DynamicEvaluate::dump(int level) const
m_inner->dump(level + 1);
}
-RefPtr<Value> DynamicEvaluate::run(TheExecutionInputType input_value)
+RefPtr<Value> DynamicEvaluate::run(RefPtr<Shell> shell)
{
- auto result = m_inner->run(input_value)->resolve_without_cast(input_value);
+ auto result = m_inner->run(shell)->resolve_without_cast(shell);
// Dynamic Evaluation behaves differently between strings and lists.
// Strings are treated as variables, and Lists are treated as commands.
if (result->is_string()) {
- auto name_part = result->resolve_as_list(input_value);
+ auto name_part = result->resolve_as_list(shell);
ASSERT(name_part.size() == 1);
return create<SimpleVariableValue>(name_part[0]);
}
// If it's anything else, we're just gonna cast it to a list.
- auto list = result->resolve_as_list(input_value);
+ auto list = result->resolve_as_list(shell);
return create<CommandValue>(move(list));
}
@@ -603,6 +610,8 @@ DynamicEvaluate::DynamicEvaluate(Position position, RefPtr<Node> inner)
: Node(move(position))
, m_inner(move(inner))
{
+ if (m_inner->is_syntax_error())
+ set_is_syntax_error();
}
DynamicEvaluate::~DynamicEvaluate()
@@ -615,7 +624,7 @@ void Fd2FdRedirection::dump(int level) const
print_indented(String::format("%d -> %d", source_fd, dest_fd), level);
}
-RefPtr<Value> Fd2FdRedirection::run(TheExecutionInputType)
+RefPtr<Value> Fd2FdRedirection::run(RefPtr<Shell>)
{
Command command;
command.redirections.append(*new FdRedirection(source_fd, dest_fd, Rewiring::Close::None));
@@ -644,7 +653,7 @@ void Glob::dump(int level) const
print_indented(m_text, level + 1);
}
-RefPtr<Value> Glob::run(TheExecutionInputType)
+RefPtr<Value> Glob::run(RefPtr<Shell>)
{
return create<GlobValue>(m_text);
}
@@ -675,12 +684,11 @@ void Execute::dump(int level) const
m_command->dump(level + 1);
}
-RefPtr<Value> Execute::run(TheExecutionInputType input_value)
+RefPtr<Value> Execute::run(RefPtr<Shell> shell)
{
RefPtr<Job> job;
- auto shell = input_value;
- auto initial_commands = m_command->run(input_value)->resolve_as_commands(input_value);
+ auto initial_commands = m_command->run(shell)->resolve_as_commands(shell);
decltype(initial_commands) commands;
for (auto& command : initial_commands) {
@@ -695,7 +703,7 @@ RefPtr<Value> Execute::run(TheExecutionInputType input_value)
subcommand_ast = ast->command();
}
RefPtr<Node> substitute = create<Join>(position(), move(subcommand_ast), create<CommandLiteral>(position(), command));
- commands.append(substitute->run(input_value)->resolve_as_commands(input_value));
+ commands.append(substitute->run(shell)->resolve_as_commands(shell));
} else {
commands.append(command);
}
@@ -851,6 +859,8 @@ Execute::Execute(Position position, RefPtr<Node> command, bool capture_stdout)
, m_command(move(command))
, m_capture_stdout(capture_stdout)
{
+ if (m_command->is_syntax_error())
+ set_is_syntax_error();
}
Execute::~Execute()
@@ -864,10 +874,10 @@ void Join::dump(int level) const
m_right->dump(level + 1);
}
-RefPtr<Value> Join::run(TheExecutionInputType input_value)
+RefPtr<Value> Join::run(RefPtr<Shell> shell)
{
- auto left = m_left->run(input_value)->resolve_as_commands(input_value);
- auto right = m_right->run(input_value)->resolve_as_commands(input_value);
+ auto left = m_left->run(shell)->resolve_as_commands(shell);
+ auto right = m_right->run(shell)->resolve_as_commands(shell);
return create<CommandSequenceValue>(join_commands(move(left), move(right)));
}
@@ -896,6 +906,8 @@ Join::Join(Position position, RefPtr<Node> left, RefPtr<Node> right)
, m_left(move(left))
, m_right(move(right))
{
+ if (m_left->is_syntax_error() || m_right->is_syntax_error())
+ set_is_syntax_error();
}
Join::~Join()
@@ -909,18 +921,17 @@ void Or::dump(int level) const
m_right->dump(level + 1);
}
-RefPtr<Value> Or::run(TheExecutionInputType input_value)
+RefPtr<Value> Or::run(RefPtr<Shell> shell)
{
- auto shell = input_value;
- auto left = m_left->run(input_value);
+ auto left = m_left->run(shell);
ASSERT(left->is_job());
auto* job_value = static_cast<JobValue*>(left.ptr());
const auto job = job_value->job();
if (!job) {
// Something has gone wrong, let's just pretend that the job failed.
- return m_right->run(input_value);
+ return m_right->run(shell);
}
shell->block_on_job(job);
@@ -928,7 +939,7 @@ RefPtr<Value> Or::run(TheExecutionInputType input_value)
if (job->exit_code() == 0)
return job_value;
- return m_right->run(input_value);
+ return m_right->run(shell);
}
void Or::highlight_in_editor(Line::Editor& editor, Shell& shell, HighlightMetadata metadata)
@@ -953,6 +964,8 @@ Or::Or(Position position, RefPtr<Node> left, RefPtr<Node> right)
, m_left(move(left))
, m_right(move(right))
{
+ if (m_left->is_syntax_error() || m_right->is_syntax_error())
+ set_is_syntax_error();
}
Or::~Or()
@@ -966,10 +979,10 @@ void Pipe::dump(int level) const
m_right->dump(level + 1);
}
-RefPtr<Value> Pipe::run(TheExecutionInputType input_value)
+RefPtr<Value> Pipe::run(RefPtr<Shell> shell)
{
- auto left = m_left->run(input_value)->resolve_as_commands(input_value);
- auto right = m_right->run(input_value)->resolve_as_commands(input_value);
+ auto left = m_left->run(shell)->resolve_as_commands(shell);
+ auto right = m_right->run(shell)->resolve_as_commands(shell);
auto last_in_left = left.take_last();
auto first_in_right = right.take_first();
@@ -1012,6 +1025,8 @@ Pipe::Pipe(Position position, RefPtr<Node> left, RefPtr<Node> right)
, m_left(move(left))
, m_right(move(right))
{
+ if (m_left->is_syntax_error() || m_right->is_syntax_error())
+ set_is_syntax_error();
}
Pipe::~Pipe()
@@ -1067,7 +1082,7 @@ Vector<Line::CompletionSuggestion> PathRedirectionNode::complete_for_editor(Shel
if (corrected_offset > node->text().length())
return {};
- return shell.complete_path(node->text(), corrected_offset);
+ return shell.complete_path("", node->text(), corrected_offset);
}
PathRedirectionNode::~PathRedirectionNode()
@@ -1081,10 +1096,10 @@ void ReadRedirection::dump(int level) const
print_indented(String::format("To %d", m_fd), level + 1);
}
-RefPtr<Value> ReadRedirection::run(TheExecutionInputType input_value)
+RefPtr<Value> ReadRedirection::run(RefPtr<Shell> shell)
{
Command command;
- auto path_segments = m_path->run(input_value)->resolve_as_list(input_value);
+ auto path_segments = m_path->run(shell)->resolve_as_list(shell);
StringBuilder builder;
builder.join(" ", path_segments);
@@ -1108,10 +1123,10 @@ void ReadWriteRedirection::dump(int level) const
print_indented(String::format("To/From %d", m_fd), level + 1);
}
-RefPtr<Value> ReadWriteRedirection::run(TheExecutionInputType input_value)
+RefPtr<Value> ReadWriteRedirection::run(RefPtr<Shell> shell)
{
Command command;
- auto path_segments = m_path->run(input_value)->resolve_as_list(input_value);
+ auto path_segments = m_path->run(shell)->resolve_as_list(shell);
StringBuilder builder;
builder.join(" ", path_segments);
@@ -1135,10 +1150,10 @@ void Sequence::dump(int level) const
m_right->dump(level + 1);
}
-RefPtr<Value> Sequence::run(TheExecutionInputType input_value)
+RefPtr<Value> Sequence::run(RefPtr<Shell> shell)
{
- auto left = m_left->run(input_value)->resolve_as_commands(input_value);
- auto right = m_right->run(input_value)->resolve_as_commands(input_value);
+ auto left = m_left->run(shell)->resolve_as_commands(shell);
+ auto right = m_right->run(shell)->resolve_as_commands(shell);
Vector<Command> commands;
commands.append(left);
@@ -1169,6 +1184,8 @@ Sequence::Sequence(Position position, RefPtr<Node> left, RefPtr<Node> right)
, m_left(move(left))
, m_right(move(right))
{
+ if (m_left->is_syntax_error() || m_right->is_syntax_error())
+ set_is_syntax_error();
}
Sequence::~Sequence()
@@ -1181,7 +1198,7 @@ void SimpleVariable::dump(int level) const
print_indented(m_name, level + 1);
}
-RefPtr<Value> SimpleVariable::run(TheExecutionInputType)
+RefPtr<Value> SimpleVariable::run(RefPtr<Shell>)
{
return create<SimpleVariableValue>(m_name);
}
@@ -1234,7 +1251,7 @@ void SpecialVariable::dump(int level) const
print_indented(String { &m_name, 1 }, level + 1);
}
-RefPtr<Value> SpecialVariable::run(TheExecutionInputType)
+RefPtr<Value> SpecialVariable::run(RefPtr<Shell>)
{
return create<SpecialVariableValue>(m_name);
}
@@ -1274,13 +1291,13 @@ void Juxtaposition::dump(int level) const
m_right->dump(level + 1);
}
-RefPtr<Value> Juxtaposition::run(TheExecutionInputType input_value)
+RefPtr<Value> Juxtaposition::run(RefPtr<Shell> shell)
{
- auto left_value = m_left->run(input_value)->resolve_without_cast(input_value);
- auto right_value = m_right->run(input_value)->resolve_without_cast(input_value);
+ auto left_value = m_left->run(shell)->resolve_without_cast(shell);
+ auto right_value = m_right->run(shell)->resolve_without_cast(shell);
- auto left = left_value->resolve_as_list(input_value);
- auto right = right_value->resolve_as_list(input_value);
+ auto left = left_value->resolve_as_list(shell);
+ auto right = right_value->resolve_as_list(shell);
if (left_value->is_string() && right_value->is_string()) {
@@ -1318,9 +1335,50 @@ void Juxtaposition::highlight_in_editor(Line::Editor& editor, Shell& shell, High
{
m_left->highlight_in_editor(editor, shell, metadata);
- // Do not highlight '/foo/bar' in '~/foo/bar'
- if (!(m_right->is_bareword() && m_left->is_tilde()))
+ // '~/foo/bar' is special, we have to actually resolve the tilde
+ // since that resolution is a pure operation, we can just go ahead
+ // and do it to get the value :)
+ if (m_right->is_bareword() && m_left->is_tilde()) {
+ auto tilde_value = m_left->run(shell)->resolve_as_list(shell)[0];
+ auto bareword_value = m_right->run(shell)->resolve_as_list(shell)[0];
+
+ StringBuilder path_builder;
+ path_builder.append(tilde_value);
+ path_builder.append("/");
+ path_builder.append(bareword_value);
+ auto path = path_builder.to_string();
+
+ if (Core::File::exists(path)) {
+ auto realpath = shell.resolve_path(path);
+ auto url = URL::create_with_file_protocol(realpath);
+ url.set_host(shell.hostname);
+ editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Hyperlink(url.to_string()) });
+ }
+
+ } else {
m_right->highlight_in_editor(editor, shell, metadata);
+ }
+}
+
+Vector<Line::CompletionSuggestion> Juxtaposition::complete_for_editor(Shell& shell, size_t offset, RefPtr<Node> matching_node)
+{
+ // '~/foo/bar' is special, we have to actually resolve the tilde
+ // then complete the bareword with that path prefix.
+ if (m_right->is_bareword() && m_left->is_tilde()) {
+ auto tilde_value = m_left->run(shell)->resolve_as_list(shell)[0];
+
+ auto corrected_offset = offset - matching_node->position().start_offset;
+ auto* node = static_cast<BarewordLiteral*>(matching_node.ptr());
+
+ if (corrected_offset > node->text().length())
+ return {};
+
+ auto text = node->text().substring(1, node->text().length() - 1);
+
+ return shell.complete_path(tilde_value, text, corrected_offset - 1);
+ }
+
+ return Node::complete_for_editor(shell, offset, matching_node);
}
HitTestResult Juxtaposition::hit_test_position(size_t offset)
@@ -1329,9 +1387,15 @@ HitTestResult Juxtaposition::hit_test_position(size_t offset)
return {};
auto result = m_left->hit_test_position(offset);
+ if (!result.closest_node_with_semantic_meaning)
+ result.closest_node_with_semantic_meaning = this;
if (result.matching_node)
return result;
- return m_right->hit_test_position(offset);
+
+ result = m_right->hit_test_position(offset);
+ if (!result.closest_node_with_semantic_meaning)
+ result.closest_node_with_semantic_meaning = this;
+ return result;
}
Juxtaposition::Juxtaposition(Position position, RefPtr<Node> left, RefPtr<Node> right)
@@ -1339,6 +1403,8 @@ Juxtaposition::Juxtaposition(Position position, RefPtr<Node> left, RefPtr<Node>
, m_left(move(left))
, m_right(move(right))
{
+ if (m_left->is_syntax_error() || m_right->is_syntax_error())
+ set_is_syntax_error();
}
Juxtaposition::~Juxtaposition()
@@ -1351,7 +1417,7 @@ void StringLiteral::dump(int level) const
print_indented(m_text, level + 1);
}
-RefPtr<Value> StringLiteral::run(TheExecutionInputType)
+RefPtr<Value> StringLiteral::run(RefPtr<Shell>)
{
return create<StringValue>(m_text);
}
@@ -1381,10 +1447,10 @@ void StringPartCompose::dump(int level) const
m_right->dump(level + 1);
}
-RefPtr<Value> StringPartCompose::run(TheExecutionInputType input_value)
+RefPtr<Value> StringPartCompose::run(RefPtr<Shell> shell)
{
- auto left = m_left->run(input_value)->resolve_as_list(input_value);
- auto right = m_right->run(input_value)->resolve_as_list(input_value);
+ auto left = m_left->run(shell)->resolve_as_list(shell);
+ auto right = m_right->run(shell)->resolve_as_list(shell);
StringBuilder builder;
builder.join(" ", left);
@@ -1415,6 +1481,8 @@ StringPartCompose::StringPartCompose(Position position, RefPtr<Node> left, RefPt
, m_left(move(left))
, m_right(move(right))
{
+ if (m_left->is_syntax_error() || m_right->is_syntax_error())
+ set_is_syntax_error();
}
StringPartCompose::~StringPartCompose()
@@ -1426,7 +1494,7 @@ void SyntaxError::dump(int level) const
Node::dump(level);
}
-RefPtr<Value> SyntaxError::run(TheExecutionInputType)
+RefPtr<Value> SyntaxError::run(RefPtr<Shell>)
{
dbg() << "SYNTAX ERROR AAAA";
return create<StringValue>("");
@@ -1440,6 +1508,7 @@ void SyntaxError::highlight_in_editor(Line::Editor& editor, Shell&, HighlightMet
SyntaxError::SyntaxError(Position position)
: Node(move(position))
{
+ set_is_syntax_error();
}
SyntaxError::~SyntaxError()
@@ -1452,14 +1521,13 @@ void Tilde::dump(int level) const
print_indented(m_username, level + 1);
}
-RefPtr<Value> Tilde::run(TheExecutionInputType)
+RefPtr<Value> Tilde::run(RefPtr<Shell>)
{
return create<TildeValue>(m_username);
}
-void Tilde::highlight_in_editor(Line::Editor& editor, Shell&, HighlightMetadata)
+void Tilde::highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata)
{
- editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Foreground(Line::Style::XtermColor::Cyan) });
}
HitTestResult Tilde::hit_test_position(size_t offset)
@@ -1470,9 +1538,20 @@ HitTestResult Tilde::hit_test_position(size_t offset)
return { this, this };
}
-Vector<Line::CompletionSuggestion> Tilde::complete_for_editor(Shell&, size_t, RefPtr<Node>)
+Vector<Line::CompletionSuggestion> Tilde::complete_for_editor(Shell& shell, size_t offset, RefPtr<Node> matching_node)
{
- return {};
+ if (!matching_node)
+ return {};
+
+ if (matching_node != this)
+ return {};
+
+ auto corrected_offset = offset - matching_node->position().start_offset - 1;
+
+ if (corrected_offset > m_username.length() + 1)
+ return {};
+
+ return shell.complete_user(m_username, corrected_offset);
}
String Tilde::text() const
@@ -1500,10 +1579,10 @@ void WriteAppendRedirection::dump(int level) const
print_indented(String::format("From %d", m_fd), level + 1);
}
-RefPtr<Value> WriteAppendRedirection::run(TheExecutionInputType input_value)
+RefPtr<Value> WriteAppendRedirection::run(RefPtr<Shell> shell)
{
Command command;
- auto path_segments = m_path->run(input_value)->resolve_as_list(input_value);
+ auto path_segments = m_path->run(shell)->resolve_as_list(shell);
StringBuilder builder;
builder.join(" ", path_segments);
@@ -1527,10 +1606,10 @@ void WriteRedirection::dump(int level) const
print_indented(String::format("From %d", m_fd), level + 1);
}
-RefPtr<Value> WriteRedirection::run(TheExecutionInputType input_value)
+RefPtr<Value> WriteRedirection::run(RefPtr<Shell> shell)
{
Command command;
- auto path_segments = m_path->run(input_value)->resolve_as_list(input_value);
+ auto path_segments = m_path->run(shell)->resolve_as_list(shell);
StringBuilder builder;
builder.join(" ", path_segments);
@@ -1557,21 +1636,20 @@ void VariableDeclarations::dump(int level) const
}
}
-RefPtr<Value> VariableDeclarations::run(TheExecutionInputType input_value)
+RefPtr<Value> VariableDeclarations::run(RefPtr<Shell> shell)
{
- auto shell = input_value;
for (auto& var : m_variables) {
- auto name_value = var.name->run(input_value)->resolve_as_list(input_value);
+ auto name_value = var.name->run(shell)->resolve_as_list(shell);
ASSERT(name_value.size() == 1);
auto name = name_value[0];
- auto value = var.value->run(input_value);
+ auto value = var.value->run(shell);
if (value->is_list()) {
- auto parts = value->resolve_as_list(input_value);
+ auto parts = value->resolve_as_list(shell);
shell->set_local_variable(name, adopt(*new ListValue(move(parts))));
} else if (value->is_command()) {
shell->set_local_variable(name, value);
} else {
- auto part = value->resolve_as_list(input_value);
+ auto part = value->resolve_as_list(shell);
shell->set_local_variable(name, adopt(*new StringValue(part[0])));
}
}
@@ -1608,6 +1686,12 @@ VariableDeclarations::VariableDeclarations(Position position, Vector<Variable> v
: Node(move(position))
, m_variables(move(variables))
{
+ for (auto& decl : m_variables) {
+ if (decl.name->is_syntax_error() || decl.value->is_syntax_error()) {
+ set_is_syntax_error();
+ break;
+ }
+ }
}
VariableDeclarations::~VariableDeclarations()
@@ -1617,10 +1701,10 @@ VariableDeclarations::~VariableDeclarations()
Value::~Value()
{
}
-Vector<AST::Command> Value::resolve_as_commands(TheExecutionInputType input_value)
+Vector<AST::Command> Value::resolve_as_commands(RefPtr<Shell> shell)
{
Command command;
- command.argv = resolve_as_list(input_value);
+ command.argv = resolve_as_list(shell);
return { command };
}
@@ -1635,11 +1719,11 @@ ListValue::~ListValue()
{
}
-Vector<String> ListValue::resolve_as_list(TheExecutionInputType input_value)
+Vector<String> ListValue::resolve_as_list(RefPtr<Shell> shell)
{
Vector<String> values;
for (auto& value : m_contained_values)
- values.append(value->resolve_as_list(input_value));
+ values.append(value->resolve_as_list(shell));
return values;
}
@@ -1652,24 +1736,24 @@ CommandSequenceValue::~CommandSequenceValue()
{
}
-Vector<String> CommandSequenceValue::resolve_as_list(TheExecutionInputType)
+Vector<String> CommandSequenceValue::resolve_as_list(RefPtr<Shell>)
{
// TODO: Somehow raise an "error".
return {};
}
-Vector<Command> CommandSequenceValue::resolve_as_commands(TheExecutionInputType)
+Vector<Command> CommandSequenceValue::resolve_as_commands(RefPtr<Shell>)
{
return m_contained_values;
}
-Vector<String> CommandValue::resolve_as_list(TheExecutionInputType)
+Vector<String> CommandValue::resolve_as_list(RefPtr<Shell>)
{
// TODO: Somehow raise an "error".
return {};
}
-Vector<Command> CommandValue::resolve_as_commands(TheExecutionInputType)
+Vector<Command> CommandValue::resolve_as_commands(RefPtr<Shell>)
{
return { m_command };
}
@@ -1681,7 +1765,7 @@ JobValue::~JobValue()
StringValue::~StringValue()
{
}
-Vector<String> StringValue::resolve_as_list(TheExecutionInputType)
+Vector<String> StringValue::resolve_as_list(RefPtr<Shell>)
{
if (is_list()) {
auto parts = StringView(m_string).split_view(m_split);
@@ -1698,19 +1782,18 @@ Vector<String> StringValue::resolve_as_list(TheExecutionInputType)
GlobValue::~GlobValue()
{
}
-Vector<String> GlobValue::resolve_as_list(TheExecutionInputType input_value)
+Vector<String> GlobValue::resolve_as_list(RefPtr<Shell> shell)
{
- auto shell = input_value;
return shell->expand_globs(m_glob, shell->cwd);
}
SimpleVariableValue::~SimpleVariableValue()
{
}
-Vector<String> SimpleVariableValue::resolve_as_list(TheExecutionInputType input_value)
+Vector<String> SimpleVariableValue::resolve_as_list(RefPtr<Shell> shell)
{
- if (auto value = resolve_without_cast(input_value); value != this)
- return value->resolve_as_list(input_value);
+ if (auto value = resolve_without_cast(shell); value != this)
+ return value->resolve_as_list(shell);
char* env_value = getenv(m_name.characters());
if (env_value == nullptr)
@@ -1724,9 +1807,8 @@ Vector<String> SimpleVariableValue::resolve_as_list(TheExecutionInputType input_
return res;
}
-RefPtr<Value> SimpleVariableValue::resolve_without_cast(TheExecutionInputType input_value)
+RefPtr<Value> SimpleVariableValue::resolve_without_cast(RefPtr<Shell> shell)
{
- auto shell = input_value;
if (auto value = shell->lookup_local_variable(m_name))
return value;
@@ -1737,9 +1819,8 @@ RefPtr<Value> SimpleVariableValue::resolve_without_cast(TheExecutionInputType in
SpecialVariableValue::~SpecialVariableValue()
{
}
-Vector<String> SpecialVariableValue::resolve_as_list(TheExecutionInputType input_value)
+Vector<String> SpecialVariableValue::resolve_as_list(RefPtr<Shell> shell)
{
- auto shell = input_value;
switch (m_name) {
case '?':
return { String::number(shell->last_return_code) };
@@ -1753,9 +1834,8 @@ Vector<String> SpecialVariableValue::resolve_as_list(TheExecutionInputType input
TildeValue::~TildeValue()
{
}
-Vector<String> TildeValue::resolve_as_list(TheExecutionInputType input_value)
+Vector<String> TildeValue::resolve_as_list(RefPtr<Shell> shell)
{
- auto shell = input_value;
StringBuilder builder;
builder.append("~");
builder.append(m_username);
diff --git a/Shell/AST.h b/Shell/AST.h
index 9094437bad..581a85ed89 100644
--- a/Shell/AST.h
+++ b/Shell/AST.h
@@ -36,8 +36,6 @@
#include <AK/Vector.h>
#include <LibLine/Editor.h>
-using TheExecutionInputType = RefPtr<Shell>;
-
namespace AST {
struct HighlightMetadata {
@@ -156,9 +154,9 @@ struct HitTestResult {
class Value : public RefCounted<Value> {
public:
- virtual Vector<String> resolve_as_list(TheExecutionInputType) = 0;
- virtual Vector<Command> resolve_as_commands(TheExecutionInputType);
- virtual RefPtr<Value> resolve_without_cast(TheExecutionInputType) { return this; }
+ virtual Vector<String> resolve_as_list(RefPtr<Shell>) = 0;
+ virtual Vector<Command> resolve_as_commands(RefPtr<Shell>);
+ virtual RefPtr<Value> resolve_without_cast(RefPtr<Shell>) { return this; }
virtual ~Value();
virtual bool is_command() const { return false; }
virtual bool is_glob() const { return false; }
@@ -169,8 +167,8 @@ public:
class CommandValue final : public Value {
public:
- virtual Vector<String> resolve_as_list(TheExecutionInputType) override;
- virtual Vector<Command> resolve_as_commands(TheExecutionInputType) override;
+ virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
+ virtual Vector<Command> resolve_as_commands(RefPtr<Shell>) override;
virtual ~CommandValue();
virtual bool is_command() const override { return true; }
CommandValue(Command command)
@@ -189,8 +187,8 @@ private:
class CommandSequenceValue final : public Value {
public:
- virtual Vector<String> resolve_as_list(TheExecutionInputType) override;
- virtual Vector<Command> resolve_as_commands(TheExecutionInputType) override;
+ virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
+ virtual Vector<Command> resolve_as_commands(RefPtr<Shell>) override;
virtual ~CommandSequenceValue();
virtual bool is_command() const override { return true; }
CommandSequenceValue(Vector<Command> commands)
@@ -204,8 +202,8 @@ private:
class JobValue final : public Value {
public:
- virtual Vector<String> resolve_as_list(TheExecutionInputType) override { ASSERT_NOT_REACHED(); }
- virtual Vector<Command> resolve_as_commands(TheExecutionInputType) override { ASSERT_NOT_REACHED(); }
+ virtual Vector<String> resolve_as_list(RefPtr<Shell>) override { ASSERT_NOT_REACHED(); }
+ virtual Vector<Command> resolve_as_commands(RefPtr<Shell>) override { ASSERT_NOT_REACHED(); }
virtual ~JobValue();
virtual bool is_job() const override { return true; }
JobValue(RefPtr<Job> job)
@@ -221,7 +219,7 @@ private:
class ListValue final : public Value {
public:
- virtual Vector<String> resolve_as_list(TheExecutionInputType) override;
+ virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
virtual ~ListValue();
virtual bool is_list() const override { return true; }
ListValue(Vector<String> values);
@@ -236,7 +234,7 @@ private:
class StringValue final : public Value {
public:
- virtual Vector<String> resolve_as_list(TheExecutionInputType) override;
+ virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
virtual ~StringValue();
virtual bool is_string() const override { return m_split.is_null(); }
virtual bool is_list() const override { return !m_split.is_null(); }
@@ -253,7 +251,7 @@ private:
class GlobValue final : public Value {
public:
- virtual Vector<String> resolve_as_list(TheExecutionInputType) override;
+ virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
virtual ~GlobValue();
virtual bool is_glob() const override { return true; }
GlobValue(String glob)
@@ -267,8 +265,8 @@ private:
class SimpleVariableValue final : public Value {
public:
- virtual Vector<String> resolve_as_list(TheExecutionInputType) override;
- RefPtr<Value> resolve_without_cast(TheExecutionInputType) override;
+ virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
+ RefPtr<Value> resolve_without_cast(RefPtr<Shell>) override;
virtual ~SimpleVariableValue();
SimpleVariableValue(String name)
: m_name(name)
@@ -281,7 +279,7 @@ private:
class SpecialVariableValue final : public Value {
public:
- virtual Vector<String> resolve_as_list(TheExecutionInputType) override;
+ virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
virtual ~SpecialVariableValue();
SpecialVariableValue(char name)
: m_name(name)
@@ -294,7 +292,7 @@ private:
class TildeValue final : public Value {
public:
- virtual Vector<String> resolve_as_list(TheExecutionInputType) override;
+ virtual Vector<String> resolve_as_list(RefPtr<Shell>) override;
virtual ~TildeValue();
virtual bool is_string() const override { return true; }
TildeValue(String name)
@@ -308,8 +306,8 @@ private:
class Node : public RefCounted<Node> {
public:
- virtual void dump(int level) = const 0;
- virtual RefPtr<Value> run(TheExecutionInputType) = 0;
+ virtual void dump(int level) const = 0;
+ 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, RefPtr<Node> matching_node);
Vector<Line::CompletionSuggestion> complete_for_editor(Shell& shell, size_t offset);
@@ -329,14 +327,16 @@ public:
virtual bool is_glob() const { return false; }
virtual bool is_tilde() const { return false; }
virtual bool is_variable_decls() const { return false; }
- virtual bool is_syntax_error() const { return false; }
+ virtual bool is_syntax_error() const { return m_is_syntax_error; }
virtual bool is_list() const { return false; }
const Position& position() const { return m_position; }
+ void set_is_syntax_error() { m_is_syntax_error = true; }
protected:
Position m_position;
+ bool m_is_syntax_error { false };
};
class PathRedirectionNode : public Node {
@@ -361,7 +361,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual String class_name() const override { return "And"; }
@@ -377,6 +377,7 @@ public:
private:
virtual void dump(int level) const override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual String class_name() const override { return "ListConcatenate"; }
@@ -393,7 +394,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual String class_name() const override { return "Background"; }
@@ -409,7 +410,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) 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; }
@@ -424,7 +425,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, RefPtr<Node> matching_node) override;
@@ -442,7 +443,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual String class_name() const override { return "CastToList"; }
@@ -458,7 +459,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) 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; }
@@ -473,7 +474,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override { ASSERT_NOT_REACHED(); }
virtual String class_name() const override { return "CommandLiteral"; }
virtual bool is_command() const override { return true; }
@@ -490,7 +491,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual String class_name() const override { return "Comment"; }
@@ -504,7 +505,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual String class_name() const override { return "DynamicEvaluate"; }
@@ -528,7 +529,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual String class_name() const override { return "DoubleQuotedString"; }
@@ -543,7 +544,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) 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; }
@@ -560,7 +561,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) 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; }
@@ -578,7 +579,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, RefPtr<Node> matching_node) override;
@@ -596,7 +597,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual String class_name() const override { return "Join"; }
@@ -614,7 +615,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual String class_name() const override { return "Or"; }
@@ -631,7 +632,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual String class_name() const override { return "Pipe"; }
@@ -648,7 +649,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual String class_name() const override { return "ReadRedirection"; }
};
@@ -659,7 +660,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual String class_name() const override { return "ReadWriteRedirection"; }
};
@@ -670,7 +671,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual String class_name() const override { return "Sequence"; }
@@ -687,7 +688,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) 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, RefPtr<Node> matching_node) override;
virtual HitTestResult hit_test_position(size_t) override;
@@ -703,7 +704,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) 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, RefPtr<Node> matching_node) override;
virtual HitTestResult hit_test_position(size_t) override;
@@ -719,9 +720,10 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
+ virtual Vector<Line::CompletionSuggestion> complete_for_editor(Shell&, size_t, RefPtr<Node> matching_node) override;
virtual String class_name() const override { return "Juxtaposition"; }
RefPtr<Node> m_left;
@@ -736,7 +738,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual String class_name() const override { return "StringLiteral"; }
@@ -750,7 +752,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual String class_name() const override { return "StringPartCompose"; }
@@ -766,7 +768,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override { return { nullptr, nullptr }; }
virtual String class_name() const override { return "SyntaxError"; }
@@ -781,7 +783,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) 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, RefPtr<Node> matching_node) override;
virtual HitTestResult hit_test_position(size_t) override;
@@ -804,7 +806,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) override;
virtual String class_name() const override { return "VariableDeclarations"; }
@@ -820,7 +822,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual String class_name() const override { return "WriteAppendRedirection"; }
};
@@ -831,7 +833,7 @@ public:
private:
virtual void dump(int level) const override;
- virtual RefPtr<Value> run(TheExecutionInputType) override;
+ virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual String class_name() const override { return "WriteRedirection"; }
};
diff --git a/Shell/Parser.cpp b/Shell/Parser.cpp
index c06c51577c..ef7d23c79b 100644
--- a/Shell/Parser.cpp
+++ b/Shell/Parser.cpp
@@ -112,7 +112,16 @@ RefPtr<AST::Node> Parser::parse()
{
m_offset = 0;
- return parse_toplevel();
+ auto toplevel = parse_toplevel();
+
+ if (m_offset < m_input.length()) {
+ // Parsing stopped midway, this is a syntax error.
+ auto error_start = push_start();
+ m_offset = m_input.length();
+ return create<AST::Join>(move(toplevel), create<AST::SyntaxError>());
+ }
+
+ return toplevel;
}
RefPtr<AST::Node> Parser::parse_toplevel()
@@ -207,9 +216,10 @@ RefPtr<AST::Node> Parser::parse_variable_decls()
if (peek() == '(') {
consume();
auto command = parse_pipe_sequence();
- expect(')');
if (!command)
m_offset = start->offset;
+ else if (!expect(')'))
+ command->set_is_syntax_error();
expression = command;
}
}
@@ -504,18 +514,26 @@ RefPtr<AST::Node> Parser::parse_string()
if (peek() == '"') {
consume();
auto inner = parse_doublequoted_string_inner();
- if (!expect('"') || !inner)
- return create<AST::SyntaxError>();
+ if (!inner)
+ inner = create<AST::SyntaxError>();
+ if (!expect('"')) {
+ inner = create<AST::DoubleQuotedString>(move(inner));
+ inner->set_is_syntax_error();
+ return inner;
+ }
return create<AST::DoubleQuotedString>(move(inner)); // Double Quoted String
}
if (peek() == '\'') {
consume();
auto text = consume_while(is_not('\''));
+ bool is_error = false;
if (!expect('\''))
- return create<AST::SyntaxError>();
-
- return create<AST::StringLiteral>(move(text)); // String Literal
+ is_error = true;
+ auto result = create<AST::StringLiteral>(move(text)); // String Literal
+ if (is_error)
+ result->set_is_syntax_error();
+ return move(result);
}
return nullptr;
@@ -648,11 +666,11 @@ RefPtr<AST::Node> Parser::parse_evaluate()
if (peek() == '(') {
consume();
auto inner = parse_pipe_sequence();
- if (!inner || !expect(')'))
+ if (!inner)
inner = create<AST::SyntaxError>();
- else
- inner = create<AST::Execute>(move(inner), true);
- return inner;
+ if (!expect(')'))
+ inner->set_is_syntax_error();
+ return create<AST::Execute>(move(inner), true);
}
auto inner = parse_expression();
@@ -718,9 +736,12 @@ RefPtr<AST::Node> Parser::parse_bareword()
if (builder.is_empty())
return nullptr;
+ auto current_end = m_offset;
auto string = builder.to_string();
if (string.starts_with('~')) {
String username;
+ RefPtr<AST::Node> tilde, text;
+
auto first_slash_index = string.index_of("/");
if (first_slash_index.has_value()) {
username = string.substring_view(1, first_slash_index.value() - 1);
@@ -729,21 +750,33 @@ RefPtr<AST::Node> Parser::parse_bareword()
username = string.substring_view(1, string.length() - 1);
string = "";
}
- auto current_end = m_offset;
- m_offset -= string.length();
- auto tilde = create<AST::Tilde>(move(username));
- auto text_start = push_start();
- m_offset = current_end;
+
+ // Synthesize a Tilde Node with the correct positioning information.
+ {
+ m_offset -= string.length();
+ tilde = create<AST::Tilde>(move(username));
+ }
+
if (string.is_empty())
return tilde;
- return create<AST::StringPartCompose>(move(tilde), create<AST::BarewordLiteral>(move(string))); // Compose Varible Bareword
+
+ // Synthesize a BarewordLiteral Node with the correct positioning information.
+ {
+ m_offset = tilde->position().end_offset;
+ auto text_start = push_start();
+ m_offset = current_end;
+ text = create<AST::BarewordLiteral>(move(string));
+ }
+
+ return create<AST::Juxtaposition>(move(tilde), move(text)); // Juxtaposition Varible Bareword
}
if (string.starts_with("\\~")) {
// Un-escape the tilde, but only at the start (where it would be an expansion)
+ string = string.substring(1, string.length() - 1);
}
- return create<AST::BarewordLiteral>(builder.to_string()); // Bareword Literal
+ return create<AST::BarewordLiteral>(move(string)); // Bareword Literal
}
RefPtr<AST::Node> Parser::parse_glob()
@@ -757,17 +790,17 @@ RefPtr<AST::Node> Parser::parse_glob()
char ch = peek();
if (ch == '*' || ch == '?') {
consume();
- // FIXME: Join all parts before making AST nodes
StringBuilder textbuilder;
if (bareword_part) {
- ASSERT(bareword_part->is_bareword() || bareword_part->is_tilde());
StringView text;
- if (bareword_part->is_tilde()) {
+ if (bareword_part->is_bareword()) {
auto bareword = static_cast<AST::BarewordLiteral*>(bareword_part.ptr());
text = bareword->text();
} else {
- auto tilde = static_cast<AST::Tilde*>(bareword_part.ptr());
- text = tilde->text();
+ // FIXME: Allow composition of tilde+bareword with globs: '~/foo/bar/baz*'
+ putback();
+ bareword_part->set_is_syntax_error();
+ return bareword_part;
}
textbuilder.append(text);
}
diff --git a/Shell/Shell.cpp b/Shell/Shell.cpp
index e18f1995bb..398d8fe631 100644
--- a/Shell/Shell.cpp
+++ b/Shell/Shell.cpp
@@ -324,6 +324,12 @@ int Shell::run_command(const StringView& cmd)
if (!command)
return 0;
+ if (command->is_syntax_error()) {
+ // FIXME: Provide descriptive messages for syntax errors.
+ fprintf(stderr, "Shell: Syntax error in command\n");
+ return 1;
+ }
+
#ifdef SH_DEBUG
dbg() << "Command follows";
command->dump(0);
@@ -664,9 +670,9 @@ Vector<Line::CompletionSuggestion> Shell::complete(const Line::Editor& editor)
return ast->complete_for_editor(*this, line.length());
}
-Vector<Line::CompletionSuggestion> Shell::complete_path(const String& part, size_t offset)
+Vector<Line::CompletionSuggestion> Shell::complete_path(const String& base, const String& part, size_t offset)
{
- auto token = part.substring_view(0, offset);
+ auto token = offset ? part.substring_view(0, offset) : "";
StringView original_token = token;
String path;
@@ -674,19 +680,30 @@ Vector<Line::CompletionSuggestion> Shell::complete_path(const String& part, size
while (last_slash >= 0 && token[last_slash] != '/')
--last_slash;
- if (last_slash >= 0) {
- // Split on the last slash. We'll use the first part as the directory
- // to search and the second part as the token to complete.
- path = token.substring_view(0, last_slash + 1);
- if (path[0] != '/')
- path = String::format("%s/%s", cwd.characters(), path.characters());
- path = LexicalPath::canonicalized_path(path);
- token = token.substring_view(last_slash + 1, token.length() - last_slash - 1);
+ StringBuilder path_builder;
+ auto init_slash_part = token.substring_view(0, last_slash + 1);
+ auto last_slash_part = token.substring_view(last_slash + 1, token.length() - last_slash - 1);
+
+ // Depending on the base, we will have to prepend cwd.
+ if (base.is_empty()) {
+ // '' /foo -> absolute
+ // '' foo -> relative
+ if (!token.starts_with('/'))
+ path_builder.append(cwd);
+ path_builder.append('/');
+ path_builder.append(init_slash_part);
} else {
- // We have no slashes, so the directory to search is the current
- // directory and the token to complete is just the original token.
- path = cwd;
- }
+ // /foo * -> absolute
+ // foo * -> relative
+ if (!base.starts_with('/'))
+ path_builder.append(cwd);
+ path_builder.append('/');
+ path_builder.append(base);
+ path_builder.append('/');
+ path_builder.append(init_slash_part);
+ }
+ path = path_builder.build();
+ token = last_slash_part;
// the invariant part of the token is actually just the last segment
// e. in `cd /foo/bar', 'bar' is the invariant
@@ -727,7 +744,7 @@ Vector<Line::CompletionSuggestion> Shell::complete_program_name(const String& na
});
if (!match)
- return complete_path(name, offset);
+ return complete_path("", name, offset);
String completion = *match;
editor->suggest(escape_token(name).length(), 0);
@@ -753,7 +770,7 @@ Vector<Line::CompletionSuggestion> Shell::complete_program_name(const String& na
Vector<Line::CompletionSuggestion> Shell::complete_variable(const String& name, size_t offset)
{
Vector<Line::CompletionSuggestion> suggestions;
- auto pattern = name.substring_view(0, offset);
+ auto pattern = offset ? name.substring_view(0, offset) : "";
editor->suggest(offset);
@@ -780,6 +797,27 @@ Vector<Line::CompletionSuggestion> Shell::complete_variable(const String& name,
return suggestions;
}
+Vector<Line::CompletionSuggestion> Shell::complete_user(const String& name, size_t offset)
+{
+ Vector<Line::CompletionSuggestion> suggestions;
+ auto pattern = offset ? name.substring_view(0, offset) : "";
+
+ editor->suggest(offset);
+
+ Core::DirIterator di("/home", Core::DirIterator::SkipParentAndBaseDir);
+
+ if (di.has_error())
+ return suggestions;
+
+ while (di.has_next()) {
+ String name = di.next_path();
+ if (name.starts_with(pattern))
+ suggestions.append(name);
+ }
+
+ return suggestions;
+}
+
bool Shell::read_single_line()
{
take_back_stdin();
diff --git a/Shell/Shell.h b/Shell/Shell.h
index 6be974027b..18b1c275a7 100644
--- a/Shell/Shell.h
+++ b/Shell/Shell.h
@@ -92,9 +92,10 @@ public:
void highlight(Line::Editor&) const;
Vector<Line::CompletionSuggestion> complete(const Line::Editor&);
- Vector<Line::CompletionSuggestion> complete_path(const String&, size_t offset);
+ Vector<Line::CompletionSuggestion> complete_path(const String& base, const String&, size_t offset);
Vector<Line::CompletionSuggestion> complete_program_name(const String&, size_t offset);
Vector<Line::CompletionSuggestion> complete_variable(const String&, size_t offset);
+ Vector<Line::CompletionSuggestion> complete_user(const String&, size_t offset);
void take_back_stdin();