/* * Copyright (c) 2022, Ali Mohammad Pur * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include namespace Shell::Posix { class Parser { public: Parser(StringView input, bool interactive = false, Optional starting_reduction = {}) : m_lexer(input) , m_in_interactive_mode(interactive) , m_eof_token(Token::eof()) { (void)fill_token_buffer(starting_reduction); } RefPtr parse(); RefPtr parse_word_list(); struct Error { DeprecatedString message; Optional position; }; auto& errors() const { return m_errors; } private: ErrorOr> next_expanded_token(Optional starting_reduction = {}); Vector perform_expansions(Vector tokens); ErrorOr fill_token_buffer(Optional starting_reduction = {}); void handle_heredoc_contents(); Token const& peek() { if (eof()) return m_eof_token; handle_heredoc_contents(); return m_token_buffer[m_token_index]; } Token const& consume() { if (eof()) return m_eof_token; handle_heredoc_contents(); return m_token_buffer[m_token_index++]; } void skip() { if (eof()) return; handle_heredoc_contents(); m_token_index++; } bool eof() const { return m_token_index == m_token_buffer.size() || m_token_buffer[m_token_index].type == Token::Type::Eof; } struct CaseItemsResult { Vector pipe_positions; Vector> nodes; }; ErrorOr> parse_complete_command(); ErrorOr> parse_list(); ErrorOr> parse_and_or(); ErrorOr> parse_pipeline(); ErrorOr> parse_pipe_sequence(); ErrorOr> parse_command(); ErrorOr> parse_compound_command(); ErrorOr> parse_subshell(); ErrorOr> parse_compound_list(); ErrorOr> parse_term(); ErrorOr> parse_for_clause(); ErrorOr> parse_case_clause(); ErrorOr> parse_if_clause(); ErrorOr> parse_while_clause(); ErrorOr> parse_until_clause(); ErrorOr> parse_function_definition(); ErrorOr> parse_function_body(); ErrorOr> parse_brace_group(); ErrorOr> parse_do_group(); ErrorOr> parse_simple_command(); ErrorOr> parse_prefix(); ErrorOr> parse_suffix(); ErrorOr> parse_io_redirect(); ErrorOr> parse_redirect_list(); ErrorOr> parse_io_file(AST::Position, Optional fd); ErrorOr> parse_io_here(AST::Position, Optional fd); ErrorOr> parse_word(); ErrorOr parse_case_list(); template void error(Token const& token, CheckedFormatString fmt, Ts&&... args) { m_errors.append(Error { DeprecatedString::formatted(fmt.view(), forward(args)...), token.position, }); } Lexer m_lexer; bool m_in_interactive_mode { false }; Vector m_token_buffer; size_t m_token_index { 0 }; Vector m_previous_token_buffer; Vector m_errors; HashMap> m_unprocessed_heredoc_entries; Token m_eof_token; bool m_disallow_command_prefix { true }; }; }