PosixParser.cpp 74 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084
  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 = String::from_code_point(text[0]),
  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. while (peek().type == Token::Type::Newline)
  604. skip();
  605. auto node = TRY(parse_pipeline());
  606. if (!node)
  607. return RefPtr<AST::Node> {};
  608. for (;;) {
  609. if (peek().type == Token::Type::AndIf) {
  610. auto and_token = consume();
  611. while (peek().type == Token::Type::Newline)
  612. skip();
  613. auto rhs = TRY(parse_pipeline());
  614. if (!rhs)
  615. return RefPtr<AST::Node> {};
  616. node = make_ref_counted<AST::And>(
  617. node->position(),
  618. *node,
  619. rhs.release_nonnull(),
  620. and_token.position.value_or(empty_position()));
  621. continue;
  622. }
  623. if (peek().type == Token::Type::OrIf) {
  624. auto or_token = consume();
  625. while (peek().type == Token::Type::Newline)
  626. skip();
  627. auto rhs = TRY(parse_pipeline());
  628. if (!rhs)
  629. return RefPtr<AST::Node> {};
  630. node = make_ref_counted<AST::And>(
  631. node->position(),
  632. *node,
  633. rhs.release_nonnull(),
  634. or_token.position.value_or(empty_position()));
  635. continue;
  636. }
  637. break;
  638. }
  639. return node;
  640. }
  641. ErrorOr<RefPtr<AST::Node>> Parser::parse_pipeline()
  642. {
  643. return parse_pipe_sequence();
  644. }
  645. ErrorOr<RefPtr<AST::Node>> Parser::parse_pipe_sequence()
  646. {
  647. auto node = TRY(parse_command());
  648. if (!node)
  649. return RefPtr<AST::Node> {};
  650. for (;;) {
  651. if (peek().type != Token::Type::Pipe)
  652. break;
  653. consume();
  654. while (peek().type == Token::Type::Newline)
  655. skip();
  656. auto rhs = TRY(parse_command());
  657. if (!rhs)
  658. return RefPtr<AST::Node> {};
  659. node = make_ref_counted<AST::Pipe>(
  660. node->position(),
  661. *node,
  662. rhs.release_nonnull());
  663. }
  664. return node;
  665. }
  666. ErrorOr<RefPtr<AST::Node>> Parser::parse_command()
  667. {
  668. auto node = TRY([this]() -> ErrorOr<RefPtr<AST::Node>> {
  669. if (auto node = TRY(parse_function_definition()))
  670. return node;
  671. if (auto node = TRY(parse_simple_command()))
  672. return make_ref_counted<AST::CastToCommand>(node->position(), *node);
  673. auto node = TRY(parse_compound_command());
  674. if (!node)
  675. return node;
  676. if (auto list = TRY(parse_redirect_list())) {
  677. auto position = list->position();
  678. node = make_ref_counted<AST::Join>(
  679. node->position().with_end(position),
  680. *node,
  681. list.release_nonnull());
  682. }
  683. return node;
  684. }());
  685. if (!node)
  686. return nullptr;
  687. return node;
  688. }
  689. ErrorOr<RefPtr<AST::Node>> Parser::parse_function_definition()
  690. {
  691. // NAME OPEN_PAREN CLOSE_PAREN newline* function_body
  692. auto start_index = m_token_index;
  693. ArmedScopeGuard reset = [&] {
  694. m_token_index = start_index;
  695. };
  696. if (peek().type != Token::Type::VariableName) {
  697. return nullptr;
  698. }
  699. auto name = consume();
  700. if (consume().type != Token::Type::OpenParen)
  701. return nullptr;
  702. if (consume().type != Token::Type::CloseParen)
  703. return nullptr;
  704. while (peek().type == Token::Type::Newline)
  705. skip();
  706. auto body = TRY(parse_function_body());
  707. if (!body)
  708. return nullptr;
  709. reset.disarm();
  710. return make_ref_counted<AST::FunctionDeclaration>(
  711. name.position.value_or(empty_position()).with_end(peek().position.value_or(empty_position())),
  712. AST::NameWithPosition { String::from_utf8(name.value).release_value_but_fixme_should_propagate_errors(), name.position.value_or(empty_position()) },
  713. Vector<AST::NameWithPosition> {},
  714. body.release_nonnull());
  715. }
  716. ErrorOr<RefPtr<AST::Node>> Parser::parse_function_body()
  717. {
  718. // compound_command redirect_list?
  719. auto node = TRY(parse_compound_command());
  720. if (!node)
  721. return nullptr;
  722. if (auto list = TRY(parse_redirect_list())) {
  723. auto position = list->position();
  724. node = make_ref_counted<AST::Join>(
  725. node->position().with_end(position),
  726. *node,
  727. list.release_nonnull());
  728. }
  729. return node;
  730. }
  731. ErrorOr<RefPtr<AST::Node>> Parser::parse_redirect_list()
  732. {
  733. // io_redirect*
  734. RefPtr<AST::Node> node;
  735. for (;;) {
  736. auto new_node = TRY(parse_io_redirect());
  737. if (!new_node)
  738. break;
  739. if (node) {
  740. node = make_ref_counted<AST::Join>(
  741. node->position().with_end(new_node->position()),
  742. *node,
  743. new_node.release_nonnull());
  744. } else {
  745. node = new_node;
  746. }
  747. }
  748. return node;
  749. }
  750. ErrorOr<RefPtr<AST::Node>> Parser::parse_compound_command()
  751. {
  752. if (auto node = TRY(parse_brace_group()))
  753. return node;
  754. if (auto node = TRY(parse_subshell()))
  755. return node;
  756. if (auto node = TRY(parse_if_clause()))
  757. return node;
  758. if (auto node = TRY(parse_for_clause()))
  759. return node;
  760. if (auto node = TRY(parse_case_clause()))
  761. return node;
  762. if (auto node = TRY(parse_while_clause()))
  763. return node;
  764. if (auto node = TRY(parse_until_clause()))
  765. return node;
  766. return nullptr;
  767. }
  768. ErrorOr<RefPtr<AST::Node>> Parser::parse_while_clause()
  769. {
  770. if (peek().type != Token::Type::While)
  771. return nullptr;
  772. auto start_position = consume().position.value_or(empty_position());
  773. auto condition = TRY(parse_compound_list());
  774. if (!condition)
  775. condition = make_ref_counted<AST::SyntaxError>(
  776. peek().position.value_or(empty_position()),
  777. "Expected condition after 'while'"_string.release_value_but_fixme_should_propagate_errors());
  778. auto do_group = TRY(parse_do_group());
  779. if (!do_group)
  780. do_group = make_ref_counted<AST::SyntaxError>(
  781. peek().position.value_or(empty_position()),
  782. "Expected 'do' after 'while'"_string.release_value_but_fixme_should_propagate_errors());
  783. // while foo; bar -> loop { if foo { bar } else { break } }
  784. auto position = start_position.with_end(peek().position.value_or(empty_position()));
  785. return make_ref_counted<AST::ForLoop>(
  786. position,
  787. Optional<AST::NameWithPosition> {},
  788. Optional<AST::NameWithPosition> {},
  789. nullptr,
  790. make_ref_counted<AST::Execute>(position,
  791. make_ref_counted<AST::IfCond>(
  792. position,
  793. Optional<AST::Position> {},
  794. condition.release_nonnull(),
  795. do_group.release_nonnull(),
  796. make_ref_counted<AST::ContinuationControl>(
  797. start_position,
  798. AST::ContinuationControl::ContinuationKind::Break))));
  799. }
  800. ErrorOr<RefPtr<AST::Node>> Parser::parse_until_clause()
  801. {
  802. if (peek().type != Token::Type::Until)
  803. return nullptr;
  804. auto start_position = consume().position.value_or(empty_position());
  805. auto condition = TRY(parse_compound_list());
  806. if (!condition)
  807. condition = make_ref_counted<AST::SyntaxError>(
  808. peek().position.value_or(empty_position()),
  809. "Expected condition after 'until'"_string.release_value_but_fixme_should_propagate_errors());
  810. auto do_group = TRY(parse_do_group());
  811. if (!do_group)
  812. do_group = make_ref_counted<AST::SyntaxError>(
  813. peek().position.value_or(empty_position()),
  814. "Expected 'do' after 'until'"_string.release_value_but_fixme_should_propagate_errors());
  815. // until foo; bar -> loop { if foo { break } else { bar } }
  816. auto position = start_position.with_end(peek().position.value_or(empty_position()));
  817. return make_ref_counted<AST::ForLoop>(
  818. position,
  819. Optional<AST::NameWithPosition> {},
  820. Optional<AST::NameWithPosition> {},
  821. nullptr,
  822. make_ref_counted<AST::Execute>(position,
  823. make_ref_counted<AST::IfCond>(
  824. position,
  825. Optional<AST::Position> {},
  826. condition.release_nonnull(),
  827. make_ref_counted<AST::ContinuationControl>(
  828. start_position,
  829. AST::ContinuationControl::ContinuationKind::Break),
  830. do_group.release_nonnull())));
  831. }
  832. ErrorOr<RefPtr<AST::Node>> Parser::parse_brace_group()
  833. {
  834. if (peek().type != Token::Type::OpenBrace)
  835. return nullptr;
  836. consume();
  837. auto list = TRY(parse_compound_list());
  838. RefPtr<AST::SyntaxError> error;
  839. if (peek().type != Token::Type::CloseBrace) {
  840. error = make_ref_counted<AST::SyntaxError>(
  841. peek().position.value_or(empty_position()),
  842. String::formatted("Expected '}}', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  843. } else {
  844. consume();
  845. }
  846. if (error) {
  847. if (list)
  848. list->set_is_syntax_error(*error);
  849. else
  850. list = error;
  851. }
  852. return make_ref_counted<AST::Execute>(list->position(), *list);
  853. }
  854. ErrorOr<RefPtr<AST::Node>> Parser::parse_case_clause()
  855. {
  856. auto start_position = peek().position.value_or(empty_position());
  857. if (peek().type != Token::Type::Case)
  858. return nullptr;
  859. skip();
  860. RefPtr<AST::SyntaxError> syntax_error;
  861. auto expr = TRY(parse_word());
  862. if (!expr)
  863. expr = make_ref_counted<AST::SyntaxError>(
  864. peek().position.value_or(empty_position()),
  865. String::formatted("Expected a word, not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  866. if (peek().type != Token::Type::In) {
  867. syntax_error = make_ref_counted<AST::SyntaxError>(
  868. peek().position.value_or(empty_position()),
  869. String::formatted("Expected 'in', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  870. } else {
  871. skip();
  872. }
  873. while (peek().type == Token::Type::Newline)
  874. skip();
  875. Vector<AST::MatchEntry> entries;
  876. for (;;) {
  877. if (eof() || peek().type == Token::Type::Esac)
  878. break;
  879. if (peek().type == Token::Type::Newline) {
  880. skip();
  881. continue;
  882. }
  883. // Parse a pattern list
  884. auto needs_dsemi = true;
  885. if (peek().type == Token::Type::OpenParen) {
  886. skip();
  887. needs_dsemi = false;
  888. }
  889. auto result = TRY(parse_case_list());
  890. if (peek().type == Token::Type::CloseParen) {
  891. skip();
  892. } else {
  893. if (!syntax_error)
  894. syntax_error = make_ref_counted<AST::SyntaxError>(
  895. peek().position.value_or(empty_position()),
  896. String::formatted("Expected ')', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  897. break;
  898. }
  899. while (peek().type == Token::Type::Newline)
  900. skip();
  901. auto compound_list = TRY(parse_compound_list());
  902. if (peek().type == Token::Type::DoubleSemicolon) {
  903. skip();
  904. } else if (needs_dsemi) {
  905. if (!syntax_error)
  906. syntax_error = make_ref_counted<AST::SyntaxError>(
  907. peek().position.value_or(empty_position()),
  908. String::formatted("Expected ';;', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  909. }
  910. if (syntax_error) {
  911. if (compound_list)
  912. compound_list->set_is_syntax_error(*syntax_error);
  913. else
  914. compound_list = syntax_error;
  915. syntax_error = nullptr;
  916. }
  917. auto position = compound_list->position();
  918. entries.append(AST::MatchEntry {
  919. .options = move(result.nodes),
  920. .match_names = {},
  921. .match_as_position = {},
  922. .pipe_positions = move(result.pipe_positions),
  923. .body = make_ref_counted<AST::Execute>(position, compound_list.release_nonnull()),
  924. });
  925. }
  926. if (peek().type != Token::Type::Esac) {
  927. syntax_error = make_ref_counted<AST::SyntaxError>(
  928. peek().position.value_or(empty_position()),
  929. String::formatted("Expected 'esac', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  930. } else {
  931. skip();
  932. }
  933. auto node = make_ref_counted<AST::MatchExpr>(
  934. start_position.with_end(peek().position.value_or(empty_position())),
  935. expr.release_nonnull(),
  936. String {},
  937. Optional<AST::Position> {},
  938. move(entries));
  939. if (syntax_error)
  940. node->set_is_syntax_error(*syntax_error);
  941. return node;
  942. }
  943. ErrorOr<Parser::CaseItemsResult> Parser::parse_case_list()
  944. {
  945. // Just a list of words split by '|', delimited by ')'
  946. Vector<NonnullRefPtr<AST::Node>> nodes;
  947. Vector<AST::Position> pipes;
  948. for (;;) {
  949. if (eof() || peek().type == Token::Type::CloseParen)
  950. break;
  951. if (peek().type != Token::Type::Word)
  952. break;
  953. auto node = TRY(parse_word());
  954. if (!node)
  955. node = make_ref_counted<AST::SyntaxError>(
  956. peek().position.value_or(empty_position()),
  957. String::formatted("Expected a word, not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  958. nodes.append(node.release_nonnull());
  959. if (peek().type == Token::Type::Pipe) {
  960. pipes.append(peek().position.value_or(empty_position()));
  961. skip();
  962. } else {
  963. break;
  964. }
  965. }
  966. if (nodes.is_empty())
  967. nodes.append(make_ref_counted<AST::SyntaxError>(
  968. peek().position.value_or(empty_position()),
  969. String::formatted("Expected a word, not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors()));
  970. return CaseItemsResult { move(pipes), move(nodes) };
  971. }
  972. ErrorOr<RefPtr<AST::Node>> Parser::parse_if_clause()
  973. {
  974. // If compound_list Then compound_list {Elif compound_list Then compound_list (Fi|Else)?} [(?=Else) compound_list] (?!=Fi) Fi
  975. auto start_position = peek().position.value_or(empty_position());
  976. if (peek().type != Token::Type::If)
  977. return nullptr;
  978. skip();
  979. auto main_condition = TRY(parse_compound_list());
  980. if (!main_condition)
  981. main_condition = make_ref_counted<AST::SyntaxError>(empty_position(), "Expected compound list after 'if'"_string.release_value_but_fixme_should_propagate_errors());
  982. RefPtr<AST::SyntaxError> syntax_error;
  983. if (peek().type != Token::Type::Then) {
  984. syntax_error = make_ref_counted<AST::SyntaxError>(
  985. peek().position.value_or(empty_position()),
  986. String::formatted("Expected 'then', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  987. } else {
  988. skip();
  989. }
  990. auto main_consequence = TRY(parse_compound_list());
  991. if (!main_consequence)
  992. main_consequence = make_ref_counted<AST::SyntaxError>(empty_position(), "Expected compound list after 'then'"_string.release_value_but_fixme_should_propagate_errors());
  993. auto node = make_ref_counted<AST::IfCond>(start_position, Optional<AST::Position>(), main_condition.release_nonnull(), main_consequence.release_nonnull(), nullptr);
  994. auto active_node = node;
  995. while (peek().type == Token::Type::Elif) {
  996. skip();
  997. auto condition = TRY(parse_compound_list());
  998. if (!condition)
  999. condition = make_ref_counted<AST::SyntaxError>(empty_position(), "Expected compound list after 'elif'"_string.release_value_but_fixme_should_propagate_errors());
  1000. if (peek().type != Token::Type::Then) {
  1001. if (!syntax_error)
  1002. syntax_error = make_ref_counted<AST::SyntaxError>(
  1003. peek().position.value_or(empty_position()),
  1004. String::formatted("Expected 'then', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  1005. } else {
  1006. skip();
  1007. }
  1008. auto consequence = TRY(parse_compound_list());
  1009. if (!consequence)
  1010. consequence = make_ref_counted<AST::SyntaxError>(empty_position(), "Expected compound list after 'then'"_string.release_value_but_fixme_should_propagate_errors());
  1011. auto new_node = make_ref_counted<AST::IfCond>(start_position, Optional<AST::Position>(), condition.release_nonnull(), consequence.release_nonnull(), nullptr);
  1012. active_node->false_branch() = new_node;
  1013. active_node = move(new_node);
  1014. }
  1015. auto needs_fi = true;
  1016. switch (peek().type) {
  1017. case Token::Type::Else:
  1018. skip();
  1019. active_node->false_branch() = TRY(parse_compound_list());
  1020. if (!active_node->false_branch())
  1021. active_node->false_branch() = make_ref_counted<AST::SyntaxError>(empty_position(), "Expected compound list after 'else'"_string.release_value_but_fixme_should_propagate_errors());
  1022. break;
  1023. case Token::Type::Fi:
  1024. skip();
  1025. needs_fi = false;
  1026. break;
  1027. default:
  1028. if (!syntax_error)
  1029. syntax_error = make_ref_counted<AST::SyntaxError>(
  1030. peek().position.value_or(empty_position()),
  1031. String::formatted("Expected 'else' or 'fi', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  1032. break;
  1033. }
  1034. if (needs_fi) {
  1035. if (peek().type != Token::Type::Fi) {
  1036. if (!syntax_error)
  1037. syntax_error = make_ref_counted<AST::SyntaxError>(
  1038. peek().position.value_or(empty_position()),
  1039. String::formatted("Expected 'fi', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  1040. } else {
  1041. skip();
  1042. }
  1043. }
  1044. if (syntax_error)
  1045. node->set_is_syntax_error(*syntax_error);
  1046. return node;
  1047. }
  1048. ErrorOr<RefPtr<AST::Node>> Parser::parse_subshell()
  1049. {
  1050. auto start_position = peek().position.value_or(empty_position());
  1051. if (peek().type != Token::Type::OpenParen)
  1052. return nullptr;
  1053. skip();
  1054. RefPtr<AST::SyntaxError> error;
  1055. auto list = TRY(parse_compound_list());
  1056. if (!list)
  1057. error = make_ref_counted<AST::SyntaxError>(peek().position.value_or(empty_position()), "Expected compound list after ("_string.release_value_but_fixme_should_propagate_errors());
  1058. if (peek().type != Token::Type::CloseParen)
  1059. error = make_ref_counted<AST::SyntaxError>(peek().position.value_or(empty_position()), "Expected ) after compound list"_string.release_value_but_fixme_should_propagate_errors());
  1060. else
  1061. skip();
  1062. if (!list)
  1063. return error;
  1064. return make_ref_counted<AST::Subshell>(
  1065. start_position.with_end(peek().position.value_or(empty_position())),
  1066. list.release_nonnull());
  1067. }
  1068. ErrorOr<RefPtr<AST::Node>> Parser::parse_compound_list()
  1069. {
  1070. while (peek().type == Token::Type::Newline)
  1071. skip();
  1072. auto term = TRY(parse_term());
  1073. if (!term)
  1074. return term;
  1075. if (is_separator(peek())) {
  1076. if (consume().type == Token::Type::And) {
  1077. term = make_ref_counted<AST::Background>(
  1078. term->position().with_end(peek().position.value_or(empty_position())),
  1079. *term);
  1080. }
  1081. }
  1082. return term;
  1083. }
  1084. ErrorOr<RefPtr<AST::Node>> Parser::parse_term()
  1085. {
  1086. Vector<NonnullRefPtr<AST::Node>> nodes;
  1087. Vector<AST::Position> positions;
  1088. auto start_position = peek().position.value_or(empty_position());
  1089. for (;;) {
  1090. auto new_node = TRY(parse_and_or());
  1091. if (!new_node)
  1092. break;
  1093. nodes.append(new_node.release_nonnull());
  1094. if (!is_separator(peek()))
  1095. break;
  1096. auto position = consume().position;
  1097. if (position.has_value())
  1098. positions.append(position.release_value());
  1099. }
  1100. auto end_position = peek().position.value_or(empty_position());
  1101. return make_ref_counted<AST::Sequence>(
  1102. start_position.with_end(end_position),
  1103. move(nodes),
  1104. move(positions));
  1105. }
  1106. ErrorOr<RefPtr<AST::Node>> Parser::parse_for_clause()
  1107. {
  1108. // FOR NAME newline+ do_group
  1109. // FOR NAME newline+ IN separator do_group
  1110. // FOR NAME IN separator do_group
  1111. // FOR NAME IN wordlist separator do_group
  1112. if (peek().type != Token::Type::For)
  1113. return nullptr;
  1114. auto start_position = consume().position.value_or(empty_position());
  1115. String name;
  1116. Optional<AST::Position> name_position;
  1117. if (peek().type == Token::Type::VariableName) {
  1118. name_position = peek().position;
  1119. name = consume().value;
  1120. } else {
  1121. name = "it"_short_string;
  1122. error(peek(), "Expected a variable name, not {}", peek().type_name());
  1123. }
  1124. auto saw_newline = false;
  1125. while (peek().type == Token::Type::Newline) {
  1126. saw_newline = true;
  1127. skip();
  1128. }
  1129. auto saw_in = false;
  1130. Optional<AST::Position> in_kw_position;
  1131. if (peek().type == Token::Type::In) {
  1132. saw_in = true;
  1133. in_kw_position = peek().position;
  1134. skip();
  1135. } else if (!saw_newline) {
  1136. error(peek(), "Expected 'in' or a newline, not {}", peek().type_name());
  1137. }
  1138. RefPtr<AST::Node> iterated_expression;
  1139. if (!saw_newline)
  1140. iterated_expression = parse_word_list();
  1141. if (saw_in) {
  1142. if (peek().type == Token::Type::Semicolon)
  1143. skip();
  1144. else
  1145. error(peek(), "Expected a semicolon, not {}", peek().type_name());
  1146. }
  1147. auto body = TRY(parse_do_group());
  1148. return AST::make_ref_counted<AST::ForLoop>(
  1149. start_position.with_end(peek().position.value_or(empty_position())),
  1150. AST::NameWithPosition { name, name_position.value_or(empty_position()) },
  1151. Optional<AST::NameWithPosition> {},
  1152. move(iterated_expression),
  1153. move(body),
  1154. move(in_kw_position),
  1155. Optional<AST::Position> {});
  1156. }
  1157. RefPtr<AST::Node> Parser::parse_word_list()
  1158. {
  1159. Vector<NonnullRefPtr<AST::Node>> nodes;
  1160. auto start_position = peek().position.value_or(empty_position());
  1161. for (; peek().type == Token::Type::Word;) {
  1162. auto word = parse_word().release_value_but_fixme_should_propagate_errors();
  1163. nodes.append(word.release_nonnull());
  1164. }
  1165. return make_ref_counted<AST::ListConcatenate>(
  1166. start_position.with_end(peek().position.value_or(empty_position())),
  1167. move(nodes));
  1168. }
  1169. ErrorOr<RefPtr<AST::Node>> Parser::parse_word()
  1170. {
  1171. if (peek().type != Token::Type::Word)
  1172. return nullptr;
  1173. auto token = consume();
  1174. RefPtr<AST::Node> word;
  1175. enum class Quote {
  1176. None,
  1177. Single,
  1178. Double,
  1179. } in_quote { Quote::None };
  1180. auto append_bareword = [&](StringView string) -> ErrorOr<void> {
  1181. if (!word && string.starts_with('~')) {
  1182. GenericLexer lexer { string };
  1183. lexer.ignore();
  1184. auto user = lexer.consume_while(is_ascii_alphanumeric);
  1185. string = lexer.remaining();
  1186. word = make_ref_counted<AST::Tilde>(token.position.value_or(empty_position()), TRY(String::from_utf8(user)));
  1187. }
  1188. if (string.is_empty())
  1189. return {};
  1190. auto node = make_ref_counted<AST::BarewordLiteral>(
  1191. token.position.value_or(empty_position()),
  1192. TRY(String::from_utf8(string)));
  1193. if (word) {
  1194. word = make_ref_counted<AST::Juxtaposition>(
  1195. word->position().with_end(token.position.value_or(empty_position())),
  1196. *word,
  1197. move(node),
  1198. AST::Juxtaposition::Mode::StringExpand);
  1199. } else {
  1200. word = move(node);
  1201. }
  1202. return {};
  1203. };
  1204. auto append_string_literal = [&](StringView string) -> ErrorOr<void> {
  1205. auto node = make_ref_counted<AST::StringLiteral>(
  1206. token.position.value_or(empty_position()),
  1207. TRY(String::from_utf8(string)),
  1208. AST::StringLiteral::EnclosureType::SingleQuotes);
  1209. if (word) {
  1210. word = make_ref_counted<AST::Juxtaposition>(
  1211. word->position().with_end(token.position.value_or(empty_position())),
  1212. *word,
  1213. move(node),
  1214. AST::Juxtaposition::Mode::StringExpand);
  1215. } else {
  1216. word = move(node);
  1217. }
  1218. return {};
  1219. };
  1220. auto append_string_part = [&](StringView string) -> ErrorOr<void> {
  1221. auto node = make_ref_counted<AST::StringLiteral>(
  1222. token.position.value_or(empty_position()),
  1223. TRY(String::from_utf8(string)),
  1224. AST::StringLiteral::EnclosureType::DoubleQuotes);
  1225. if (word) {
  1226. word = make_ref_counted<AST::Juxtaposition>(
  1227. word->position().with_end(token.position.value_or(empty_position())),
  1228. *word,
  1229. move(node),
  1230. AST::Juxtaposition::Mode::StringExpand);
  1231. } else {
  1232. word = move(node);
  1233. }
  1234. return {};
  1235. };
  1236. auto append_arithmetic_expansion = [&](ResolvedArithmeticExpansion const& x) -> ErrorOr<void> {
  1237. auto node = make_ref_counted<AST::ImmediateExpression>(
  1238. token.position.value_or(empty_position()),
  1239. AST::NameWithPosition {
  1240. TRY("math"_string),
  1241. token.position.value_or(empty_position()),
  1242. },
  1243. Vector<NonnullRefPtr<AST::Node>> {
  1244. make_ref_counted<AST::ImmediateExpression>(
  1245. token.position.value_or(empty_position()),
  1246. AST::NameWithPosition {
  1247. TRY("reexpand"_string),
  1248. token.position.value_or(empty_position()),
  1249. },
  1250. Vector<NonnullRefPtr<AST::Node>> {
  1251. make_ref_counted<AST::StringLiteral>(
  1252. token.position.value_or(empty_position()),
  1253. TRY(String::from_utf8(x.source_expression)),
  1254. AST::StringLiteral::EnclosureType::DoubleQuotes),
  1255. },
  1256. Optional<AST::Position> {}) },
  1257. Optional<AST::Position> {});
  1258. if (word) {
  1259. word = make_ref_counted<AST::Juxtaposition>(
  1260. word->position().with_end(token.position.value_or(empty_position())),
  1261. *word,
  1262. move(node),
  1263. AST::Juxtaposition::Mode::StringExpand);
  1264. } else {
  1265. word = move(node);
  1266. }
  1267. return {};
  1268. };
  1269. auto append_parameter_expansion = [&](ResolvedParameterExpansion const& x) -> ErrorOr<void> {
  1270. StringView immediate_function_name;
  1271. RefPtr<AST::Node> node;
  1272. switch (x.op) {
  1273. case ResolvedParameterExpansion::Op::UseDefaultValue:
  1274. immediate_function_name = "value_or_default"sv;
  1275. break;
  1276. case ResolvedParameterExpansion::Op::AssignDefaultValue:
  1277. immediate_function_name = "assign_default"sv;
  1278. break;
  1279. case ResolvedParameterExpansion::Op::IndicateErrorIfEmpty:
  1280. immediate_function_name = "error_if_empty"sv;
  1281. break;
  1282. case ResolvedParameterExpansion::Op::UseAlternativeValue:
  1283. immediate_function_name = "null_or_alternative"sv;
  1284. break;
  1285. case ResolvedParameterExpansion::Op::UseDefaultValueIfUnset:
  1286. immediate_function_name = "defined_value_or_default"sv;
  1287. break;
  1288. case ResolvedParameterExpansion::Op::AssignDefaultValueIfUnset:
  1289. immediate_function_name = "assign_defined_default"sv;
  1290. break;
  1291. case ResolvedParameterExpansion::Op::IndicateErrorIfUnset:
  1292. immediate_function_name = "error_if_unset"sv;
  1293. break;
  1294. case ResolvedParameterExpansion::Op::UseAlternativeValueIfUnset:
  1295. immediate_function_name = "null_if_unset_or_alternative"sv;
  1296. break;
  1297. case ResolvedParameterExpansion::Op::RemoveLargestSuffixByPattern:
  1298. // FIXME: Implement this
  1299. case ResolvedParameterExpansion::Op::RemoveSmallestSuffixByPattern:
  1300. immediate_function_name = "remove_suffix"sv;
  1301. break;
  1302. case ResolvedParameterExpansion::Op::RemoveLargestPrefixByPattern:
  1303. // FIXME: Implement this
  1304. case ResolvedParameterExpansion::Op::RemoveSmallestPrefixByPattern:
  1305. immediate_function_name = "remove_prefix"sv;
  1306. break;
  1307. case ResolvedParameterExpansion::Op::StringLength:
  1308. immediate_function_name = "length_of_variable"sv;
  1309. break;
  1310. case ResolvedParameterExpansion::Op::GetPositionalParameter:
  1311. case ResolvedParameterExpansion::Op::GetVariable:
  1312. node = make_ref_counted<AST::SimpleVariable>(
  1313. token.position.value_or(empty_position()),
  1314. x.parameter);
  1315. break;
  1316. case ResolvedParameterExpansion::Op::GetLastBackgroundPid:
  1317. node = make_ref_counted<AST::SyntaxError>(
  1318. token.position.value_or(empty_position()),
  1319. TRY("$! not implemented"_string));
  1320. break;
  1321. case ResolvedParameterExpansion::Op::GetPositionalParameterList:
  1322. node = make_ref_counted<AST::SpecialVariable>(
  1323. token.position.value_or(empty_position()),
  1324. '*');
  1325. break;
  1326. case ResolvedParameterExpansion::Op::GetCurrentOptionFlags:
  1327. node = make_ref_counted<AST::SyntaxError>(
  1328. token.position.value_or(empty_position()),
  1329. TRY("The current option flags are not available in parameter expansions"_string));
  1330. break;
  1331. case ResolvedParameterExpansion::Op::GetPositionalParameterCount:
  1332. node = make_ref_counted<AST::SpecialVariable>(
  1333. token.position.value_or(empty_position()),
  1334. '#');
  1335. break;
  1336. case ResolvedParameterExpansion::Op::GetLastExitStatus:
  1337. node = make_ref_counted<AST::SpecialVariable>(
  1338. token.position.value_or(empty_position()),
  1339. '?');
  1340. break;
  1341. case ResolvedParameterExpansion::Op::GetPositionalParameterListAsString:
  1342. node = make_ref_counted<AST::SyntaxError>(
  1343. token.position.value_or(empty_position()),
  1344. TRY("$* not implemented"_string));
  1345. break;
  1346. case ResolvedParameterExpansion::Op::GetShellProcessId:
  1347. node = make_ref_counted<AST::SpecialVariable>(
  1348. token.position.value_or(empty_position()),
  1349. '$');
  1350. break;
  1351. }
  1352. if (!node) {
  1353. Vector<NonnullRefPtr<AST::Node>> arguments;
  1354. arguments.append(make_ref_counted<AST::BarewordLiteral>(
  1355. token.position.value_or(empty_position()),
  1356. x.parameter));
  1357. if (!x.argument.is_empty()) {
  1358. // dbgln("Will parse {}", x.argument);
  1359. arguments.append(*TRY(Parser { x.argument }.parse_word()));
  1360. }
  1361. node = make_ref_counted<AST::ImmediateExpression>(
  1362. token.position.value_or(empty_position()),
  1363. AST::NameWithPosition {
  1364. TRY(String::from_utf8(immediate_function_name)),
  1365. token.position.value_or(empty_position()),
  1366. },
  1367. move(arguments),
  1368. Optional<AST::Position> {});
  1369. }
  1370. if (x.expand == ResolvedParameterExpansion::Expand::Word) {
  1371. node = make_ref_counted<AST::ImmediateExpression>(
  1372. token.position.value_or(empty_position()),
  1373. AST::NameWithPosition {
  1374. TRY("reexpand"_string),
  1375. token.position.value_or(empty_position()),
  1376. },
  1377. Vector { node.release_nonnull() },
  1378. Optional<AST::Position> {});
  1379. }
  1380. if (word) {
  1381. word = make_ref_counted<AST::Juxtaposition>(
  1382. word->position().with_end(token.position.value_or(empty_position())),
  1383. *word,
  1384. node.release_nonnull(),
  1385. AST::Juxtaposition::Mode::StringExpand);
  1386. } else {
  1387. word = move(node);
  1388. }
  1389. return {};
  1390. };
  1391. auto append_command_expansion = [&](ResolvedCommandExpansion const& x) -> ErrorOr<void> {
  1392. if (!x.command)
  1393. return {};
  1394. RefPtr<AST::Execute> execute_node;
  1395. if (x.command->is_execute()) {
  1396. execute_node = const_cast<AST::Execute&>(static_cast<AST::Execute const&>(*x.command));
  1397. execute_node->capture_stdout();
  1398. } else {
  1399. execute_node = make_ref_counted<AST::Execute>(
  1400. word ? word->position() : empty_position(),
  1401. *x.command,
  1402. true);
  1403. }
  1404. if (word) {
  1405. word = make_ref_counted<AST::Juxtaposition>(
  1406. word->position(),
  1407. *word,
  1408. execute_node.release_nonnull(),
  1409. AST::Juxtaposition::Mode::StringExpand);
  1410. } else {
  1411. word = move(execute_node);
  1412. }
  1413. return {};
  1414. };
  1415. auto append_string = [&](StringView string) -> ErrorOr<void> {
  1416. if (string.is_empty())
  1417. return {};
  1418. Optional<size_t> run_start;
  1419. auto escape = false;
  1420. for (size_t i = 0; i < string.length(); ++i) {
  1421. auto ch = string[i];
  1422. switch (ch) {
  1423. case '\\':
  1424. if (!escape && i + 1 < string.length()) {
  1425. if (run_start.has_value())
  1426. TRY(append_string_literal(string.substring_view(*run_start, i - *run_start)));
  1427. run_start = i + 1;
  1428. if (is_one_of(string[i + 1], '"', '\'', '$', '`', '\\')) {
  1429. escape = in_quote != Quote::Single;
  1430. continue;
  1431. }
  1432. }
  1433. break;
  1434. case '\'':
  1435. if (in_quote == Quote::Single) {
  1436. in_quote = Quote::None;
  1437. TRY(append_string_literal(string.substring_view(*run_start, i - *run_start)));
  1438. run_start = i + 1;
  1439. continue;
  1440. }
  1441. if (in_quote == Quote::Double) {
  1442. escape = false;
  1443. continue;
  1444. }
  1445. [[fallthrough]];
  1446. case '"':
  1447. if (ch == '\'' && in_quote == Quote::Single) {
  1448. escape = false;
  1449. continue;
  1450. }
  1451. if (!escape) {
  1452. if (ch == '"' && in_quote == Quote::Double) {
  1453. in_quote = Quote::None;
  1454. if (run_start.has_value())
  1455. TRY(append_string_part(string.substring_view(*run_start, i - *run_start)));
  1456. run_start = i + 1;
  1457. continue;
  1458. }
  1459. if (run_start.has_value())
  1460. TRY(append_bareword(string.substring_view(*run_start, i - *run_start)));
  1461. in_quote = ch == '\'' ? Quote::Single : Quote::Double;
  1462. run_start = i + 1;
  1463. }
  1464. escape = false;
  1465. [[fallthrough]];
  1466. default:
  1467. if (!run_start.has_value())
  1468. run_start = i;
  1469. escape = false;
  1470. continue;
  1471. }
  1472. }
  1473. if (run_start.has_value())
  1474. TRY(append_bareword(string.substring_view(*run_start, string.length() - *run_start)));
  1475. return {};
  1476. };
  1477. if (!token.resolved_expansions.is_empty())
  1478. dbgln_if(SHELL_POSIX_PARSER_DEBUG, "Expanding '{}' with {} expansion entries", token.value, token.resolved_expansions.size());
  1479. size_t current_offset = 0;
  1480. auto value_bytes = token.value.bytes_as_string_view();
  1481. for (auto& expansion : token.resolved_expansions) {
  1482. TRY(expansion.visit(
  1483. [&](ResolvedParameterExpansion const& x) -> ErrorOr<void> {
  1484. dbgln_if(SHELL_POSIX_PARSER_DEBUG, " Expanding '{}' ({}+{})", x.to_deprecated_string(), x.range.start, x.range.length);
  1485. if (x.range.start >= value_bytes.length()) {
  1486. dbgln("Parameter expansion range {}-{} is out of bounds for '{}'", x.range.start, x.range.length, value_bytes);
  1487. return {};
  1488. }
  1489. if (x.range.start != current_offset) {
  1490. TRY(append_string(value_bytes.substring_view(current_offset, x.range.start - current_offset)));
  1491. current_offset = x.range.start;
  1492. }
  1493. current_offset += x.range.length;
  1494. return append_parameter_expansion(x);
  1495. },
  1496. [&](ResolvedArithmeticExpansion const& x) -> ErrorOr<void> {
  1497. if (x.range.start >= value_bytes.length()) {
  1498. dbgln("Parameter expansion range {}-{} is out of bounds for '{}'", x.range.start, x.range.length, value_bytes);
  1499. return {};
  1500. }
  1501. if (x.range.start != current_offset) {
  1502. TRY(append_string(value_bytes.substring_view(current_offset, x.range.start - current_offset)));
  1503. current_offset = x.range.start;
  1504. }
  1505. current_offset += x.range.length;
  1506. return append_arithmetic_expansion(x);
  1507. },
  1508. [&](ResolvedCommandExpansion const& x) -> ErrorOr<void> {
  1509. if (x.range.start >= value_bytes.length()) {
  1510. dbgln("Parameter expansion range {}-{} is out of bounds for '{}'", x.range.start, x.range.length, value_bytes);
  1511. return {};
  1512. }
  1513. if (x.range.start != current_offset) {
  1514. TRY(append_string(value_bytes.substring_view(current_offset, x.range.start - current_offset)));
  1515. current_offset = x.range.start;
  1516. }
  1517. current_offset += x.range.length;
  1518. return append_command_expansion(x);
  1519. }));
  1520. }
  1521. if (current_offset > value_bytes.length()) {
  1522. dbgln("Parameter expansion range {}- is out of bounds for '{}'", current_offset, value_bytes);
  1523. return word;
  1524. }
  1525. if (current_offset != value_bytes.length())
  1526. TRY(append_string(value_bytes.substring_view(current_offset)));
  1527. return word;
  1528. }
  1529. ErrorOr<RefPtr<AST::Node>> Parser::parse_do_group()
  1530. {
  1531. if (peek().type != Token::Type::Do) {
  1532. return make_ref_counted<AST::SyntaxError>(
  1533. peek().position.value_or(empty_position()),
  1534. String::formatted("Expected 'do', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  1535. }
  1536. consume();
  1537. auto list = TRY(parse_compound_list());
  1538. RefPtr<AST::SyntaxError> error;
  1539. if (peek().type != Token::Type::Done) {
  1540. error = make_ref_counted<AST::SyntaxError>(
  1541. peek().position.value_or(empty_position()),
  1542. String::formatted("Expected 'done', not {}", peek().type_name()).release_value_but_fixme_should_propagate_errors());
  1543. } else {
  1544. consume();
  1545. }
  1546. if (error) {
  1547. if (list)
  1548. list->set_is_syntax_error(*error);
  1549. else
  1550. list = error;
  1551. }
  1552. return make_ref_counted<AST::Execute>(list->position(), *list);
  1553. }
  1554. ErrorOr<RefPtr<AST::Node>> Parser::parse_simple_command()
  1555. {
  1556. auto start_position = peek().position.value_or(empty_position());
  1557. Vector<String> definitions;
  1558. Vector<NonnullRefPtr<AST::Node>> nodes;
  1559. for (;;) {
  1560. if (auto io_redirect = TRY(parse_io_redirect()))
  1561. nodes.append(*io_redirect);
  1562. else
  1563. break;
  1564. }
  1565. while (peek().type == Token::Type::AssignmentWord) {
  1566. definitions.append(peek().value);
  1567. if (nodes.is_empty()) {
  1568. // run_with_env -e*(assignments) -- (command)
  1569. nodes.append(make_ref_counted<AST::BarewordLiteral>(
  1570. empty_position(),
  1571. TRY("run_with_env"_string)));
  1572. }
  1573. auto position = peek().position.value_or(empty_position());
  1574. nodes.append(make_ref_counted<AST::ImmediateExpression>(
  1575. position,
  1576. AST::NameWithPosition {
  1577. TRY("reexpand"_string),
  1578. position,
  1579. },
  1580. Vector<NonnullRefPtr<AST::Node>> {
  1581. make_ref_counted<AST::StringLiteral>(
  1582. position,
  1583. TRY(String::formatted("-e{}", consume().value)),
  1584. AST::StringLiteral::EnclosureType::DoubleQuotes),
  1585. },
  1586. Optional<AST::Position> {}));
  1587. }
  1588. if (!definitions.is_empty()) {
  1589. nodes.append(make_ref_counted<AST::BarewordLiteral>(
  1590. empty_position(),
  1591. "--"_short_string));
  1592. }
  1593. // WORD or io_redirect: IO_NUMBER or io_file
  1594. if (!is_one_of(peek().type,
  1595. Token::Type::Word, Token::Type::IoNumber,
  1596. Token::Type::Less, Token::Type::LessAnd, Token::Type::Great, Token::Type::GreatAnd,
  1597. Token::Type::DoubleGreat, Token::Type::LessGreat, Token::Type::Clobber)) {
  1598. if (!nodes.is_empty()) {
  1599. Vector<AST::VariableDeclarations::Variable> variables;
  1600. for (auto& definition : definitions) {
  1601. auto equal_offset = definition.find_byte_offset('=');
  1602. auto split_offset = equal_offset.value_or(definition.bytes().size());
  1603. auto name = make_ref_counted<AST::BarewordLiteral>(
  1604. empty_position(),
  1605. TRY(definition.substring_from_byte_offset_with_shared_superstring(0, split_offset)));
  1606. auto position = peek().position.value_or(empty_position());
  1607. auto expanded_value = make_ref_counted<AST::ImmediateExpression>(
  1608. position,
  1609. AST::NameWithPosition {
  1610. TRY("reexpand"_string),
  1611. position,
  1612. },
  1613. Vector<NonnullRefPtr<AST::Node>> {
  1614. make_ref_counted<AST::StringLiteral>(
  1615. position,
  1616. TRY(definition.substring_from_byte_offset_with_shared_superstring(split_offset + 1)),
  1617. AST::StringLiteral::EnclosureType::DoubleQuotes),
  1618. },
  1619. Optional<AST::Position> {});
  1620. variables.append({ move(name), move(expanded_value) });
  1621. }
  1622. return make_ref_counted<AST::VariableDeclarations>(empty_position(), move(variables));
  1623. }
  1624. return nullptr;
  1625. }
  1626. // auto first = true;
  1627. for (;;) {
  1628. if (peek().type == Token::Type::Word) {
  1629. auto new_word = TRY(parse_word());
  1630. if (!new_word)
  1631. break;
  1632. // if (first) {
  1633. // first = false;
  1634. // new_word = make_ref_counted<AST::ImmediateExpression>(
  1635. // new_word->position(),
  1636. // AST::NameWithPosition {
  1637. // "substitute_aliases"sv,
  1638. // empty_position(),
  1639. // },
  1640. // Vector<NonnullRefPtr<AST::Node>> { *new_word },
  1641. // Optional<AST::Position> {});
  1642. // }
  1643. nodes.append(new_word.release_nonnull());
  1644. } else if (auto io_redirect = TRY(parse_io_redirect())) {
  1645. nodes.append(io_redirect.release_nonnull());
  1646. } else {
  1647. break;
  1648. }
  1649. }
  1650. auto node = make_ref_counted<AST::ListConcatenate>(
  1651. start_position.with_end(peek().position.value_or(empty_position())),
  1652. move(nodes));
  1653. return node;
  1654. }
  1655. ErrorOr<RefPtr<AST::Node>> Parser::parse_io_redirect()
  1656. {
  1657. auto start_position = peek().position.value_or(empty_position());
  1658. auto start_index = m_token_index;
  1659. // io_redirect: IO_NUMBER? io_file | IO_NUMBER? io_here
  1660. Optional<int> io_number;
  1661. if (peek().type == Token::Type::IoNumber)
  1662. io_number = consume().value.bytes_as_string_view().to_int();
  1663. if (auto io_file = TRY(parse_io_file(start_position, io_number)))
  1664. return io_file;
  1665. if (auto io_here = TRY(parse_io_here(start_position, io_number)))
  1666. return io_here;
  1667. m_token_index = start_index;
  1668. return nullptr;
  1669. }
  1670. ErrorOr<RefPtr<AST::Node>> Parser::parse_io_here(AST::Position start_position, Optional<int> fd)
  1671. {
  1672. // io_here: IO_NUMBER? (DLESS | DLESSDASH) WORD
  1673. auto io_operator = peek().type;
  1674. if (!is_one_of(io_operator, Token::Type::DoubleLess, Token::Type::DoubleLessDash))
  1675. return nullptr;
  1676. auto io_operator_token = consume();
  1677. auto redirection_fd = fd.value_or(0);
  1678. auto end_keyword = consume();
  1679. if (!is_one_of(end_keyword.type, Token::Type::Word, Token::Type::Token))
  1680. 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);
  1681. auto [end_keyword_text, allow_interpolation] = Lexer::process_heredoc_key(end_keyword);
  1682. RefPtr<AST::SyntaxError> error;
  1683. auto position = start_position.with_end(peek().position.value_or(empty_position()));
  1684. auto result = make_ref_counted<AST::Heredoc>(
  1685. position,
  1686. end_keyword_text,
  1687. allow_interpolation,
  1688. io_operator == Token::Type::DoubleLessDash,
  1689. Optional<int> { redirection_fd });
  1690. m_unprocessed_heredoc_entries.set(end_keyword_text, result);
  1691. if (error)
  1692. result->set_is_syntax_error(*error);
  1693. return result;
  1694. }
  1695. ErrorOr<RefPtr<AST::Node>> Parser::parse_io_file(AST::Position start_position, Optional<int> fd)
  1696. {
  1697. auto start_index = m_token_index;
  1698. // io_file = (LESS | LESSAND | GREAT | GREATAND | DGREAT | LESSGREAT | CLOBBER) WORD
  1699. auto io_operator = peek().type;
  1700. if (!is_one_of(io_operator,
  1701. Token::Type::Less, Token::Type::LessAnd, Token::Type::Great, Token::Type::GreatAnd,
  1702. Token::Type::DoubleGreat, Token::Type::LessGreat, Token::Type::Clobber))
  1703. return nullptr;
  1704. auto io_operator_token = consume();
  1705. auto word = TRY(parse_word());
  1706. if (!word) {
  1707. m_token_index = start_index;
  1708. return nullptr;
  1709. }
  1710. auto position = start_position.with_end(peek().position.value_or(empty_position()));
  1711. switch (io_operator) {
  1712. case Token::Type::Less:
  1713. return make_ref_counted<AST::ReadRedirection>(
  1714. position,
  1715. fd.value_or(0),
  1716. word.release_nonnull());
  1717. case Token::Type::Clobber:
  1718. // FIXME: Add support for clobber (and 'noclobber')
  1719. case Token::Type::Great:
  1720. return make_ref_counted<AST::WriteRedirection>(
  1721. position,
  1722. fd.value_or(1),
  1723. word.release_nonnull());
  1724. case Token::Type::DoubleGreat:
  1725. return make_ref_counted<AST::WriteAppendRedirection>(
  1726. position,
  1727. fd.value_or(1),
  1728. word.release_nonnull());
  1729. case Token::Type::LessGreat:
  1730. return make_ref_counted<AST::ReadWriteRedirection>(
  1731. position,
  1732. fd.value_or(0),
  1733. word.release_nonnull());
  1734. case Token::Type::LessAnd:
  1735. case Token::Type::GreatAnd: {
  1736. auto is_less = io_operator == Token::Type::LessAnd;
  1737. auto source_fd = fd.value_or(is_less ? 0 : 1);
  1738. if (word->is_bareword()) {
  1739. auto maybe_target_fd = static_ptr_cast<AST::BarewordLiteral>(word)->text().bytes_as_string_view().to_int();
  1740. if (maybe_target_fd.has_value()) {
  1741. auto target_fd = maybe_target_fd.release_value();
  1742. if (is_less)
  1743. swap(source_fd, target_fd);
  1744. return make_ref_counted<AST::Fd2FdRedirection>(
  1745. position,
  1746. source_fd,
  1747. target_fd);
  1748. }
  1749. }
  1750. if (is_less) {
  1751. return make_ref_counted<AST::ReadRedirection>(
  1752. position,
  1753. source_fd,
  1754. word.release_nonnull());
  1755. }
  1756. return make_ref_counted<AST::WriteRedirection>(
  1757. position,
  1758. source_fd,
  1759. word.release_nonnull());
  1760. }
  1761. default:
  1762. VERIFY_NOT_REACHED();
  1763. }
  1764. }
  1765. }