Parser.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167
  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. #include "Parser.h"
  27. #include <ctype.h>
  28. #include <stdio.h>
  29. #include <unistd.h>
  30. char Parser::peek()
  31. {
  32. if (m_offset == m_input.length())
  33. return 0;
  34. ASSERT(m_offset < m_input.length());
  35. return m_input[m_offset];
  36. }
  37. char Parser::consume()
  38. {
  39. auto ch = peek();
  40. ++m_offset;
  41. return ch;
  42. }
  43. void Parser::putback()
  44. {
  45. ASSERT(m_offset > 0);
  46. --m_offset;
  47. }
  48. bool Parser::expect(char ch)
  49. {
  50. return expect(StringView { &ch, 1 });
  51. }
  52. bool Parser::expect(const StringView& expected)
  53. {
  54. auto offset_at_start = m_offset;
  55. if (expected.length() + m_offset > m_input.length())
  56. return false;
  57. for (size_t i = 0; i < expected.length(); ++i) {
  58. if (peek() != expected[i]) {
  59. m_offset = offset_at_start;
  60. return false;
  61. }
  62. consume();
  63. }
  64. return true;
  65. }
  66. template<typename A, typename... Args>
  67. NonnullRefPtr<A> Parser::create(Args... args)
  68. {
  69. return adopt(*new A(AST::Position { m_rule_start_offsets.last(), m_offset }, args...));
  70. }
  71. [[nodiscard]] OwnPtr<Parser::ScopedOffset> Parser::push_start()
  72. {
  73. return make<ScopedOffset>(m_rule_start_offsets, m_offset);
  74. }
  75. static constexpr bool is_whitespace(char c)
  76. {
  77. return c == ' ' || c == '\t';
  78. }
  79. static constexpr bool is_word_character(char c)
  80. {
  81. return (c <= '9' && c >= '0') || (c <= 'Z' && c >= 'A') || (c <= 'z' && c >= 'a') || c == '_';
  82. }
  83. static constexpr bool is_digit(char c)
  84. {
  85. return c <= '9' && c >= '0';
  86. }
  87. static constexpr auto is_not(char c)
  88. {
  89. return [c](char ch) { return ch != c; };
  90. }
  91. static constexpr auto is_any_of(StringView s)
  92. {
  93. return [s](char ch) { return s.contains(ch); };
  94. }
  95. static inline char to_byte(char a, char b)
  96. {
  97. char buf[3] { a, b, 0 };
  98. return strtol(buf, nullptr, 16);
  99. }
  100. RefPtr<AST::Node> Parser::parse()
  101. {
  102. m_offset = 0;
  103. auto toplevel = parse_toplevel();
  104. if (m_offset < m_input.length()) {
  105. // Parsing stopped midway, this is a syntax error.
  106. auto error_start = push_start();
  107. m_offset = m_input.length();
  108. auto syntax_error_node = create<AST::SyntaxError>("Unexpected tokens past the end");
  109. if (toplevel)
  110. return create<AST::Join>(move(toplevel), move(syntax_error_node));
  111. return syntax_error_node;
  112. }
  113. return toplevel;
  114. }
  115. RefPtr<AST::Node> Parser::parse_toplevel()
  116. {
  117. auto rule_start = push_start();
  118. if (auto sequence = parse_sequence())
  119. return create<AST::Execute>(sequence);
  120. return nullptr;
  121. }
  122. RefPtr<AST::Node> Parser::parse_sequence()
  123. {
  124. consume_while(is_any_of(" \t\n;")); // ignore whitespaces or terminators without effect.
  125. auto rule_start = push_start();
  126. auto var_decls = parse_variable_decls();
  127. switch (peek()) {
  128. case '}':
  129. return var_decls;
  130. case ';':
  131. case '\n': {
  132. if (!var_decls)
  133. break;
  134. consume_while(is_any_of("\n;"));
  135. auto rest = parse_sequence();
  136. if (rest)
  137. return create<AST::Sequence>(move(var_decls), move(rest));
  138. return var_decls;
  139. }
  140. default:
  141. break;
  142. }
  143. auto first = parse_function_decl();
  144. if (!first)
  145. first = parse_or_logical_sequence();
  146. if (!first)
  147. return var_decls;
  148. if (var_decls)
  149. first = create<AST::Sequence>(move(var_decls), move(first));
  150. consume_while(is_whitespace);
  151. switch (peek()) {
  152. case ';':
  153. case '\n':
  154. consume_while(is_any_of("\n;"));
  155. if (auto expr = parse_sequence()) {
  156. return create<AST::Sequence>(move(first), move(expr)); // Sequence
  157. }
  158. return first;
  159. case '&': {
  160. auto execute_pipe_seq = first->would_execute() ? first : static_cast<RefPtr<AST::Node>>(create<AST::Execute>(first));
  161. consume();
  162. auto bg = create<AST::Background>(move(first)); // Execute Background
  163. if (auto rest = parse_sequence())
  164. return create<AST::Sequence>(move(bg), move(rest)); // Sequence Background Sequence
  165. return bg;
  166. }
  167. default:
  168. return first;
  169. }
  170. }
  171. RefPtr<AST::Node> Parser::parse_variable_decls()
  172. {
  173. auto rule_start = push_start();
  174. consume_while(is_whitespace);
  175. auto offset_before_name = m_offset;
  176. auto var_name = consume_while(is_word_character);
  177. if (var_name.is_empty())
  178. return nullptr;
  179. if (!expect('=')) {
  180. m_offset = offset_before_name;
  181. return nullptr;
  182. }
  183. auto name_expr = create<AST::BarewordLiteral>(move(var_name));
  184. auto start = push_start();
  185. auto expression = parse_expression();
  186. if (!expression || expression->is_syntax_error()) {
  187. m_offset = start->offset;
  188. if (peek() == '(') {
  189. consume();
  190. auto command = parse_pipe_sequence();
  191. if (!command)
  192. m_offset = start->offset;
  193. else if (!expect(')'))
  194. command->set_is_syntax_error(*create<AST::SyntaxError>("Expected a terminating close paren"));
  195. expression = command;
  196. }
  197. }
  198. if (!expression) {
  199. if (is_whitespace(peek())) {
  200. auto string_start = push_start();
  201. expression = create<AST::StringLiteral>("");
  202. } else {
  203. m_offset = offset_before_name;
  204. return nullptr;
  205. }
  206. }
  207. Vector<AST::VariableDeclarations::Variable> variables;
  208. variables.append({ move(name_expr), expression.release_nonnull() });
  209. if (consume_while(is_whitespace).is_empty())
  210. return create<AST::VariableDeclarations>(move(variables));
  211. auto rest = parse_variable_decls();
  212. if (!rest)
  213. return create<AST::VariableDeclarations>(move(variables));
  214. ASSERT(rest->is_variable_decls());
  215. auto* rest_decl = static_cast<AST::VariableDeclarations*>(rest.ptr());
  216. variables.append(rest_decl->variables());
  217. return create<AST::VariableDeclarations>(move(variables));
  218. }
  219. RefPtr<AST::Node> Parser::parse_function_decl()
  220. {
  221. auto rule_start = push_start();
  222. auto restore = [&] {
  223. m_offset = rule_start->offset;
  224. return nullptr;
  225. };
  226. consume_while(is_whitespace);
  227. auto offset_before_name = m_offset;
  228. auto function_name = consume_while(is_word_character);
  229. auto offset_after_name = m_offset;
  230. if (function_name.is_empty())
  231. return restore();
  232. if (!expect('('))
  233. return restore();
  234. Vector<AST::FunctionDeclaration::NameWithPosition> arguments;
  235. for (;;) {
  236. consume_while(is_whitespace);
  237. if (expect(')'))
  238. break;
  239. auto name_offset = m_offset;
  240. auto arg_name = consume_while(is_word_character);
  241. if (arg_name.is_empty()) {
  242. // FIXME: Should this be a syntax error, or just return?
  243. return restore();
  244. }
  245. arguments.append({ arg_name, { name_offset, m_offset } });
  246. }
  247. consume_while(is_whitespace);
  248. {
  249. RefPtr<AST::Node> syntax_error;
  250. {
  251. auto obrace_error_start = push_start();
  252. syntax_error = create<AST::SyntaxError>("Expected an open brace '{' to start a function body");
  253. }
  254. if (!expect('{')) {
  255. return create<AST::FunctionDeclaration>(
  256. AST::FunctionDeclaration::NameWithPosition {
  257. move(function_name),
  258. { offset_before_name, offset_after_name } },
  259. move(arguments),
  260. move(syntax_error));
  261. }
  262. }
  263. auto body = parse_toplevel();
  264. {
  265. RefPtr<AST::SyntaxError> syntax_error;
  266. {
  267. auto cbrace_error_start = push_start();
  268. syntax_error = create<AST::SyntaxError>("Expected a close brace '}' to end a function body");
  269. }
  270. if (!expect('}')) {
  271. if (body)
  272. body->set_is_syntax_error(*syntax_error);
  273. else
  274. body = move(syntax_error);
  275. return create<AST::FunctionDeclaration>(
  276. AST::FunctionDeclaration::NameWithPosition {
  277. move(function_name),
  278. { offset_before_name, offset_after_name } },
  279. move(arguments),
  280. move(body));
  281. }
  282. }
  283. return create<AST::FunctionDeclaration>(
  284. AST::FunctionDeclaration::NameWithPosition {
  285. move(function_name),
  286. { offset_before_name, offset_after_name } },
  287. move(arguments),
  288. move(body));
  289. }
  290. RefPtr<AST::Node> Parser::parse_or_logical_sequence()
  291. {
  292. consume_while(is_whitespace);
  293. auto rule_start = push_start();
  294. auto and_sequence = parse_and_logical_sequence();
  295. if (!and_sequence)
  296. return nullptr;
  297. consume_while(is_whitespace);
  298. auto saved_offset = m_offset;
  299. if (!expect("||")) {
  300. m_offset = saved_offset;
  301. return and_sequence;
  302. }
  303. auto right_and_sequence = parse_and_logical_sequence();
  304. if (!right_and_sequence)
  305. right_and_sequence = create<AST::SyntaxError>("Expected an expression after '||'");
  306. return create<AST::Or>(move(and_sequence), move(right_and_sequence));
  307. }
  308. RefPtr<AST::Node> Parser::parse_and_logical_sequence()
  309. {
  310. consume_while(is_whitespace);
  311. auto rule_start = push_start();
  312. auto pipe_sequence = parse_pipe_sequence();
  313. if (!pipe_sequence)
  314. return nullptr;
  315. consume_while(is_whitespace);
  316. auto saved_offset = m_offset;
  317. if (!expect("&&")) {
  318. m_offset = saved_offset;
  319. return pipe_sequence;
  320. }
  321. auto right_and_sequence = parse_and_logical_sequence();
  322. if (!right_and_sequence)
  323. right_and_sequence = create<AST::SyntaxError>("Expected an expression after '&&'");
  324. return create<AST::And>(move(pipe_sequence), move(right_and_sequence));
  325. }
  326. RefPtr<AST::Node> Parser::parse_pipe_sequence()
  327. {
  328. auto rule_start = push_start();
  329. auto left = parse_control_structure();
  330. if (!left) {
  331. if (auto cmd = parse_command())
  332. left = cmd;
  333. else
  334. return nullptr;
  335. }
  336. consume_while(is_whitespace);
  337. if (peek() != '|')
  338. return left;
  339. consume();
  340. if (auto pipe_seq = parse_pipe_sequence()) {
  341. return create<AST::Pipe>(move(left), move(pipe_seq)); // Pipe
  342. }
  343. putback();
  344. return left;
  345. }
  346. RefPtr<AST::Node> Parser::parse_command()
  347. {
  348. auto rule_start = push_start();
  349. consume_while(is_whitespace);
  350. auto redir = parse_redirection();
  351. if (!redir) {
  352. auto list_expr = parse_list_expression();
  353. if (!list_expr)
  354. return nullptr;
  355. auto cast = create<AST::CastToCommand>(move(list_expr)); // Cast List Command
  356. auto next_command = parse_command();
  357. if (!next_command)
  358. return cast;
  359. return create<AST::Join>(move(cast), move(next_command)); // Join List Command
  360. }
  361. auto command = parse_command();
  362. if (!command)
  363. return redir;
  364. return create<AST::Join>(move(redir), command); // Join Command Command
  365. }
  366. RefPtr<AST::Node> Parser::parse_control_structure()
  367. {
  368. auto rule_start = push_start();
  369. consume_while(is_whitespace);
  370. if (auto for_loop = parse_for_loop())
  371. return for_loop;
  372. if (auto if_expr = parse_if_expr())
  373. return if_expr;
  374. if (auto subshell = parse_subshell())
  375. return subshell;
  376. return nullptr;
  377. }
  378. RefPtr<AST::Node> Parser::parse_for_loop()
  379. {
  380. auto rule_start = push_start();
  381. if (!expect("for")) {
  382. m_offset = rule_start->offset;
  383. return nullptr;
  384. }
  385. if (consume_while(is_any_of(" \t\n")).is_empty()) {
  386. m_offset = rule_start->offset;
  387. return nullptr;
  388. }
  389. auto variable_name = consume_while(is_word_character);
  390. Optional<size_t> in_start_position;
  391. if (variable_name.is_empty()) {
  392. variable_name = "it";
  393. } else {
  394. consume_while(is_whitespace);
  395. auto in_error_start = push_start();
  396. in_start_position = in_error_start->offset;
  397. if (!expect("in")) {
  398. auto syntax_error = create<AST::SyntaxError>("Expected 'in' after a variable name in a 'for' loop");
  399. return create<AST::ForLoop>(move(variable_name), move(syntax_error), nullptr); // ForLoop Var Iterated Block
  400. }
  401. }
  402. consume_while(is_whitespace);
  403. RefPtr<AST::Node> iterated_expression;
  404. {
  405. auto iter_error_start = push_start();
  406. iterated_expression = parse_expression();
  407. if (!iterated_expression) {
  408. auto syntax_error = create<AST::SyntaxError>("Expected an expression in 'for' loop");
  409. return create<AST::ForLoop>(move(variable_name), move(syntax_error), nullptr, move(in_start_position)); // ForLoop Var Iterated Block
  410. }
  411. }
  412. consume_while(is_any_of(" \t\n"));
  413. {
  414. auto obrace_error_start = push_start();
  415. if (!expect('{')) {
  416. auto syntax_error = create<AST::SyntaxError>("Expected an open brace '{' to start a 'for' loop body");
  417. return create<AST::ForLoop>(move(variable_name), move(iterated_expression), move(syntax_error), move(in_start_position)); // ForLoop Var Iterated Block
  418. }
  419. }
  420. auto body = parse_toplevel();
  421. {
  422. auto cbrace_error_start = push_start();
  423. if (!expect('}')) {
  424. auto error_start = push_start();
  425. RefPtr<AST::SyntaxError> syntax_error = create<AST::SyntaxError>("Expected a close brace '}' to end a 'for' loop body");
  426. if (body)
  427. body->set_is_syntax_error(*syntax_error);
  428. else
  429. body = syntax_error;
  430. }
  431. }
  432. return create<AST::ForLoop>(move(variable_name), move(iterated_expression), move(body), move(in_start_position)); // ForLoop Var Iterated Block
  433. }
  434. RefPtr<AST::Node> Parser::parse_if_expr()
  435. {
  436. auto rule_start = push_start();
  437. if (!expect("if")) {
  438. m_offset = rule_start->offset;
  439. return nullptr;
  440. }
  441. if (consume_while(is_any_of(" \t\n")).is_empty()) {
  442. m_offset = rule_start->offset;
  443. return nullptr;
  444. }
  445. RefPtr<AST::Node> condition;
  446. {
  447. auto cond_error_start = push_start();
  448. condition = parse_or_logical_sequence();
  449. if (!condition) {
  450. auto syntax_error = create<AST::SyntaxError>("Expected a logical sequence after 'if'");
  451. return create<AST::IfCond>(Optional<AST::Position> {}, move(syntax_error), nullptr, nullptr);
  452. }
  453. }
  454. auto parse_braced_toplevel = [&]() -> RefPtr<AST::Node> {
  455. {
  456. auto obrace_error_start = push_start();
  457. if (!expect('{')) {
  458. auto syntax_error = create<AST::SyntaxError>("Expected an open brace '{' to start an 'if' true branch");
  459. return syntax_error;
  460. }
  461. }
  462. auto body = parse_toplevel();
  463. {
  464. auto cbrace_error_start = push_start();
  465. if (!expect('}')) {
  466. auto error_start = push_start();
  467. RefPtr<AST::SyntaxError> syntax_error = create<AST::SyntaxError>("Expected a close brace '}' to end an 'if' true branch");
  468. if (body)
  469. body->set_is_syntax_error(*syntax_error);
  470. else
  471. body = syntax_error;
  472. }
  473. }
  474. return body;
  475. };
  476. consume_while(is_whitespace);
  477. auto true_branch = parse_braced_toplevel();
  478. if (true_branch && true_branch->is_syntax_error())
  479. return create<AST::IfCond>(Optional<AST::Position> {}, move(condition), move(true_branch), nullptr); // If expr syntax_error
  480. consume_while(is_whitespace);
  481. Optional<AST::Position> else_position;
  482. {
  483. auto else_start = push_start();
  484. if (expect("else"))
  485. else_position = AST::Position { else_start->offset, m_offset };
  486. }
  487. if (else_position.has_value()) {
  488. consume_while(is_whitespace);
  489. if (peek() == '{') {
  490. auto false_branch = parse_braced_toplevel();
  491. return create<AST::IfCond>(else_position, move(condition), move(true_branch), move(false_branch)); // If expr true_branch Else false_branch
  492. }
  493. auto else_if_branch = parse_if_expr();
  494. return create<AST::IfCond>(else_position, move(condition), move(true_branch), move(else_if_branch)); // If expr true_branch Else If ...
  495. }
  496. return create<AST::IfCond>(else_position, move(condition), move(true_branch), nullptr); // If expr true_branch
  497. }
  498. RefPtr<AST::Node> Parser::parse_subshell()
  499. {
  500. auto rule_start = push_start();
  501. if (!expect('{'))
  502. return nullptr;
  503. auto body = parse_toplevel();
  504. {
  505. auto cbrace_error_start = push_start();
  506. if (!expect('}')) {
  507. auto error_start = push_start();
  508. RefPtr<AST::SyntaxError> syntax_error = create<AST::SyntaxError>("Expected a close brace '}' to end a subshell");
  509. if (body)
  510. body->set_is_syntax_error(*syntax_error);
  511. else
  512. body = syntax_error;
  513. }
  514. }
  515. return create<AST::Subshell>(move(body));
  516. }
  517. RefPtr<AST::Node> Parser::parse_redirection()
  518. {
  519. auto rule_start = push_start();
  520. auto pipe_fd = 0;
  521. auto number = consume_while(is_digit);
  522. if (number.is_empty()) {
  523. pipe_fd = -1;
  524. } else {
  525. auto fd = number.to_int();
  526. ASSERT(fd.has_value());
  527. pipe_fd = fd.value();
  528. }
  529. switch (peek()) {
  530. case '>': {
  531. consume();
  532. if (peek() == '>') {
  533. consume();
  534. consume_while(is_whitespace);
  535. pipe_fd = pipe_fd >= 0 ? pipe_fd : STDOUT_FILENO;
  536. auto path = parse_expression();
  537. if (!path) {
  538. if (!at_end()) {
  539. // Eat a character and hope the problem goes away
  540. consume();
  541. }
  542. return create<AST::SyntaxError>("Expected a path");
  543. }
  544. return create<AST::WriteAppendRedirection>(pipe_fd, move(path)); // Redirection WriteAppend
  545. }
  546. if (peek() == '&') {
  547. consume();
  548. // FIXME: 'fd>&-' Syntax not the best. needs discussion.
  549. if (peek() == '-') {
  550. consume();
  551. pipe_fd = pipe_fd >= 0 ? pipe_fd : STDOUT_FILENO;
  552. return create<AST::CloseFdRedirection>(pipe_fd); // Redirection CloseFd
  553. }
  554. int dest_pipe_fd = 0;
  555. auto number = consume_while(is_digit);
  556. pipe_fd = pipe_fd >= 0 ? pipe_fd : STDOUT_FILENO;
  557. if (number.is_empty()) {
  558. dest_pipe_fd = -1;
  559. } else {
  560. auto fd = number.to_int();
  561. ASSERT(fd.has_value());
  562. dest_pipe_fd = fd.value();
  563. }
  564. auto redir = create<AST::Fd2FdRedirection>(pipe_fd, dest_pipe_fd); // Redirection Fd2Fd
  565. if (dest_pipe_fd == -1)
  566. redir->set_is_syntax_error(*create<AST::SyntaxError>("Expected a file descriptor"));
  567. return redir;
  568. }
  569. consume_while(is_whitespace);
  570. pipe_fd = pipe_fd >= 0 ? pipe_fd : STDOUT_FILENO;
  571. auto path = parse_expression();
  572. if (!path) {
  573. if (!at_end()) {
  574. // Eat a character and hope the problem goes away
  575. consume();
  576. }
  577. return create<AST::SyntaxError>("Expected a path");
  578. }
  579. return create<AST::WriteRedirection>(pipe_fd, move(path)); // Redirection Write
  580. }
  581. case '<': {
  582. consume();
  583. enum {
  584. Read,
  585. ReadWrite,
  586. } mode { Read };
  587. if (peek() == '>') {
  588. mode = ReadWrite;
  589. consume();
  590. }
  591. consume_while(is_whitespace);
  592. pipe_fd = pipe_fd >= 0 ? pipe_fd : STDIN_FILENO;
  593. auto path = parse_expression();
  594. if (!path) {
  595. if (!at_end()) {
  596. // Eat a character and hope the problem goes away
  597. consume();
  598. }
  599. return create<AST::SyntaxError>("Expected a path");
  600. }
  601. if (mode == Read)
  602. return create<AST::ReadRedirection>(pipe_fd, move(path)); // Redirection Read
  603. return create<AST::ReadWriteRedirection>(pipe_fd, move(path)); // Redirection ReadWrite
  604. }
  605. default:
  606. m_offset = rule_start->offset;
  607. return nullptr;
  608. }
  609. }
  610. RefPtr<AST::Node> Parser::parse_list_expression()
  611. {
  612. consume_while(is_whitespace);
  613. auto rule_start = push_start();
  614. Vector<RefPtr<AST::Node>> nodes;
  615. do {
  616. auto expr = parse_expression();
  617. if (!expr)
  618. break;
  619. nodes.append(move(expr));
  620. } while (!consume_while(is_whitespace).is_empty());
  621. if (nodes.is_empty())
  622. return nullptr;
  623. return create<AST::ListConcatenate>(move(nodes)); // Concatenate List
  624. }
  625. RefPtr<AST::Node> Parser::parse_expression()
  626. {
  627. auto rule_start = push_start();
  628. auto starting_char = peek();
  629. auto read_concat = [&](auto expr) -> RefPtr<AST::Node> {
  630. if (is_whitespace(peek()))
  631. return expr;
  632. if (auto next_expr = parse_expression())
  633. return create<AST::Juxtaposition>(move(expr), move(next_expr));
  634. return expr;
  635. };
  636. if (strchr("&|){} ;<>\n", starting_char) != nullptr)
  637. return nullptr;
  638. if (isdigit(starting_char)) {
  639. ScopedValueRollback offset_rollback { m_offset };
  640. auto redir = parse_redirection();
  641. if (redir)
  642. return nullptr;
  643. }
  644. if (starting_char == '$') {
  645. if (auto variable = parse_variable())
  646. return read_concat(variable);
  647. if (auto inline_exec = parse_evaluate())
  648. return read_concat(inline_exec);
  649. }
  650. if (starting_char == '#')
  651. return parse_comment();
  652. if (starting_char == '(') {
  653. consume();
  654. auto list = parse_list_expression();
  655. if (!expect(')')) {
  656. m_offset = rule_start->offset;
  657. return nullptr;
  658. }
  659. return read_concat(create<AST::CastToList>(move(list))); // Cast To List
  660. }
  661. return read_concat(parse_string_composite());
  662. }
  663. RefPtr<AST::Node> Parser::parse_string_composite()
  664. {
  665. auto rule_start = push_start();
  666. if (auto string = parse_string()) {
  667. if (auto next_part = parse_string_composite())
  668. return create<AST::Juxtaposition>(move(string), move(next_part)); // Concatenate String StringComposite
  669. return string;
  670. }
  671. if (auto variable = parse_variable()) {
  672. if (auto next_part = parse_string_composite())
  673. return create<AST::Juxtaposition>(move(variable), move(next_part)); // Concatenate Variable StringComposite
  674. return variable;
  675. }
  676. if (auto glob = parse_glob()) {
  677. if (auto next_part = parse_string_composite())
  678. return create<AST::Juxtaposition>(move(glob), move(next_part)); // Concatenate Glob StringComposite
  679. return glob;
  680. }
  681. if (auto bareword = parse_bareword()) {
  682. if (auto next_part = parse_string_composite())
  683. return create<AST::Juxtaposition>(move(bareword), move(next_part)); // Concatenate Bareword StringComposite
  684. return bareword;
  685. }
  686. if (auto inline_command = parse_evaluate()) {
  687. if (auto next_part = parse_string_composite())
  688. return create<AST::Juxtaposition>(move(inline_command), move(next_part)); // Concatenate Execute StringComposite
  689. return inline_command;
  690. }
  691. return nullptr;
  692. }
  693. RefPtr<AST::Node> Parser::parse_string()
  694. {
  695. auto rule_start = push_start();
  696. if (at_end())
  697. return nullptr;
  698. if (peek() == '"') {
  699. consume();
  700. auto inner = parse_doublequoted_string_inner();
  701. if (!inner)
  702. inner = create<AST::SyntaxError>("Unexpected EOF in string");
  703. if (!expect('"')) {
  704. inner = create<AST::DoubleQuotedString>(move(inner));
  705. inner->set_is_syntax_error(*create<AST::SyntaxError>("Expected a terminating double quote"));
  706. return inner;
  707. }
  708. return create<AST::DoubleQuotedString>(move(inner)); // Double Quoted String
  709. }
  710. if (peek() == '\'') {
  711. consume();
  712. auto text = consume_while(is_not('\''));
  713. bool is_error = false;
  714. if (!expect('\''))
  715. is_error = true;
  716. auto result = create<AST::StringLiteral>(move(text)); // String Literal
  717. if (is_error)
  718. result->set_is_syntax_error(*create<AST::SyntaxError>("Expected a terminating single quote"));
  719. return move(result);
  720. }
  721. return nullptr;
  722. }
  723. RefPtr<AST::Node> Parser::parse_doublequoted_string_inner()
  724. {
  725. auto rule_start = push_start();
  726. if (at_end())
  727. return nullptr;
  728. StringBuilder builder;
  729. while (!at_end() && peek() != '"') {
  730. if (peek() == '\\') {
  731. consume();
  732. if (at_end()) {
  733. break;
  734. }
  735. auto ch = consume();
  736. switch (ch) {
  737. case '\\':
  738. default:
  739. builder.append(ch);
  740. break;
  741. case 'x': {
  742. if (m_input.length() <= m_offset + 2)
  743. break;
  744. auto first_nibble = tolower(consume());
  745. auto second_nibble = tolower(consume());
  746. if (!isxdigit(first_nibble) || !isxdigit(second_nibble)) {
  747. builder.append(first_nibble);
  748. builder.append(second_nibble);
  749. break;
  750. }
  751. builder.append(to_byte(first_nibble, second_nibble));
  752. break;
  753. }
  754. case 'a':
  755. builder.append('\a');
  756. break;
  757. case 'b':
  758. builder.append('\b');
  759. break;
  760. case 'e':
  761. builder.append('\x1b');
  762. break;
  763. case 'f':
  764. builder.append('\f');
  765. break;
  766. case 'r':
  767. builder.append('\r');
  768. break;
  769. case 'n':
  770. builder.append('\n');
  771. break;
  772. }
  773. continue;
  774. }
  775. if (peek() == '$') {
  776. auto string_literal = create<AST::StringLiteral>(builder.to_string()); // String Literal
  777. if (auto variable = parse_variable()) {
  778. auto inner = create<AST::StringPartCompose>(
  779. move(string_literal),
  780. move(variable)); // Compose String Variable
  781. if (auto string = parse_doublequoted_string_inner()) {
  782. return create<AST::StringPartCompose>(move(inner), move(string)); // Compose Composition Composition
  783. }
  784. return inner;
  785. }
  786. if (auto evaluate = parse_evaluate()) {
  787. auto composition = create<AST::StringPartCompose>(
  788. move(string_literal),
  789. move(evaluate)); // Compose String Sequence
  790. if (auto string = parse_doublequoted_string_inner()) {
  791. return create<AST::StringPartCompose>(move(composition), move(string)); // Compose Composition Composition
  792. }
  793. return composition;
  794. }
  795. }
  796. builder.append(consume());
  797. }
  798. return create<AST::StringLiteral>(builder.to_string()); // String Literal
  799. }
  800. RefPtr<AST::Node> Parser::parse_variable()
  801. {
  802. auto rule_start = push_start();
  803. if (at_end())
  804. return nullptr;
  805. if (peek() != '$')
  806. return nullptr;
  807. consume();
  808. switch (peek()) {
  809. case '$':
  810. case '?':
  811. case '*':
  812. case '#':
  813. return create<AST::SpecialVariable>(consume()); // Variable Special
  814. default:
  815. break;
  816. }
  817. auto name = consume_while(is_word_character);
  818. if (name.length() == 0) {
  819. putback();
  820. return nullptr;
  821. }
  822. return create<AST::SimpleVariable>(move(name)); // Variable Simple
  823. }
  824. RefPtr<AST::Node> Parser::parse_evaluate()
  825. {
  826. auto rule_start = push_start();
  827. if (at_end())
  828. return nullptr;
  829. if (peek() != '$')
  830. return nullptr;
  831. consume();
  832. if (peek() == '(') {
  833. consume();
  834. auto inner = parse_pipe_sequence();
  835. if (!inner)
  836. inner = create<AST::SyntaxError>("Unexpected EOF in list");
  837. if (!expect(')'))
  838. inner->set_is_syntax_error(*create<AST::SyntaxError>("Expected a terminating close paren"));
  839. return create<AST::Execute>(move(inner), true);
  840. }
  841. auto inner = parse_expression();
  842. if (!inner) {
  843. inner = create<AST::SyntaxError>("Expected a command");
  844. } else {
  845. if (inner->is_list()) {
  846. auto execute_inner = create<AST::Execute>(move(inner), true);
  847. inner = execute_inner;
  848. } else {
  849. auto dyn_inner = create<AST::DynamicEvaluate>(move(inner));
  850. inner = dyn_inner;
  851. }
  852. }
  853. return inner;
  854. }
  855. RefPtr<AST::Node> Parser::parse_comment()
  856. {
  857. if (at_end())
  858. return nullptr;
  859. if (peek() != '#')
  860. return nullptr;
  861. consume();
  862. auto text = consume_while(is_not('\n'));
  863. return create<AST::Comment>(move(text)); // Comment
  864. }
  865. RefPtr<AST::Node> Parser::parse_bareword()
  866. {
  867. auto rule_start = push_start();
  868. StringBuilder builder;
  869. auto is_acceptable_bareword_character = [](char c) {
  870. return strchr("\\\"'*$&#|(){} ?;<>\n", c) == nullptr;
  871. };
  872. while (!at_end()) {
  873. char ch = peek();
  874. if (ch == '\\') {
  875. consume();
  876. if (!at_end()) {
  877. ch = consume();
  878. if (is_acceptable_bareword_character(ch))
  879. builder.append('\\');
  880. }
  881. builder.append(ch);
  882. continue;
  883. }
  884. if (is_acceptable_bareword_character(ch)) {
  885. builder.append(consume());
  886. continue;
  887. }
  888. break;
  889. }
  890. if (builder.is_empty())
  891. return nullptr;
  892. auto current_end = m_offset;
  893. auto string = builder.to_string();
  894. if (string.starts_with('~')) {
  895. String username;
  896. RefPtr<AST::Node> tilde, text;
  897. auto first_slash_index = string.index_of("/");
  898. if (first_slash_index.has_value()) {
  899. username = string.substring_view(1, first_slash_index.value() - 1);
  900. string = string.substring_view(first_slash_index.value(), string.length() - first_slash_index.value());
  901. } else {
  902. username = string.substring_view(1, string.length() - 1);
  903. string = "";
  904. }
  905. // Synthesize a Tilde Node with the correct positioning information.
  906. {
  907. m_offset -= string.length();
  908. tilde = create<AST::Tilde>(move(username));
  909. }
  910. if (string.is_empty())
  911. return tilde;
  912. // Synthesize a BarewordLiteral Node with the correct positioning information.
  913. {
  914. m_offset = tilde->position().end_offset;
  915. auto text_start = push_start();
  916. m_offset = current_end;
  917. text = create<AST::BarewordLiteral>(move(string));
  918. }
  919. return create<AST::Juxtaposition>(move(tilde), move(text)); // Juxtaposition Varible Bareword
  920. }
  921. if (string.starts_with("\\~")) {
  922. // Un-escape the tilde, but only at the start (where it would be an expansion)
  923. string = string.substring(1, string.length() - 1);
  924. }
  925. return create<AST::BarewordLiteral>(move(string)); // Bareword Literal
  926. }
  927. RefPtr<AST::Node> Parser::parse_glob()
  928. {
  929. auto rule_start = push_start();
  930. auto bareword_part = parse_bareword();
  931. if (at_end())
  932. return bareword_part;
  933. char ch = peek();
  934. if (ch == '*' || ch == '?') {
  935. consume();
  936. StringBuilder textbuilder;
  937. if (bareword_part) {
  938. StringView text;
  939. if (bareword_part->is_bareword()) {
  940. auto bareword = static_cast<AST::BarewordLiteral*>(bareword_part.ptr());
  941. text = bareword->text();
  942. } else {
  943. // FIXME: Allow composition of tilde+bareword with globs: '~/foo/bar/baz*'
  944. putback();
  945. bareword_part->set_is_syntax_error(*create<AST::SyntaxError>(String::format("Unexpected %s inside a glob", bareword_part->class_name().characters())));
  946. return bareword_part;
  947. }
  948. textbuilder.append(text);
  949. }
  950. textbuilder.append(ch);
  951. auto glob_after = parse_glob();
  952. if (glob_after) {
  953. if (glob_after->is_glob()) {
  954. auto glob = static_cast<AST::BarewordLiteral*>(glob_after.ptr());
  955. textbuilder.append(glob->text());
  956. } else if (glob_after->is_bareword()) {
  957. auto bareword = static_cast<AST::BarewordLiteral*>(glob_after.ptr());
  958. textbuilder.append(bareword->text());
  959. } else {
  960. ASSERT_NOT_REACHED();
  961. }
  962. }
  963. return create<AST::Glob>(textbuilder.to_string()); // Glob
  964. }
  965. return bareword_part;
  966. }
  967. StringView Parser::consume_while(Function<bool(char)> condition)
  968. {
  969. auto start_offset = m_offset;
  970. while (!at_end() && condition(peek()))
  971. consume();
  972. return m_input.substring_view(start_offset, m_offset - start_offset);
  973. }