Skip to content

Commit

Permalink
Simplify consuming solidus separated component values (facebook#48826)
Browse files Browse the repository at this point in the history
Summary:

This ends up being a not uncommon pattern, so lets make it a bit easier.

Changelog: [Internal]

Reviewed By: lenaic

Differential Revision: D68359563
  • Loading branch information
NickGerleman authored and facebook-github-bot committed Jan 21, 2025
1 parent 212fdf8 commit d8fd848
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 18 deletions.
21 changes: 5 additions & 16 deletions packages/react-native/ReactCommon/react/renderer/css/CSSRatio.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,15 @@ struct CSSDataTypeParser<CSSRatio> {
if (isValidRatioPart(token.numericValue())) {
float numerator = token.numericValue();

auto hasSolidus = parser.peekComponentValue<bool>(
CSSComponentValueDelimiter::Whitespace,
[&](const CSSPreservedToken& token) {
return token.type() == CSSTokenType::Delim &&
token.stringValue() == "/";
});

if (!hasSolidus) {
return CSSRatio{numerator, 1.0f};
}

parser.consumeComponentValue(CSSComponentValueDelimiter::Whitespace);

auto denominator = parseNextCSSValue<CSSNumber>(
parser, CSSComponentValueDelimiter::Whitespace);

auto denominator = peekNextCSSValue<CSSNumber>(
parser, CSSComponentValueDelimiter::Solidus);
if (std::holds_alternative<CSSNumber>(denominator) &&
isValidRatioPart(std::get<CSSNumber>(denominator).value)) {
parser.consumeComponentValue(CSSComponentValueDelimiter::Solidus);
return CSSRatio{numerator, std::get<CSSNumber>(denominator).value};
}

return CSSRatio{numerator, 1.0f};
}

return {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ enum class CSSComponentValueDelimiter {
Comma,
Whitespace,
CommaOrWhitespace,
Solidus,
None,
};

Expand Down Expand Up @@ -249,6 +250,15 @@ struct CSSComponentValueVisitorDispatcher {
}
parser.consumeWhitespace();
break;
case CSSComponentValueDelimiter::Solidus:
parser.consumeWhitespace();
if (parser.peek().type() != CSSTokenType::Delim ||
parser.peek().stringValue() != "/") {
return ReturnT{};
}
parser.consumeToken();
parser.consumeWhitespace();
break;
case CSSComponentValueDelimiter::None:
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,7 @@ constexpr auto parseCSSProperty(std::string_view css)

/**
* Attempts to parse the next CSS value of a given set of data types, at the
* current location of the syntax parser, advancing the syntax parser if
* successful.
* current location of the syntax parser, advancing the syntax parser
*/
template <CSSDataType... AllowedTypesT>
constexpr auto parseNextCSSValue(
Expand All @@ -181,4 +180,20 @@ constexpr auto parseNextCSSValue(
return valueParser.consumeValue<AllowedTypesT...>(delimeter);
}

/**
* Attempts to parse the next CSS value of a given set of data types, at the
* current location of the syntax parser, without advancing the syntax parser
*/
template <CSSDataType... AllowedTypesT>
constexpr auto peekNextCSSValue(
CSSSyntaxParser& syntaxParser,
CSSComponentValueDelimiter delimeter = CSSComponentValueDelimiter::None)
-> std::variant<std::monostate, AllowedTypesT...> {
auto savedParser = syntaxParser;
detail::CSSValueParser valueParser(syntaxParser);
auto ret = valueParser.consumeValue<AllowedTypesT...>(delimeter);
syntaxParser = savedParser;
return ret;
}

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -477,4 +477,45 @@ TEST(CSSSyntaxParser, simple_block_without_visitor_consumed) {
EXPECT_EQ(identValue, "bar");
}

TEST(CSSSyntaxParser, solidus_delimiter) {
CSSSyntaxParser parser{"foo / bar"};

auto identValue = parser.consumeComponentValue<std::string_view>(
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "foo");
return token.stringValue();
});

EXPECT_EQ(identValue, "foo");

auto identValue2 = parser.consumeComponentValue<std::string_view>(
CSSComponentValueDelimiter::Solidus, [](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "bar");
return token.stringValue();
});

EXPECT_EQ(identValue2, "bar");
}

TEST(CSSSyntaxParser, solidus_delimiter_not_present) {
CSSSyntaxParser parser{"foo bar"};

auto identValue = parser.consumeComponentValue<std::string_view>(
[](const CSSPreservedToken& token) {
EXPECT_EQ(token.type(), CSSTokenType::Ident);
EXPECT_EQ(token.stringValue(), "foo");
return token.stringValue();
});

EXPECT_EQ(identValue, "foo");

auto identValue2 = parser.consumeComponentValue<bool>(
CSSComponentValueDelimiter::Solidus,
[](const CSSPreservedToken& /*token*/) { return true; });

EXPECT_FALSE(identValue2);
}

} // namespace facebook::react

0 comments on commit d8fd848

Please sign in to comment.