PosixParser.cpp 73 KB

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