Parser.cpp 23 KB

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