PosixParser.cpp 70 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986
  1. /*
  2. * Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/CharacterTypes.h>
  7. #include <AK/Debug.h>
  8. #include <AK/StringUtils.h>
  9. #include <Shell/PosixParser.h>
  10. static Shell::AST::Position empty_position()
  11. {
  12. return { 0, 0, { 0, 0 }, { 0, 0 } };
  13. }
  14. template<typename T, typename... Ts>
  15. static inline bool is_one_of(T const& value, Ts const&... values)
  16. {
  17. return ((value == values) || ...);
  18. }
  19. static inline bool is_io_operator(Shell::Posix::Token const& token)
  20. {
  21. using namespace Shell::Posix;
  22. return is_one_of(token.type,
  23. Token::Type::Less, Token::Type::Great,
  24. Token::Type::LessAnd, Token::Type::GreatAnd,
  25. Token::Type::DoubleLess, Token::Type::DoubleGreat,
  26. Token::Type::DoubleLessDash, Token::Type::LessGreat,
  27. Token::Type::Clobber);
  28. }
  29. static inline bool is_separator(Shell::Posix::Token const& token)
  30. {
  31. using namespace Shell::Posix;
  32. return is_one_of(token.type,
  33. Token::Type::Semicolon, Token::Type::Newline,
  34. Token::Type::AndIf, Token::Type::OrIf,
  35. Token::Type::Pipe,
  36. Token::Type::And);
  37. }
  38. static inline bool is_a_reserved_word_position(Shell::Posix::Token const& token, Optional<Shell::Posix::Token> const& previous_token, Optional<Shell::Posix::Token> const& previous_previous_token)
  39. {
  40. using namespace Shell::Posix;
  41. auto is_start_of_command = !previous_token.has_value()
  42. || previous_token->value.is_empty()
  43. || is_separator(*previous_token)
  44. || is_one_of(previous_token->type,
  45. Token::Type::OpenParen, Token::Type::CloseParen, Token::Type::Newline, Token::Type::DoubleSemicolon,
  46. Token::Type::Semicolon, Token::Type::Pipe, Token::Type::OrIf, Token::Type::AndIf);
  47. if (is_start_of_command)
  48. return true;
  49. if (!previous_token.has_value())
  50. return false;
  51. auto previous_is_reserved_word = is_one_of(previous_token->value,
  52. "for"sv, "in"sv, "case"sv, "if"sv, "then"sv, "else"sv,
  53. "elif"sv, "while"sv, "until"sv, "do"sv, "done"sv, "esac"sv,
  54. "fi"sv, "!"sv, "{"sv, "}"sv);
  55. if (previous_is_reserved_word)
  56. return true;
  57. if (!previous_previous_token.has_value())
  58. return false;
  59. auto is_third_in_case = previous_previous_token->value == "case"sv
  60. && token.type == Token::Type::Token && token.value == "in"sv;
  61. if (is_third_in_case)
  62. return true;
  63. auto is_third_in_for = previous_previous_token->value == "for"sv
  64. && token.type == Token::Type::Token && is_one_of(token.value, "in"sv, "do"sv);
  65. return is_third_in_for;
  66. }
  67. static inline bool is_reserved(Shell::Posix::Token const& token)
  68. {
  69. using namespace Shell::Posix;
  70. return is_one_of(token.type,
  71. Token::Type::If, Token::Type::Then, Token::Type::Else,
  72. Token::Type::Elif, Token::Type::Fi, Token::Type::Do,
  73. Token::Type::Done, Token::Type::Case, Token::Type::Esac,
  74. Token::Type::While, Token::Type::Until, Token::Type::For,
  75. Token::Type::In, Token::Type::OpenBrace, Token::Type::CloseBrace,
  76. Token::Type::Bang);
  77. }
  78. static inline bool is_valid_name(StringView word)
  79. {
  80. // Dr.POSIX: a word consisting solely of underscores, digits, and alphabetics from the portable character set. The first character of a name is not a digit.
  81. return !word.is_empty()
  82. && !is_ascii_digit(word[0])
  83. && all_of(word, [](auto ch) { return is_ascii_alphanumeric(ch) || ch == '_'; });
  84. }
  85. namespace Shell::Posix {
  86. void Parser::fill_token_buffer(Optional<Reduction> starting_reduction)
  87. {
  88. for (;;) {
  89. auto token = next_expanded_token(starting_reduction);
  90. if (!token.has_value())
  91. break;
  92. #if SHELL_POSIX_PARSER_DEBUG
  93. DeprecatedString position = "(~)";
  94. if (token->position.has_value())
  95. position = DeprecatedString::formatted("{}:{}", token->position->start_offset, token->position->end_offset);
  96. DeprecatedString expansions = "";
  97. for (auto& exp : token->resolved_expansions)
  98. exp.visit(
  99. [&](ResolvedParameterExpansion& x) { expansions = DeprecatedString::formatted("{}param({}),", expansions, x.to_deprecated_string()); },
  100. [&](ResolvedCommandExpansion& x) { expansions = DeprecatedString::formatted("{}command({:p})", expansions, x.command.ptr()); });
  101. DeprecatedString rexpansions = "";
  102. for (auto& exp : token->expansions)
  103. exp.visit(
  104. [&](ParameterExpansion& x) { rexpansions = DeprecatedString::formatted("{}param({}) from {} to {},", rexpansions, x.parameter.string_view(), x.range.start, x.range.length); },
  105. [&](auto&) { rexpansions = DeprecatedString::formatted("{}...,", rexpansions); });
  106. dbgln("Token @ {}: '{}' (type {}) - parsed expansions: {} - raw expansions: {}", position, token->value.replace("\n"sv, "\\n"sv, ReplaceMode::All), token->type_name(), expansions, rexpansions);
  107. #endif
  108. }
  109. m_token_index = 0;
  110. }
  111. RefPtr<AST::Node> Parser::parse()
  112. {
  113. return parse_complete_command();
  114. }
  115. void Parser::handle_heredoc_contents()
  116. {
  117. while (!eof() && m_token_buffer[m_token_index].type == Token::Type::HeredocContents) {
  118. auto& token = m_token_buffer[m_token_index++];
  119. auto entry = m_unprocessed_heredoc_entries.get(token.relevant_heredoc_key.value());
  120. if (!entry.has_value()) {
  121. error(token, "Discarding unexpected heredoc contents for key '{}'", *token.relevant_heredoc_key);
  122. continue;
  123. }
  124. auto& heredoc = **entry;
  125. RefPtr<AST::Node> contents;
  126. if (heredoc.allow_interpolation()) {
  127. Parser parser { token.value, m_in_interactive_mode, Reduction::HeredocContents };
  128. contents = parser.parse_word();
  129. } else {
  130. contents = make_ref_counted<AST::StringLiteral>(token.position.value_or(empty_position()), String::from_utf8(token.value).release_value_but_fixme_should_propagate_errors(), AST::StringLiteral::EnclosureType::None);
  131. }
  132. if (contents)
  133. heredoc.set_contents(contents);
  134. m_unprocessed_heredoc_entries.remove(*token.relevant_heredoc_key);
  135. }
  136. }
  137. Optional<Token> Parser::next_expanded_token(Optional<Reduction> starting_reduction)
  138. {
  139. while (m_token_buffer.find_if([](auto& token) { return token.type == Token::Type::Eof; }).is_end()) {
  140. auto tokens = m_lexer.batch_next(starting_reduction);
  141. auto expanded = perform_expansions(move(tokens));
  142. m_token_buffer.extend(expanded);
  143. }
  144. if (m_token_buffer.size() == m_token_index)
  145. return {};
  146. return m_token_buffer[m_token_index++];
  147. }
  148. Vector<Token> Parser::perform_expansions(Vector<Token> tokens)
  149. {
  150. if (tokens.is_empty())
  151. return {};
  152. Vector<Token> expanded_tokens;
  153. auto previous_token = Optional<Token>();
  154. auto previous_previous_token = Optional<Token>();
  155. auto tokens_taken_from_buffer = 0;
  156. expanded_tokens.ensure_capacity(tokens.size());
  157. auto swap_expansions = [&] {
  158. if (previous_previous_token.has_value())
  159. expanded_tokens.append(previous_previous_token.release_value());
  160. if (previous_token.has_value())
  161. expanded_tokens.append(previous_token.release_value());
  162. for (; tokens_taken_from_buffer > 0; tokens_taken_from_buffer--)
  163. m_token_buffer.append(expanded_tokens.take_first());
  164. swap(tokens, expanded_tokens);
  165. expanded_tokens.clear_with_capacity();
  166. };
  167. // (1) join all consecutive newlines (this works around a grammar ambiguity)
  168. auto previous_was_newline = !m_token_buffer.is_empty() && m_token_buffer.last().type == Token::Type::Newline;
  169. for (auto& token : tokens) {
  170. if (token.type == Token::Type::Newline) {
  171. if (previous_was_newline)
  172. continue;
  173. previous_was_newline = true;
  174. } else {
  175. previous_was_newline = false;
  176. }
  177. expanded_tokens.append(move(token));
  178. }
  179. swap_expansions();
  180. // (2) Detect reserved words
  181. if (m_token_buffer.size() >= 1) {
  182. previous_token = m_token_buffer.take_last();
  183. tokens_taken_from_buffer++;
  184. }
  185. if (m_token_buffer.size() >= 1) {
  186. previous_previous_token = m_token_buffer.take_last();
  187. tokens_taken_from_buffer++;
  188. }
  189. auto check_reserved_word = [&](auto& token) {
  190. if (is_a_reserved_word_position(token, previous_token, previous_previous_token)) {
  191. if (token.value == "if"sv)
  192. token.type = Token::Type::If;
  193. else if (token.value == "then"sv)
  194. token.type = Token::Type::Then;
  195. else if (token.value == "else"sv)
  196. token.type = Token::Type::Else;
  197. else if (token.value == "elif"sv)
  198. token.type = Token::Type::Elif;
  199. else if (token.value == "fi"sv)
  200. token.type = Token::Type::Fi;
  201. else if (token.value == "while"sv)
  202. token.type = Token::Type::While;
  203. else if (token.value == "until"sv)
  204. token.type = Token::Type::Until;
  205. else if (token.value == "do"sv)
  206. token.type = Token::Type::Do;
  207. else if (token.value == "done"sv)
  208. token.type = Token::Type::Done;
  209. else if (token.value == "case"sv)
  210. token.type = Token::Type::Case;
  211. else if (token.value == "esac"sv)
  212. token.type = Token::Type::Esac;
  213. else if (token.value == "for"sv)
  214. token.type = Token::Type::For;
  215. else if (token.value == "in"sv)
  216. token.type = Token::Type::In;
  217. else if (token.value == "!"sv)
  218. token.type = Token::Type::Bang;
  219. else if (token.value == "{"sv)
  220. token.type = Token::Type::OpenBrace;
  221. else if (token.value == "}"sv)
  222. token.type = Token::Type::CloseBrace;
  223. else if (token.type == Token::Type::Token)
  224. token.type = Token::Type::Word;
  225. } else if (token.type == Token::Type::Token) {
  226. token.type = Token::Type::Word;
  227. }
  228. };
  229. for (auto& token : tokens) {
  230. if (!previous_token.has_value()) {
  231. check_reserved_word(token);
  232. previous_token = token;
  233. continue;
  234. }
  235. if (!previous_previous_token.has_value()) {
  236. check_reserved_word(token);
  237. previous_previous_token = move(previous_token);
  238. previous_token = token;
  239. continue;
  240. }
  241. check_reserved_word(token);
  242. expanded_tokens.append(exchange(*previous_previous_token, exchange(*previous_token, move(token))));
  243. }
  244. swap_expansions();
  245. // (3) Detect io_number tokens
  246. previous_token = Optional<Token>();
  247. tokens_taken_from_buffer = 0;
  248. if (m_token_buffer.size() >= 1) {
  249. previous_token = m_token_buffer.take_last();
  250. tokens_taken_from_buffer++;
  251. }
  252. for (auto& token : tokens) {
  253. if (!previous_token.has_value()) {
  254. previous_token = token;
  255. continue;
  256. }
  257. if (is_io_operator(token) && previous_token->type == Token::Type::Word && all_of(previous_token->value, is_ascii_digit)) {
  258. previous_token->type = Token::Type::IoNumber;
  259. }
  260. expanded_tokens.append(exchange(*previous_token, move(token)));
  261. }
  262. swap_expansions();
  263. // (4) Try to identify simple commands
  264. previous_token = Optional<Token>();
  265. tokens_taken_from_buffer = 0;
  266. if (m_token_buffer.size() >= 1) {
  267. previous_token = m_token_buffer.take_last();
  268. tokens_taken_from_buffer++;
  269. }
  270. for (auto& token : tokens) {
  271. if (!previous_token.has_value()) {
  272. token.could_be_start_of_a_simple_command = true;
  273. previous_token = token;
  274. continue;
  275. }
  276. token.could_be_start_of_a_simple_command = is_one_of(previous_token->type, Token::Type::OpenParen, Token::Type::CloseParen, Token::Type::Newline)
  277. || is_separator(*previous_token)
  278. || (!is_reserved(*previous_token) && is_reserved(token));
  279. expanded_tokens.append(exchange(*previous_token, move(token)));
  280. }
  281. swap_expansions();
  282. // (5) Detect assignment words
  283. for (auto& token : tokens) {
  284. if (token.could_be_start_of_a_simple_command)
  285. m_disallow_command_prefix = false;
  286. // Check if we're in a command prefix (could be an assignment)
  287. if (!m_disallow_command_prefix && token.type == Token::Type::Word && token.value.contains('=')) {
  288. // If the word before '=' is a valid name, this is an assignment
  289. auto parts = token.value.split_limit('=', 2);
  290. if (is_valid_name(parts[0]))
  291. token.type = Token::Type::AssignmentWord;
  292. else
  293. m_disallow_command_prefix = true;
  294. } else {
  295. m_disallow_command_prefix = true;
  296. }
  297. expanded_tokens.append(move(token));
  298. }
  299. swap_expansions();
  300. // (6) Parse expansions
  301. for (auto& token : tokens) {
  302. if (!is_one_of(token.type, Token::Type::Word, Token::Type::AssignmentWord)) {
  303. expanded_tokens.append(move(token));
  304. continue;
  305. }
  306. Vector<ResolvedExpansion> resolved_expansions;
  307. for (auto& expansion : token.expansions) {
  308. auto resolved = expansion.visit(
  309. [&](ParameterExpansion const& expansion) -> ResolvedExpansion {
  310. auto text = expansion.parameter.string_view();
  311. // ${NUMBER}
  312. if (all_of(text, is_ascii_digit)) {
  313. return ResolvedParameterExpansion {
  314. .parameter = expansion.parameter.to_deprecated_string(),
  315. .argument = {},
  316. .range = expansion.range,
  317. .op = ResolvedParameterExpansion::Op::GetPositionalParameter,
  318. };
  319. }
  320. if (text.length() == 1) {
  321. ResolvedParameterExpansion::Op op;
  322. switch (text[0]) {
  323. case '!':
  324. op = ResolvedParameterExpansion::Op::GetLastBackgroundPid;
  325. break;
  326. case '@':
  327. op = ResolvedParameterExpansion::Op::GetPositionalParameterList;
  328. break;
  329. case '-':
  330. op = ResolvedParameterExpansion::Op::GetCurrentOptionFlags;
  331. break;
  332. case '#':
  333. op = ResolvedParameterExpansion::Op::GetPositionalParameterCount;
  334. break;
  335. case '?':
  336. op = ResolvedParameterExpansion::Op::GetLastExitStatus;
  337. break;
  338. case '*':
  339. op = ResolvedParameterExpansion::Op::GetPositionalParameterListAsString;
  340. break;
  341. case '$':
  342. op = ResolvedParameterExpansion::Op::GetShellProcessId;
  343. break;
  344. default:
  345. if (is_valid_name(text)) {
  346. op = ResolvedParameterExpansion::Op::GetVariable;
  347. } else {
  348. error(token, "Unknown parameter expansion: {}", text);
  349. return ResolvedParameterExpansion {
  350. .parameter = expansion.parameter.to_deprecated_string(),
  351. .argument = {},
  352. .range = expansion.range,
  353. .op = ResolvedParameterExpansion::Op::StringLength,
  354. };
  355. }
  356. }
  357. return ResolvedParameterExpansion {
  358. .parameter = {},
  359. .argument = {},
  360. .range = expansion.range,
  361. .op = op,
  362. };
  363. }
  364. if (text.starts_with('#')) {
  365. return ResolvedParameterExpansion {
  366. .parameter = text.substring_view(1).to_deprecated_string(),
  367. .argument = {},
  368. .range = expansion.range,
  369. .op = ResolvedParameterExpansion::Op::StringLength,
  370. };
  371. }
  372. GenericLexer lexer { text };
  373. auto parameter = lexer.consume_while([first = true](char c) mutable {
  374. if (first) {
  375. first = false;
  376. return is_ascii_alpha(c) || c == '_';
  377. }
  378. return is_ascii_alphanumeric(c) || c == '_';
  379. });
  380. StringView argument;
  381. ResolvedParameterExpansion::Op op;
  382. switch (lexer.peek()) {
  383. case ':':
  384. lexer.ignore();
  385. switch (lexer.is_eof() ? 0 : lexer.consume()) {
  386. case '-':
  387. argument = lexer.consume_all();
  388. op = ResolvedParameterExpansion::Op::UseDefaultValue;
  389. break;
  390. case '=':
  391. argument = lexer.consume_all();
  392. op = ResolvedParameterExpansion::Op::AssignDefaultValue;
  393. break;
  394. case '?':
  395. argument = lexer.consume_all();
  396. op = ResolvedParameterExpansion::Op::IndicateErrorIfEmpty;
  397. break;
  398. case '+':
  399. argument = lexer.consume_all();
  400. op = ResolvedParameterExpansion::Op::UseAlternativeValue;
  401. break;
  402. default:
  403. error(token, "Unknown parameter expansion: {}", text);
  404. return ResolvedParameterExpansion {
  405. .parameter = parameter.to_deprecated_string(),
  406. .argument = {},
  407. .range = expansion.range,
  408. .op = ResolvedParameterExpansion::Op::StringLength,
  409. };
  410. }
  411. break;
  412. case '-':
  413. lexer.ignore();
  414. argument = lexer.consume_all();
  415. op = ResolvedParameterExpansion::Op::UseDefaultValueIfUnset;
  416. break;
  417. case '=':
  418. lexer.ignore();
  419. argument = lexer.consume_all();
  420. op = ResolvedParameterExpansion::Op::AssignDefaultValueIfUnset;
  421. break;
  422. case '?':
  423. lexer.ignore();
  424. argument = lexer.consume_all();
  425. op = ResolvedParameterExpansion::Op::IndicateErrorIfUnset;
  426. break;
  427. case '+':
  428. lexer.ignore();
  429. argument = lexer.consume_all();
  430. op = ResolvedParameterExpansion::Op::UseAlternativeValueIfUnset;
  431. break;
  432. case '%':
  433. if (lexer.consume_specific('%'))
  434. op = ResolvedParameterExpansion::Op::RemoveLargestSuffixByPattern;
  435. else
  436. op = ResolvedParameterExpansion::Op::RemoveSmallestSuffixByPattern;
  437. argument = lexer.consume_all();
  438. break;
  439. case '#':
  440. if (lexer.consume_specific('#'))
  441. op = ResolvedParameterExpansion::Op::RemoveLargestPrefixByPattern;
  442. else
  443. op = ResolvedParameterExpansion::Op::RemoveSmallestPrefixByPattern;
  444. argument = lexer.consume_all();
  445. break;
  446. default:
  447. if (is_valid_name(text)) {
  448. op = ResolvedParameterExpansion::Op::GetVariable;
  449. } else {
  450. error(token, "Unknown parameter expansion: {}", text);
  451. return ResolvedParameterExpansion {
  452. .parameter = parameter.to_deprecated_string(),
  453. .argument = {},
  454. .range = expansion.range,
  455. .op = ResolvedParameterExpansion::Op::StringLength,
  456. };
  457. }
  458. }
  459. VERIFY(lexer.is_eof());
  460. return ResolvedParameterExpansion {
  461. .parameter = parameter.to_deprecated_string(),
  462. .argument = argument.to_deprecated_string(),
  463. .range = expansion.range,
  464. .op = op,
  465. .expand = ResolvedParameterExpansion::Expand::Word,
  466. };
  467. },
  468. [&](ArithmeticExpansion const& expansion) -> ResolvedExpansion {
  469. error(token, "Arithmetic expansion is not supported");
  470. return ResolvedParameterExpansion {
  471. .parameter = ""sv,
  472. .argument = ""sv,
  473. .range = expansion.range,
  474. .op = ResolvedParameterExpansion::Op::StringLength,
  475. .expand = ResolvedParameterExpansion::Expand::Nothing,
  476. };
  477. },
  478. [&](CommandExpansion const& expansion) -> ResolvedExpansion {
  479. Parser parser { expansion.command.string_view() };
  480. auto node = parser.parse();
  481. m_errors.extend(move(parser.m_errors));
  482. return ResolvedCommandExpansion {
  483. move(node),
  484. expansion.range,
  485. };
  486. });
  487. resolved_expansions.append(move(resolved));
  488. }
  489. token.resolved_expansions = move(resolved_expansions);
  490. expanded_tokens.append(move(token));
  491. }
  492. swap_expansions();
  493. // (7) Loop variables
  494. previous_token = {};
  495. tokens_taken_from_buffer = 0;
  496. if (m_token_buffer.size() >= 1) {
  497. previous_token = m_token_buffer.take_last();
  498. tokens_taken_from_buffer++;
  499. }
  500. for (auto& token : tokens) {
  501. if (!previous_token.has_value()) {
  502. previous_token = token;
  503. continue;
  504. }
  505. if (previous_token->type == Token::Type::For && token.type == Token::Type::Word && is_valid_name(token.value)) {
  506. token.type = Token::Type::VariableName;
  507. }
  508. expanded_tokens.append(exchange(*previous_token, token));
  509. }
  510. swap_expansions();
  511. // (8) Function names
  512. previous_token = {};
  513. previous_previous_token = {};
  514. tokens_taken_from_buffer = 0;
  515. if (m_token_buffer.size() >= 1) {
  516. previous_token = m_token_buffer.take_last();
  517. tokens_taken_from_buffer++;
  518. }
  519. if (m_token_buffer.size() >= 1) {
  520. previous_previous_token = m_token_buffer.take_last();
  521. tokens_taken_from_buffer++;
  522. }
  523. for (auto& token : tokens) {
  524. if (!previous_token.has_value()) {
  525. previous_token = token;
  526. continue;
  527. }
  528. if (!previous_previous_token.has_value()) {
  529. previous_previous_token = move(previous_token);
  530. previous_token = token;
  531. continue;
  532. }
  533. // NAME ( )
  534. if (previous_previous_token->could_be_start_of_a_simple_command
  535. && previous_previous_token->type == Token::Type::Word
  536. && previous_token->type == Token::Type::OpenParen
  537. && token.type == Token::Type::CloseParen) {
  538. previous_previous_token->type = Token::Type::VariableName;
  539. }
  540. expanded_tokens.append(exchange(*previous_previous_token, exchange(*previous_token, token)));
  541. }
  542. swap_expansions();
  543. return tokens;
  544. }
  545. RefPtr<AST::Node> Parser::parse_complete_command()
  546. {
  547. auto list = [&] {
  548. // separator...
  549. while (is_separator(peek()))
  550. skip();
  551. // list EOF
  552. auto list = parse_list();
  553. if (eof())
  554. return list;
  555. // list separator EOF
  556. while (is_separator(peek()))
  557. skip();
  558. if (eof())
  559. return list;
  560. auto position = peek().position;
  561. auto syntax_error = make_ref_counted<AST::SyntaxError>(
  562. position.value_or(empty_position()),
  563. String::from_utf8("Extra tokens after complete command"sv).release_value_but_fixme_should_propagate_errors());
  564. if (list)
  565. list->set_is_syntax_error(*syntax_error);
  566. else
  567. list = syntax_error;
  568. return list;
  569. }();
  570. if (!list)
  571. return nullptr;
  572. return make_ref_counted<AST::Execute>(list->position(), *list);
  573. }
  574. RefPtr<AST::Node> Parser::parse_list()
  575. {
  576. NonnullRefPtrVector<AST::Node> nodes;
  577. Vector<AST::Position> positions;
  578. auto start_position = peek().position.value_or(empty_position());
  579. for (;;) {
  580. auto new_node = parse_and_or();
  581. if (!new_node)
  582. break;
  583. if (peek().type == Token::Type::And) {
  584. new_node = make_ref_counted<AST::Background>(
  585. new_node->position(),
  586. *new_node);
  587. }
  588. nodes.append(new_node.release_nonnull());
  589. if (!is_separator(peek()) || eof())
  590. break;
  591. auto position = consume().position;
  592. if (position.has_value())
  593. positions.append(position.release_value());
  594. }
  595. auto end_position = peek().position.value_or(empty_position());
  596. return make_ref_counted<AST::Sequence>(
  597. AST::Position {
  598. start_position.start_offset,
  599. end_position.end_offset,
  600. start_position.start_line,
  601. start_position.end_line,
  602. },
  603. move(nodes),
  604. move(positions));
  605. }
  606. RefPtr<AST::Node> Parser::parse_and_or()
  607. {
  608. auto node = parse_pipeline();
  609. if (!node)
  610. return {};
  611. for (;;) {
  612. if (peek().type == Token::Type::AndIf) {
  613. auto and_token = consume();
  614. while (peek().type == Token::Type::Newline)
  615. skip();
  616. auto rhs = parse_pipeline();
  617. if (!rhs)
  618. return {};
  619. node = make_ref_counted<AST::And>(
  620. node->position(),
  621. *node,
  622. rhs.release_nonnull(),
  623. and_token.position.value_or(empty_position()));
  624. continue;
  625. }
  626. if (peek().type == Token::Type::OrIf) {
  627. auto or_token = consume();
  628. while (peek().type == Token::Type::Newline)
  629. skip();
  630. auto rhs = parse_pipeline();
  631. if (!rhs)
  632. return {};
  633. node = make_ref_counted<AST::And>(
  634. node->position(),
  635. *node,
  636. rhs.release_nonnull(),
  637. or_token.position.value_or(empty_position()));
  638. continue;
  639. }
  640. break;
  641. }
  642. return node;
  643. }
  644. RefPtr<AST::Node> Parser::parse_pipeline()
  645. {
  646. return parse_pipe_sequence();
  647. }
  648. RefPtr<AST::Node> Parser::parse_pipe_sequence()
  649. {
  650. auto node = parse_command();
  651. if (!node)
  652. return {};
  653. for (;;) {
  654. if (peek().type != Token::Type::Pipe)
  655. break;
  656. consume();
  657. while (peek().type == Token::Type::Newline)
  658. skip();
  659. auto rhs = parse_command();
  660. if (!rhs)
  661. return {};
  662. node = make_ref_counted<AST::Pipe>(
  663. node->position(),
  664. *node,
  665. rhs.release_nonnull());
  666. }
  667. return node;
  668. }
  669. RefPtr<AST::Node> Parser::parse_command()
  670. {
  671. auto node = [this] {
  672. if (auto node = parse_function_definition())
  673. return node;
  674. if (auto node = parse_simple_command())
  675. return node;
  676. auto node = parse_compound_command();
  677. if (!node)
  678. return node;
  679. if (auto list = parse_redirect_list()) {
  680. auto position = list->position();
  681. node = make_ref_counted<AST::Join>(
  682. node->position().with_end(position),
  683. *node,
  684. list.release_nonnull());
  685. }
  686. return node;
  687. }();
  688. if (!node)
  689. return nullptr;
  690. return make_ref_counted<AST::CastToCommand>(node->position(), *node);
  691. }
  692. RefPtr<AST::Node> Parser::parse_function_definition()
  693. {
  694. // NAME OPEN_PAREN CLOSE_PAREN newline* function_body
  695. auto start_index = m_token_index;
  696. ArmedScopeGuard reset = [&] {
  697. m_token_index = start_index;
  698. };
  699. if (peek().type != Token::Type::VariableName) {
  700. return nullptr;
  701. }
  702. auto name = consume();
  703. if (consume().type != Token::Type::OpenParen)
  704. return nullptr;
  705. if (consume().type != Token::Type::CloseParen)
  706. return nullptr;
  707. while (peek().type == Token::Type::Newline)
  708. skip();
  709. auto body = parse_function_body();
  710. if (!body)
  711. return nullptr;
  712. reset.disarm();
  713. return make_ref_counted<AST::FunctionDeclaration>(
  714. name.position.value_or(empty_position()).with_end(peek().position.value_or(empty_position())),
  715. AST::NameWithPosition { String::from_utf8(name.value).release_value_but_fixme_should_propagate_errors(), name.position.value_or(empty_position()) },
  716. Vector<AST::NameWithPosition> {},
  717. body.release_nonnull());
  718. }
  719. RefPtr<AST::Node> Parser::parse_function_body()
  720. {
  721. // compound_command redirect_list?
  722. auto node = parse_compound_command();
  723. if (!node)
  724. return nullptr;
  725. if (auto list = parse_redirect_list()) {
  726. auto position = list->position();
  727. node = make_ref_counted<AST::Join>(
  728. node->position().with_end(position),
  729. *node,
  730. list.release_nonnull());
  731. }
  732. return node;
  733. }
  734. RefPtr<AST::Node> Parser::parse_redirect_list()
  735. {
  736. // io_redirect*
  737. RefPtr<AST::Node> node;
  738. for (;;) {
  739. auto new_node = parse_io_redirect();
  740. if (!new_node)
  741. break;
  742. if (node) {
  743. node = make_ref_counted<AST::Join>(
  744. node->position().with_end(new_node->position()),
  745. *node,
  746. new_node.release_nonnull());
  747. } else {
  748. node = new_node;
  749. }
  750. }
  751. return node;
  752. }
  753. RefPtr<AST::Node> Parser::parse_compound_command()
  754. {
  755. if (auto node = parse_brace_group())
  756. return node;
  757. if (auto node = parse_subshell())
  758. return node;
  759. if (auto node = parse_if_clause())
  760. return node;
  761. if (auto node = parse_for_clause())
  762. return node;
  763. if (auto node = parse_case_clause())
  764. return node;
  765. if (auto node = parse_while_clause())
  766. return node;
  767. if (auto node = parse_until_clause())
  768. return node;
  769. return {};
  770. }
  771. RefPtr<AST::Node> Parser::parse_while_clause()
  772. {
  773. if (peek().type != Token::Type::While)
  774. return nullptr;
  775. auto start_position = consume().position.value_or(empty_position());
  776. auto condition = parse_compound_list();
  777. if (!condition)
  778. condition = make_ref_counted<AST::SyntaxError>(
  779. peek().position.value_or(empty_position()),
  780. String::from_utf8("Expected condition after 'while'"sv).release_value_but_fixme_should_propagate_errors());
  781. auto do_group = parse_do_group();
  782. if (!do_group)
  783. do_group = make_ref_counted<AST::SyntaxError>(
  784. peek().position.value_or(empty_position()),
  785. String::from_utf8("Expected 'do' after 'while'"sv).release_value_but_fixme_should_propagate_errors());
  786. // while foo; bar -> loop { if foo { bar } else { break } }
  787. return make_ref_counted<AST::ForLoop>(
  788. start_position.with_end(peek().position.value_or(empty_position())),
  789. Optional<AST::NameWithPosition> {},
  790. Optional<AST::NameWithPosition> {},
  791. nullptr,
  792. make_ref_counted<AST::IfCond>(
  793. start_position.with_end(peek().position.value_or(empty_position())),
  794. Optional<AST::Position> {},
  795. condition.release_nonnull(),
  796. do_group.release_nonnull(),
  797. make_ref_counted<AST::ContinuationControl>(
  798. start_position,
  799. AST::ContinuationControl::ContinuationKind::Break)));
  800. }
  801. RefPtr<AST::Node> Parser::parse_until_clause()
  802. {
  803. if (peek().type != Token::Type::Until)
  804. return nullptr;
  805. auto start_position = consume().position.value_or(empty_position());
  806. auto condition = parse_compound_list();
  807. if (!condition)
  808. condition = make_ref_counted<AST::SyntaxError>(
  809. peek().position.value_or(empty_position()),
  810. String::from_utf8("Expected condition after 'until'"sv).release_value_but_fixme_should_propagate_errors());
  811. auto do_group = parse_do_group();
  812. if (!do_group)
  813. do_group = make_ref_counted<AST::SyntaxError>(
  814. peek().position.value_or(empty_position()),
  815. String::from_utf8("Expected 'do' after 'until'"sv).release_value_but_fixme_should_propagate_errors());
  816. // until foo; bar -> loop { if foo { break } else { bar } }
  817. return make_ref_counted<AST::ForLoop>(
  818. start_position.with_end(peek().position.value_or(empty_position())),
  819. Optional<AST::NameWithPosition> {},
  820. Optional<AST::NameWithPosition> {},
  821. nullptr,
  822. make_ref_counted<AST::IfCond>(
  823. start_position.with_end(peek().position.value_or(empty_position())),
  824. Optional<AST::Position> {},
  825. condition.release_nonnull(),
  826. make_ref_counted<AST::ContinuationControl>(
  827. start_position,
  828. AST::ContinuationControl::ContinuationKind::Break),
  829. do_group.release_nonnull()));
  830. }
  831. RefPtr<AST::Node> Parser::parse_brace_group()
  832. {
  833. if (peek().type != Token::Type::OpenBrace)
  834. return nullptr;
  835. consume();
  836. auto list = parse_compound_list();
  837. RefPtr<AST::SyntaxError> error;
  838. if (peek().type != Token::Type::CloseBrace) {
  839. error = make_ref_counted<AST::SyntaxError>(
  840. peek().position.value_or(empty_position()),
  841. String::formatted("Expected '}}', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  842. } else {
  843. consume();
  844. }
  845. if (error) {
  846. if (list)
  847. list->set_is_syntax_error(*error);
  848. else
  849. list = error;
  850. }
  851. return make_ref_counted<AST::Execute>(list->position(), *list);
  852. }
  853. RefPtr<AST::Node> Parser::parse_case_clause()
  854. {
  855. auto start_position = peek().position.value_or(empty_position());
  856. if (peek().type != Token::Type::Case)
  857. return nullptr;
  858. skip();
  859. RefPtr<AST::SyntaxError> syntax_error;
  860. auto expr = parse_word();
  861. if (!expr)
  862. expr = make_ref_counted<AST::SyntaxError>(
  863. peek().position.value_or(empty_position()),
  864. String::formatted("Expected a word, not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  865. if (peek().type != Token::Type::In) {
  866. syntax_error = make_ref_counted<AST::SyntaxError>(
  867. peek().position.value_or(empty_position()),
  868. String::formatted("Expected 'in', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  869. } else {
  870. skip();
  871. }
  872. while (peek().type == Token::Type::Newline)
  873. skip();
  874. Vector<AST::MatchEntry> entries;
  875. for (;;) {
  876. if (eof() || peek().type == Token::Type::Esac)
  877. break;
  878. if (peek().type == Token::Type::Newline) {
  879. skip();
  880. continue;
  881. }
  882. // Parse a pattern list
  883. auto needs_dsemi = true;
  884. if (peek().type == Token::Type::OpenParen) {
  885. skip();
  886. needs_dsemi = false;
  887. }
  888. auto result = parse_case_list();
  889. if (peek().type == Token::Type::CloseParen) {
  890. skip();
  891. } else {
  892. if (!syntax_error)
  893. syntax_error = make_ref_counted<AST::SyntaxError>(
  894. peek().position.value_or(empty_position()),
  895. String::formatted("Expected ')', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  896. break;
  897. }
  898. while (peek().type == Token::Type::Newline)
  899. skip();
  900. auto compound_list = parse_compound_list();
  901. if (peek().type == Token::Type::DoubleSemicolon) {
  902. skip();
  903. } else if (needs_dsemi) {
  904. if (!syntax_error)
  905. syntax_error = make_ref_counted<AST::SyntaxError>(
  906. peek().position.value_or(empty_position()),
  907. String::formatted("Expected ';;', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  908. }
  909. if (syntax_error) {
  910. if (compound_list)
  911. compound_list->set_is_syntax_error(*syntax_error);
  912. else
  913. compound_list = syntax_error;
  914. syntax_error = nullptr;
  915. }
  916. entries.append(AST::MatchEntry {
  917. .options = move(result.nodes),
  918. .match_names = {},
  919. .match_as_position = {},
  920. .pipe_positions = move(result.pipe_positions),
  921. .body = move(compound_list),
  922. });
  923. }
  924. if (peek().type != Token::Type::Esac) {
  925. syntax_error = make_ref_counted<AST::SyntaxError>(
  926. peek().position.value_or(empty_position()),
  927. String::formatted("Expected 'esac', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  928. } else {
  929. skip();
  930. }
  931. auto node = make_ref_counted<AST::MatchExpr>(
  932. start_position.with_end(peek().position.value_or(empty_position())),
  933. expr.release_nonnull(),
  934. String {},
  935. Optional<AST::Position> {},
  936. move(entries));
  937. if (syntax_error)
  938. node->set_is_syntax_error(*syntax_error);
  939. return node;
  940. }
  941. Parser::CaseItemsResult Parser::parse_case_list()
  942. {
  943. // Just a list of words split by '|', delimited by ')'
  944. NonnullRefPtrVector<AST::Node> nodes;
  945. Vector<AST::Position> pipes;
  946. for (;;) {
  947. if (eof() || peek().type == Token::Type::CloseParen)
  948. break;
  949. if (peek().type != Token::Type::Word)
  950. break;
  951. auto node = parse_word();
  952. if (!node)
  953. node = make_ref_counted<AST::SyntaxError>(
  954. peek().position.value_or(empty_position()),
  955. String::formatted("Expected a word, not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  956. nodes.append(node.release_nonnull());
  957. if (peek().type == Token::Type::Pipe) {
  958. pipes.append(peek().position.value_or(empty_position()));
  959. skip();
  960. } else {
  961. break;
  962. }
  963. }
  964. if (nodes.is_empty())
  965. nodes.append(make_ref_counted<AST::SyntaxError>(
  966. peek().position.value_or(empty_position()),
  967. String::formatted("Expected a word, not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors()));
  968. return { move(pipes), move(nodes) };
  969. }
  970. RefPtr<AST::Node> Parser::parse_if_clause()
  971. {
  972. // If compound_list Then compound_list {Elif compound_list Then compound_list (Fi|Else)?} [(?=Else) compound_list] (?!=Fi) Fi
  973. auto start_position = peek().position.value_or(empty_position());
  974. if (peek().type != Token::Type::If)
  975. return nullptr;
  976. skip();
  977. auto main_condition = parse_compound_list();
  978. if (!main_condition)
  979. main_condition = make_ref_counted<AST::SyntaxError>(empty_position(), String::from_utf8("Expected compound list after 'if'"sv).release_value_but_fixme_should_propagate_errors());
  980. RefPtr<AST::SyntaxError> syntax_error;
  981. if (peek().type != Token::Type::Then) {
  982. syntax_error = make_ref_counted<AST::SyntaxError>(
  983. peek().position.value_or(empty_position()),
  984. String::formatted("Expected 'then', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  985. } else {
  986. skip();
  987. }
  988. auto main_consequence = parse_compound_list();
  989. if (!main_consequence)
  990. main_consequence = make_ref_counted<AST::SyntaxError>(empty_position(), String::from_utf8("Expected compound list after 'then'"sv).release_value_but_fixme_should_propagate_errors());
  991. auto node = make_ref_counted<AST::IfCond>(start_position, Optional<AST::Position>(), main_condition.release_nonnull(), main_consequence.release_nonnull(), nullptr);
  992. auto active_node = node;
  993. while (peek().type == Token::Type::Elif) {
  994. skip();
  995. auto condition = parse_compound_list();
  996. if (!condition)
  997. condition = make_ref_counted<AST::SyntaxError>(empty_position(), String::from_utf8("Expected compound list after 'elif'"sv).release_value_but_fixme_should_propagate_errors());
  998. if (peek().type != Token::Type::Then) {
  999. if (!syntax_error)
  1000. syntax_error = make_ref_counted<AST::SyntaxError>(
  1001. peek().position.value_or(empty_position()),
  1002. String::formatted("Expected 'then', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  1003. } else {
  1004. skip();
  1005. }
  1006. auto consequence = parse_compound_list();
  1007. if (!consequence)
  1008. consequence = make_ref_counted<AST::SyntaxError>(empty_position(), String::from_utf8("Expected compound list after 'then'"sv).release_value_but_fixme_should_propagate_errors());
  1009. auto new_node = make_ref_counted<AST::IfCond>(start_position, Optional<AST::Position>(), condition.release_nonnull(), consequence.release_nonnull(), nullptr);
  1010. active_node->false_branch() = new_node;
  1011. active_node = move(new_node);
  1012. }
  1013. auto needs_fi = true;
  1014. switch (peek().type) {
  1015. case Token::Type::Else:
  1016. skip();
  1017. active_node->false_branch() = parse_compound_list();
  1018. if (!active_node->false_branch())
  1019. active_node->false_branch() = make_ref_counted<AST::SyntaxError>(empty_position(), String::from_utf8("Expected compound list after 'else'"sv).release_value_but_fixme_should_propagate_errors());
  1020. break;
  1021. case Token::Type::Fi:
  1022. needs_fi = false;
  1023. break;
  1024. default:
  1025. if (!syntax_error)
  1026. syntax_error = make_ref_counted<AST::SyntaxError>(
  1027. peek().position.value_or(empty_position()),
  1028. String::formatted("Expected 'else' or 'fi', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  1029. break;
  1030. }
  1031. if (needs_fi) {
  1032. if (peek().type != Token::Type::Fi) {
  1033. if (!syntax_error)
  1034. syntax_error = make_ref_counted<AST::SyntaxError>(
  1035. peek().position.value_or(empty_position()),
  1036. String::formatted("Expected 'fi', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  1037. } else {
  1038. skip();
  1039. }
  1040. }
  1041. if (syntax_error)
  1042. node->set_is_syntax_error(*syntax_error);
  1043. return node;
  1044. }
  1045. RefPtr<AST::Node> Parser::parse_subshell()
  1046. {
  1047. auto start_position = peek().position.value_or(empty_position());
  1048. if (peek().type != Token::Type::OpenParen)
  1049. return nullptr;
  1050. skip();
  1051. RefPtr<AST::SyntaxError> error;
  1052. auto list = parse_compound_list();
  1053. if (!list)
  1054. error = make_ref_counted<AST::SyntaxError>(peek().position.value_or(empty_position()), String::from_utf8("Expected compound list after ("sv).release_value_but_fixme_should_propagate_errors());
  1055. if (peek().type != Token::Type::CloseParen)
  1056. error = make_ref_counted<AST::SyntaxError>(peek().position.value_or(empty_position()), String::from_utf8("Expected ) after compound list"sv).release_value_but_fixme_should_propagate_errors());
  1057. else
  1058. skip();
  1059. if (!list)
  1060. return error;
  1061. return make_ref_counted<AST::Subshell>(
  1062. start_position.with_end(peek().position.value_or(empty_position())),
  1063. list.release_nonnull());
  1064. }
  1065. RefPtr<AST::Node> Parser::parse_compound_list()
  1066. {
  1067. while (peek().type == Token::Type::Newline)
  1068. skip();
  1069. auto term = parse_term();
  1070. if (!term)
  1071. return term;
  1072. if (is_separator(peek())) {
  1073. if (consume().type == Token::Type::And) {
  1074. term = make_ref_counted<AST::Background>(
  1075. term->position().with_end(peek().position.value_or(empty_position())),
  1076. *term);
  1077. }
  1078. }
  1079. return term;
  1080. }
  1081. RefPtr<AST::Node> Parser::parse_term()
  1082. {
  1083. NonnullRefPtrVector<AST::Node> nodes;
  1084. Vector<AST::Position> positions;
  1085. auto start_position = peek().position.value_or(empty_position());
  1086. for (;;) {
  1087. auto new_node = parse_and_or();
  1088. if (!new_node)
  1089. break;
  1090. nodes.append(new_node.release_nonnull());
  1091. if (!is_separator(peek()))
  1092. break;
  1093. auto position = consume().position;
  1094. if (position.has_value())
  1095. positions.append(position.release_value());
  1096. }
  1097. auto end_position = peek().position.value_or(empty_position());
  1098. return make_ref_counted<AST::Sequence>(
  1099. start_position.with_end(end_position),
  1100. move(nodes),
  1101. move(positions));
  1102. }
  1103. RefPtr<AST::Node> Parser::parse_for_clause()
  1104. {
  1105. // FOR NAME newline+ do_group
  1106. // FOR NAME newline+ IN separator do_group
  1107. // FOR NAME IN separator do_group
  1108. // FOR NAME IN wordlist separator do_group
  1109. if (peek().type != Token::Type::For)
  1110. return nullptr;
  1111. auto start_position = consume().position.value_or(empty_position());
  1112. DeprecatedString name;
  1113. Optional<AST::Position> name_position;
  1114. if (peek().type == Token::Type::VariableName) {
  1115. name_position = peek().position;
  1116. name = consume().value;
  1117. } else {
  1118. name = "it";
  1119. error(peek(), "Expected a variable name, not {}", peek().type_name());
  1120. }
  1121. auto saw_newline = false;
  1122. while (peek().type == Token::Type::Newline) {
  1123. saw_newline = true;
  1124. skip();
  1125. }
  1126. auto saw_in = false;
  1127. Optional<AST::Position> in_kw_position;
  1128. if (peek().type == Token::Type::In) {
  1129. saw_in = true;
  1130. in_kw_position = peek().position;
  1131. skip();
  1132. } else if (!saw_newline) {
  1133. error(peek(), "Expected 'in' or a newline, not {}", peek().type_name());
  1134. }
  1135. RefPtr<AST::Node> iterated_expression;
  1136. if (!saw_newline)
  1137. iterated_expression = parse_word_list();
  1138. if (saw_in) {
  1139. if (peek().type == Token::Type::Semicolon)
  1140. skip();
  1141. else
  1142. error(peek(), "Expected a semicolon, not {}", peek().type_name());
  1143. }
  1144. auto body = parse_do_group();
  1145. return AST::make_ref_counted<AST::ForLoop>(
  1146. start_position.with_end(peek().position.value_or(empty_position())),
  1147. AST::NameWithPosition { String::from_deprecated_string(name).release_value_but_fixme_should_propagate_errors(), name_position.value_or(empty_position()) },
  1148. Optional<AST::NameWithPosition> {},
  1149. move(iterated_expression),
  1150. move(body),
  1151. move(in_kw_position),
  1152. Optional<AST::Position> {});
  1153. }
  1154. RefPtr<AST::Node> Parser::parse_word_list()
  1155. {
  1156. NonnullRefPtrVector<AST::Node> nodes;
  1157. auto start_position = peek().position.value_or(empty_position());
  1158. for (; peek().type == Token::Type::Word;) {
  1159. auto word = parse_word();
  1160. nodes.append(word.release_nonnull());
  1161. }
  1162. return make_ref_counted<AST::ListConcatenate>(
  1163. start_position.with_end(peek().position.value_or(empty_position())),
  1164. move(nodes));
  1165. }
  1166. RefPtr<AST::Node> Parser::parse_word()
  1167. {
  1168. if (peek().type != Token::Type::Word)
  1169. return nullptr;
  1170. auto token = consume();
  1171. RefPtr<AST::Node> word;
  1172. enum class Quote {
  1173. None,
  1174. Single,
  1175. Double,
  1176. } in_quote { Quote::None };
  1177. auto append_bareword = [&](StringView string) {
  1178. if (!word && string.starts_with('~')) {
  1179. GenericLexer lexer { string };
  1180. lexer.ignore();
  1181. auto user = lexer.consume_while(is_ascii_alphanumeric);
  1182. string = lexer.remaining();
  1183. word = make_ref_counted<AST::Tilde>(token.position.value_or(empty_position()), String::from_utf8(user).release_value_but_fixme_should_propagate_errors());
  1184. }
  1185. if (string.is_empty())
  1186. return;
  1187. auto node = make_ref_counted<AST::BarewordLiteral>(token.position.value_or(empty_position()), String::from_utf8(string).release_value_but_fixme_should_propagate_errors());
  1188. if (word) {
  1189. word = make_ref_counted<AST::Juxtaposition>(
  1190. word->position().with_end(token.position.value_or(empty_position())),
  1191. *word,
  1192. move(node),
  1193. AST::Juxtaposition::Mode::StringExpand);
  1194. } else {
  1195. word = move(node);
  1196. }
  1197. };
  1198. auto append_string_literal = [&](StringView string) {
  1199. if (string.is_empty())
  1200. return;
  1201. auto node = make_ref_counted<AST::StringLiteral>(token.position.value_or(empty_position()), String::from_utf8(string).release_value_but_fixme_should_propagate_errors(), AST::StringLiteral::EnclosureType::SingleQuotes);
  1202. if (word) {
  1203. word = make_ref_counted<AST::Juxtaposition>(
  1204. word->position().with_end(token.position.value_or(empty_position())),
  1205. *word,
  1206. move(node),
  1207. AST::Juxtaposition::Mode::StringExpand);
  1208. } else {
  1209. word = move(node);
  1210. }
  1211. };
  1212. auto append_string_part = [&](StringView string) {
  1213. if (string.is_empty())
  1214. return;
  1215. auto node = make_ref_counted<AST::StringLiteral>(token.position.value_or(empty_position()), String::from_utf8(string).release_value_but_fixme_should_propagate_errors(), AST::StringLiteral::EnclosureType::DoubleQuotes);
  1216. if (word) {
  1217. word = make_ref_counted<AST::Juxtaposition>(
  1218. word->position().with_end(token.position.value_or(empty_position())),
  1219. *word,
  1220. move(node),
  1221. AST::Juxtaposition::Mode::StringExpand);
  1222. } else {
  1223. word = move(node);
  1224. }
  1225. };
  1226. auto append_parameter_expansion = [&](ResolvedParameterExpansion const& x) {
  1227. DeprecatedString immediate_function_name;
  1228. RefPtr<AST::Node> node;
  1229. switch (x.op) {
  1230. case ResolvedParameterExpansion::Op::UseDefaultValue:
  1231. immediate_function_name = "value_or_default";
  1232. break;
  1233. case ResolvedParameterExpansion::Op::AssignDefaultValue:
  1234. immediate_function_name = "assign_default";
  1235. break;
  1236. case ResolvedParameterExpansion::Op::IndicateErrorIfEmpty:
  1237. immediate_function_name = "error_if_empty";
  1238. break;
  1239. case ResolvedParameterExpansion::Op::UseAlternativeValue:
  1240. immediate_function_name = "null_or_alternative";
  1241. break;
  1242. case ResolvedParameterExpansion::Op::UseDefaultValueIfUnset:
  1243. immediate_function_name = "defined_value_or_default";
  1244. break;
  1245. case ResolvedParameterExpansion::Op::AssignDefaultValueIfUnset:
  1246. immediate_function_name = "assign_defined_default";
  1247. break;
  1248. case ResolvedParameterExpansion::Op::IndicateErrorIfUnset:
  1249. immediate_function_name = "error_if_unset";
  1250. break;
  1251. case ResolvedParameterExpansion::Op::UseAlternativeValueIfUnset:
  1252. immediate_function_name = "null_if_unset_or_alternative";
  1253. break;
  1254. case ResolvedParameterExpansion::Op::RemoveLargestSuffixByPattern:
  1255. // FIXME: Implement this
  1256. case ResolvedParameterExpansion::Op::RemoveSmallestSuffixByPattern:
  1257. immediate_function_name = "remove_suffix";
  1258. break;
  1259. case ResolvedParameterExpansion::Op::RemoveLargestPrefixByPattern:
  1260. // FIXME: Implement this
  1261. case ResolvedParameterExpansion::Op::RemoveSmallestPrefixByPattern:
  1262. immediate_function_name = "remove_prefix";
  1263. break;
  1264. case ResolvedParameterExpansion::Op::StringLength:
  1265. immediate_function_name = "length_of_variable";
  1266. break;
  1267. case ResolvedParameterExpansion::Op::GetPositionalParameter:
  1268. case ResolvedParameterExpansion::Op::GetVariable:
  1269. node = make_ref_counted<AST::SimpleVariable>(
  1270. token.position.value_or(empty_position()),
  1271. String::from_deprecated_string(x.parameter).release_value_but_fixme_should_propagate_errors());
  1272. break;
  1273. case ResolvedParameterExpansion::Op::GetLastBackgroundPid:
  1274. node = make_ref_counted<AST::SyntaxError>(
  1275. token.position.value_or(empty_position()),
  1276. String::from_utf8("$! not implemented"sv).release_value_but_fixme_should_propagate_errors());
  1277. break;
  1278. case ResolvedParameterExpansion::Op::GetPositionalParameterList:
  1279. node = make_ref_counted<AST::SpecialVariable>(
  1280. token.position.value_or(empty_position()),
  1281. '*');
  1282. break;
  1283. case ResolvedParameterExpansion::Op::GetCurrentOptionFlags:
  1284. node = make_ref_counted<AST::SyntaxError>(
  1285. token.position.value_or(empty_position()),
  1286. String::from_utf8("The current option flags are not available in parameter expansions"sv).release_value_but_fixme_should_propagate_errors());
  1287. break;
  1288. case ResolvedParameterExpansion::Op::GetPositionalParameterCount:
  1289. node = make_ref_counted<AST::SpecialVariable>(
  1290. token.position.value_or(empty_position()),
  1291. '#');
  1292. break;
  1293. case ResolvedParameterExpansion::Op::GetLastExitStatus:
  1294. node = make_ref_counted<AST::SpecialVariable>(
  1295. token.position.value_or(empty_position()),
  1296. '?');
  1297. break;
  1298. case ResolvedParameterExpansion::Op::GetPositionalParameterListAsString:
  1299. node = make_ref_counted<AST::SyntaxError>(
  1300. token.position.value_or(empty_position()),
  1301. String::from_utf8("$* not implemented"sv).release_value_but_fixme_should_propagate_errors());
  1302. break;
  1303. case ResolvedParameterExpansion::Op::GetShellProcessId:
  1304. node = make_ref_counted<AST::SpecialVariable>(
  1305. token.position.value_or(empty_position()),
  1306. '$');
  1307. break;
  1308. }
  1309. if (!node) {
  1310. NonnullRefPtrVector<AST::Node> arguments;
  1311. arguments.append(make_ref_counted<AST::BarewordLiteral>(
  1312. token.position.value_or(empty_position()),
  1313. String::from_deprecated_string(x.parameter).release_value_but_fixme_should_propagate_errors()));
  1314. if (!x.argument.is_empty()) {
  1315. // dbgln("Will parse {}", x.argument);
  1316. arguments.append(*Parser { x.argument }.parse_word());
  1317. }
  1318. node = make_ref_counted<AST::ImmediateExpression>(
  1319. token.position.value_or(empty_position()),
  1320. AST::NameWithPosition {
  1321. String::from_deprecated_string(immediate_function_name).release_value_but_fixme_should_propagate_errors(),
  1322. token.position.value_or(empty_position()),
  1323. },
  1324. move(arguments),
  1325. Optional<AST::Position> {});
  1326. }
  1327. if (x.expand == ResolvedParameterExpansion::Expand::Word) {
  1328. node = make_ref_counted<AST::ImmediateExpression>(
  1329. token.position.value_or(empty_position()),
  1330. AST::NameWithPosition {
  1331. String::from_utf8("reexpand"sv).release_value_but_fixme_should_propagate_errors(),
  1332. token.position.value_or(empty_position()),
  1333. },
  1334. Vector { node.release_nonnull() },
  1335. Optional<AST::Position> {});
  1336. }
  1337. if (word) {
  1338. word = make_ref_counted<AST::Juxtaposition>(
  1339. word->position().with_end(token.position.value_or(empty_position())),
  1340. *word,
  1341. node.release_nonnull(),
  1342. AST::Juxtaposition::Mode::StringExpand);
  1343. } else {
  1344. word = move(node);
  1345. }
  1346. };
  1347. auto append_command_expansion = [&](ResolvedCommandExpansion const& x) {
  1348. if (!x.command)
  1349. return;
  1350. RefPtr<AST::Execute> execute_node;
  1351. if (x.command->is_execute()) {
  1352. execute_node = const_cast<AST::Execute&>(static_cast<AST::Execute const&>(*x.command));
  1353. execute_node->capture_stdout();
  1354. } else {
  1355. execute_node = make_ref_counted<AST::Execute>(
  1356. word ? word->position() : empty_position(),
  1357. *x.command,
  1358. true);
  1359. }
  1360. if (word) {
  1361. word = make_ref_counted<AST::Juxtaposition>(
  1362. word->position(),
  1363. *word,
  1364. execute_node.release_nonnull(),
  1365. AST::Juxtaposition::Mode::StringExpand);
  1366. } else {
  1367. word = move(execute_node);
  1368. }
  1369. };
  1370. auto append_string = [&](StringView string) {
  1371. if (string.is_empty())
  1372. return;
  1373. Optional<size_t> run_start;
  1374. auto escape = false;
  1375. for (size_t i = 0; i < string.length(); ++i) {
  1376. auto ch = string[i];
  1377. switch (ch) {
  1378. case '\\':
  1379. if (!escape && i + 1 < string.length()) {
  1380. if (is_one_of(string[i + 1], '"', '\'', '$', '`', '\\')) {
  1381. escape = in_quote != Quote::Single;
  1382. continue;
  1383. }
  1384. }
  1385. break;
  1386. case '\'':
  1387. if (in_quote == Quote::Single) {
  1388. in_quote = Quote::None;
  1389. append_string_literal(string.substring_view(*run_start, i - *run_start));
  1390. run_start = i + 1;
  1391. continue;
  1392. }
  1393. if (in_quote == Quote::Double) {
  1394. escape = false;
  1395. continue;
  1396. }
  1397. [[fallthrough]];
  1398. case '"':
  1399. if (ch == '\'' && in_quote == Quote::Single) {
  1400. escape = false;
  1401. continue;
  1402. }
  1403. if (!escape) {
  1404. if (ch == '"' && in_quote == Quote::Double) {
  1405. in_quote = Quote::None;
  1406. if (run_start.has_value())
  1407. append_string_part(string.substring_view(*run_start, i - *run_start));
  1408. run_start = i + 1;
  1409. continue;
  1410. }
  1411. if (run_start.has_value())
  1412. append_bareword(string.substring_view(*run_start, i - *run_start));
  1413. in_quote = ch == '\'' ? Quote::Single : Quote::Double;
  1414. run_start = i + 1;
  1415. }
  1416. escape = false;
  1417. [[fallthrough]];
  1418. default:
  1419. if (!run_start.has_value())
  1420. run_start = i;
  1421. escape = false;
  1422. continue;
  1423. }
  1424. }
  1425. if (run_start.has_value())
  1426. append_bareword(string.substring_view(*run_start, string.length() - *run_start));
  1427. };
  1428. if (!token.resolved_expansions.is_empty())
  1429. dbgln_if(SHELL_POSIX_PARSER_DEBUG, "Expanding '{}' with {} expansion entries", token.value, token.resolved_expansions.size());
  1430. size_t current_offset = 0;
  1431. for (auto& expansion : token.resolved_expansions) {
  1432. expansion.visit(
  1433. [&](ResolvedParameterExpansion const& x) {
  1434. dbgln_if(SHELL_POSIX_PARSER_DEBUG, " Expanding '{}' ({}+{})", x.to_deprecated_string(), x.range.start, x.range.length);
  1435. if (x.range.start >= token.value.length()) {
  1436. dbgln("Parameter expansion range {}-{} is out of bounds for '{}'", x.range.start, x.range.length, token.value);
  1437. return;
  1438. }
  1439. if (x.range.start != current_offset) {
  1440. append_string(token.value.substring_view(current_offset, x.range.start - current_offset));
  1441. current_offset = x.range.start;
  1442. }
  1443. current_offset += x.range.length;
  1444. append_parameter_expansion(x);
  1445. },
  1446. [&](ResolvedCommandExpansion const& x) {
  1447. if (x.range.start >= token.value.length()) {
  1448. dbgln("Parameter expansion range {}-{} is out of bounds for '{}'", x.range.start, x.range.length, token.value);
  1449. return;
  1450. }
  1451. if (x.range.start != current_offset) {
  1452. append_string(token.value.substring_view(current_offset, x.range.start - current_offset));
  1453. current_offset = x.range.start;
  1454. }
  1455. current_offset += x.range.length;
  1456. append_command_expansion(x);
  1457. });
  1458. }
  1459. if (current_offset > token.value.length()) {
  1460. dbgln("Parameter expansion range {}- is out of bounds for '{}'", current_offset, token.value);
  1461. return word;
  1462. }
  1463. if (current_offset != token.value.length())
  1464. append_string(token.value.substring_view(current_offset));
  1465. return word;
  1466. }
  1467. RefPtr<AST::Node> Parser::parse_do_group()
  1468. {
  1469. if (peek().type != Token::Type::Do) {
  1470. return make_ref_counted<AST::SyntaxError>(
  1471. peek().position.value_or(empty_position()),
  1472. String::formatted("Expected 'do', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  1473. }
  1474. consume();
  1475. auto list = parse_compound_list();
  1476. RefPtr<AST::SyntaxError> error;
  1477. if (peek().type != Token::Type::Done) {
  1478. error = make_ref_counted<AST::SyntaxError>(
  1479. peek().position.value_or(empty_position()),
  1480. String::formatted("Expected 'done', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  1481. } else {
  1482. consume();
  1483. }
  1484. if (error) {
  1485. if (list)
  1486. list->set_is_syntax_error(*error);
  1487. else
  1488. list = error;
  1489. }
  1490. return make_ref_counted<AST::Execute>(list->position(), *list);
  1491. }
  1492. RefPtr<AST::Node> Parser::parse_simple_command()
  1493. {
  1494. auto start_position = peek().position.value_or(empty_position());
  1495. Vector<DeprecatedString> definitions;
  1496. NonnullRefPtrVector<AST::Node> nodes;
  1497. for (;;) {
  1498. if (auto io_redirect = parse_io_redirect())
  1499. nodes.append(*io_redirect);
  1500. else
  1501. break;
  1502. }
  1503. while (peek().type == Token::Type::AssignmentWord) {
  1504. definitions.append(peek().value);
  1505. if (!nodes.is_empty()) {
  1506. nodes.append(
  1507. make_ref_counted<AST::BarewordLiteral>(
  1508. peek().position.value_or(empty_position()),
  1509. String::from_deprecated_string(consume().value).release_value_but_fixme_should_propagate_errors()));
  1510. } else {
  1511. // env (assignments) (command)
  1512. nodes.append(make_ref_counted<AST::BarewordLiteral>(
  1513. empty_position(),
  1514. String::from_utf8_short_string("env"sv)));
  1515. nodes.append(
  1516. make_ref_counted<AST::BarewordLiteral>(
  1517. peek().position.value_or(empty_position()),
  1518. String::from_deprecated_string(consume().value).release_value_but_fixme_should_propagate_errors()));
  1519. }
  1520. }
  1521. // WORD or io_redirect: IO_NUMBER or io_file
  1522. if (!is_one_of(peek().type,
  1523. Token::Type::Word, Token::Type::IoNumber,
  1524. Token::Type::Less, Token::Type::LessAnd, Token::Type::Great, Token::Type::GreatAnd,
  1525. Token::Type::DoubleGreat, Token::Type::LessGreat, Token::Type::Clobber)) {
  1526. if (!nodes.is_empty()) {
  1527. Vector<AST::VariableDeclarations::Variable> variables;
  1528. for (auto& definition : definitions) {
  1529. auto parts = definition.split_limit('=', 2, SplitBehavior::KeepEmpty);
  1530. auto name = make_ref_counted<AST::BarewordLiteral>(
  1531. empty_position(),
  1532. String::from_deprecated_string(parts[0]).release_value_but_fixme_should_propagate_errors());
  1533. auto value = make_ref_counted<AST::BarewordLiteral>(
  1534. empty_position(),
  1535. String::from_deprecated_string(parts.size() > 1 ? parts[1] : "").release_value_but_fixme_should_propagate_errors());
  1536. variables.append({ move(name), move(value) });
  1537. }
  1538. return make_ref_counted<AST::VariableDeclarations>(empty_position(), move(variables));
  1539. }
  1540. return nullptr;
  1541. }
  1542. // auto first = true;
  1543. for (;;) {
  1544. if (peek().type == Token::Type::Word) {
  1545. auto new_word = parse_word();
  1546. if (!new_word)
  1547. break;
  1548. // if (first) {
  1549. // first = false;
  1550. // new_word = make_ref_counted<AST::ImmediateExpression>(
  1551. // new_word->position(),
  1552. // AST::NameWithPosition {
  1553. // "substitute_aliases"sv,
  1554. // empty_position(),
  1555. // },
  1556. // NonnullRefPtrVector<AST::Node> { *new_word },
  1557. // Optional<AST::Position> {});
  1558. // }
  1559. nodes.append(new_word.release_nonnull());
  1560. } else if (auto io_redirect = parse_io_redirect()) {
  1561. nodes.append(io_redirect.release_nonnull());
  1562. } else {
  1563. break;
  1564. }
  1565. }
  1566. auto node = make_ref_counted<AST::ListConcatenate>(
  1567. start_position.with_end(peek().position.value_or(empty_position())),
  1568. move(nodes));
  1569. return node;
  1570. }
  1571. RefPtr<AST::Node> Parser::parse_io_redirect()
  1572. {
  1573. auto start_position = peek().position.value_or(empty_position());
  1574. auto start_index = m_token_index;
  1575. // io_redirect: IO_NUMBER? io_file | IO_NUMBER? io_here
  1576. Optional<int> io_number;
  1577. if (peek().type == Token::Type::IoNumber)
  1578. io_number = consume().value.to_int(TrimWhitespace::No);
  1579. if (auto io_file = parse_io_file(start_position, io_number))
  1580. return io_file;
  1581. if (auto io_here = parse_io_here(start_position, io_number))
  1582. return io_here;
  1583. m_token_index = start_index;
  1584. return nullptr;
  1585. }
  1586. RefPtr<AST::Node> Parser::parse_io_here(AST::Position start_position, Optional<int> fd)
  1587. {
  1588. // io_here: IO_NUMBER? (DLESS | DLESSDASH) WORD
  1589. auto io_operator = peek().type;
  1590. if (!is_one_of(io_operator, Token::Type::DoubleLess, Token::Type::DoubleLessDash))
  1591. return nullptr;
  1592. auto io_operator_token = consume();
  1593. auto redirection_fd = fd.value_or(0);
  1594. auto end_keyword = consume();
  1595. if (!is_one_of(end_keyword.type, Token::Type::Word, Token::Type::Token))
  1596. return make_ref_counted<AST::SyntaxError>(io_operator_token.position.value_or(start_position), String::from_utf8("Expected a heredoc keyword"sv).release_value_but_fixme_should_propagate_errors(), true);
  1597. auto [end_keyword_text, allow_interpolation] = Lexer::process_heredoc_key(end_keyword);
  1598. RefPtr<AST::SyntaxError> error;
  1599. auto position = start_position.with_end(peek().position.value_or(empty_position()));
  1600. auto result = make_ref_counted<AST::Heredoc>(
  1601. position,
  1602. String::from_deprecated_string(end_keyword_text).release_value_but_fixme_should_propagate_errors(),
  1603. allow_interpolation,
  1604. io_operator == Token::Type::DoubleLessDash,
  1605. Optional<int> { redirection_fd });
  1606. m_unprocessed_heredoc_entries.set(end_keyword_text, result);
  1607. if (error)
  1608. result->set_is_syntax_error(*error);
  1609. return result;
  1610. }
  1611. RefPtr<AST::Node> Parser::parse_io_file(AST::Position start_position, Optional<int> fd)
  1612. {
  1613. auto start_index = m_token_index;
  1614. // io_file = (LESS | LESSAND | GREAT | GREATAND | DGREAT | LESSGREAT | CLOBBER) WORD
  1615. auto io_operator = peek().type;
  1616. if (!is_one_of(io_operator,
  1617. Token::Type::Less, Token::Type::LessAnd, Token::Type::Great, Token::Type::GreatAnd,
  1618. Token::Type::DoubleGreat, Token::Type::LessGreat, Token::Type::Clobber))
  1619. return nullptr;
  1620. auto io_operator_token = consume();
  1621. auto word = parse_word();
  1622. if (!word) {
  1623. m_token_index = start_index;
  1624. return nullptr;
  1625. }
  1626. auto position = start_position.with_end(peek().position.value_or(empty_position()));
  1627. switch (io_operator) {
  1628. case Token::Type::Less:
  1629. return make_ref_counted<AST::ReadRedirection>(
  1630. position,
  1631. fd.value_or(0),
  1632. word.release_nonnull());
  1633. case Token::Type::Clobber:
  1634. // FIXME: Add support for clobber (and 'noclobber')
  1635. case Token::Type::Great:
  1636. return make_ref_counted<AST::WriteRedirection>(
  1637. position,
  1638. fd.value_or(1),
  1639. word.release_nonnull());
  1640. case Token::Type::DoubleGreat:
  1641. return make_ref_counted<AST::WriteAppendRedirection>(
  1642. position,
  1643. fd.value_or(1),
  1644. word.release_nonnull());
  1645. case Token::Type::LessGreat:
  1646. return make_ref_counted<AST::ReadWriteRedirection>(
  1647. position,
  1648. fd.value_or(0),
  1649. word.release_nonnull());
  1650. case Token::Type::LessAnd:
  1651. case Token::Type::GreatAnd: {
  1652. auto is_less = io_operator == Token::Type::LessAnd;
  1653. auto source_fd = fd.value_or(is_less ? 0 : 1);
  1654. if (word->is_bareword()) {
  1655. auto maybe_target_fd = static_ptr_cast<AST::BarewordLiteral>(word)->text().bytes_as_string_view().to_int();
  1656. if (maybe_target_fd.has_value()) {
  1657. auto target_fd = maybe_target_fd.release_value();
  1658. if (is_less)
  1659. swap(source_fd, target_fd);
  1660. return make_ref_counted<AST::Fd2FdRedirection>(
  1661. position,
  1662. source_fd,
  1663. target_fd);
  1664. }
  1665. }
  1666. if (is_less) {
  1667. return make_ref_counted<AST::ReadRedirection>(
  1668. position,
  1669. source_fd,
  1670. word.release_nonnull());
  1671. }
  1672. return make_ref_counted<AST::WriteRedirection>(
  1673. position,
  1674. source_fd,
  1675. word.release_nonnull());
  1676. }
  1677. default:
  1678. VERIFY_NOT_REACHED();
  1679. }
  1680. }
  1681. }