PosixParser.cpp 75 KB

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