1#pragma once23#include <array>4#include <cstddef>5#include <functional>6#include <istream>7#include <map>8#include <memory>9#include <optional>10#include <stdexcept>11#include <string>12#include <string_view>13#include <utility>14#include <vector>1516#include "Ast.hpp"1718#define END '\0'1920std::vector<std::string> split(std::string haystack, const std::string &needle);21bool locate(const std::string &program, std::string &output);2223namespace builtins24{25using registry_map =26 std::map<std::string,27 std::function<void(const std::vector<std::string> &)>>;28extern registry_map REGISTRY;2930void register_defaults();31} // namespace builtins3233namespace parsing34{35class ParseError : public std::logic_error36{37 public:38 ParseError(ast::Position position, std::string message);39 ast::Position position;40};4142enum class SymbolType {43 end,44 token,4546 newline,4748 and_if,49 or_if,50 double_semi,5152 double_less,53 double_great,54 less_and,55 great_and,56 less_great,57 double_less_dash,5859 clobber,60};6162constexpr std::array operators{63 std::pair{SymbolType::double_less_dash, "<<-"},64 std::pair{SymbolType::and_if, "&&"},65 std::pair{SymbolType::or_if, "||"},66 std::pair{SymbolType::double_semi, ";;"},67 std::pair{SymbolType::double_less, "<<"},68 std::pair{SymbolType::double_great, ">>"},69 std::pair{SymbolType::less_and, "<&"},70 std::pair{SymbolType::great_and, ">&"},71 std::pair{SymbolType::less_great, "<>"},72 std::pair{SymbolType::clobber, ">|"},73};7475std::size_t operator_len(SymbolType op);76bool is_operator_start(char ch);7778class BasicParser79{80 private:81 std::istream ∈82 std::vector<char> buffer;8384 protected:85 bool continue_line;86 std::vector<std::shared_ptr<ast::IORedirect>> here_documents;87 ast::Position current_position;8889 char peekChar(const std::size_t index);90 std::string peekWord(char end);91 char readChar(void);92 std::optional<std::string> readString(std::size_t len);93 bool expect(const std::string token);94 void setError(const std::string msg);95 void clearError();9697 public:98 std::shared_ptr<ParseError> error;99100 // BasicParser(const std::string &line);101 BasicParser(std::istream &stream);102103 SymbolType nextSymbol();104};105106class Parser : public BasicParser107{108 private:109 int arith_nested_parens;110 std::optional<ast::Word::ParameterOp> expectParameterOp();111 std::optional<ast::IORedirectOp> ioRedirectOp();112113 protected:114 void pushWordString(std::vector<std::unique_ptr<ast::Word>> &vec,115 std::string &str, ast::Position begin);116117 public:118 Parser(std::istream &stream);119120 int linebreak();121122 std::optional<std::string> peekName(bool in_braces);123124 template <bool expect> std::unique_ptr<ast::Word> word(char end);125 template <bool expect> bool token(std::string_view str);126127 bool token(std::string_view str, bool expect);128129 std::unique_ptr<ast::Word> arithmeticWord(char end);130 std::unique_ptr<ast::Word::String> singleQuotes();131 std::unique_ptr<ast::Word::List> doubleQuotes();132 std::unique_ptr<ast::Word::Command> backQuotes();133134 std::unique_ptr<ast::Word> expectDollar();135 /*136 * except starts with "$", could be :137 * ${expression} -> parameter138 * $(command)139 * $((arithmetic))140 * $parameter141 */142 std::unique_ptr<ast::Word::Parameter> expectParameter();143 // $(command), not for general command144 std::unique_ptr<ast::Word::Command> expectWordCommand();145 std::unique_ptr<ast::Word::Arithmetic> expectArithmetic();146147 template <typename T>148 std::vector<std::unique_ptr<T>>149 wordList(std::function<std::unique_ptr<T>(char)> func, const char end);150151 std::unique_ptr<ast::Program> expectProgram();152 template <bool expect>153 std::vector<std::unique_ptr<ast::CommandList>> completeCommand();154 std::unique_ptr<ast::Word> hereDocLine();155 template <bool with_heredoc>156 std::unique_ptr<ast::CommandList> commandList();157158 std::unique_ptr<ast::AndOrList> andOrList();159 std::unique_ptr<ast::AndOrList::Pipeline> pipeline();160 std::optional<char> separatorOp();161162 std::unique_ptr<ast::Command> command();163 std::shared_ptr<ast::IORedirect> ioRedirect();164 std::unique_ptr<ast::Assignment> assignment();165 bool completeHeredoc(std::shared_ptr<ast::IORedirect> redir);166167 std::unique_ptr<ast::Command> simpleCommand();168169 std::unique_ptr<ast::Command> compoundCommand();170 std::unique_ptr<ast::Command::BraceGroup> braceGroup();171 std::unique_ptr<ast::Command::SubShell> subshell();172 std::unique_ptr<ast::Command::IfClause> ifClause();173 std::unique_ptr<ast::Command> elsePart();174175 std::tuple<std::vector<std::unique_ptr<ast::CommandList>>, ast::Range,176 ast::Range>177 expectDoGroup();178 std::unique_ptr<ast::Command::ForClause> forClause();179 std::unique_ptr<ast::Command::LoopClause> loopClause();180 std::unique_ptr<ast::Command::CaseClause> caseClause();181182 std::pair<std::unique_ptr<struct ast::CaseItem>, bool>183 expectCaseItem(); // return std::pair<item, dsemi(;;)>184185 std::unique_ptr<ast::Command::FunctionDefine> functionDefine();186187 template <bool expect>188 std::vector<std::unique_ptr<ast::CommandList>> compoundList();189};190} // namespace parsing