Skip to content

Commit

Permalink
Add CSSDelimeter::OptionalWhitespace and CSSDelimeter::CommaOrWhitesp…
Browse files Browse the repository at this point in the history
…aceOrSolidus (facebook#48828)

Summary:

1. Rename `CSSComponentValueDelimeter` to `CSSDelimeter` bc the names are getting way too long.
2. Make the distinction between `Whitespace` and `OptionalWhitespace`. Note that for property values, and function blocks, the value parser will already remove trailing/leading whitespace, but it's weird that whitespace unlike others was not required to be present
3. Add `CSSDelimeter::CommaOrWhitespaceOrSolidus` for simpler parsing in the common pattern of alpha values, and move CSSColor function parsing to use that

Changelog: [Internal]

Reviewed By: lenaic

Differential Revision: D68461968
  • Loading branch information
NickGerleman authored and facebook-github-bot committed Jan 22, 2025
1 parent 68786c7 commit 4e2f739
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ constexpr std::optional<CSSColor> parseRgbFunction(CSSSyntaxParser& parser) {
if (std::holds_alternative<CSSNumber>(firstValue)) {
redNumber = std::get<CSSNumber>(firstValue).value;

auto green = parseNextCSSValue<CSSNumber>(
parser, CSSComponentValueDelimiter::CommaOrWhitespace);
auto green =
parseNextCSSValue<CSSNumber>(parser, CSSDelimiter::CommaOrWhitespace);
if (!std::holds_alternative<CSSNumber>(green)) {
return {};
}
greenNumber = std::get<CSSNumber>(green).value;

auto blue = parseNextCSSValue<CSSNumber>(
parser, CSSComponentValueDelimiter::CommaOrWhitespace);
auto blue =
parseNextCSSValue<CSSNumber>(parser, CSSDelimiter::CommaOrWhitespace);
if (!std::holds_alternative<CSSNumber>(blue)) {
return {};
}
Expand All @@ -70,31 +70,22 @@ constexpr std::optional<CSSColor> parseRgbFunction(CSSSyntaxParser& parser) {
redNumber = std::get<CSSPercentage>(firstValue).value * 2.55f;

auto green = parseNextCSSValue<CSSPercentage>(
parser, CSSComponentValueDelimiter::CommaOrWhitespace);
parser, CSSDelimiter::CommaOrWhitespace);
if (!std::holds_alternative<CSSPercentage>(green)) {
return {};
}
greenNumber = std::get<CSSPercentage>(green).value * 2.55f;

auto blue = parseNextCSSValue<CSSPercentage>(
parser, CSSComponentValueDelimiter::CommaOrWhitespace);
parser, CSSDelimiter::CommaOrWhitespace);
if (!std::holds_alternative<CSSPercentage>(blue)) {
return {};
}
blueNumber = std::get<CSSPercentage>(blue).value * 2.55f;
}

auto alphaValue = peekNextCSSValue<CSSNumber, CSSPercentage>(
parser, CSSComponentValueDelimiter::CommaOrWhitespace);
if (!std::holds_alternative<std::monostate>(alphaValue)) {
parser.consumeComponentValue(CSSComponentValueDelimiter::CommaOrWhitespace);
} else {
alphaValue = peekNextCSSValue<CSSNumber, CSSPercentage>(
parser, CSSComponentValueDelimiter::Solidus);
if (!std::holds_alternative<std::monostate>(alphaValue)) {
parser.consumeComponentValue(CSSComponentValueDelimiter::Solidus);
}
}
auto alphaValue = parseNextCSSValue<CSSNumber, CSSPercentage>(
parser, CSSDelimiter::CommaOrWhitespaceOrSolidus);

float alphaNumber = std::holds_alternative<std::monostate>(alphaValue) ? 1.0f
: std::holds_alternative<CSSNumber>(alphaValue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ struct CSSDataTypeParser<CSSRatio> {
if (isValidRatioPart(token.numericValue())) {
float numerator = token.numericValue();

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

Expand Down
112 changes: 69 additions & 43 deletions packages/react-native/ReactCommon/react/renderer/css/CSSSyntaxParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,13 @@ concept CSSUniqueComponentValueVisitors =
/**
* Describes the delimeter to expect before the next component value.
*/
enum class CSSComponentValueDelimiter {
Comma,
enum class CSSDelimiter {
Whitespace,
CommaOrWhitespace,
OptionalWhitespace,
Solidus,
Comma,
CommaOrWhitespace,
CommaOrWhitespaceOrSolidus,
None,
};

Expand Down Expand Up @@ -142,7 +144,7 @@ class CSSSyntaxParser {
*/
template <typename ReturnT = std::nullptr_t>
constexpr ReturnT consumeComponentValue(
CSSComponentValueDelimiter delimiter,
CSSDelimiter delimiter,
const CSSComponentValueVisitor<ReturnT> auto&... visitors)
requires(CSSUniqueComponentValueVisitors<ReturnT, decltype(visitors)...>);

Expand Down Expand Up @@ -172,7 +174,7 @@ class CSSSyntaxParser {
*/
template <typename ReturnT = std::nullptr_t>
constexpr ReturnT peekComponentValue(
CSSComponentValueDelimiter delimiter,
CSSDelimiter delimiter,
const CSSComponentValueVisitor<ReturnT> auto&... visitors)
requires(CSSUniqueComponentValueVisitors<ReturnT, decltype(visitors)...>);

Expand Down Expand Up @@ -229,38 +231,10 @@ struct CSSComponentValueVisitorDispatcher {
CSSSyntaxParser& parser;

constexpr ReturnT consumeComponentValue(
CSSComponentValueDelimiter delimiter,
CSSDelimiter delimiter,
const VisitorsT&... visitors) {
switch (delimiter) {
case CSSComponentValueDelimiter::Comma:
parser.consumeWhitespace();
if (parser.peek().type() != CSSTokenType::Comma) {
return ReturnT{};
}
parser.consumeToken();
parser.consumeWhitespace();
break;
case CSSComponentValueDelimiter::Whitespace:
parser.consumeWhitespace();
break;
case CSSComponentValueDelimiter::CommaOrWhitespace:
parser.consumeWhitespace();
if (parser.peek().type() == CSSTokenType::Comma) {
parser.consumeToken();
}
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;
if (!consumeDelimiter(delimiter)) {
return {};
}

if (parser.peek().type() == parser.terminator_) {
Expand Down Expand Up @@ -301,8 +275,62 @@ struct CSSComponentValueVisitorDispatcher {
return ReturnT{};
}

/**
* Consume a delimiter, returning false if a required delimiter is not found.
*/
constexpr bool consumeDelimiter(CSSDelimiter delimiter) {
if (delimiter == CSSDelimiter::None) {
return true;
}

bool hasWhiteSpace = parser.peek().type() == CSSTokenType::WhiteSpace;
parser.consumeWhitespace();

switch (delimiter) {
case CSSDelimiter::Comma:
if (parser.peek().type() == CSSTokenType::Comma) {
parser.consumeToken();
parser.consumeWhitespace();
return true;
}
return false;
case CSSDelimiter::Whitespace:
return hasWhiteSpace;
case CSSDelimiter::OptionalWhitespace:
return true;
case CSSDelimiter::CommaOrWhitespace:
if (parser.peek().type() == CSSTokenType::Comma) {
parser.consumeToken();
parser.consumeWhitespace();
return true;
}
return hasWhiteSpace;
case CSSDelimiter::Solidus:
if (parser.peek().type() == CSSTokenType::Delim &&
parser.peek().stringValue() == "/") {
parser.consumeToken();
parser.consumeWhitespace();
return true;
}
return false;
case CSSDelimiter::CommaOrWhitespaceOrSolidus:
if (parser.peek().type() == CSSTokenType::Comma ||
(parser.peek().type() == CSSTokenType::Delim &&
parser.peek().stringValue() == "/")) {
parser.consumeToken();
parser.consumeWhitespace();
return true;
}
return hasWhiteSpace;
case CSSDelimiter::None:
return true;
}

return false;
}

constexpr ReturnT peekComponentValue(
CSSComponentValueDelimiter delimiter,
CSSDelimiter delimiter,
const VisitorsT&... visitors) {
auto originalParser = parser;
auto ret = consumeComponentValue(delimiter, visitors...);
Expand Down Expand Up @@ -393,7 +421,7 @@ struct CSSComponentValueVisitorDispatcher {

template <typename ReturnT>
constexpr ReturnT CSSSyntaxParser::consumeComponentValue(
CSSComponentValueDelimiter delimiter,
CSSDelimiter delimiter,
const CSSComponentValueVisitor<ReturnT> auto&... visitors)
requires(CSSUniqueComponentValueVisitors<ReturnT, decltype(visitors)...>)
{
Expand All @@ -407,13 +435,12 @@ constexpr ReturnT CSSSyntaxParser::consumeComponentValue(
const CSSComponentValueVisitor<ReturnT> auto&... visitors)
requires(CSSUniqueComponentValueVisitors<ReturnT, decltype(visitors)...>)
{
return consumeComponentValue<ReturnT>(
CSSComponentValueDelimiter::None, visitors...);
return consumeComponentValue<ReturnT>(CSSDelimiter::None, visitors...);
}

template <typename ReturnT>
constexpr ReturnT CSSSyntaxParser::peekComponentValue(
CSSComponentValueDelimiter delimiter,
CSSDelimiter delimiter,
const CSSComponentValueVisitor<ReturnT> auto&... visitors)
requires(CSSUniqueComponentValueVisitors<ReturnT, decltype(visitors)...>)
{
Expand All @@ -427,8 +454,7 @@ constexpr ReturnT CSSSyntaxParser::peekComponentValue(
const CSSComponentValueVisitor<ReturnT> auto&... visitors)
requires(CSSUniqueComponentValueVisitors<ReturnT, decltype(visitors)...>)
{
return peekComponentValue<ReturnT>(
CSSComponentValueDelimiter::None, visitors...);
return peekComponentValue<ReturnT>(CSSDelimiter::None, visitors...);
}

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class CSSValueParser {
*/
template <CSSDataType... AllowedTypesT>
constexpr std::variant<std::monostate, AllowedTypesT...> consumeValue(
CSSComponentValueDelimiter delimeter = CSSComponentValueDelimiter::None) {
CSSDelimiter delimeter = CSSDelimiter::None) {
using ReturnT = std::variant<std::monostate, AllowedTypesT...>;

return parser_.consumeComponentValue<ReturnT>(
Expand Down Expand Up @@ -174,7 +174,7 @@ constexpr auto parseCSSProperty(std::string_view css)
template <CSSDataType... AllowedTypesT>
constexpr auto parseNextCSSValue(
CSSSyntaxParser& syntaxParser,
CSSComponentValueDelimiter delimeter = CSSComponentValueDelimiter::None)
CSSDelimiter delimeter = CSSDelimiter::None)
-> std::variant<std::monostate, AllowedTypesT...> {
detail::CSSValueParser valueParser(syntaxParser);
return valueParser.consumeValue<AllowedTypesT...>(delimeter);
Expand All @@ -187,7 +187,7 @@ constexpr auto parseNextCSSValue(
template <CSSDataType... AllowedTypesT>
constexpr auto peekNextCSSValue(
CSSSyntaxParser& syntaxParser,
CSSComponentValueDelimiter delimeter = CSSComponentValueDelimiter::None)
CSSDelimiter delimeter = CSSDelimiter::None)
-> std::variant<std::monostate, AllowedTypesT...> {
auto savedParser = syntaxParser;
detail::CSSValueParser valueParser(syntaxParser);
Expand Down
Loading

0 comments on commit 4e2f739

Please sign in to comment.