Parser.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  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. if (expected.length() + m_offset > m_input.length())
  55. return false;
  56. for (size_t i = 0; i < expected.length(); ++i) {
  57. if (peek() != expected[i])
  58. return false;
  59. consume();
  60. }
  61. return true;
  62. }
  63. template<typename A, typename... Args>
  64. RefPtr<A> Parser::create(Args... args)
  65. {
  66. return adopt(*new A(AST::Position { m_rule_start_offsets.last(), m_offset }, args...));
  67. }
  68. [[nodiscard]] OwnPtr<Parser::ScopedOffset> Parser::push_start()
  69. {
  70. return make<ScopedOffset>(m_rule_start_offsets, m_offset);
  71. }
  72. static constexpr bool is_whitespace(char c)
  73. {
  74. return c == ' ' || c == '\t';
  75. }
  76. static constexpr bool is_word_character(char c)
  77. {
  78. return (c <= '9' && c >= '0') || (c <= 'Z' && c >= 'A') || (c <= 'z' && c >= 'a') || c == '_';
  79. }
  80. static constexpr bool is_digit(char c)
  81. {
  82. return c <= '9' && c >= '0';
  83. }
  84. static constexpr auto is_not(char c)
  85. {
  86. return [c](char ch) { return ch != c; };
  87. }
  88. static inline char to_byte(char a, char b)
  89. {
  90. char buf[3] { a, b, 0 };
  91. return strtol(buf, nullptr, 16);
  92. }
  93. RefPtr<AST::Node> Parser::parse()
  94. {
  95. m_offset = 0;
  96. return parse_toplevel();
  97. }
  98. RefPtr<AST::Node> Parser::parse_toplevel()
  99. {
  100. auto rule_start = push_start();
  101. if (auto sequence = parse_sequence())
  102. return create<AST::Execute>(sequence);
  103. return nullptr;
  104. }
  105. RefPtr<AST::Node> Parser::parse_sequence()
  106. {
  107. auto rule_start = push_start();
  108. auto var_decls = parse_variable_decls();
  109. auto pipe_seq = parse_pipe_sequence();
  110. if (!pipe_seq)
  111. return var_decls;
  112. if (var_decls)
  113. pipe_seq = create<AST::Sequence>(move(var_decls), move(pipe_seq));
  114. consume_while(is_whitespace);
  115. switch (peek()) {
  116. case ';':
  117. consume();
  118. if (auto expr = parse_sequence()) {
  119. return create<AST::Sequence>(move(pipe_seq), move(expr)); // Sequence
  120. }
  121. return pipe_seq;
  122. case '&': {
  123. auto execute_pipe_seq = create<AST::Execute>(pipe_seq);
  124. consume();
  125. if (peek() == '&') {
  126. consume();
  127. if (auto expr = parse_sequence()) {
  128. return create<AST::And>(move(execute_pipe_seq), move(expr)); // And
  129. }
  130. return execute_pipe_seq;
  131. }
  132. auto bg = create<AST::Background>(move(pipe_seq)); // Execute Background
  133. if (auto rest = parse_sequence())
  134. return create<AST::Sequence>(move(bg), move(rest)); // Sequence Background Sequence
  135. return bg;
  136. }
  137. case '|': {
  138. auto execute_pipe_seq = create<AST::Execute>(pipe_seq);
  139. consume();
  140. if (peek() != '|') {
  141. putback();
  142. return execute_pipe_seq;
  143. }
  144. consume();
  145. if (auto expr = parse_sequence()) {
  146. return create<AST::Or>(move(execute_pipe_seq), move(expr)); // Or
  147. }
  148. putback();
  149. return execute_pipe_seq;
  150. }
  151. default:
  152. return pipe_seq;
  153. }
  154. }
  155. RefPtr<AST::Node> Parser::parse_variable_decls()
  156. {
  157. auto rule_start = push_start();
  158. consume_while(is_whitespace);
  159. auto offset_before_name = m_offset;
  160. auto var_name = consume_while(is_word_character);
  161. if (var_name.is_empty())
  162. return nullptr;
  163. if (!expect('=')) {
  164. m_offset = offset_before_name;
  165. return nullptr;
  166. }
  167. auto name_expr = create<AST::BarewordLiteral>(move(var_name));
  168. auto expression = parse_expression();
  169. if (!expression) {
  170. if (is_whitespace(peek())) {
  171. auto string_start = push_start();
  172. expression = create<AST::StringLiteral>("");
  173. } else {
  174. m_offset = offset_before_name;
  175. return nullptr;
  176. }
  177. }
  178. Vector<AST::VariableDeclarations::Variable> variables;
  179. variables.append({ move(name_expr), move(expression) });
  180. if (consume_while(is_whitespace).is_empty())
  181. return create<AST::VariableDeclarations>(move(variables));
  182. auto rest = parse_variable_decls();
  183. if (!rest)
  184. return create<AST::VariableDeclarations>(move(variables));
  185. ASSERT(rest->is_variable_decls());
  186. auto* rest_decl = static_cast<AST::VariableDeclarations*>(rest.ptr());
  187. variables.append(rest_decl->variables());
  188. return create<AST::VariableDeclarations>(move(variables));
  189. }
  190. RefPtr<AST::Node> Parser::parse_pipe_sequence()
  191. {
  192. auto rule_start = push_start();
  193. auto command = parse_command();
  194. if (!command)
  195. return nullptr;
  196. consume_while(is_whitespace);
  197. if (peek() != '|')
  198. return command;
  199. consume();
  200. if (auto pipe_seq = parse_pipe_sequence()) {
  201. return create<AST::Pipe>(move(command), move(pipe_seq)); // Pipe
  202. }
  203. putback();
  204. return command;
  205. }
  206. RefPtr<AST::Node> Parser::parse_command()
  207. {
  208. auto rule_start = push_start();
  209. consume_while(is_whitespace);
  210. auto redir = parse_redirection();
  211. if (!redir) {
  212. auto list_expr = parse_list_expression();
  213. if (!list_expr)
  214. return nullptr;
  215. auto cast = create<AST::CastToCommand>(move(list_expr)); // Cast List Command
  216. auto next_command = parse_command();
  217. if (!next_command)
  218. return cast;
  219. return create<AST::Join>(move(cast), move(next_command)); // Join List Command
  220. }
  221. auto command = parse_command();
  222. if (!command)
  223. return redir;
  224. return create<AST::Join>(move(redir), command); // Join Command Command
  225. }
  226. RefPtr<AST::Node> Parser::parse_redirection()
  227. {
  228. auto rule_start = push_start();
  229. auto pipe_fd = 0;
  230. auto number = consume_while(is_digit);
  231. if (number.is_empty()) {
  232. pipe_fd = -1;
  233. } else {
  234. auto fd = number.to_int();
  235. ASSERT(fd.has_value());
  236. pipe_fd = fd.value();
  237. }
  238. switch (peek()) {
  239. case '>': {
  240. consume();
  241. if (peek() == '>') {
  242. consume();
  243. consume_while(is_whitespace);
  244. pipe_fd = pipe_fd >= 0 ? pipe_fd : STDOUT_FILENO;
  245. auto path = parse_expression();
  246. if (!path) {
  247. if (!at_end()) {
  248. // Eat a character and hope the problem goes away
  249. consume();
  250. }
  251. return create<AST::SyntaxError>();
  252. }
  253. return create<AST::WriteAppendRedirection>(pipe_fd, move(path)); // Redirection WriteAppend
  254. }
  255. if (peek() == '&') {
  256. consume();
  257. // FIXME: 'fd>&-' Syntax not the best. needs discussion.
  258. if (peek() == '-') {
  259. consume();
  260. pipe_fd = pipe_fd >= 0 ? pipe_fd : STDOUT_FILENO;
  261. return create<AST::CloseFdRedirection>(pipe_fd); // Redirection CloseFd
  262. }
  263. int dest_pipe_fd = 0;
  264. auto number = consume_while(is_digit);
  265. pipe_fd = pipe_fd >= 0 ? pipe_fd : STDOUT_FILENO;
  266. if (number.is_empty()) {
  267. dest_pipe_fd = -1;
  268. } else {
  269. auto fd = number.to_int();
  270. ASSERT(fd.has_value());
  271. dest_pipe_fd = fd.value();
  272. }
  273. return create<AST::Fd2FdRedirection>(pipe_fd, dest_pipe_fd); // Redirection Fd2Fd
  274. }
  275. consume_while(is_whitespace);
  276. pipe_fd = pipe_fd >= 0 ? pipe_fd : STDOUT_FILENO;
  277. auto path = parse_expression();
  278. if (!path) {
  279. if (!at_end()) {
  280. // Eat a character and hope the problem goes away
  281. consume();
  282. }
  283. return create<AST::SyntaxError>();
  284. }
  285. return create<AST::WriteRedirection>(pipe_fd, move(path)); // Redirection Write
  286. }
  287. case '<': {
  288. consume();
  289. enum {
  290. Read,
  291. ReadWrite,
  292. } mode { Read };
  293. if (peek() == '>') {
  294. mode = ReadWrite;
  295. consume();
  296. }
  297. consume_while(is_whitespace);
  298. pipe_fd = pipe_fd >= 0 ? pipe_fd : STDIN_FILENO;
  299. auto path = parse_expression();
  300. if (!path) {
  301. if (!at_end()) {
  302. // Eat a character and hope the problem goes away
  303. consume();
  304. }
  305. return create<AST::SyntaxError>();
  306. }
  307. if (mode == Read)
  308. return create<AST::ReadRedirection>(pipe_fd, move(path)); // Redirection Read
  309. return create<AST::ReadWriteRedirection>(pipe_fd, move(path)); // Redirection ReadWrite
  310. }
  311. default:
  312. return nullptr;
  313. }
  314. }
  315. RefPtr<AST::Node> Parser::parse_list_expression()
  316. {
  317. consume_while(is_whitespace);
  318. auto rule_start = push_start();
  319. auto expr = parse_expression();
  320. if (!expr)
  321. return nullptr;
  322. if (consume_while(is_whitespace).is_empty())
  323. return expr;
  324. auto list = parse_list_expression();
  325. if (!list)
  326. return create<AST::CastToList>(move(expr));
  327. return create<AST::ListConcatenate>(move(expr), move(list)); // Join Element List
  328. }
  329. RefPtr<AST::Node> Parser::parse_expression()
  330. {
  331. auto rule_start = push_start();
  332. auto starting_char = peek();
  333. auto read_concat = [&](auto expr) -> RefPtr<AST::Node> {
  334. if (is_whitespace(peek()))
  335. return expr;
  336. if (auto next_expr = parse_expression())
  337. return create<AST::Juxtaposition>(move(expr), move(next_expr));
  338. return expr;
  339. };
  340. if (strchr("&|[]){} ;<>", starting_char) != nullptr)
  341. return nullptr;
  342. if (isdigit(starting_char)) {
  343. ScopedValueRollback offset_rollback { m_offset };
  344. auto redir = parse_redirection();
  345. if (redir)
  346. return nullptr;
  347. }
  348. if (starting_char == '$') {
  349. if (auto variable = parse_variable())
  350. return read_concat(variable);
  351. if (auto inline_exec = parse_evaluate())
  352. return read_concat(inline_exec);
  353. }
  354. if (starting_char == '#')
  355. return parse_comment();
  356. if (starting_char == '(') {
  357. consume();
  358. auto list = parse_list_expression();
  359. if (!list)
  360. list = create<AST::SyntaxError>();
  361. if (!expect(')'))
  362. return read_concat(create<AST::SyntaxError>());
  363. return read_concat(create<AST::CastToList>(move(list))); // Cast To List
  364. }
  365. return read_concat(parse_string_composite());
  366. }
  367. RefPtr<AST::Node> Parser::parse_string_composite()
  368. {
  369. auto rule_start = push_start();
  370. if (auto string = parse_string()) {
  371. if (auto next_part = parse_string_composite())
  372. return create<AST::Juxtaposition>(move(string), move(next_part)); // Concatenate String StringComposite
  373. return string;
  374. }
  375. if (auto variable = parse_variable()) {
  376. if (auto next_part = parse_string_composite())
  377. return create<AST::Juxtaposition>(move(variable), move(next_part)); // Concatenate Variable StringComposite
  378. return variable;
  379. }
  380. if (auto glob = parse_glob()) {
  381. if (auto next_part = parse_string_composite())
  382. return create<AST::Juxtaposition>(move(glob), move(next_part)); // Concatenate Glob StringComposite
  383. return glob;
  384. }
  385. if (auto bareword = parse_bareword()) {
  386. if (auto next_part = parse_string_composite())
  387. return create<AST::Juxtaposition>(move(bareword), move(next_part)); // Concatenate Bareword StringComposite
  388. return bareword;
  389. }
  390. if (auto inline_command = parse_evaluate()) {
  391. if (auto next_part = parse_string_composite())
  392. return create<AST::Juxtaposition>(move(inline_command), move(next_part)); // Concatenate Execute StringComposite
  393. return inline_command;
  394. }
  395. return nullptr;
  396. }
  397. RefPtr<AST::Node> Parser::parse_string()
  398. {
  399. auto rule_start = push_start();
  400. if (at_end())
  401. return nullptr;
  402. if (peek() == '"') {
  403. consume();
  404. auto inner = parse_doublequoted_string_inner();
  405. if (!expect('"') || !inner)
  406. return create<AST::SyntaxError>();
  407. return create<AST::DoubleQuotedString>(move(inner)); // Double Quoted String
  408. }
  409. if (peek() == '\'') {
  410. consume();
  411. auto text = consume_while(is_not('\''));
  412. if (!expect('\''))
  413. return create<AST::SyntaxError>();
  414. return create<AST::StringLiteral>(move(text)); // String Literal
  415. }
  416. return nullptr;
  417. }
  418. RefPtr<AST::Node> Parser::parse_doublequoted_string_inner()
  419. {
  420. auto rule_start = push_start();
  421. if (at_end())
  422. return nullptr;
  423. StringBuilder builder;
  424. while (!at_end() && peek() != '"') {
  425. if (peek() == '\\') {
  426. consume();
  427. if (at_end()) {
  428. break;
  429. }
  430. auto ch = consume();
  431. switch (ch) {
  432. case '\\':
  433. default:
  434. builder.append(ch);
  435. break;
  436. case 'x': {
  437. if (m_input.length() <= m_offset + 2)
  438. break;
  439. auto first_nibble = tolower(consume());
  440. auto second_nibble = tolower(consume());
  441. if (!isxdigit(first_nibble) || !isxdigit(second_nibble)) {
  442. builder.append(first_nibble);
  443. builder.append(second_nibble);
  444. break;
  445. }
  446. builder.append(to_byte(first_nibble, second_nibble));
  447. break;
  448. }
  449. case 'a':
  450. builder.append('\a');
  451. break;
  452. case 'b':
  453. builder.append('\b');
  454. break;
  455. case 'e':
  456. builder.append('\x1b');
  457. break;
  458. case 'f':
  459. builder.append('\f');
  460. break;
  461. case 'r':
  462. builder.append('\r');
  463. break;
  464. case 'n':
  465. builder.append('\n');
  466. break;
  467. }
  468. continue;
  469. }
  470. if (peek() == '$') {
  471. auto string_literal = create<AST::StringLiteral>(builder.to_string()); // String Literal
  472. if (auto variable = parse_variable()) {
  473. auto inner = create<AST::StringPartCompose>(
  474. move(string_literal),
  475. move(variable)); // Compose String Variable
  476. if (auto string = parse_doublequoted_string_inner()) {
  477. return create<AST::StringPartCompose>(move(inner), move(string)); // Compose Composition Composition
  478. }
  479. return inner;
  480. }
  481. if (auto evaluate = parse_evaluate()) {
  482. auto composition = create<AST::StringPartCompose>(
  483. move(string_literal),
  484. move(evaluate)); // Compose String Sequence
  485. if (auto string = parse_doublequoted_string_inner()) {
  486. return create<AST::StringPartCompose>(move(composition), move(string)); // Compose Composition Composition
  487. }
  488. return composition;
  489. }
  490. }
  491. builder.append(consume());
  492. }
  493. return create<AST::StringLiteral>(builder.to_string()); // String Literal
  494. }
  495. RefPtr<AST::Node> Parser::parse_variable()
  496. {
  497. auto rule_start = push_start();
  498. if (at_end())
  499. return nullptr;
  500. if (peek() != '$')
  501. return nullptr;
  502. consume();
  503. switch (peek()) {
  504. case '$':
  505. case '?':
  506. return create<AST::SpecialVariable>(consume()); // Variable Special
  507. default:
  508. break;
  509. }
  510. auto name = consume_while(is_word_character);
  511. if (name.length() == 0) {
  512. putback();
  513. return nullptr;
  514. }
  515. return create<AST::SimpleVariable>(move(name)); // Variable Simple
  516. }
  517. RefPtr<AST::Node> Parser::parse_evaluate()
  518. {
  519. auto rule_start = push_start();
  520. if (at_end())
  521. return nullptr;
  522. if (peek() != '$')
  523. return nullptr;
  524. consume();
  525. auto inner = parse_expression();
  526. if (!inner) {
  527. inner = create<AST::SyntaxError>();
  528. } else {
  529. if (inner->is_list()) {
  530. auto execute_inner = create<AST::Execute>(move(inner));
  531. execute_inner->capture_stdout();
  532. inner = execute_inner;
  533. } else {
  534. // Trying to evaluate something other than a list
  535. // FIXME: This bit be dynamic, what do?
  536. auto dyn_inner = create<AST::DynamicEvaluate>(move(inner));
  537. inner = dyn_inner;
  538. }
  539. }
  540. return inner;
  541. }
  542. RefPtr<AST::Node> Parser::parse_comment()
  543. {
  544. if (at_end())
  545. return nullptr;
  546. if (peek() != '#')
  547. return nullptr;
  548. consume();
  549. auto text = consume_while(is_not('\n'));
  550. if (peek() == '\n')
  551. consume();
  552. return create<AST::Comment>(move(text)); // Comment
  553. }
  554. RefPtr<AST::Node> Parser::parse_bareword()
  555. {
  556. auto rule_start = push_start();
  557. StringBuilder builder;
  558. auto is_acceptable_bareword_character = [](char c) {
  559. return strchr("\\\"'*$&#|()[]{} ?;<>", c) == nullptr;
  560. };
  561. while (!at_end()) {
  562. char ch = peek();
  563. if (ch == '\\') {
  564. consume();
  565. if (!at_end()) {
  566. ch = consume();
  567. if (is_acceptable_bareword_character(ch))
  568. builder.append('\\');
  569. }
  570. builder.append(ch);
  571. continue;
  572. }
  573. if (is_acceptable_bareword_character(ch)) {
  574. builder.append(consume());
  575. continue;
  576. }
  577. break;
  578. }
  579. if (builder.is_empty())
  580. return nullptr;
  581. auto string = builder.to_string();
  582. if (string.starts_with('~')) {
  583. String username;
  584. auto first_slash_index = string.index_of("/");
  585. if (first_slash_index.has_value()) {
  586. username = string.substring_view(1, first_slash_index.value() - 1);
  587. string = string.substring_view(first_slash_index.value(), string.length() - first_slash_index.value());
  588. } else {
  589. username = string.substring_view(1, string.length() - 1);
  590. string = "";
  591. }
  592. auto current_end = m_offset;
  593. m_offset -= string.length();
  594. auto tilde = create<AST::Tilde>(move(username));
  595. auto text_start = push_start();
  596. m_offset = current_end;
  597. if (string.is_empty())
  598. return tilde;
  599. return create<AST::StringPartCompose>(move(tilde), create<AST::BarewordLiteral>(move(string))); // Compose Varible Bareword
  600. }
  601. if (string.starts_with("\\~")) {
  602. // Un-escape the tilde, but only at the start (where it would be an expansion)
  603. }
  604. return create<AST::BarewordLiteral>(builder.to_string()); // Bareword Literal
  605. }
  606. RefPtr<AST::Node> Parser::parse_glob()
  607. {
  608. auto rule_start = push_start();
  609. auto bareword_part = parse_bareword();
  610. if (at_end())
  611. return bareword_part;
  612. char ch = peek();
  613. if (ch == '*' || ch == '?') {
  614. consume();
  615. // FIXME: Join all parts before making AST nodes
  616. StringBuilder textbuilder;
  617. if (bareword_part) {
  618. ASSERT(bareword_part->is_bareword() || bareword_part->is_tilde());
  619. StringView text;
  620. if (bareword_part->is_tilde()) {
  621. auto bareword = static_cast<AST::BarewordLiteral*>(bareword_part.ptr());
  622. text = bareword->text();
  623. } else {
  624. auto tilde = static_cast<AST::Tilde*>(bareword_part.ptr());
  625. text = tilde->text();
  626. }
  627. textbuilder.append(text);
  628. }
  629. textbuilder.append(ch);
  630. auto glob_after = parse_glob();
  631. if (glob_after) {
  632. if (glob_after->is_glob()) {
  633. auto glob = static_cast<AST::BarewordLiteral*>(glob_after.ptr());
  634. textbuilder.append(glob->text());
  635. } else if (glob_after->is_bareword()) {
  636. auto bareword = static_cast<AST::BarewordLiteral*>(glob_after.ptr());
  637. textbuilder.append(bareword->text());
  638. } else {
  639. ASSERT_NOT_REACHED();
  640. }
  641. }
  642. return create<AST::Glob>(textbuilder.to_string()); // Glob
  643. }
  644. return bareword_part;
  645. }
  646. StringView Parser::consume_while(Function<bool(char)> condition)
  647. {
  648. auto start_offset = m_offset;
  649. while (!at_end() && condition(peek()))
  650. consume();
  651. return m_input.substring_view(start_offset, m_offset - start_offset);
  652. }