mush

git clone git://git.lin.moe/mush.git

  1#pragma once
  2
  3#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>
 15
 16#include "Ast.hpp"
 17
 18#define END '\0'
 19
 20std::vector<std::string> split(std::string haystack, const std::string &needle);
 21bool locate(const std::string &program, std::string &output);
 22
 23namespace builtins
 24{
 25using registry_map =
 26    std::map<std::string,
 27	     std::function<void(const std::vector<std::string> &)>>;
 28extern registry_map REGISTRY;
 29
 30void register_defaults();
 31} // namespace builtins
 32
 33namespace parsing
 34{
 35class ParseError : public std::logic_error
 36{
 37      public:
 38	ParseError(ast::Position position, std::string message);
 39	ast::Position position;
 40};
 41
 42enum class SymbolType {
 43	end,
 44	token,
 45
 46	newline,
 47
 48	and_if,
 49	or_if,
 50	double_semi,
 51
 52	double_less,
 53	double_great,
 54	less_and,
 55	great_and,
 56	less_great,
 57	double_less_dash,
 58
 59	clobber,
 60};
 61
 62constexpr 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};
 74
 75std::size_t operator_len(SymbolType op);
 76bool is_operator_start(char ch);
 77
 78class BasicParser
 79{
 80      private:
 81	std::istream &in;
 82	std::vector<char> buffer;
 83
 84      protected:
 85	bool continue_line;
 86	std::vector<std::shared_ptr<ast::IORedirect>> here_documents;
 87	ast::Position current_position;
 88
 89	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();
 96
 97      public:
 98	std::shared_ptr<ParseError> error;
 99
100	// BasicParser(const std::string &line);
101	BasicParser(std::istream &stream);
102
103	SymbolType nextSymbol();
104};
105
106class Parser : public BasicParser
107{
108      private:
109	int arith_nested_parens;
110	std::optional<ast::Word::ParameterOp> expectParameterOp();
111	std::optional<ast::IORedirectOp> ioRedirectOp();
112
113      protected:
114	void pushWordString(std::vector<std::unique_ptr<ast::Word>> &vec,
115			    std::string &str, ast::Position begin);
116
117      public:
118	Parser(std::istream &stream);
119
120	int linebreak();
121
122	std::optional<std::string> peekName(bool in_braces);
123
124	template <bool expect> std::unique_ptr<ast::Word> word(char end);
125	template <bool expect> bool token(std::string_view str);
126
127	bool token(std::string_view str, bool expect);
128
129	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();
133
134	std::unique_ptr<ast::Word> expectDollar();
135	/*
136	 * except starts with "$", could be :
137	 * ${expression} -> parameter
138	 * $(command)
139	 * $((arithmetic))
140	 * $parameter
141	 */
142	std::unique_ptr<ast::Word::Parameter> expectParameter();
143	// $(command), not for general command
144	std::unique_ptr<ast::Word::Command> expectWordCommand();
145	std::unique_ptr<ast::Word::Arithmetic> expectArithmetic();
146
147	template <typename T>
148	std::vector<std::unique_ptr<T>>
149	wordList(std::function<std::unique_ptr<T>(char)> func, const char end);
150
151	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();
157
158	std::unique_ptr<ast::AndOrList> andOrList();
159	std::unique_ptr<ast::AndOrList::Pipeline> pipeline();
160	std::optional<char> separatorOp();
161
162	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);
166
167	std::unique_ptr<ast::Command> simpleCommand();
168
169	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();
174
175	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();
181
182	std::pair<std::unique_ptr<struct ast::CaseItem>, bool>
183	expectCaseItem(); // return std::pair<item, dsemi(;;)>
184
185	std::unique_ptr<ast::Command::FunctionDefine> functionDefine();
186
187	template <bool expect>
188	std::vector<std::unique_ptr<ast::CommandList>> compoundList();
189};
190} // namespace parsing