| 534 | } |
| 535 | |
| 536 | BAN::ErrorOr<SingleCommand> TokenParser::parse_single_command() |
| 537 | { |
| 538 | SingleCommand result; |
| 539 | |
| 540 | while (peek_token().type() == Token::Type::Whitespace) |
| 541 | consume_token(); |
| 542 | |
| 543 | while (peek_token().type() == Token::Type::String) |
| 544 | { |
| 545 | BAN::String env_name; |
| 546 | |
| 547 | const auto& string = peek_token().string(); |
| 548 | if (!isalpha(string.front())) |
| 549 | break; |
| 550 | |
| 551 | const auto env_len = string.sv().find([](char ch) { return !(isalnum(ch) || ch == '_'); }); |
| 552 | if (!env_len.has_value() || string[*env_len] != '=') |
| 553 | break; |
| 554 | TRY(env_name.append(string.sv().substring(0, *env_len))); |
| 555 | |
| 556 | auto full_value = TRY(parse_argument()); |
| 557 | ASSERT(!full_value.parts.empty()); |
| 558 | ASSERT(full_value.parts.front().has<CommandArgument::FixedString>()); |
| 559 | |
| 560 | auto& first_arg = full_value.parts.front().get<CommandArgument::FixedString>(); |
| 561 | ASSERT(first_arg.value.sv().starts_with(env_name)); |
| 562 | ASSERT(first_arg.value[*env_len] == '='); |
| 563 | for (size_t i = 0; i < *env_len + 1; i++) |
| 564 | first_arg.value.remove(0); |
| 565 | if (first_arg.value.empty()) |
| 566 | full_value.parts.remove(0); |
| 567 | |
| 568 | SingleCommand::EnvironmentVariable environment_variable; |
| 569 | environment_variable.name = BAN::move(env_name); |
| 570 | environment_variable.value = BAN::move(full_value); |
| 571 | TRY(result.environment.emplace_back(BAN::move(environment_variable))); |
| 572 | |
| 573 | while (peek_token().type() == Token::Type::Whitespace) |
| 574 | consume_token(); |
| 575 | } |
| 576 | |
| 577 | BAN::HashSet<BAN::String> used_aliases; |
| 578 | while (peek_token().type() == Token::Type::String) |
| 579 | { |
| 580 | auto token = read_token(); |
| 581 | |
| 582 | bool can_be_alias = false; |
| 583 | switch (peek_token().type()) |
| 584 | { |
| 585 | case Token::Type::EOF_: |
| 586 | case Token::Type::Ampersand: |
| 587 | case Token::Type::CloseParen: |
| 588 | case Token::Type::Pipe: |
| 589 | case Token::Type::Semicolon: |
| 590 | case Token::Type::Whitespace: |
| 591 | can_be_alias = true; |
| 592 | break; |
| 593 | case Token::Type::Backslash: |
nothing calls this directly
no test coverage detected