diff options
-rw-r--r-- | Userland/Shell/PosixLexer.cpp | 186 | ||||
-rw-r--r-- | Userland/Shell/PosixLexer.h | 70 | ||||
-rw-r--r-- | Userland/Shell/PosixParser.cpp | 370 | ||||
-rw-r--r-- | Userland/Shell/PosixParser.h | 64 |
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; |