Parser.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #pragma once
  27. #include "AST.h"
  28. #include <AK/Function.h>
  29. #include <AK/RefPtr.h>
  30. #include <AK/String.h>
  31. #include <AK/StringBuilder.h>
  32. #include <AK/Vector.h>
  33. class Parser {
  34. public:
  35. Parser(StringView input)
  36. : m_input(move(input))
  37. {
  38. }
  39. RefPtr<AST::Node> parse();
  40. struct SavedOffset {
  41. size_t offset;
  42. AST::Position::Line line;
  43. };
  44. SavedOffset save_offset() const;
  45. private:
  46. RefPtr<AST::Node> parse_toplevel();
  47. RefPtr<AST::Node> parse_sequence();
  48. RefPtr<AST::Node> parse_function_decl();
  49. RefPtr<AST::Node> parse_and_logical_sequence();
  50. RefPtr<AST::Node> parse_or_logical_sequence();
  51. RefPtr<AST::Node> parse_variable_decls();
  52. RefPtr<AST::Node> parse_pipe_sequence();
  53. RefPtr<AST::Node> parse_command();
  54. RefPtr<AST::Node> parse_control_structure();
  55. RefPtr<AST::Node> parse_for_loop();
  56. RefPtr<AST::Node> parse_if_expr();
  57. RefPtr<AST::Node> parse_subshell();
  58. RefPtr<AST::Node> parse_match_expr();
  59. AST::MatchEntry parse_match_entry();
  60. RefPtr<AST::Node> parse_match_pattern();
  61. RefPtr<AST::Node> parse_redirection();
  62. RefPtr<AST::Node> parse_list_expression();
  63. RefPtr<AST::Node> parse_expression();
  64. RefPtr<AST::Node> parse_string_composite();
  65. RefPtr<AST::Node> parse_string();
  66. RefPtr<AST::Node> parse_doublequoted_string_inner();
  67. RefPtr<AST::Node> parse_variable();
  68. RefPtr<AST::Node> parse_evaluate();
  69. RefPtr<AST::Node> parse_comment();
  70. RefPtr<AST::Node> parse_bareword();
  71. RefPtr<AST::Node> parse_glob();
  72. template<typename A, typename... Args>
  73. NonnullRefPtr<A> create(Args... args);
  74. bool at_end() const { return m_input.length() <= m_offset; }
  75. char peek();
  76. char consume();
  77. bool expect(char);
  78. bool expect(const StringView&);
  79. void restore_to(size_t offset, AST::Position::Line line)
  80. {
  81. m_offset = offset;
  82. m_line = move(line);
  83. }
  84. AST::Position::Line line() const { return m_line; }
  85. StringView consume_while(Function<bool(char)>);
  86. struct ScopedOffset {
  87. ScopedOffset(Vector<size_t>& offsets, Vector<AST::Position::Line>& lines, size_t offset, size_t lineno, size_t linecol)
  88. : offsets(offsets)
  89. , lines(lines)
  90. , offset(offset)
  91. , line({ lineno, linecol })
  92. {
  93. offsets.append(offset);
  94. lines.append(line);
  95. }
  96. ~ScopedOffset()
  97. {
  98. auto last = offsets.take_last();
  99. ASSERT(last == offset);
  100. auto last_line = lines.take_last();
  101. ASSERT(last_line == line);
  102. }
  103. Vector<size_t>& offsets;
  104. Vector<AST::Position::Line>& lines;
  105. size_t offset;
  106. AST::Position::Line line;
  107. };
  108. void restore_to(const ScopedOffset& offset) { restore_to(offset.offset, offset.line); }
  109. OwnPtr<ScopedOffset> push_start();
  110. StringView m_input;
  111. size_t m_offset { 0 };
  112. AST::Position::Line m_line { 0, 0 };
  113. Vector<size_t> m_rule_start_offsets;
  114. Vector<AST::Position::Line> m_rule_start_lines;
  115. };
  116. #if 0
  117. constexpr auto the_grammar = R"(
  118. toplevel :: sequence?
  119. sequence :: variable_decls? or_logical_sequence terminator sequence
  120. | variable_decls? or_logical_sequence '&' sequence
  121. | variable_decls? or_logical_sequence
  122. | variable_decls? function_decl (terminator sequence)?
  123. | variable_decls? terminator sequence
  124. function_decl :: identifier '(' (ws* identifier)* ')' ws* '{' toplevel '}'
  125. or_logical_sequence :: and_logical_sequence '|' '|' and_logical_sequence
  126. | and_logical_sequence
  127. and_logical_sequence :: pipe_sequence '&' '&' and_logical_sequence
  128. | pipe_sequence
  129. terminator :: ';'
  130. | '\n'
  131. variable_decls :: identifier '=' expression (' '+ variable_decls)? ' '*
  132. | identifier '=' '(' pipe_sequence ')' (' '+ variable_decls)? ' '*
  133. pipe_sequence :: command '|' pipe_sequence
  134. | command
  135. | control_structure '|' pipe_sequence
  136. | control_structure
  137. control_structure :: for_expr
  138. | if_expr
  139. | subshell
  140. | match_expr
  141. for_expr :: 'for' ws+ (identifier ' '+ 'in' ws*)? expression ws+ '{' toplevel '}'
  142. if_expr :: 'if' ws+ or_logical_sequence ws+ '{' toplevel '}' else_clause?
  143. else_clause :: else '{' toplevel '}'
  144. | else if_expr
  145. subshell :: '{' toplevel '}'
  146. match_expr :: 'match' ws+ expression ws* ('as' ws+ identifier)? '{' match_entry* '}'
  147. match_entry :: match_pattern ws* '{' toplevel '}'
  148. match_pattern :: expression (ws* '|' ws* expression)*
  149. command :: redirection command
  150. | list_expression command?
  151. redirection :: number? '>'{1,2} ' '* string_composite
  152. | number? '<' ' '* string_composite
  153. | number? '>' '&' number
  154. | number? '>' '&' '-'
  155. list_expression :: ' '* expression (' '+ list_expression)?
  156. expression :: evaluate expression?
  157. | string_composite expression?
  158. | comment expression?
  159. | '(' list_expression ')' expression?
  160. evaluate :: '$' '(' pipe_sequence ')'
  161. | '$' expression {eval / dynamic resolve}
  162. string_composite :: string string_composite?
  163. | variable string_composite?
  164. | bareword string_composite?
  165. | glob string_composite?
  166. string :: '"' dquoted_string_inner '"'
  167. | "'" [^']* "'"
  168. dquoted_string_inner :: '\' . dquoted_string_inner? {concat}
  169. | variable dquoted_string_inner? {compose}
  170. | . dquoted_string_inner?
  171. | '\' 'x' digit digit dquoted_string_inner?
  172. | '\' [abefrn] dquoted_string_inner?
  173. variable :: '$' identifier
  174. | '$' '$'
  175. | '$' '?'
  176. | '$' '*'
  177. | '$' '#'
  178. | ...
  179. comment :: '#' [^\n]*
  180. bareword :: [^"'*$&#|()[\]{} ?;<>] bareword?
  181. | '\' [^"'*$&#|()[\]{} ?;<>] bareword?
  182. bareword_with_tilde_expansion :: '~' bareword?
  183. glob :: [*?] bareword?
  184. | bareword [*?]
  185. )";
  186. #endif