15
15
16
16
namespace facebook ::react {
17
17
18
+ class CSSSyntaxParser ;
19
+
18
20
/* *
19
21
* Describes context for a CSS function component value.
20
22
*/
@@ -41,9 +43,10 @@ struct CSSSimpleBlock {
41
43
* of the function block.
42
44
*/
43
45
template <typename T, typename ReturnT>
44
- concept CSSFunctionVisitor = requires (T visitor, CSSFunctionBlock func) {
45
- { visitor (func) } -> std::convertible_to<ReturnT>;
46
- };
46
+ concept CSSFunctionVisitor =
47
+ requires (T visitor, CSSFunctionBlock func, CSSSyntaxParser& blockParser) {
48
+ { visitor (func, blockParser) } -> std::convertible_to<ReturnT>;
49
+ };
47
50
48
51
/* *
49
52
* A CSSPreservedTokenVisitor is called after parsing a preserved token
@@ -61,9 +64,10 @@ concept CSSPreservedTokenVisitor =
61
64
* of the block.
62
65
*/
63
66
template <typename T, typename ReturnT>
64
- concept CSSSimpleBlockVisitor = requires (T visitor, CSSSimpleBlock block) {
65
- { visitor (block) } -> std::convertible_to<ReturnT>;
66
- };
67
+ concept CSSSimpleBlockVisitor =
68
+ requires (T visitor, CSSSimpleBlock block, CSSSyntaxParser& blockParser) {
69
+ { visitor (block, blockParser) } -> std::convertible_to<ReturnT>;
70
+ };
67
71
68
72
/* *
69
73
* Any visitor for a component value.
@@ -164,6 +168,11 @@ class CSSSyntaxParser {
164
168
}
165
169
166
170
private:
171
+ CSSSyntaxParser (CSSSyntaxParser& parser, CSSTokenType terminator)
172
+ : tokenizer_{parser.tokenizer_ },
173
+ currentToken_{parser.currentToken_ },
174
+ terminator_{terminator} {}
175
+
167
176
constexpr const CSSToken& peek () const {
168
177
return currentToken_;
169
178
}
@@ -174,8 +183,14 @@ class CSSSyntaxParser {
174
183
return prevToken;
175
184
}
176
185
186
+ constexpr void advanceToBlockParser (CSSSyntaxParser& blockParser) {
187
+ currentToken_ = blockParser.currentToken_ ;
188
+ tokenizer_ = blockParser.tokenizer_ ;
189
+ }
190
+
177
191
CSSTokenizer tokenizer_;
178
192
CSSToken currentToken_;
193
+ CSSTokenType terminator_{CSSTokenType::EndOfFile};
179
194
};
180
195
181
196
template <typename ReturnT, CSSComponentValueVisitor<ReturnT>... VisitorsT>
@@ -201,6 +216,10 @@ struct CSSComponentValueVisitorDispatcher {
201
216
break ;
202
217
}
203
218
219
+ if (parser.peek ().type () == parser.terminator_ ) {
220
+ return {};
221
+ }
222
+
204
223
switch (parser.peek ().type ()) {
205
224
case CSSTokenType::Function:
206
225
if (auto ret = visitFunction (visitors...)) {
@@ -235,28 +254,22 @@ struct CSSComponentValueVisitorDispatcher {
235
254
return ReturnT{};
236
255
}
237
256
238
- constexpr ReturnT consumeNextCommaDelimitedValue (
239
- const VisitorsT&... visitors) {
240
- parser.consumeWhitespace ();
241
- if (parser.consumeToken ().type () != CSSTokenType::Comma) {
242
- return {};
243
- }
244
- parser.consumeWhitespace ();
245
- return consumeComponentValue (std::forward<VisitorsT>(visitors)...);
246
- }
247
-
248
- constexpr ReturnT consumeNextWhitespaceDelimitedValue (
249
- const VisitorsT&... visitors) {
250
- parser.consumeWhitespace ();
251
- return consumeComponentValue (std::forward<VisitorsT>(visitors)...);
252
- }
253
-
254
257
constexpr std::optional<ReturnT> visitFunction (
255
258
const CSSComponentValueVisitor<ReturnT> auto & visitor,
256
259
const CSSComponentValueVisitor<ReturnT> auto &... rest) {
257
260
if constexpr (CSSFunctionVisitor<decltype (visitor), ReturnT>) {
258
- auto functionValue =
259
- visitor ({.name = parser.consumeToken ().stringValue ()});
261
+ auto name = parser.consumeToken ().stringValue ();
262
+
263
+ // CSS syntax spec says whitespace is a preserved token, but CSS values
264
+ // spec allows whitespace around parens for all function notation, so we
265
+ // allow this to let the visitors not need to deal with leading/trailing
266
+ // whitespace. https://www.w3.org/TR/css-values-3/#functional-notations
267
+ parser.consumeWhitespace ();
268
+
269
+ auto blockParser =
270
+ CSSSyntaxParser{parser, CSSTokenType::CloseParen /* terminator*/ };
271
+ auto functionValue = visitor ({name}, blockParser);
272
+ parser.advanceToBlockParser (blockParser);
260
273
parser.consumeWhitespace ();
261
274
if (parser.peek ().type () == CSSTokenType::CloseParen) {
262
275
parser.consumeToken ();
@@ -273,16 +286,16 @@ struct CSSComponentValueVisitorDispatcher {
273
286
return {};
274
287
}
275
288
276
- // Can be one of std::monostate (variant null-type), CSSWideKeyword,
277
- // CSSLength, or CSSPercentage
278
-
279
289
constexpr std::optional<ReturnT> visitSimpleBlock (
280
290
CSSTokenType endToken,
281
291
const CSSComponentValueVisitor<ReturnT> auto & visitor,
282
292
const CSSComponentValueVisitor<ReturnT> auto &... rest) {
283
293
if constexpr (CSSSimpleBlockVisitor<decltype (visitor), ReturnT>) {
284
- auto blockValue =
285
- visitor ({.openBracketType = parser.consumeToken ().type ()});
294
+ auto openBracketType = parser.consumeToken ().type ();
295
+ parser.consumeWhitespace ();
296
+ auto blockParser = CSSSyntaxParser{parser, endToken};
297
+ auto blockValue = visitor ({openBracketType}, blockParser);
298
+ parser.advanceToBlockParser (blockParser);
286
299
parser.consumeWhitespace ();
287
300
if (parser.peek ().type () == endToken) {
288
301
parser.consumeToken ();
0 commit comments