From 77e96017716572ffdc84da087fc10c9929a0d54e Mon Sep 17 00:00:00 2001 From: Tab Atkins-Bittner Date: Mon, 9 Oct 2023 16:09:12 -0700 Subject: [PATCH] [css-syntax-3] Per WG resolution, {} blocks are only allowed as the entire value of a property. #9317 --- css-syntax-3/Overview.bs | 107 ++++++++++++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 13 deletions(-) diff --git a/css-syntax-3/Overview.bs b/css-syntax-3/Overview.bs index 1c763cfa069..61be4c87b23 100644 --- a/css-syntax-3/Overview.bs +++ b/css-syntax-3/Overview.bs @@ -2828,6 +2828,79 @@ Consume a block's contents append it to |rules|. +
+ Implementation note + + This spec, as with many CSS specs, + has been written to prioritize understandability + over efficiency. + A number of algorithms, + notably the above "parse as a declaration, then parse as a rule" behavior + can be fairly inefficient + if implemented naively as described. + + However, the behavior has been carefully written + to allow "early exits" as much as possible. + In particular, + and roughly in order of when the exit can occur: + + * If the first non-whitespace token + isn't an <> + for a recognized property name (or a custom property name), + you can immediately stop parsing as a declaration + and reparse as a rule instead. + If the next non-whitespace token isn't a <>, + you can similarly immediately stop parsing as a declaration. + + (That is, ''font+ ...'' is guaranteed to not be a property, + nor is not-a-prop-name: ....) + + * If the first two non-whitespace tokens + are a custom property name and a colon, + it's definitely a custom property + and won't ever produce a valid rule, + so even if the custom property ends up invalid + there's no need to try and reparse as a rule. + + (That is, ''--foo:hover {...}'' is guaranteed to be a custom property, + not a rule.) + + * If the first three non-whitespace tokens + are a valid property name, a colon, and anything other than a <<{-token>>, + and then while parsing the declaration's value you encounter a <<{-token>>, + you can immediately stop parsing as a declaration + and reparse as a rule instead. + + (That is, ''font:bar {...'' is guaranteed to be an invalid property.) + + * If you see a recognized property name, a colon, and a {}-block, + but the first non-whitespace tokens following that block + isn't either immediately the final semicolon, + or the !important followed by the semicolon, + you can immediately stop parsing as a declaration + and reparse as a rule instead. + + (That is, ''font: {} bar ...'' is guaranteed to be an invalid property; + you don't need to keep parsing until you hit a semicolon.) + + Similarly, + even tho the parsing requirements are specified + to rely on checking the grammar of the declarations + as you parse, + a generic processor + trying to implement a non-CSS language + on top of the generic CSS syntax + can still get away with just verifying that declarations + start with an ident, a colon, + and then either contain solely a {}-block + or no {}-block at all. + They'll just spent a little more time on parsing + than an implementation with grammar knowledge + in cases like ''foo:hover ... {}'', + since they can't early-exit on the first token. +
+ +

Consume a declaration

@@ -2873,19 +2946,6 @@ Consume a declaration and with <> as the stop token, and set |decl|'s value to the result. - If |decl|'s name is a [=custom property name string=], - then set |decl|'s |original text| - to the segment of the original source text string - corresponding to the tokens - returned by the [=consume a list of component values=] call. - - If |decl|'s name is an [=ASCII case-insensitive=] match for "unicode-range", - [=consume the value of a unicode-range descriptor=] - from the segment of the original source text string - corresponding to the tokens - returned by the [=consume a list of component values=] call, - and replace |decl|'s value with the result. -
  • If the last two non-<>s in |decl|'s value are a <> with the value "!" @@ -2897,6 +2957,27 @@ Consume a declaration While the last item in |decl|'s value is a <>, [=list/remove=] that token. +
  • + If |decl|'s name is a [=custom property name string=], + then set |decl|'s |original text| + to the segment of the original source text string + corresponding to the tokens + of |decl|'s value. + + Otherwise, if |decl|'s value contains a top-level [=simple block=] + with an associated token of <<{-token>>, + and also contains any other non-<> value, + return nothing. + (That is, a top-level {}-block is only allowed + as the entire value of a non-custom property.) + + Otherwise, if |decl|'s name is an [=ASCII case-insensitive=] match for "unicode-range", + [=consume the value of a unicode-range descriptor=] + from the segment of the original source text string + corresponding to the tokens + returned by the [=consume a list of component values=] call, + and replace |decl|'s value with the result. +
  • If |decl| is valid in the current context, return it;