diff --git a/base/cvd/cuttlefish/host/commands/cvd/BUILD.bazel b/base/cvd/cuttlefish/host/commands/cvd/BUILD.bazel index cc33be811d..e6fd03d690 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/cvd/BUILD.bazel @@ -108,7 +108,6 @@ cc_library( "cli/parser/load_configs_parser.cpp", "cli/parser/selector_parser.cpp", "cli/request_context.cpp", - "cli/selector/arguments_lexer.cpp", "cli/selector/arguments_separator.cpp", "cli/selector/creation_analyzer.cpp", "cli/selector/device_selector_utils.cpp", @@ -203,7 +202,6 @@ cc_library( "cli/parser/load_configs_parser.h", "cli/parser/selector_parser.h", "cli/request_context.h", - "cli/selector/arguments_lexer.h", "cli/selector/arguments_separator.h", "cli/selector/creation_analyzer.h", "cli/selector/device_selector_utils.h", @@ -311,9 +309,6 @@ cc_test( "unittests/parser/metrics_configs_test.cc", "unittests/parser/test_common.cc", "unittests/parser/test_common.h", - "unittests/selector/client_lexer_helper.cpp", - "unittests/selector/client_lexer_helper.h", - "unittests/selector/client_lexer_test.cpp", "unittests/selector/group_record_test.cpp", "unittests/selector/host_tool_target_test.cpp", "unittests/selector/instance_database_helper.cpp", diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/selector/arguments_lexer.cpp b/base/cvd/cuttlefish/host/commands/cvd/cli/selector/arguments_lexer.cpp deleted file mode 100644 index ec20462605..0000000000 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/selector/arguments_lexer.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "host/commands/cvd/cli/selector/arguments_lexer.h" - -#include -#include -#include - -#include - -#include "host/commands/cvd/cli/selector/selector_constants.h" -#include "host/commands/cvd/instances/instance_database_utils.h" - -namespace cuttlefish { -namespace selector { -namespace { - -class ArgumentsLexer { - public: - static Result Build(); - - Result> Tokenize( - const std::vector& args) const; - - private: - // Lexer factory function will internally generate this, - // and give it to ArgumentsLexer. - struct FlagPatterns { - /* represents flags that takes values - * e.g. -group_name, --group_name (which may take an additional - * positional arg, or use its default value.) - * - * With the given example, this set shall be: - * {"-group_name", "--group_name"} - */ - std::unordered_set value_patterns; - }; - ArgumentsLexer(FlagPatterns&& flag_patterns); - - Result Process(const std::string& token) const; - - struct FlagValuePair { - std::string flag_string; - std::string value; - }; - Result Separate( - const std::string& equal_included_string) const; - // flag_string starts with "-" or "--" - static bool Registered(const std::string& flag_string, - const FlagPatterns& flag_patterns); - bool Registered(const std::string& flag_string) const { - return Registered(flag_string, flag_patterns_); - } - FlagPatterns flag_patterns_; -}; - -/* - * At the top level, there are only two tokens: flag and positional tokens. - * - * A flag token starts with "-" or "--" followed by one or more non "-" letters. - * A positional token starts with any character other than "-". - * - * Between flag tokens, there are "known" and "unknown" flag tokens. - * - * Eventually, we get two sets, each include strings start with "-" or "--". - * - * Say, the two sets are BaseSet and NoPrependedSet. - * - * Given a non boolean flag --bar, these will happen: - * BaseSet = BaseSet U {"--bar", "-bar"} - * - * Later on, when the parser reads a token, the parser will look up the - * two sets to see if the token that is supposedly a flag is a known - * flag. - */ -Result ArgumentsLexer::Build() { - // Change together: ParseCommonSelectorArguments in selector_common_parser.cpp - std::unordered_set known_flags{SelectorFlags::kGroupName, - SelectorFlags::kInstanceName, - SelectorFlags::kVerbosity}; - - FlagPatterns flag_patterns; - for (const auto& non_bool_flag : known_flags) { - const auto one_dash = "-" + non_bool_flag; - const auto two_dashes = "--" + non_bool_flag; - CF_EXPECT(!ArgumentsLexer::Registered(one_dash, flag_patterns)); - CF_EXPECT(!ArgumentsLexer::Registered(two_dashes, flag_patterns)); - flag_patterns.value_patterns.insert(one_dash); - flag_patterns.value_patterns.insert(two_dashes); - } - - return ArgumentsLexer(std::move(flag_patterns)); -} - -ArgumentsLexer::ArgumentsLexer(FlagPatterns&& flag_patterns) - : flag_patterns_{std::move(flag_patterns)} {} - -bool ArgumentsLexer::Registered(const std::string& flag_string, - const FlagPatterns& flag_patterns) { - return Contains(flag_patterns.value_patterns, flag_string); -} - -Result ArgumentsLexer::Process(const std::string& token) const { - if (token == "--") { - return ArgToken{ArgType::kDoubleDash, token}; - } - std::regex flag_and_value_pattern("[\\-][\\-]?[^\\-]+.*=.*"); - std::regex flag_pattern("[\\-][\\-]?[^\\-]+.*"); - std::regex base_pattern("[^\\-]+.*"); - if (std::regex_match(token, base_pattern)) { - return ArgToken{ArgType::kPositional, token}; - } - if (!std::regex_match(token, flag_pattern)) { - return ArgToken{ArgType::kError, token}; - } - // --flag=value - if (std::regex_match(token, flag_and_value_pattern)) { - auto [flag_string, value] = CF_EXPECT(Separate(token)); - // is --flag registered? - if (Contains(flag_patterns_.value_patterns, flag_string)) { - return ArgToken{ArgType::kKnownFlagAndValue, token}; - } - return ArgToken{ArgType::kUnknownFlag, token}; - } - if (Contains(flag_patterns_.value_patterns, token)) { - return ArgToken{ArgType::kKnownValueFlag, token}; - } - return ArgToken{ArgType::kUnknownFlag, token}; -} - -Result> ArgumentsLexer::Tokenize( - const std::vector& args) const { - std::vector tokenized; - for (const auto& arg : args) { - auto arg_token = CF_EXPECT(Process(arg)); - tokenized.emplace_back(arg_token); - } - return tokenized; -} - -Result ArgumentsLexer::Separate( - const std::string& equal_included_string) const { - CF_EXPECT(Contains(equal_included_string, "=")); - auto equal_sign_pos = equal_included_string.find_first_of('='); - auto first_token = equal_included_string.substr(0, equal_sign_pos); - auto second_token = equal_included_string.substr(equal_sign_pos + 1); - return FlagValuePair{.flag_string = first_token, .value = second_token}; -} - -} // namespace - -Result> TokenizeArguments( - const std::vector& args) { - ArgumentsLexer lexer = CF_EXPECT(ArgumentsLexer::Build()); - - return CF_EXPECT(lexer.Tokenize(args)); -} - -} // namespace selector -} // namespace cuttlefish diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/selector/arguments_lexer.h b/base/cvd/cuttlefish/host/commands/cvd/cli/selector/arguments_lexer.h deleted file mode 100644 index b2c1b307ce..0000000000 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/selector/arguments_lexer.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include - -#include "common/libs/utils/result.h" - -namespace cuttlefish { -namespace selector { - -/** - * A "token" is each piece of command line argument that is mostly - * separated by " ". - * - * Each token has a type. The type is a useful information for the - * grammar parser, which will use this lexer. - * - * Before going into the details, we assume that a set of flags are - * pre-registered, and the user may still give unregisterred flags. - * - * Note that the purpose of this lexer/parser is to separate cvd - * client specific arguments and the "subcmd" from the rest. So, - * "registered" arguments would be the cvd client specific arguments. - * The unregisterred arguments would be for the sub tool. - * - * Also, in terms of lexing, boolean flags are different from other - * value-taking flags. A boolean flag --foo could be --nofoo. - * - * 1. kKnownValueFlag - * --foo, -foo that may take a non-boolean value - * 2. kKnownFlagAndValue - * --foo=value, -foo=value, which does not take more values - * 3. kKnownBoolFlag - * --daemon, -daemon, etc, which may take a boolean arg - * 4. kKnownBoolNoFlag - * --nodaemon, -nodaemon, etc, which does not take another argument. - * 5. kUnknownFlag - * -anything_else or --anything_else - * --anything_else=any_value, etc - * Note that if we don't know the type of the flag, we will have to forward - * the entire thing to the subcmd as is. - * 6. kPositional - * mostly without leading "-" or "--" - * 7. kDoubleDash - * A literally "--" - * cvd and its subtools as of not are not really using that. - * However, it might be useful in the future for any subtool of cvd, so - * we allow "--" in the subcmd arguments only in the parser level. - * In the lexer level, we simply returns kDoubleDash token. - * 8. kError - * The rest. - * - */ -enum class ArgType : int { - kKnownValueFlag, - kKnownFlagAndValue, - kKnownBoolFlag, - kKnownBoolNoFlag, - kUnknownFlag, - kPositional, - kDoubleDash, - kError -}; - -class ArgToken { - public: - ArgToken() = delete; - ArgToken(const ArgType arg_type, const std::string& token) - : type_(arg_type), token_(token) {} - ArgToken(const ArgToken& src) = default; - ArgToken(ArgToken&& src) = default; - ArgToken& operator=(const ArgToken& src) { - type_ = src.type_; - token_ = src.token_; - return *this; - } - ArgToken& operator=(ArgToken&& src) { - type_ = std::move(src.type_); - token_ = std::move(src.token_); - return *this; - } - - auto Type() const { return type_; } - const auto& Token() const { return token_; } - auto& Token() { return token_; } - bool operator==(const ArgToken& dst) const { - return Type() == dst.Type() && Token() == dst.Token(); - } - - private: - ArgType type_; - std::string token_; -}; - -Result> TokenizeArguments( - const std::vector& args); - -} // namespace selector -} // namespace cuttlefish diff --git a/base/cvd/cuttlefish/host/commands/cvd/unittests/selector/client_lexer_helper.cpp b/base/cvd/cuttlefish/host/commands/cvd/unittests/selector/client_lexer_helper.cpp deleted file mode 100644 index 6053abfd52..0000000000 --- a/base/cvd/cuttlefish/host/commands/cvd/unittests/selector/client_lexer_helper.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (C) 2022 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "host/commands/cvd/unittests/selector/client_lexer_helper.h" - -namespace cuttlefish { -namespace selector { - -LexerTestBase::LexerTestBase() { Init(); } - -void LexerTestBase::Init() { - auto param = GetParam(); - lex_input_ = param.lex_input_; - expected_tokens_ = param.expected_tokens_; -} - -} // namespace selector -} // namespace cuttlefish diff --git a/base/cvd/cuttlefish/host/commands/cvd/unittests/selector/client_lexer_helper.h b/base/cvd/cuttlefish/host/commands/cvd/unittests/selector/client_lexer_helper.h deleted file mode 100644 index 5a49bb6454..0000000000 --- a/base/cvd/cuttlefish/host/commands/cvd/unittests/selector/client_lexer_helper.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (C) 2022 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include - -#include - -#include "host/commands/cvd/cli/selector/arguments_lexer.h" - -namespace cuttlefish { -namespace selector { - -using Tokens = std::vector; - -struct LexerInputOutput { - std::string lex_input_; - std::optional expected_tokens_; -}; - -class LexerTestBase : public testing::TestWithParam { - protected: - LexerTestBase(); - void Init(); - - std::string lex_input_; - std::optional expected_tokens_; -}; - -class EmptyArgsLexTest : public LexerTestBase {}; -class NonBooleanArgsTest : public LexerTestBase {}; -class BooleanArgsTest : public LexerTestBase {}; -class BothArgsTest : public LexerTestBase {}; - -class BooleanBadArgsTest : public LexerTestBase {}; - -} // namespace selector -} // namespace cuttlefish diff --git a/base/cvd/cuttlefish/host/commands/cvd/unittests/selector/client_lexer_test.cpp b/base/cvd/cuttlefish/host/commands/cvd/unittests/selector/client_lexer_test.cpp deleted file mode 100644 index 272d9a1a15..0000000000 --- a/base/cvd/cuttlefish/host/commands/cvd/unittests/selector/client_lexer_test.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// -// Copyright (C) 2022 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include -#include - -#include "common/libs/utils/result.h" -#include "common/libs/utils/result_matchers.h" -#include "host/commands/cvd/cli/selector/arguments_lexer.h" -#include "host/commands/cvd/unittests/selector/client_lexer_helper.h" - -namespace cuttlefish { -namespace selector { -namespace { - -Result> Tokenize(const std::string& args) { - auto args_vec = android::base::Tokenize(args, " "); - return CF_EXPECT(TokenizeArguments(args_vec)); -} - -} // namespace - -TEST_P(EmptyArgsLexTest, SuccessExpectedTest) { - EXPECT_THAT(Tokenize(lex_input_), IsOkAndValue(*expected_tokens_)); -} - -INSTANTIATE_TEST_SUITE_P( - ClientSpecificOptionParser, EmptyArgsLexTest, - testing::Values( - LexerInputOutput{.lex_input_ = "", .expected_tokens_ = Tokens{}}, - LexerInputOutput{.lex_input_ = "", .expected_tokens_ = Tokens{}}, - LexerInputOutput{.lex_input_ = "", .expected_tokens_ = Tokens{}}, - LexerInputOutput{.lex_input_ = "", .expected_tokens_ = Tokens{}})); - -TEST_P(NonBooleanArgsTest, SuccessExpectedTest) { - EXPECT_THAT(Tokenize(lex_input_), IsOkAndValue(*expected_tokens_)); -} - -INSTANTIATE_TEST_SUITE_P( - ClientSpecificOptionParser, NonBooleanArgsTest, - testing::Values( - LexerInputOutput{ - .lex_input_ = "cvd --group_name=yumi", - .expected_tokens_ = Tokens{ArgToken{ArgType::kPositional, "cvd"}, - ArgToken{ArgType::kKnownFlagAndValue, - "--group_name=yumi"}}}, - LexerInputOutput{ - .lex_input_ = "cvd --group_name yumi", - .expected_tokens_ = Tokens{ArgToken{ArgType::kPositional, "cvd"}, - ArgToken{ArgType::kKnownValueFlag, - "--group_name"}, - ArgToken{ArgType::kPositional, "yumi"}}}, - LexerInputOutput{.lex_input_ = "cvd --group_name yumi start --daemon", - .expected_tokens_ = Tokens{ - ArgToken{ArgType::kPositional, "cvd"}, - ArgToken{ArgType::kKnownValueFlag, "--group_name"}, - ArgToken{ArgType::kPositional, "yumi"}, - ArgToken{ArgType::kPositional, "start"}, - ArgToken{ArgType::kUnknownFlag, "--daemon"}}})); - -TEST_P(BooleanBadArgsTest, FailureExpectedTest) { - auto tokenized_result = Tokenize(lex_input_); - - if (!expected_tokens_) { - ASSERT_FALSE(tokenized_result.ok()) - << "Lexing " << lex_input_ << " should have failed."; - return; - } - EXPECT_THAT(tokenized_result, IsOkAndValue(*expected_tokens_)); -} - -INSTANTIATE_TEST_SUITE_P( - ClientSpecificOptionParser, BooleanBadArgsTest, - testing::Values( - LexerInputOutput{ - .lex_input_ = "cvd --yesclean", - .expected_tokens_ = Tokens{ArgToken{ArgType::kPositional, "cvd"}, - ArgToken{ArgType::kUnknownFlag, - "--yesclean"}}}, - LexerInputOutput{ - .lex_input_ = "cvd --clean", - .expected_tokens_ = Tokens{ArgToken{ArgType::kPositional, "cvd"}, - ArgToken{ArgType::kUnknownFlag, - "--clean"}}}, - LexerInputOutput{.lex_input_ = "cvd --clean false", - .expected_tokens_ = Tokens{ - ArgToken{ArgType::kPositional, "cvd"}, - ArgToken{ArgType::kUnknownFlag, "--clean"}, - ArgToken{ArgType::kPositional, "false"}}})); - -} // namespace selector -} // namespace cuttlefish