summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Userland/Shell/PosixLexer.cpp186
-rw-r--r--Userland/Shell/PosixLexer.h70
-rw-r--r--Userland/Shell/PosixParser.cpp370
-rw-r--r--Userland/Shell/PosixParser.h64
4 files changed, 358 insertions, 332 deletions
diff --git a/Userland/Shell/PosixLexer.cpp b/Userland/Shell/PosixLexer.cpp
index 4806d350fc..60e18010db 100644
--- a/Userland/Shell/PosixLexer.cpp
+++ b/Userland/Shell/PosixLexer.cpp
@@ -23,19 +23,19 @@ static bool is_part_of_operator(StringView text, char ch)
namespace Shell::Posix {
-Vector<Token> Lexer::batch_next(Optional<Reduction> starting_reduction)
+ErrorOr<Vector<Token>> Lexer::batch_next(Optional<Reduction> starting_reduction)
{
if (starting_reduction.has_value())
m_next_reduction = *starting_reduction;
for (; m_next_reduction != Reduction::None;) {
- auto result = reduce(m_next_reduction);
+ auto result = TRY(reduce(m_next_reduction));
m_next_reduction = result.next_reduction;
if (!result.tokens.is_empty())
return result.tokens;
}
- return {};
+ return Vector<Token> {};
}
ExpansionRange Lexer::range(ssize_t offset) const
@@ -79,11 +79,11 @@ bool Lexer::consume_specific(char ch)
return false;
}
-Lexer::ReductionResult Lexer::reduce(Reduction reduction)
+ErrorOr<Lexer::ReductionResult> Lexer::reduce(Reduction reduction)
{
switch (reduction) {
case Reduction::None:
- return { {}, Reduction::None };
+ return ReductionResult { {}, Reduction::None };
case Reduction::End:
return reduce_end();
case Reduction::Operator:
@@ -117,9 +117,9 @@ Lexer::ReductionResult Lexer::reduce(Reduction reduction)
VERIFY_NOT_REACHED();
}
-Lexer::ReductionResult Lexer::reduce_end()
+ErrorOr<Lexer::ReductionResult> Lexer::reduce_end()
{
- return {
+ return ReductionResult {
.tokens = { Token::eof() },
.next_reduction = Reduction::None,
};
@@ -205,21 +205,21 @@ Lexer::HeredocKeyResult Lexer::process_heredoc_key(Token const& token)
// NOTE: Not checking the final state as any garbage that even partially parses is allowed to be used as a key :/
return {
- .key = builder.to_deprecated_string(),
+ .key = builder.to_string().release_value_but_fixme_should_propagate_errors(),
.allow_interpolation = !had_a_single_quote_segment,
};
}
-Lexer::ReductionResult Lexer::reduce_operator()
+ErrorOr<Lexer::ReductionResult> Lexer::reduce_operator()
{
if (m_lexer.is_eof()) {
if (is_operator(m_state.buffer.string_view())) {
- auto tokens = Token::operators_from(m_state);
+ auto tokens = TRY(Token::operators_from(m_state));
m_state.buffer.clear();
m_state.position.start_offset = m_state.position.end_offset;
m_state.position.start_line = m_state.position.end_line;
- return {
+ return ReductionResult {
.tokens = move(tokens),
.next_reduction = Reduction::End,
};
@@ -230,7 +230,7 @@ Lexer::ReductionResult Lexer::reduce_operator()
if (is_part_of_operator(m_state.buffer.string_view(), m_lexer.peek())) {
m_state.buffer.append(consume());
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::Operator,
};
@@ -238,7 +238,7 @@ Lexer::ReductionResult Lexer::reduce_operator()
auto tokens = Vector<Token> {};
if (is_operator(m_state.buffer.string_view())) {
- tokens.extend(Token::operators_from(m_state));
+ tokens.extend(TRY(Token::operators_from(m_state)));
m_state.buffer.clear();
m_state.position.start_offset = m_state.position.end_offset;
m_state.position.start_line = m_state.position.end_line;
@@ -246,11 +246,11 @@ Lexer::ReductionResult Lexer::reduce_operator()
auto expect_heredoc_entry = !tokens.is_empty() && (tokens.last().type == Token::Type::DoubleLessDash || tokens.last().type == Token::Type::DoubleLess);
- auto result = reduce(Reduction::Start);
+ auto result = TRY(reduce(Reduction::Start));
tokens.extend(move(result.tokens));
while (expect_heredoc_entry && tokens.size() == 1) {
- result = reduce(result.next_reduction);
+ result = TRY(reduce(result.next_reduction));
tokens.extend(move(result.tokens));
}
@@ -263,16 +263,16 @@ Lexer::ReductionResult Lexer::reduce_operator()
});
}
- return {
+ return ReductionResult {
.tokens = move(tokens),
.next_reduction = result.next_reduction,
};
}
-Lexer::ReductionResult Lexer::reduce_comment()
+ErrorOr<Lexer::ReductionResult> Lexer::reduce_comment()
{
if (m_lexer.is_eof()) {
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::End,
};
@@ -280,24 +280,24 @@ Lexer::ReductionResult Lexer::reduce_comment()
if (consume() == '\n') {
m_state.on_new_line = true;
- return {
+ return ReductionResult {
.tokens = { Token::newline() },
.next_reduction = Reduction::Start,
};
}
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::Comment,
};
}
-Lexer::ReductionResult Lexer::reduce_single_quoted_string()
+ErrorOr<Lexer::ReductionResult> Lexer::reduce_single_quoted_string()
{
if (m_lexer.is_eof()) {
- auto tokens = Token::maybe_from_state(m_state);
+ auto tokens = TRY(Token::maybe_from_state(m_state));
tokens.append(Token::continuation('\''));
- return {
+ return ReductionResult {
.tokens = move(tokens),
.next_reduction = Reduction::End,
};
@@ -307,25 +307,25 @@ Lexer::ReductionResult Lexer::reduce_single_quoted_string()
m_state.buffer.append(ch);
if (ch == '\'') {
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::Start,
};
}
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::SingleQuotedString,
};
}
-Lexer::ReductionResult Lexer::reduce_double_quoted_string()
+ErrorOr<Lexer::ReductionResult> Lexer::reduce_double_quoted_string()
{
m_state.previous_reduction = Reduction::DoubleQuotedString;
if (m_lexer.is_eof()) {
- auto tokens = Token::maybe_from_state(m_state);
+ auto tokens = TRY(Token::maybe_from_state(m_state));
tokens.append(Token::continuation('"'));
- return {
+ return ReductionResult {
.tokens = move(tokens),
.next_reduction = Reduction::End,
};
@@ -337,7 +337,7 @@ Lexer::ReductionResult Lexer::reduce_double_quoted_string()
if (m_state.escaping) {
m_state.escaping = false;
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::DoubleQuotedString,
};
@@ -346,13 +346,13 @@ Lexer::ReductionResult Lexer::reduce_double_quoted_string()
switch (ch) {
case '\\':
m_state.escaping = true;
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::DoubleQuotedString,
};
case '"':
m_state.previous_reduction = Reduction::Start;
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::Start,
};
@@ -361,25 +361,25 @@ Lexer::ReductionResult Lexer::reduce_double_quoted_string()
m_state.expansions.empend(CommandExpansion { .command = StringBuilder {}, .range = range() });
else
m_state.expansions.empend(ParameterExpansion { .parameter = StringBuilder {}, .range = range() });
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::Expansion,
};
case '`':
m_state.expansions.empend(CommandExpansion { .command = StringBuilder {}, .range = range() });
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::CommandExpansion,
};
default:
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::DoubleQuotedString,
};
}
}
-Lexer::ReductionResult Lexer::reduce_expansion()
+ErrorOr<Lexer::ReductionResult> Lexer::reduce_expansion()
{
if (m_lexer.is_eof())
return reduce(m_state.previous_reduction);
@@ -390,14 +390,14 @@ Lexer::ReductionResult Lexer::reduce_expansion()
case '{':
consume();
m_state.buffer.append(ch);
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::ExtendedParameterExpansion,
};
case '(':
consume();
m_state.buffer.append(ch);
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::CommandOrArithmeticSubstitutionExpansion,
};
@@ -410,7 +410,7 @@ Lexer::ReductionResult Lexer::reduce_expansion()
expansion.parameter.append(ch);
expansion.range.length = m_state.position.end_offset - expansion.range.start - m_state.position.start_offset;
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::ParameterExpansion,
};
@@ -430,13 +430,13 @@ Lexer::ReductionResult Lexer::reduce_expansion()
}
}
-Lexer::ReductionResult Lexer::reduce_command_expansion()
+ErrorOr<Lexer::ReductionResult> Lexer::reduce_command_expansion()
{
if (m_lexer.is_eof()) {
auto& expansion = m_state.expansions.last().get<CommandExpansion>();
expansion.range.length = m_state.position.end_offset - expansion.range.start - m_state.position.start_offset;
- return {
+ return ReductionResult {
.tokens = { Token::continuation('`') },
.next_reduction = m_state.previous_reduction,
};
@@ -449,7 +449,7 @@ Lexer::ReductionResult Lexer::reduce_command_expansion()
auto& expansion = m_state.expansions.last().get<CommandExpansion>();
expansion.range.length = m_state.position.end_offset - expansion.range.start - m_state.position.start_offset;
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = m_state.previous_reduction,
};
@@ -457,7 +457,7 @@ Lexer::ReductionResult Lexer::reduce_command_expansion()
if (!m_state.escaping && ch == '\\') {
m_state.escaping = true;
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::CommandExpansion,
};
@@ -466,21 +466,21 @@ Lexer::ReductionResult Lexer::reduce_command_expansion()
m_state.escaping = false;
m_state.buffer.append(ch);
m_state.expansions.last().get<CommandExpansion>().command.append(ch);
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::CommandExpansion,
};
}
-Lexer::ReductionResult Lexer::reduce_heredoc_contents()
+ErrorOr<Lexer::ReductionResult> Lexer::reduce_heredoc_contents()
{
if (m_lexer.is_eof()) {
- auto tokens = Token::maybe_from_state(m_state);
+ auto tokens = TRY(Token::maybe_from_state(m_state));
m_state.buffer.clear();
m_state.position.start_offset = m_state.position.end_offset;
m_state.position.start_line = m_state.position.end_line;
- return {
+ return ReductionResult {
.tokens = move(tokens),
.next_reduction = Reduction::End,
};
@@ -489,7 +489,7 @@ Lexer::ReductionResult Lexer::reduce_heredoc_contents()
if (!m_state.escaping && consume_specific('\\')) {
m_state.escaping = true;
m_state.buffer.append('\\');
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::HeredocContents,
};
@@ -502,7 +502,7 @@ Lexer::ReductionResult Lexer::reduce_heredoc_contents()
else
m_state.expansions.empend(ParameterExpansion { .parameter = StringBuilder {}, .range = range() });
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::Expansion,
};
@@ -511,7 +511,7 @@ Lexer::ReductionResult Lexer::reduce_heredoc_contents()
if (!m_state.escaping && consume_specific('`')) {
m_state.buffer.append('`');
m_state.expansions.empend(CommandExpansion { .command = StringBuilder {}, .range = range() });
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::CommandExpansion,
};
@@ -519,25 +519,25 @@ Lexer::ReductionResult Lexer::reduce_heredoc_contents()
m_state.escaping = false;
m_state.buffer.append(consume());
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::HeredocContents,
};
}
-Lexer::ReductionResult Lexer::reduce_start()
+ErrorOr<Lexer::ReductionResult> Lexer::reduce_start()
{
auto was_on_new_line = m_state.on_new_line;
m_state.on_new_line = false;
if (m_lexer.is_eof()) {
- auto tokens = Token::maybe_from_state(m_state);
+ auto tokens = TRY(Token::maybe_from_state(m_state));
m_state.buffer.clear();
m_state.expansions.clear();
m_state.position.start_offset = m_state.position.end_offset;
m_state.position.start_line = m_state.position.end_line;
- return {
+ return ReductionResult {
.tokens = move(tokens),
.next_reduction = Reduction::End,
};
@@ -555,7 +555,7 @@ Lexer::ReductionResult Lexer::reduce_start()
if (m_lexer.consume_specific('\n')) {
if (entry.dedent)
m_lexer.ignore_while(is_any_of("\t"sv));
- if (m_lexer.consume_specific(entry.key.view())) {
+ if (m_lexer.consume_specific(entry.key.bytes_as_string_view())) {
if (m_lexer.consume_specific('\n') || m_lexer.is_eof()) {
end_index = possible_end_index;
break;
@@ -572,7 +572,7 @@ Lexer::ReductionResult Lexer::reduce_start()
m_state.buffer.clear();
m_state.buffer.append(contents);
- auto token = Token::maybe_from_state(m_state).first();
+ auto token = TRY(Token::maybe_from_state(m_state)).first();
token.relevant_heredoc_key = entry.key;
token.type = Token::Type::HeredocContents;
@@ -582,7 +582,7 @@ Lexer::ReductionResult Lexer::reduce_start()
m_state.buffer.clear();
- return {
+ return ReductionResult {
.tokens = { move(token) },
.next_reduction = Reduction::Start,
};
@@ -595,7 +595,7 @@ Lexer::ReductionResult Lexer::reduce_start()
m_state.buffer.clear();
m_state.buffer.append(buffer);
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::Start,
};
@@ -603,14 +603,14 @@ Lexer::ReductionResult Lexer::reduce_start()
if (!m_state.escaping && m_lexer.peek() == '#' && m_state.buffer.is_empty()) {
consume();
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::Comment,
};
}
if (!m_state.escaping && consume_specific('\n')) {
- auto tokens = Token::maybe_from_state(m_state);
+ auto tokens = TRY(Token::maybe_from_state(m_state));
tokens.append(Token::newline());
m_state.on_new_line = true;
@@ -620,7 +620,7 @@ Lexer::ReductionResult Lexer::reduce_start()
m_state.position.start_offset = m_state.position.end_offset;
m_state.position.start_line = m_state.position.end_line;
- return {
+ return ReductionResult {
.tokens = move(tokens),
.next_reduction = Reduction::Start,
};
@@ -629,21 +629,21 @@ Lexer::ReductionResult Lexer::reduce_start()
if (!m_state.escaping && consume_specific('\\')) {
m_state.escaping = true;
m_state.buffer.append('\\');
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::Start,
};
}
if (!m_state.escaping && is_part_of_operator(""sv, m_lexer.peek())) {
- auto tokens = Token::maybe_from_state(m_state);
+ auto tokens = TRY(Token::maybe_from_state(m_state));
m_state.buffer.clear();
m_state.buffer.append(consume());
m_state.expansions.clear();
m_state.position.start_offset = m_state.position.end_offset;
m_state.position.start_line = m_state.position.end_line;
- return {
+ return ReductionResult {
.tokens = move(tokens),
.next_reduction = Reduction::Operator,
};
@@ -651,7 +651,7 @@ Lexer::ReductionResult Lexer::reduce_start()
if (!m_state.escaping && consume_specific('\'')) {
m_state.buffer.append('\'');
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::SingleQuotedString,
};
@@ -659,7 +659,7 @@ Lexer::ReductionResult Lexer::reduce_start()
if (!m_state.escaping && consume_specific('"')) {
m_state.buffer.append('"');
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::DoubleQuotedString,
};
@@ -667,13 +667,13 @@ Lexer::ReductionResult Lexer::reduce_start()
if (!m_state.escaping && is_ascii_space(m_lexer.peek())) {
consume();
- auto tokens = Token::maybe_from_state(m_state);
+ auto tokens = TRY(Token::maybe_from_state(m_state));
m_state.buffer.clear();
m_state.expansions.clear();
m_state.position.start_offset = m_state.position.end_offset;
m_state.position.start_line = m_state.position.end_line;
- return {
+ return ReductionResult {
.tokens = move(tokens),
.next_reduction = Reduction::Start,
};
@@ -686,7 +686,7 @@ Lexer::ReductionResult Lexer::reduce_start()
else
m_state.expansions.empend(ParameterExpansion { .parameter = StringBuilder {}, .range = range() });
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::Expansion,
};
@@ -695,7 +695,7 @@ Lexer::ReductionResult Lexer::reduce_start()
if (!m_state.escaping && consume_specific('`')) {
m_state.buffer.append('`');
m_state.expansions.empend(CommandExpansion { .command = StringBuilder {}, .range = range() });
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::CommandExpansion,
};
@@ -703,20 +703,20 @@ Lexer::ReductionResult Lexer::reduce_start()
m_state.escaping = false;
m_state.buffer.append(consume());
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::Start,
};
}
-Lexer::ReductionResult Lexer::reduce_arithmetic_expansion()
+ErrorOr<Lexer::ReductionResult> Lexer::reduce_arithmetic_expansion()
{
if (m_lexer.is_eof()) {
auto& expansion = m_state.expansions.last().get<ArithmeticExpansion>();
expansion.range.length = m_state.position.end_offset - expansion.range.start - m_state.position.start_offset;
- return {
- .tokens = { Token::continuation("$((") },
+ return ReductionResult {
+ .tokens = { Token::continuation(String::from_utf8_short_string("$(("sv)) },
.next_reduction = m_state.previous_reduction,
};
}
@@ -724,11 +724,11 @@ Lexer::ReductionResult Lexer::reduce_arithmetic_expansion()
if (m_lexer.peek() == ')' && m_state.buffer.string_view().ends_with(')')) {
m_state.buffer.append(consume());
auto& expansion = m_state.expansions.last().get<ArithmeticExpansion>();
- expansion.expression = expansion.value.to_deprecated_string().substring(0, expansion.value.length() - 1);
+ expansion.expression = TRY(String::from_utf8(expansion.value.string_view().substring_view(0, expansion.value.length() - 1)));
expansion.value.clear();
expansion.range.length = m_state.position.end_offset - expansion.range.start - m_state.position.start_offset;
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = m_state.previous_reduction,
};
@@ -737,13 +737,13 @@ Lexer::ReductionResult Lexer::reduce_arithmetic_expansion()
auto ch = consume();
m_state.buffer.append(ch);
m_state.expansions.last().get<ArithmeticExpansion>().value.append(ch);
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::ArithmeticExpansion,
};
}
-Lexer::ReductionResult Lexer::reduce_special_parameter_expansion()
+ErrorOr<Lexer::ReductionResult> Lexer::reduce_special_parameter_expansion()
{
auto ch = consume();
m_state.buffer.append(ch);
@@ -755,18 +755,18 @@ Lexer::ReductionResult Lexer::reduce_special_parameter_expansion()
expansion.parameter.append(ch);
expansion.range.length = m_state.position.end_offset - expansion.range.start - m_state.position.start_offset;
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = m_state.previous_reduction,
};
}
-Lexer::ReductionResult Lexer::reduce_parameter_expansion()
+ErrorOr<Lexer::ReductionResult> Lexer::reduce_parameter_expansion()
{
auto& expansion = m_state.expansions.last().get<ParameterExpansion>();
if (m_lexer.is_eof()) {
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::Start,
};
@@ -778,7 +778,7 @@ Lexer::ReductionResult Lexer::reduce_parameter_expansion()
expansion.parameter.append(next);
expansion.range.length = m_state.position.end_offset - expansion.range.start - m_state.position.start_offset;
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::ParameterExpansion,
};
@@ -787,11 +787,11 @@ Lexer::ReductionResult Lexer::reduce_parameter_expansion()
return reduce(m_state.previous_reduction);
}
-Lexer::ReductionResult Lexer::reduce_command_or_arithmetic_substitution_expansion()
+ErrorOr<Lexer::ReductionResult> Lexer::reduce_command_or_arithmetic_substitution_expansion()
{
if (m_lexer.is_eof()) {
- return {
- .tokens = { Token::continuation("$(") },
+ return ReductionResult {
+ .tokens = { Token::continuation(String::from_utf8_short_string("$("sv)) },
.next_reduction = m_state.previous_reduction,
};
}
@@ -800,11 +800,11 @@ Lexer::ReductionResult Lexer::reduce_command_or_arithmetic_substitution_expansio
if (ch == '(' && m_state.buffer.string_view().ends_with("$("sv)) {
m_state.buffer.append(consume());
m_state.expansions.last() = ArithmeticExpansion {
- .expression = "",
+ .expression = {},
.value = StringBuilder {},
.range = range(-2)
};
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::ArithmeticExpansion,
};
@@ -815,7 +815,7 @@ Lexer::ReductionResult Lexer::reduce_command_or_arithmetic_substitution_expansio
m_state.expansions.last().visit([&](auto& expansion) {
expansion.range.length = m_state.position.end_offset - expansion.range.start - m_state.position.start_offset;
});
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = m_state.previous_reduction,
};
@@ -823,19 +823,19 @@ Lexer::ReductionResult Lexer::reduce_command_or_arithmetic_substitution_expansio
m_state.buffer.append(consume());
m_state.expansions.last().get<CommandExpansion>().command.append(ch);
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::CommandOrArithmeticSubstitutionExpansion,
};
}
-Lexer::ReductionResult Lexer::reduce_extended_parameter_expansion()
+ErrorOr<Lexer::ReductionResult> Lexer::reduce_extended_parameter_expansion()
{
auto& expansion = m_state.expansions.last().get<ParameterExpansion>();
if (m_lexer.is_eof()) {
- return {
- .tokens = { Token::continuation("${") },
+ return ReductionResult {
+ .tokens = { Token::continuation(String::from_utf8_short_string("${"sv)) },
.next_reduction = m_state.previous_reduction,
};
}
@@ -845,7 +845,7 @@ Lexer::ReductionResult Lexer::reduce_extended_parameter_expansion()
m_state.buffer.append(consume());
expansion.range.length = m_state.position.end_offset - expansion.range.start - m_state.position.start_offset;
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = m_state.previous_reduction,
};
@@ -855,7 +855,7 @@ Lexer::ReductionResult Lexer::reduce_extended_parameter_expansion()
expansion.parameter.append(ch);
expansion.range.length = m_state.position.end_offset - expansion.range.start - m_state.position.start_offset;
- return {
+ return ReductionResult {
.tokens = {},
.next_reduction = Reduction::ExtendedParameterExpansion,
};
diff --git a/Userland/Shell/PosixLexer.h b/Userland/Shell/PosixLexer.h
index 3c002b6db7..9a69689a1a 100644
--- a/Userland/Shell/PosixLexer.h
+++ b/Userland/Shell/PosixLexer.h
@@ -6,9 +6,9 @@
#pragma once
-#include <AK/DeprecatedString.h>
#include <AK/GenericLexer.h>
#include <AK/Queue.h>
+#include <AK/String.h>
#include <AK/Variant.h>
#include <AK/Vector.h>
#include <Shell/AST.h>
@@ -51,7 +51,7 @@ struct CommandExpansion {
};
struct ArithmeticExpansion {
- DeprecatedString expression;
+ String expression;
StringBuilder value;
ExpansionRange range;
};
@@ -59,8 +59,8 @@ struct ArithmeticExpansion {
using Expansion = Variant<ParameterExpansion, CommandExpansion, ArithmeticExpansion>;
struct ResolvedParameterExpansion {
- DeprecatedString parameter;
- DeprecatedString argument;
+ String parameter;
+ String argument;
ExpansionRange range;
enum class Op {
UseDefaultValue, // ${parameter:-word}
@@ -182,7 +182,7 @@ struct ResolvedCommandExpansion {
using ResolvedExpansion = Variant<ResolvedParameterExpansion, ResolvedCommandExpansion>;
struct HeredocEntry {
- DeprecatedString key;
+ String key;
bool allow_interpolation;
bool dedent;
};
@@ -257,27 +257,27 @@ struct Token {
};
Type type;
- DeprecatedString value;
+ String value;
Optional<AST::Position> position;
Vector<Expansion> expansions;
Vector<ResolvedExpansion> resolved_expansions {};
StringView original_text;
- Optional<DeprecatedString> relevant_heredoc_key {};
+ Optional<String> relevant_heredoc_key {};
bool could_be_start_of_a_simple_command { false };
- static Vector<Token> maybe_from_state(State const& state)
+ static ErrorOr<Vector<Token>> maybe_from_state(State const& state)
{
if (state.buffer.is_empty() || state.buffer.string_view().trim_whitespace().is_empty())
- return {};
+ return Vector<Token> {};
auto token = Token {
.type = Type::Token,
- .value = state.buffer.to_deprecated_string(),
+ .value = TRY(state.buffer.to_string()),
.position = state.position,
.expansions = state.expansions,
.original_text = {},
};
- return { move(token) };
+ return Vector<Token> { move(token) };
}
static Optional<Token::Type> operator_from_name(StringView name)
@@ -320,14 +320,14 @@ struct Token {
return {};
}
- static Vector<Token> operators_from(State const& state)
+ static ErrorOr<Vector<Token>> operators_from(State const& state)
{
- auto name = state.buffer.string_view();
+ auto name = TRY(state.buffer.to_string());
auto type = operator_from_name(name);
if (!type.has_value())
- return {};
+ return Vector<Token> {};
- return {
+ return Vector {
Token {
.type = *type,
.value = name,
@@ -353,7 +353,7 @@ struct Token {
{
return {
.type = Type::Newline,
- .value = "\n",
+ .value = String::from_utf8_short_string("\n"sv),
.position = {},
.expansions = {},
.original_text = {},
@@ -364,14 +364,14 @@ struct Token {
{
return {
.type = Type::Continuation,
- .value = DeprecatedString::formatted("{:c}", expected),
+ .value = String::from_code_point(expected),
.position = {},
.expansions = {},
.original_text = {},
};
}
- static Token continuation(DeprecatedString expected)
+ static Token continuation(String expected)
{
return {
.type = Type::Continuation,
@@ -392,10 +392,10 @@ public:
{
}
- Vector<Token> batch_next(Optional<Reduction> starting_reduction = {});
+ ErrorOr<Vector<Token>> batch_next(Optional<Reduction> starting_reduction = {});
struct HeredocKeyResult {
- DeprecatedString key;
+ String key;
bool allow_interpolation;
};
@@ -407,21 +407,21 @@ private:
Reduction next_reduction { Reduction::None };
};
- ReductionResult reduce(Reduction);
- ReductionResult reduce_end();
- ReductionResult reduce_operator();
- ReductionResult reduce_comment();
- ReductionResult reduce_single_quoted_string();
- ReductionResult reduce_double_quoted_string();
- ReductionResult reduce_expansion();
- ReductionResult reduce_command_expansion();
- ReductionResult reduce_start();
- ReductionResult reduce_arithmetic_expansion();
- ReductionResult reduce_special_parameter_expansion();
- ReductionResult reduce_parameter_expansion();
- ReductionResult reduce_command_or_arithmetic_substitution_expansion();
- ReductionResult reduce_extended_parameter_expansion();
- ReductionResult reduce_heredoc_contents();
+ ErrorOr<ReductionResult> reduce(Reduction);
+ ErrorOr<ReductionResult> reduce_end();
+ ErrorOr<ReductionResult> reduce_operator();
+ ErrorOr<ReductionResult> reduce_comment();
+ ErrorOr<ReductionResult> reduce_single_quoted_string();
+ ErrorOr<ReductionResult> reduce_double_quoted_string();
+ ErrorOr<ReductionResult> reduce_expansion();
+ ErrorOr<ReductionResult> reduce_command_expansion();
+ ErrorOr<ReductionResult> reduce_start();
+ ErrorOr<ReductionResult> reduce_arithmetic_expansion();
+ ErrorOr<ReductionResult> reduce_special_parameter_expansion();
+ ErrorOr<ReductionResult> reduce_parameter_expansion();
+ ErrorOr<ReductionResult> reduce_command_or_arithmetic_substitution_expansion();
+ ErrorOr<ReductionResult> reduce_extended_parameter_expansion();
+ ErrorOr<ReductionResult> reduce_heredoc_contents();
char consume();
bool consume_specific(char);
diff --git a/Userland/Shell/PosixParser.cpp b/Userland/Shell/PosixParser.cpp
index fea91a5b95..59607730f0 100644
--- a/Userland/Shell/PosixParser.cpp
+++ b/Userland/Shell/PosixParser.cpp
@@ -101,10 +101,10 @@ static inline bool is_valid_name(StringView word)
}
namespace Shell::Posix {
-void Parser::fill_token_buffer(Optional<Reduction> starting_reduction)
+ErrorOr<void> Parser::fill_token_buffer(Optional<Reduction> starting_reduction)
{
for (;;) {
- auto token = next_expanded_token(starting_reduction);
+ auto token = TRY(next_expanded_token(starting_reduction));
if (!token.has_value())
break;
#if SHELL_POSIX_PARSER_DEBUG
@@ -125,11 +125,13 @@ void Parser::fill_token_buffer(Optional<Reduction> starting_reduction)
#endif
}
m_token_index = 0;
+
+ return {};
}
RefPtr<AST::Node> Parser::parse()
{
- return parse_complete_command();
+ return parse_complete_command().release_value_but_fixme_should_propagate_errors();
}
void Parser::handle_heredoc_contents()
@@ -147,7 +149,7 @@ void Parser::handle_heredoc_contents()
RefPtr<AST::Node> contents;
if (heredoc.allow_interpolation()) {
Parser parser { token.value, m_in_interactive_mode, Reduction::HeredocContents };
- contents = parser.parse_word();
+ contents = parser.parse_word().release_value_but_fixme_should_propagate_errors();
} else {
contents = make_ref_counted<AST::StringLiteral>(token.position.value_or(empty_position()), String::from_utf8(token.value).release_value_but_fixme_should_propagate_errors(), AST::StringLiteral::EnclosureType::None);
}
@@ -158,16 +160,16 @@ void Parser::handle_heredoc_contents()
}
}
-Optional<Token> Parser::next_expanded_token(Optional<Reduction> starting_reduction)
+ErrorOr<Optional<Token>> Parser::next_expanded_token(Optional<Reduction> starting_reduction)
{
while (m_token_buffer.find_if([](auto& token) { return token.type == Token::Type::Eof; }).is_end()) {
- auto tokens = m_lexer.batch_next(starting_reduction);
+ auto tokens = TRY(m_lexer.batch_next(starting_reduction));
auto expanded = perform_expansions(move(tokens));
m_token_buffer.extend(expanded);
}
if (m_token_buffer.size() == m_token_index)
- return {};
+ return OptionalNone {};
return m_token_buffer[m_token_index++];
}
@@ -297,7 +299,7 @@ Vector<Token> Parser::perform_expansions(Vector<Token> tokens)
continue;
}
- if (is_io_operator(token) && previous_token->type == Token::Type::Word && all_of(previous_token->value, is_ascii_digit)) {
+ if (is_io_operator(token) && previous_token->type == Token::Type::Word && all_of(previous_token->value.bytes_as_string_view(), is_ascii_digit)) {
previous_token->type = Token::Type::IoNumber;
}
@@ -339,8 +341,8 @@ Vector<Token> Parser::perform_expansions(Vector<Token> tokens)
// Check if we're in a command prefix (could be an assignment)
if (!m_disallow_command_prefix && token.type == Token::Type::Word && token.value.contains('=')) {
// If the word before '=' is a valid name, this is an assignment
- auto parts = token.value.split_limit('=', 2);
- if (is_valid_name(parts[0]))
+ auto equal_offset = *token.value.find_byte_offset('=');
+ if (is_valid_name(token.value.bytes_as_string_view().substring_view(0, equal_offset)))
token.type = Token::Type::AssignmentWord;
else
m_disallow_command_prefix = true;
@@ -368,7 +370,7 @@ Vector<Token> Parser::perform_expansions(Vector<Token> tokens)
// ${NUMBER}
if (all_of(text, is_ascii_digit)) {
return ResolvedParameterExpansion {
- .parameter = expansion.parameter.to_deprecated_string(),
+ .parameter = expansion.parameter.to_string().release_value_but_fixme_should_propagate_errors(),
.argument = {},
.range = expansion.range,
.op = ResolvedParameterExpansion::Op::GetPositionalParameter,
@@ -405,7 +407,7 @@ Vector<Token> Parser::perform_expansions(Vector<Token> tokens)
} else {
error(token, "Unknown parameter expansion: {}", text);
return ResolvedParameterExpansion {
- .parameter = expansion.parameter.to_deprecated_string(),
+ .parameter = expansion.parameter.to_string().release_value_but_fixme_should_propagate_errors(),
.argument = {},
.range = expansion.range,
.op = ResolvedParameterExpansion::Op::StringLength,
@@ -423,7 +425,7 @@ Vector<Token> Parser::perform_expansions(Vector<Token> tokens)
if (text.starts_with('#')) {
return ResolvedParameterExpansion {
- .parameter = text.substring_view(1).to_deprecated_string(),
+ .parameter = String::from_utf8(text.substring_view(1)).release_value_but_fixme_should_propagate_errors(),
.argument = {},
.range = expansion.range,
.op = ResolvedParameterExpansion::Op::StringLength,
@@ -464,7 +466,7 @@ Vector<Token> Parser::perform_expansions(Vector<Token> tokens)
default:
error(token, "Unknown parameter expansion: {}", text);
return ResolvedParameterExpansion {
- .parameter = parameter.to_deprecated_string(),
+ .parameter = String::from_utf8(parameter).release_value_but_fixme_should_propagate_errors(),
.argument = {},
.range = expansion.range,
.op = ResolvedParameterExpansion::Op::StringLength,
@@ -511,7 +513,7 @@ Vector<Token> Parser::perform_expansions(Vector<Token> tokens)
} else {
error(token, "Unknown parameter expansion: {}", text);
return ResolvedParameterExpansion {
- .parameter = parameter.to_deprecated_string(),
+ .parameter = String::from_utf8(parameter).release_value_but_fixme_should_propagate_errors(),
.argument = {},
.range = expansion.range,
.op = ResolvedParameterExpansion::Op::StringLength,
@@ -521,8 +523,8 @@ Vector<Token> Parser::perform_expansions(Vector<Token> tokens)
VERIFY(lexer.is_eof());
return ResolvedParameterExpansion {
- .parameter = parameter.to_deprecated_string(),
- .argument = argument.to_deprecated_string(),
+ .parameter = String::from_utf8(parameter).release_value_but_fixme_should_propagate_errors(),
+ .argument = String::from_utf8(argument).release_value_but_fixme_should_propagate_errors(),
.range = expansion.range,
.op = op,
.expand = ResolvedParameterExpansion::Expand::Word,
@@ -531,8 +533,8 @@ Vector<Token> Parser::perform_expansions(Vector<Token> tokens)
[&](ArithmeticExpansion const& expansion) -> ResolvedExpansion {
error(token, "Arithmetic expansion is not supported");
return ResolvedParameterExpansion {
- .parameter = ""sv,
- .argument = ""sv,
+ .parameter = {},
+ .argument = {},
.range = expansion.range,
.op = ResolvedParameterExpansion::Op::StringLength,
.expand = ResolvedParameterExpansion::Expand::Nothing,
@@ -621,15 +623,15 @@ Vector<Token> Parser::perform_expansions(Vector<Token> tokens)
return tokens;
}
-RefPtr<AST::Node> Parser::parse_complete_command()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_complete_command()
{
- auto list = [&] {
+ auto list = TRY([&]() -> ErrorOr<RefPtr<AST::Node>> {
// separator...
while (is_separator(peek()))
skip();
// list EOF
- auto list = parse_list();
+ auto list = TRY(parse_list());
if (eof())
return list;
@@ -651,7 +653,7 @@ RefPtr<AST::Node> Parser::parse_complete_command()
list = syntax_error;
return list;
- }();
+ }());
if (!list)
return nullptr;
@@ -659,7 +661,7 @@ RefPtr<AST::Node> Parser::parse_complete_command()
return make_ref_counted<AST::Execute>(list->position(), *list);
}
-RefPtr<AST::Node> Parser::parse_list()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_list()
{
NonnullRefPtrVector<AST::Node> nodes;
Vector<AST::Position> positions;
@@ -667,7 +669,7 @@ RefPtr<AST::Node> Parser::parse_list()
auto start_position = peek().position.value_or(empty_position());
for (;;) {
- auto new_node = parse_and_or();
+ auto new_node = TRY(parse_and_or());
if (!new_node)
break;
@@ -700,11 +702,11 @@ RefPtr<AST::Node> Parser::parse_list()
move(positions));
}
-RefPtr<AST::Node> Parser::parse_and_or()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_and_or()
{
- auto node = parse_pipeline();
+ auto node = TRY(parse_pipeline());
if (!node)
- return {};
+ return RefPtr<AST::Node> {};
for (;;) {
if (peek().type == Token::Type::AndIf) {
@@ -712,9 +714,9 @@ RefPtr<AST::Node> Parser::parse_and_or()
while (peek().type == Token::Type::Newline)
skip();
- auto rhs = parse_pipeline();
+ auto rhs = TRY(parse_pipeline());
if (!rhs)
- return {};
+ return RefPtr<AST::Node> {};
node = make_ref_counted<AST::And>(
node->position(),
*node,
@@ -727,9 +729,9 @@ RefPtr<AST::Node> Parser::parse_and_or()
while (peek().type == Token::Type::Newline)
skip();
- auto rhs = parse_pipeline();
+ auto rhs = TRY(parse_pipeline());
if (!rhs)
- return {};
+ return RefPtr<AST::Node> {};
node = make_ref_counted<AST::And>(
node->position(),
*node,
@@ -743,16 +745,16 @@ RefPtr<AST::Node> Parser::parse_and_or()
return node;
}
-RefPtr<AST::Node> Parser::parse_pipeline()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_pipeline()
{
return parse_pipe_sequence();
}
-RefPtr<AST::Node> Parser::parse_pipe_sequence()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_pipe_sequence()
{
- auto node = parse_command();
+ auto node = TRY(parse_command());
if (!node)
- return {};
+ return RefPtr<AST::Node> {};
for (;;) {
if (peek().type != Token::Type::Pipe)
@@ -762,9 +764,9 @@ RefPtr<AST::Node> Parser::parse_pipe_sequence()
while (peek().type == Token::Type::Newline)
skip();
- auto rhs = parse_command();
+ auto rhs = TRY(parse_command());
if (!rhs)
- return {};
+ return RefPtr<AST::Node> {};
node = make_ref_counted<AST::Pipe>(
node->position(),
*node,
@@ -774,20 +776,20 @@ RefPtr<AST::Node> Parser::parse_pipe_sequence()
return node;
}
-RefPtr<AST::Node> Parser::parse_command()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_command()
{
- auto node = [this] {
- if (auto node = parse_function_definition())
+ auto node = TRY([this]() -> ErrorOr<RefPtr<AST::Node>> {
+ if (auto node = TRY(parse_function_definition()))
return node;
- if (auto node = parse_simple_command())
+ if (auto node = TRY(parse_simple_command()))
return node;
- auto node = parse_compound_command();
+ auto node = TRY(parse_compound_command());
if (!node)
return node;
- if (auto list = parse_redirect_list()) {
+ if (auto list = TRY(parse_redirect_list())) {
auto position = list->position();
node = make_ref_counted<AST::Join>(
node->position().with_end(position),
@@ -796,7 +798,7 @@ RefPtr<AST::Node> Parser::parse_command()
}
return node;
- }();
+ }());
if (!node)
return nullptr;
@@ -804,7 +806,7 @@ RefPtr<AST::Node> Parser::parse_command()
return make_ref_counted<AST::CastToCommand>(node->position(), *node);
}
-RefPtr<AST::Node> Parser::parse_function_definition()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_function_definition()
{
// NAME OPEN_PAREN CLOSE_PAREN newline* function_body
@@ -828,7 +830,7 @@ RefPtr<AST::Node> Parser::parse_function_definition()
while (peek().type == Token::Type::Newline)
skip();
- auto body = parse_function_body();
+ auto body = TRY(parse_function_body());
if (!body)
return nullptr;
@@ -842,15 +844,15 @@ RefPtr<AST::Node> Parser::parse_function_definition()
body.release_nonnull());
}
-RefPtr<AST::Node> Parser::parse_function_body()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_function_body()
{
// compound_command redirect_list?
- auto node = parse_compound_command();
+ auto node = TRY(parse_compound_command());
if (!node)
return nullptr;
- if (auto list = parse_redirect_list()) {
+ if (auto list = TRY(parse_redirect_list())) {
auto position = list->position();
node = make_ref_counted<AST::Join>(
node->position().with_end(position),
@@ -861,14 +863,14 @@ RefPtr<AST::Node> Parser::parse_function_body()
return node;
}
-RefPtr<AST::Node> Parser::parse_redirect_list()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_redirect_list()
{
// io_redirect*
RefPtr<AST::Node> node;
for (;;) {
- auto new_node = parse_io_redirect();
+ auto new_node = TRY(parse_io_redirect());
if (!new_node)
break;
@@ -885,45 +887,45 @@ RefPtr<AST::Node> Parser::parse_redirect_list()
return node;
}
-RefPtr<AST::Node> Parser::parse_compound_command()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_compound_command()
{
- if (auto node = parse_brace_group())
+ if (auto node = TRY(parse_brace_group()))
return node;
- if (auto node = parse_subshell())
+ if (auto node = TRY(parse_subshell()))
return node;
- if (auto node = parse_if_clause())
+ if (auto node = TRY(parse_if_clause()))
return node;
- if (auto node = parse_for_clause())
+ if (auto node = TRY(parse_for_clause()))
return node;
- if (auto node = parse_case_clause())
+ if (auto node = TRY(parse_case_clause()))
return node;
- if (auto node = parse_while_clause())
+ if (auto node = TRY(parse_while_clause()))
return node;
- if (auto node = parse_until_clause())
+ if (auto node = TRY(parse_until_clause()))
return node;
- return {};
+ return nullptr;
}
-RefPtr<AST::Node> Parser::parse_while_clause()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_while_clause()
{
if (peek().type != Token::Type::While)
return nullptr;
auto start_position = consume().position.value_or(empty_position());
- auto condition = parse_compound_list();
+ auto condition = TRY(parse_compound_list());
if (!condition)
condition = make_ref_counted<AST::SyntaxError>(
peek().position.value_or(empty_position()),
String::from_utf8("Expected condition after 'while'"sv).release_value_but_fixme_should_propagate_errors());
- auto do_group = parse_do_group();
+ auto do_group = TRY(parse_do_group());
if (!do_group)
do_group = make_ref_counted<AST::SyntaxError>(
peek().position.value_or(empty_position()),
@@ -945,19 +947,19 @@ RefPtr<AST::Node> Parser::parse_while_clause()
AST::ContinuationControl::ContinuationKind::Break)));
}
-RefPtr<AST::Node> Parser::parse_until_clause()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_until_clause()
{
if (peek().type != Token::Type::Until)
return nullptr;
auto start_position = consume().position.value_or(empty_position());
- auto condition = parse_compound_list();
+ auto condition = TRY(parse_compound_list());
if (!condition)
condition = make_ref_counted<AST::SyntaxError>(
peek().position.value_or(empty_position()),
String::from_utf8("Expected condition after 'until'"sv).release_value_but_fixme_should_propagate_errors());
- auto do_group = parse_do_group();
+ auto do_group = TRY(parse_do_group());
if (!do_group)
do_group = make_ref_counted<AST::SyntaxError>(
peek().position.value_or(empty_position()),
@@ -979,14 +981,14 @@ RefPtr<AST::Node> Parser::parse_until_clause()
do_group.release_nonnull()));
}
-RefPtr<AST::Node> Parser::parse_brace_group()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_brace_group()
{
if (peek().type != Token::Type::OpenBrace)
return nullptr;
consume();
- auto list = parse_compound_list();
+ auto list = TRY(parse_compound_list());
RefPtr<AST::SyntaxError> error;
if (peek().type != Token::Type::CloseBrace) {
@@ -1007,7 +1009,7 @@ RefPtr<AST::Node> Parser::parse_brace_group()
return make_ref_counted<AST::Execute>(list->position(), *list);
}
-RefPtr<AST::Node> Parser::parse_case_clause()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_case_clause()
{
auto start_position = peek().position.value_or(empty_position());
if (peek().type != Token::Type::Case)
@@ -1016,7 +1018,7 @@ RefPtr<AST::Node> Parser::parse_case_clause()
skip();
RefPtr<AST::SyntaxError> syntax_error;
- auto expr = parse_word();
+ auto expr = TRY(parse_word());
if (!expr)
expr = make_ref_counted<AST::SyntaxError>(
peek().position.value_or(empty_position()),
@@ -1051,7 +1053,7 @@ RefPtr<AST::Node> Parser::parse_case_clause()
needs_dsemi = false;
}
- auto result = parse_case_list();
+ auto result = TRY(parse_case_list());
if (peek().type == Token::Type::CloseParen) {
skip();
@@ -1066,7 +1068,7 @@ RefPtr<AST::Node> Parser::parse_case_clause()
while (peek().type == Token::Type::Newline)
skip();
- auto compound_list = parse_compound_list();
+ auto compound_list = TRY(parse_compound_list());
if (peek().type == Token::Type::DoubleSemicolon) {
skip();
@@ -1115,7 +1117,7 @@ RefPtr<AST::Node> Parser::parse_case_clause()
return node;
}
-Parser::CaseItemsResult Parser::parse_case_list()
+ErrorOr<Parser::CaseItemsResult> Parser::parse_case_list()
{
// Just a list of words split by '|', delimited by ')'
NonnullRefPtrVector<AST::Node> nodes;
@@ -1128,7 +1130,7 @@ Parser::CaseItemsResult Parser::parse_case_list()
if (peek().type != Token::Type::Word)
break;
- auto node = parse_word();
+ auto node = TRY(parse_word());
if (!node)
node = make_ref_counted<AST::SyntaxError>(
peek().position.value_or(empty_position()),
@@ -1149,10 +1151,10 @@ Parser::CaseItemsResult Parser::parse_case_list()
peek().position.value_or(empty_position()),
String::formatted("Expected a word, not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors()));
- return { move(pipes), move(nodes) };
+ return CaseItemsResult { move(pipes), move(nodes) };
}
-RefPtr<AST::Node> Parser::parse_if_clause()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_if_clause()
{
// If compound_list Then compound_list {Elif compound_list Then compound_list (Fi|Else)?} [(?=Else) compound_list] (?!=Fi) Fi
auto start_position = peek().position.value_or(empty_position());
@@ -1160,7 +1162,7 @@ RefPtr<AST::Node> Parser::parse_if_clause()
return nullptr;
skip();
- auto main_condition = parse_compound_list();
+ auto main_condition = TRY(parse_compound_list());
if (!main_condition)
main_condition = make_ref_counted<AST::SyntaxError>(empty_position(), String::from_utf8("Expected compound list after 'if'"sv).release_value_but_fixme_should_propagate_errors());
@@ -1173,7 +1175,7 @@ RefPtr<AST::Node> Parser::parse_if_clause()
skip();
}
- auto main_consequence = parse_compound_list();
+ auto main_consequence = TRY(parse_compound_list());
if (!main_consequence)
main_consequence = make_ref_counted<AST::SyntaxError>(empty_position(), String::from_utf8("Expected compound list after 'then'"sv).release_value_but_fixme_should_propagate_errors());
@@ -1182,7 +1184,7 @@ RefPtr<AST::Node> Parser::parse_if_clause()
while (peek().type == Token::Type::Elif) {
skip();
- auto condition = parse_compound_list();
+ auto condition = TRY(parse_compound_list());
if (!condition)
condition = make_ref_counted<AST::SyntaxError>(empty_position(), String::from_utf8("Expected compound list after 'elif'"sv).release_value_but_fixme_should_propagate_errors());
@@ -1195,7 +1197,7 @@ RefPtr<AST::Node> Parser::parse_if_clause()
skip();
}
- auto consequence = parse_compound_list();
+ auto consequence = TRY(parse_compound_list());
if (!consequence)
consequence = make_ref_counted<AST::SyntaxError>(empty_position(), String::from_utf8("Expected compound list after 'then'"sv).release_value_but_fixme_should_propagate_errors());
@@ -1209,7 +1211,7 @@ RefPtr<AST::Node> Parser::parse_if_clause()
switch (peek().type) {
case Token::Type::Else:
skip();
- active_node->false_branch() = parse_compound_list();
+ active_node->false_branch() = TRY(parse_compound_list());
if (!active_node->false_branch())
active_node->false_branch() = make_ref_counted<AST::SyntaxError>(empty_position(), String::from_utf8("Expected compound list after 'else'"sv).release_value_but_fixme_should_propagate_errors());
break;
@@ -1241,7 +1243,7 @@ RefPtr<AST::Node> Parser::parse_if_clause()
return node;
}
-RefPtr<AST::Node> Parser::parse_subshell()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_subshell()
{
auto start_position = peek().position.value_or(empty_position());
if (peek().type != Token::Type::OpenParen)
@@ -1250,7 +1252,7 @@ RefPtr<AST::Node> Parser::parse_subshell()
skip();
RefPtr<AST::SyntaxError> error;
- auto list = parse_compound_list();
+ auto list = TRY(parse_compound_list());
if (!list)
error = make_ref_counted<AST::SyntaxError>(peek().position.value_or(empty_position()), String::from_utf8("Expected compound list after ("sv).release_value_but_fixme_should_propagate_errors());
@@ -1267,12 +1269,12 @@ RefPtr<AST::Node> Parser::parse_subshell()
list.release_nonnull());
}
-RefPtr<AST::Node> Parser::parse_compound_list()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_compound_list()
{
while (peek().type == Token::Type::Newline)
skip();
- auto term = parse_term();
+ auto term = TRY(parse_term());
if (!term)
return term;
@@ -1287,7 +1289,7 @@ RefPtr<AST::Node> Parser::parse_compound_list()
return term;
}
-RefPtr<AST::Node> Parser::parse_term()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_term()
{
NonnullRefPtrVector<AST::Node> nodes;
Vector<AST::Position> positions;
@@ -1295,7 +1297,7 @@ RefPtr<AST::Node> Parser::parse_term()
auto start_position = peek().position.value_or(empty_position());
for (;;) {
- auto new_node = parse_and_or();
+ auto new_node = TRY(parse_and_or());
if (!new_node)
break;
@@ -1317,7 +1319,7 @@ RefPtr<AST::Node> Parser::parse_term()
move(positions));
}
-RefPtr<AST::Node> Parser::parse_for_clause()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_for_clause()
{
// FOR NAME newline+ do_group
// FOR NAME newline+ IN separator do_group
@@ -1329,13 +1331,13 @@ RefPtr<AST::Node> Parser::parse_for_clause()
auto start_position = consume().position.value_or(empty_position());
- DeprecatedString name;
+ String name;
Optional<AST::Position> name_position;
if (peek().type == Token::Type::VariableName) {
name_position = peek().position;
name = consume().value;
} else {
- name = "it";
+ name = String::from_utf8_short_string("it"sv);
error(peek(), "Expected a variable name, not {}", peek().type_name());
}
@@ -1366,10 +1368,10 @@ RefPtr<AST::Node> Parser::parse_for_clause()
error(peek(), "Expected a semicolon, not {}", peek().type_name());
}
- auto body = parse_do_group();
+ auto body = TRY(parse_do_group());
return AST::make_ref_counted<AST::ForLoop>(
start_position.with_end(peek().position.value_or(empty_position())),
- AST::NameWithPosition { String::from_deprecated_string(name).release_value_but_fixme_should_propagate_errors(), name_position.value_or(empty_position()) },
+ AST::NameWithPosition { name, name_position.value_or(empty_position()) },
Optional<AST::NameWithPosition> {},
move(iterated_expression),
move(body),
@@ -1384,7 +1386,7 @@ RefPtr<AST::Node> Parser::parse_word_list()
auto start_position = peek().position.value_or(empty_position());
for (; peek().type == Token::Type::Word;) {
- auto word = parse_word();
+ auto word = parse_word().release_value_but_fixme_should_propagate_errors();
nodes.append(word.release_nonnull());
}
@@ -1393,7 +1395,7 @@ RefPtr<AST::Node> Parser::parse_word_list()
move(nodes));
}
-RefPtr<AST::Node> Parser::parse_word()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_word()
{
if (peek().type != Token::Type::Word)
return nullptr;
@@ -1407,20 +1409,22 @@ RefPtr<AST::Node> Parser::parse_word()
Double,
} in_quote { Quote::None };
- auto append_bareword = [&](StringView string) {
+ auto append_bareword = [&](StringView string) -> ErrorOr<void> {
if (!word && string.starts_with('~')) {
GenericLexer lexer { string };
lexer.ignore();
auto user = lexer.consume_while(is_ascii_alphanumeric);
string = lexer.remaining();
- word = make_ref_counted<AST::Tilde>(token.position.value_or(empty_position()), String::from_utf8(user).release_value_but_fixme_should_propagate_errors());
+ word = make_ref_counted<AST::Tilde>(token.position.value_or(empty_position()), TRY(String::from_utf8(user)));
}
if (string.is_empty())
- return;
+ return {};
- auto node = make_ref_counted<AST::BarewordLiteral>(token.position.value_or(empty_position()), String::from_utf8(string).release_value_but_fixme_should_propagate_errors());
+ auto node = make_ref_counted<AST::BarewordLiteral>(
+ token.position.value_or(empty_position()),
+ TRY(String::from_utf8(string)));
if (word) {
word = make_ref_counted<AST::Juxtaposition>(
@@ -1431,13 +1435,18 @@ RefPtr<AST::Node> Parser::parse_word()
} else {
word = move(node);
}
+
+ return {};
};
- auto append_string_literal = [&](StringView string) {
+ auto append_string_literal = [&](StringView string) -> ErrorOr<void> {
if (string.is_empty())
- return;
+ return {};
- auto node = make_ref_counted<AST::StringLiteral>(token.position.value_or(empty_position()), String::from_utf8(string).release_value_but_fixme_should_propagate_errors(), AST::StringLiteral::EnclosureType::SingleQuotes);
+ auto node = make_ref_counted<AST::StringLiteral>(
+ token.position.value_or(empty_position()),
+ TRY(String::from_utf8(string)),
+ AST::StringLiteral::EnclosureType::SingleQuotes);
if (word) {
word = make_ref_counted<AST::Juxtaposition>(
@@ -1448,13 +1457,18 @@ RefPtr<AST::Node> Parser::parse_word()
} else {
word = move(node);
}
+
+ return {};
};
- auto append_string_part = [&](StringView string) {
+ auto append_string_part = [&](StringView string) -> ErrorOr<void> {
if (string.is_empty())
- return;
+ return {};
- auto node = make_ref_counted<AST::StringLiteral>(token.position.value_or(empty_position()), String::from_utf8(string).release_value_but_fixme_should_propagate_errors(), AST::StringLiteral::EnclosureType::DoubleQuotes);
+ auto node = make_ref_counted<AST::StringLiteral>(
+ token.position.value_or(empty_position()),
+ TRY(String::from_utf8(string)),
+ AST::StringLiteral::EnclosureType::DoubleQuotes);
if (word) {
word = make_ref_counted<AST::Juxtaposition>(
@@ -1465,59 +1479,61 @@ RefPtr<AST::Node> Parser::parse_word()
} else {
word = move(node);
}
+
+ return {};
};
- auto append_parameter_expansion = [&](ResolvedParameterExpansion const& x) {
- DeprecatedString immediate_function_name;
+ auto append_parameter_expansion = [&](ResolvedParameterExpansion const& x) -> ErrorOr<void> {
+ StringView immediate_function_name;
RefPtr<AST::Node> node;
switch (x.op) {
case ResolvedParameterExpansion::Op::UseDefaultValue:
- immediate_function_name = "value_or_default";
+ immediate_function_name = "value_or_default"sv;
break;
case ResolvedParameterExpansion::Op::AssignDefaultValue:
- immediate_function_name = "assign_default";
+ immediate_function_name = "assign_default"sv;
break;
case ResolvedParameterExpansion::Op::IndicateErrorIfEmpty:
- immediate_function_name = "error_if_empty";
+ immediate_function_name = "error_if_empty"sv;
break;
case ResolvedParameterExpansion::Op::UseAlternativeValue:
- immediate_function_name = "null_or_alternative";
+ immediate_function_name = "null_or_alternative"sv;
break;
case ResolvedParameterExpansion::Op::UseDefaultValueIfUnset:
- immediate_function_name = "defined_value_or_default";
+ immediate_function_name = "defined_value_or_default"sv;
break;
case ResolvedParameterExpansion::Op::AssignDefaultValueIfUnset:
- immediate_function_name = "assign_defined_default";
+ immediate_function_name = "assign_defined_default"sv;
break;
case ResolvedParameterExpansion::Op::IndicateErrorIfUnset:
- immediate_function_name = "error_if_unset";
+ immediate_function_name = "error_if_unset"sv;
break;
case ResolvedParameterExpansion::Op::UseAlternativeValueIfUnset:
- immediate_function_name = "null_if_unset_or_alternative";
+ immediate_function_name = "null_if_unset_or_alternative"sv;
break;
case ResolvedParameterExpansion::Op::RemoveLargestSuffixByPattern:
// FIXME: Implement this
case ResolvedParameterExpansion::Op::RemoveSmallestSuffixByPattern:
- immediate_function_name = "remove_suffix";
+ immediate_function_name = "remove_suffix"sv;
break;
case ResolvedParameterExpansion::Op::RemoveLargestPrefixByPattern:
// FIXME: Implement this
case ResolvedParameterExpansion::Op::RemoveSmallestPrefixByPattern:
- immediate_function_name = "remove_prefix";
+ immediate_function_name = "remove_prefix"sv;
break;
case ResolvedParameterExpansion::Op::StringLength:
- immediate_function_name = "length_of_variable";
+ immediate_function_name = "length_of_variable"sv;
break;
case ResolvedParameterExpansion::Op::GetPositionalParameter:
case ResolvedParameterExpansion::Op::GetVariable:
node = make_ref_counted<AST::SimpleVariable>(
token.position.value_or(empty_position()),
- String::from_deprecated_string(x.parameter).release_value_but_fixme_should_propagate_errors());
+ x.parameter);
break;
case ResolvedParameterExpansion::Op::GetLastBackgroundPid:
node = make_ref_counted<AST::SyntaxError>(
token.position.value_or(empty_position()),
- String::from_utf8("$! not implemented"sv).release_value_but_fixme_should_propagate_errors());
+ TRY(String::from_utf8("$! not implemented"sv)));
break;
case ResolvedParameterExpansion::Op::GetPositionalParameterList:
node = make_ref_counted<AST::SpecialVariable>(
@@ -1527,7 +1543,7 @@ RefPtr<AST::Node> Parser::parse_word()
case ResolvedParameterExpansion::Op::GetCurrentOptionFlags:
node = make_ref_counted<AST::SyntaxError>(
token.position.value_or(empty_position()),
- String::from_utf8("The current option flags are not available in parameter expansions"sv).release_value_but_fixme_should_propagate_errors());
+ TRY(String::from_utf8("The current option flags are not available in parameter expansions"sv)));
break;
case ResolvedParameterExpansion::Op::GetPositionalParameterCount:
node = make_ref_counted<AST::SpecialVariable>(
@@ -1542,7 +1558,7 @@ RefPtr<AST::Node> Parser::parse_word()
case ResolvedParameterExpansion::Op::GetPositionalParameterListAsString:
node = make_ref_counted<AST::SyntaxError>(
token.position.value_or(empty_position()),
- String::from_utf8("$* not implemented"sv).release_value_but_fixme_should_propagate_errors());
+ TRY(String::from_utf8("$* not implemented"sv)));
break;
case ResolvedParameterExpansion::Op::GetShellProcessId:
node = make_ref_counted<AST::SpecialVariable>(
@@ -1555,17 +1571,17 @@ RefPtr<AST::Node> Parser::parse_word()
NonnullRefPtrVector<AST::Node> arguments;
arguments.append(make_ref_counted<AST::BarewordLiteral>(
token.position.value_or(empty_position()),
- String::from_deprecated_string(x.parameter).release_value_but_fixme_should_propagate_errors()));
+ x.parameter));
if (!x.argument.is_empty()) {
// dbgln("Will parse {}", x.argument);
- arguments.append(*Parser { x.argument }.parse_word());
+ arguments.append(*TRY(Parser { x.argument }.parse_word()));
}
node = make_ref_counted<AST::ImmediateExpression>(
token.position.value_or(empty_position()),
AST::NameWithPosition {
- String::from_deprecated_string(immediate_function_name).release_value_but_fixme_should_propagate_errors(),
+ TRY(String::from_utf8(immediate_function_name)),
token.position.value_or(empty_position()),
},
move(arguments),
@@ -1576,7 +1592,7 @@ RefPtr<AST::Node> Parser::parse_word()
node = make_ref_counted<AST::ImmediateExpression>(
token.position.value_or(empty_position()),
AST::NameWithPosition {
- String::from_utf8("reexpand"sv).release_value_but_fixme_should_propagate_errors(),
+ TRY(String::from_utf8("reexpand"sv)),
token.position.value_or(empty_position()),
},
Vector { node.release_nonnull() },
@@ -1592,11 +1608,13 @@ RefPtr<AST::Node> Parser::parse_word()
} else {
word = move(node);
}
+
+ return {};
};
- auto append_command_expansion = [&](ResolvedCommandExpansion const& x) {
+ auto append_command_expansion = [&](ResolvedCommandExpansion const& x) -> ErrorOr<void> {
if (!x.command)
- return;
+ return {};
RefPtr<AST::Execute> execute_node;
@@ -1619,11 +1637,13 @@ RefPtr<AST::Node> Parser::parse_word()
} else {
word = move(execute_node);
}
+
+ return {};
};
- auto append_string = [&](StringView string) {
+ auto append_string = [&](StringView string) -> ErrorOr<void> {
if (string.is_empty())
- return;
+ return {};
Optional<size_t> run_start;
auto escape = false;
@@ -1641,7 +1661,7 @@ RefPtr<AST::Node> Parser::parse_word()
case '\'':
if (in_quote == Quote::Single) {
in_quote = Quote::None;
- append_string_literal(string.substring_view(*run_start, i - *run_start));
+ TRY(append_string_literal(string.substring_view(*run_start, i - *run_start)));
run_start = i + 1;
continue;
}
@@ -1659,12 +1679,12 @@ RefPtr<AST::Node> Parser::parse_word()
if (ch == '"' && in_quote == Quote::Double) {
in_quote = Quote::None;
if (run_start.has_value())
- append_string_part(string.substring_view(*run_start, i - *run_start));
+ TRY(append_string_part(string.substring_view(*run_start, i - *run_start)));
run_start = i + 1;
continue;
}
if (run_start.has_value())
- append_bareword(string.substring_view(*run_start, i - *run_start));
+ TRY(append_bareword(string.substring_view(*run_start, i - *run_start)));
in_quote = ch == '\'' ? Quote::Single : Quote::Double;
run_start = i + 1;
}
@@ -1679,55 +1699,59 @@ RefPtr<AST::Node> Parser::parse_word()
}
if (run_start.has_value())
- append_bareword(string.substring_view(*run_start, string.length() - *run_start));
+ TRY(append_bareword(string.substring_view(*run_start, string.length() - *run_start)));
+
+ return {};
};
if (!token.resolved_expansions.is_empty())
dbgln_if(SHELL_POSIX_PARSER_DEBUG, "Expanding '{}' with {} expansion entries", token.value, token.resolved_expansions.size());
+
size_t current_offset = 0;
+ auto value_bytes = token.value.bytes_as_string_view();
for (auto& expansion : token.resolved_expansions) {
- expansion.visit(
- [&](ResolvedParameterExpansion const& x) {
+ TRY(expansion.visit(
+ [&](ResolvedParameterExpansion const& x) -> ErrorOr<void> {
dbgln_if(SHELL_POSIX_PARSER_DEBUG, " Expanding '{}' ({}+{})", x.to_deprecated_string(), x.range.start, x.range.length);
- if (x.range.start >= token.value.length()) {
- dbgln("Parameter expansion range {}-{} is out of bounds for '{}'", x.range.start, x.range.length, token.value);
- return;
+ if (x.range.start >= value_bytes.length()) {
+ dbgln("Parameter expansion range {}-{} is out of bounds for '{}'", x.range.start, x.range.length, value_bytes);
+ return {};
}
if (x.range.start != current_offset) {
- append_string(token.value.substring_view(current_offset, x.range.start - current_offset));
+ TRY(append_string(value_bytes.substring_view(current_offset, x.range.start - current_offset)));
current_offset = x.range.start;
}
current_offset += x.range.length;
- append_parameter_expansion(x);
+ return append_parameter_expansion(x);
},
- [&](ResolvedCommandExpansion const& x) {
- if (x.range.start >= token.value.length()) {
- dbgln("Parameter expansion range {}-{} is out of bounds for '{}'", x.range.start, x.range.length, token.value);
- return;
+ [&](ResolvedCommandExpansion const& x) -> ErrorOr<void> {
+ if (x.range.start >= value_bytes.length()) {
+ dbgln("Parameter expansion range {}-{} is out of bounds for '{}'", x.range.start, x.range.length, value_bytes);
+ return {};
}
if (x.range.start != current_offset) {
- append_string(token.value.substring_view(current_offset, x.range.start - current_offset));
+ TRY(append_string(value_bytes.substring_view(current_offset, x.range.start - current_offset)));
current_offset = x.range.start;
}
current_offset += x.range.length;
- append_command_expansion(x);
- });
+ return append_command_expansion(x);
+ }));
}
- if (current_offset > token.value.length()) {
- dbgln("Parameter expansion range {}- is out of bounds for '{}'", current_offset, token.value);
+ if (current_offset > value_bytes.length()) {
+ dbgln("Parameter expansion range {}- is out of bounds for '{}'", current_offset, value_bytes);
return word;
}
- if (current_offset != token.value.length())
- append_string(token.value.substring_view(current_offset));
+ if (current_offset != value_bytes.length())
+ TRY(append_string(value_bytes.substring_view(current_offset)));
return word;
}
-RefPtr<AST::Node> Parser::parse_do_group()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_do_group()
{
if (peek().type != Token::Type::Do) {
return make_ref_counted<AST::SyntaxError>(
@@ -1737,7 +1761,7 @@ RefPtr<AST::Node> Parser::parse_do_group()
consume();
- auto list = parse_compound_list();
+ auto list = TRY(parse_compound_list());
RefPtr<AST::SyntaxError> error;
if (peek().type != Token::Type::Done) {
@@ -1758,15 +1782,15 @@ RefPtr<AST::Node> Parser::parse_do_group()
return make_ref_counted<AST::Execute>(list->position(), *list);
}
-RefPtr<AST::Node> Parser::parse_simple_command()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_simple_command()
{
auto start_position = peek().position.value_or(empty_position());
- Vector<DeprecatedString> definitions;
+ Vector<String> definitions;
NonnullRefPtrVector<AST::Node> nodes;
for (;;) {
- if (auto io_redirect = parse_io_redirect())
+ if (auto io_redirect = TRY(parse_io_redirect()))
nodes.append(*io_redirect);
else
break;
@@ -1779,7 +1803,7 @@ RefPtr<AST::Node> Parser::parse_simple_command()
nodes.append(
make_ref_counted<AST::BarewordLiteral>(
peek().position.value_or(empty_position()),
- String::from_deprecated_string(consume().value).release_value_but_fixme_should_propagate_errors()));
+ consume().value));
} else {
// env (assignments) (command)
nodes.append(make_ref_counted<AST::BarewordLiteral>(
@@ -1789,7 +1813,7 @@ RefPtr<AST::Node> Parser::parse_simple_command()
nodes.append(
make_ref_counted<AST::BarewordLiteral>(
peek().position.value_or(empty_position()),
- String::from_deprecated_string(consume().value).release_value_but_fixme_should_propagate_errors()));
+ consume().value));
}
}
@@ -1801,13 +1825,15 @@ RefPtr<AST::Node> Parser::parse_simple_command()
if (!nodes.is_empty()) {
Vector<AST::VariableDeclarations::Variable> variables;
for (auto& definition : definitions) {
- auto parts = definition.split_limit('=', 2, SplitBehavior::KeepEmpty);
+ auto equal_offset = definition.find_byte_offset('=');
+ auto split_offset = equal_offset.value_or(definition.bytes().size());
auto name = make_ref_counted<AST::BarewordLiteral>(
empty_position(),
- String::from_deprecated_string(parts[0]).release_value_but_fixme_should_propagate_errors());
+ definition.substring_from_byte_offset_with_shared_superstring(0, split_offset).release_value_but_fixme_should_propagate_errors());
+
auto value = make_ref_counted<AST::BarewordLiteral>(
empty_position(),
- String::from_deprecated_string(parts.size() > 1 ? parts[1] : "").release_value_but_fixme_should_propagate_errors());
+ definition.substring_from_byte_offset_with_shared_superstring(equal_offset.map([](auto x) { return x + 1; }).value_or(definition.bytes().size())).release_value_but_fixme_should_propagate_errors());
variables.append({ move(name), move(value) });
}
@@ -1820,7 +1846,7 @@ RefPtr<AST::Node> Parser::parse_simple_command()
// auto first = true;
for (;;) {
if (peek().type == Token::Type::Word) {
- auto new_word = parse_word();
+ auto new_word = TRY(parse_word());
if (!new_word)
break;
@@ -1837,7 +1863,7 @@ RefPtr<AST::Node> Parser::parse_simple_command()
// }
nodes.append(new_word.release_nonnull());
- } else if (auto io_redirect = parse_io_redirect()) {
+ } else if (auto io_redirect = TRY(parse_io_redirect())) {
nodes.append(io_redirect.release_nonnull());
} else {
break;
@@ -1851,7 +1877,7 @@ RefPtr<AST::Node> Parser::parse_simple_command()
return node;
}
-RefPtr<AST::Node> Parser::parse_io_redirect()
+ErrorOr<RefPtr<AST::Node>> Parser::parse_io_redirect()
{
auto start_position = peek().position.value_or(empty_position());
auto start_index = m_token_index;
@@ -1860,19 +1886,19 @@ RefPtr<AST::Node> Parser::parse_io_redirect()
Optional<int> io_number;
if (peek().type == Token::Type::IoNumber)
- io_number = consume().value.to_int(TrimWhitespace::No);
+ io_number = consume().value.bytes_as_string_view().to_int();
- if (auto io_file = parse_io_file(start_position, io_number))
+ if (auto io_file = TRY(parse_io_file(start_position, io_number)))
return io_file;
- if (auto io_here = parse_io_here(start_position, io_number))
+ if (auto io_here = TRY(parse_io_here(start_position, io_number)))
return io_here;
m_token_index = start_index;
return nullptr;
}
-RefPtr<AST::Node> Parser::parse_io_here(AST::Position start_position, Optional<int> fd)
+ErrorOr<RefPtr<AST::Node>> Parser::parse_io_here(AST::Position start_position, Optional<int> fd)
{
// io_here: IO_NUMBER? (DLESS | DLESSDASH) WORD
auto io_operator = peek().type;
@@ -1893,7 +1919,7 @@ RefPtr<AST::Node> Parser::parse_io_here(AST::Position start_position, Optional<i
auto position = start_position.with_end(peek().position.value_or(empty_position()));
auto result = make_ref_counted<AST::Heredoc>(
position,
- String::from_deprecated_string(end_keyword_text).release_value_but_fixme_should_propagate_errors(),
+ end_keyword_text,
allow_interpolation,
io_operator == Token::Type::DoubleLessDash,
Optional<int> { redirection_fd });
@@ -1906,7 +1932,7 @@ RefPtr<AST::Node> Parser::parse_io_here(AST::Position start_position, Optional<i
return result;
}
-RefPtr<AST::Node> Parser::parse_io_file(AST::Position start_position, Optional<int> fd)
+ErrorOr<RefPtr<AST::Node>> Parser::parse_io_file(AST::Position start_position, Optional<int> fd)
{
auto start_index = m_token_index;
@@ -1919,7 +1945,7 @@ RefPtr<AST::Node> Parser::parse_io_file(AST::Position start_position, Optional<i
auto io_operator_token = consume();
- auto word = parse_word();
+ auto word = TRY(parse_word());
if (!word) {
m_token_index = start_index;
return nullptr;
diff --git a/Userland/Shell/PosixParser.h b/Userland/Shell/PosixParser.h
index 3ffebaa347..06a79426d9 100644
--- a/Userland/Shell/PosixParser.h
+++ b/Userland/Shell/PosixParser.h
@@ -18,7 +18,7 @@ public:
, m_in_interactive_mode(interactive)
, m_eof_token(Token::eof())
{
- fill_token_buffer(starting_reduction);
+ (void)fill_token_buffer(starting_reduction);
}
RefPtr<AST::Node> parse();
@@ -31,9 +31,9 @@ public:
auto& errors() const { return m_errors; }
private:
- Optional<Token> next_expanded_token(Optional<Reduction> starting_reduction = {});
+ ErrorOr<Optional<Token>> next_expanded_token(Optional<Reduction> starting_reduction = {});
Vector<Token> perform_expansions(Vector<Token> tokens);
- void fill_token_buffer(Optional<Reduction> starting_reduction = {});
+ ErrorOr<void> fill_token_buffer(Optional<Reduction> starting_reduction = {});
void handle_heredoc_contents();
Token const& peek()
@@ -66,34 +66,34 @@ private:
NonnullRefPtrVector<AST::Node> nodes;
};
- RefPtr<AST::Node> parse_complete_command();
- RefPtr<AST::Node> parse_list();
- RefPtr<AST::Node> parse_and_or();
- RefPtr<AST::Node> parse_pipeline();
- RefPtr<AST::Node> parse_pipe_sequence();
- RefPtr<AST::Node> parse_command();
- RefPtr<AST::Node> parse_compound_command();
- RefPtr<AST::Node> parse_subshell();
- RefPtr<AST::Node> parse_compound_list();
- RefPtr<AST::Node> parse_term();
- RefPtr<AST::Node> parse_for_clause();
- RefPtr<AST::Node> parse_case_clause();
- CaseItemsResult parse_case_list();
- RefPtr<AST::Node> parse_if_clause();
- RefPtr<AST::Node> parse_while_clause();
- RefPtr<AST::Node> parse_until_clause();
- RefPtr<AST::Node> parse_function_definition();
- RefPtr<AST::Node> parse_function_body();
- RefPtr<AST::Node> parse_brace_group();
- RefPtr<AST::Node> parse_do_group();
- RefPtr<AST::Node> parse_simple_command();
- RefPtr<AST::Node> parse_prefix();
- RefPtr<AST::Node> parse_suffix();
- RefPtr<AST::Node> parse_io_redirect();
- RefPtr<AST::Node> parse_redirect_list();
- RefPtr<AST::Node> parse_io_file(AST::Position, Optional<int> fd);
- RefPtr<AST::Node> parse_io_here(AST::Position, Optional<int> fd);
- RefPtr<AST::Node> parse_word();
+ ErrorOr<RefPtr<AST::Node>> parse_complete_command();
+ ErrorOr<RefPtr<AST::Node>> parse_list();
+ ErrorOr<RefPtr<AST::Node>> parse_and_or();
+ ErrorOr<RefPtr<AST::Node>> parse_pipeline();
+ ErrorOr<RefPtr<AST::Node>> parse_pipe_sequence();
+ ErrorOr<RefPtr<AST::Node>> parse_command();
+ ErrorOr<RefPtr<AST::Node>> parse_compound_command();
+ ErrorOr<RefPtr<AST::Node>> parse_subshell();
+ ErrorOr<RefPtr<AST::Node>> parse_compound_list();
+ ErrorOr<RefPtr<AST::Node>> parse_term();
+ ErrorOr<RefPtr<AST::Node>> parse_for_clause();
+ ErrorOr<RefPtr<AST::Node>> parse_case_clause();
+ ErrorOr<RefPtr<AST::Node>> parse_if_clause();
+ ErrorOr<RefPtr<AST::Node>> parse_while_clause();
+ ErrorOr<RefPtr<AST::Node>> parse_until_clause();
+ ErrorOr<RefPtr<AST::Node>> parse_function_definition();
+ ErrorOr<RefPtr<AST::Node>> parse_function_body();
+ ErrorOr<RefPtr<AST::Node>> parse_brace_group();
+ ErrorOr<RefPtr<AST::Node>> parse_do_group();
+ ErrorOr<RefPtr<AST::Node>> parse_simple_command();
+ ErrorOr<RefPtr<AST::Node>> parse_prefix();
+ ErrorOr<RefPtr<AST::Node>> parse_suffix();
+ ErrorOr<RefPtr<AST::Node>> parse_io_redirect();
+ ErrorOr<RefPtr<AST::Node>> parse_redirect_list();
+ ErrorOr<RefPtr<AST::Node>> parse_io_file(AST::Position, Optional<int> fd);
+ ErrorOr<RefPtr<AST::Node>> parse_io_here(AST::Position, Optional<int> fd);
+ ErrorOr<RefPtr<AST::Node>> parse_word();
+ ErrorOr<CaseItemsResult> parse_case_list();
template<typename... Ts>
void error(Token const& token, CheckedFormatString<Ts...> fmt, Ts&&... args)
@@ -111,7 +111,7 @@ private:
Vector<Token> m_previous_token_buffer;
Vector<Error> m_errors;
- HashMap<DeprecatedString, NonnullRefPtr<AST::Heredoc>> m_unprocessed_heredoc_entries;
+ HashMap<String, NonnullRefPtr<AST::Heredoc>> m_unprocessed_heredoc_entries;
Token m_eof_token;