Serenity Operating System
at master 121 lines 3.8 kB view raw
1/* 2 * Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include <Shell/AST.h> 10#include <Shell/PosixLexer.h> 11 12namespace Shell::Posix { 13 14class Parser { 15public: 16 Parser(StringView input, bool interactive = false, Optional<Reduction> starting_reduction = {}) 17 : m_lexer(input) 18 , m_in_interactive_mode(interactive) 19 , m_eof_token(Token::eof()) 20 { 21 (void)fill_token_buffer(starting_reduction); 22 } 23 24 RefPtr<AST::Node> parse(); 25 RefPtr<AST::Node> parse_word_list(); 26 27 struct Error { 28 DeprecatedString message; 29 Optional<AST::Position> position; 30 }; 31 auto& errors() const { return m_errors; } 32 33private: 34 ErrorOr<Optional<Token>> next_expanded_token(Optional<Reduction> starting_reduction = {}); 35 Vector<Token> perform_expansions(Vector<Token> tokens); 36 ErrorOr<void> fill_token_buffer(Optional<Reduction> starting_reduction = {}); 37 void handle_heredoc_contents(); 38 39 Token const& peek() 40 { 41 if (eof()) 42 return m_eof_token; 43 handle_heredoc_contents(); 44 return m_token_buffer[m_token_index]; 45 } 46 Token const& consume() 47 { 48 if (eof()) 49 return m_eof_token; 50 handle_heredoc_contents(); 51 return m_token_buffer[m_token_index++]; 52 } 53 void skip() 54 { 55 if (eof()) 56 return; 57 m_token_index++; 58 } 59 bool eof() const 60 { 61 return m_token_index == m_token_buffer.size() || m_token_buffer[m_token_index].type == Token::Type::Eof; 62 } 63 64 struct CaseItemsResult { 65 Vector<AST::Position> pipe_positions; 66 Vector<NonnullRefPtr<AST::Node>> nodes; 67 }; 68 69 ErrorOr<RefPtr<AST::Node>> parse_complete_command(); 70 ErrorOr<RefPtr<AST::Node>> parse_list(); 71 ErrorOr<RefPtr<AST::Node>> parse_and_or(); 72 ErrorOr<RefPtr<AST::Node>> parse_pipeline(); 73 ErrorOr<RefPtr<AST::Node>> parse_pipe_sequence(); 74 ErrorOr<RefPtr<AST::Node>> parse_command(); 75 ErrorOr<RefPtr<AST::Node>> parse_compound_command(); 76 ErrorOr<RefPtr<AST::Node>> parse_subshell(); 77 ErrorOr<RefPtr<AST::Node>> parse_compound_list(); 78 ErrorOr<RefPtr<AST::Node>> parse_term(); 79 ErrorOr<RefPtr<AST::Node>> parse_for_clause(); 80 ErrorOr<RefPtr<AST::Node>> parse_case_clause(); 81 ErrorOr<RefPtr<AST::Node>> parse_if_clause(); 82 ErrorOr<RefPtr<AST::Node>> parse_while_clause(); 83 ErrorOr<RefPtr<AST::Node>> parse_until_clause(); 84 ErrorOr<RefPtr<AST::Node>> parse_function_definition(); 85 ErrorOr<RefPtr<AST::Node>> parse_function_body(); 86 ErrorOr<RefPtr<AST::Node>> parse_brace_group(); 87 ErrorOr<RefPtr<AST::Node>> parse_do_group(); 88 ErrorOr<RefPtr<AST::Node>> parse_simple_command(); 89 ErrorOr<RefPtr<AST::Node>> parse_prefix(); 90 ErrorOr<RefPtr<AST::Node>> parse_suffix(); 91 ErrorOr<RefPtr<AST::Node>> parse_io_redirect(); 92 ErrorOr<RefPtr<AST::Node>> parse_redirect_list(); 93 ErrorOr<RefPtr<AST::Node>> parse_io_file(AST::Position, Optional<int> fd); 94 ErrorOr<RefPtr<AST::Node>> parse_io_here(AST::Position, Optional<int> fd); 95 ErrorOr<RefPtr<AST::Node>> parse_word(); 96 ErrorOr<CaseItemsResult> parse_case_list(); 97 98 template<typename... Ts> 99 void error(Token const& token, CheckedFormatString<Ts...> fmt, Ts&&... args) 100 { 101 m_errors.append(Error { 102 DeprecatedString::formatted(fmt.view(), forward<Ts>(args)...), 103 token.position, 104 }); 105 } 106 107 Lexer m_lexer; 108 bool m_in_interactive_mode { false }; 109 Vector<Token, 2> m_token_buffer; 110 size_t m_token_index { 0 }; 111 Vector<Token> m_previous_token_buffer; 112 113 Vector<Error> m_errors; 114 HashMap<String, NonnullRefPtr<AST::Heredoc>> m_unprocessed_heredoc_entries; 115 116 Token m_eof_token; 117 118 bool m_disallow_command_prefix { true }; 119}; 120 121}