@@ -17,6 +17,11 @@ export struct Sst;
1717
1818export using Content = Vec<Sst>;
1919
20+ export enum struct Important {
21+ UNSET,
22+ YES,
23+ };
24+
2025#define FOREACH_SST (SST ) \
2126 SST (RULE) \
2227 SST (FUNC) \
@@ -40,13 +45,19 @@ export struct Sst {
4045 Token token = Token(Token::NIL);
4146 Opt<Box<Sst>> prefix{};
4247 Content content{};
48+ Important important = Important::UNSET;
4349
4450 Sst (Type type) : type(type) {}
4551
4652 Sst (Token token) : type(TOKEN), token(token) {}
4753
4854 Sst (Content content) : type(LIST), content(content) {}
4955
56+ // https://drafts.csswg.org/css-variables-2/#guaranteed-invalid
57+ static Sst guaranteedInvalid () {
58+ return Token::badString (" " );
59+ }
60+
5061 void repr (Io::Emit& e) const {
5162 if (type == TOKEN) {
5263 e (" {}" , token);
@@ -200,18 +211,48 @@ Sst consumeAtRule(Lexer& lex) {
200211 }
201212}
202213
203- export Content consumeDeclarationValue (Lexer& lex) {
214+ Important consumeImportant (Lexer& lex) {
215+ if (lex.peek () != Css::Token::delim (" !" ))
216+ return Important::UNSET;
217+ lex.next ();
218+
219+ auto copy = lex;
220+ eatWhitespace (copy);
221+ if (copy.next () != Css::Token::ident (" important" ))
222+ return Important::UNSET;
223+ lex = copy;
224+ return Important::YES;
225+ }
226+
227+ export bool endedDeclarationValue (Lexer& lex) {
228+ return lex.peek () == Token::END_OF_FILE or
229+ lex.peek () == Token::SEMICOLON or
230+ lex.peek () == Token::RIGHT_CURLY_BRACKET;
231+ }
232+
233+ export Tuple<Content, Important> consumeDeclarationValue (Lexer& lex) {
204234 Content value;
235+
205236 // 3. While the next input token is a <whitespace-token>, consume the next input token.
206237 eatWhitespace (lex);
207238
208239 // 4. As long as the next input token is anything other than an <EOF-token>,
209240 // consume a component value and append it to the declaration’s value.
210- while ((lex.peek () != Token::END_OF_FILE and lex.peek () != Token::SEMICOLON and lex.peek () != Token::RIGHT_CURLY_BRACKET)) {
211- value.pushBack (consumeComponentValue (lex));
212- eatWhitespace (lex);
241+ while (endedDeclarationValue (lex)) {
242+ // 5. If the last two non-<whitespace-token>s in the declaration’s
243+ // value are a <delim-token> with the value "!" followed by an
244+ // <ident-token> with a value that is an ASCII case-insensitive match
245+ // for "important", remove them from the declaration’s value
246+ // and set the declaration’s important flag to true.
247+ if (consumeImportant (lex) == Important::YES) {
248+ eatWhitespace (lex);
249+ return {std::move (value), Important::UNSET};
250+ } else {
251+ value.pushBack (consumeComponentValue (lex));
252+ eatWhitespace (lex);
253+ }
213254 }
214- return value;
255+ return { std::move ( value), Important::UNSET} ;
215256}
216257
217258// https://www.w3.org/TR/css-syntax-3/#consume-style-block
@@ -286,6 +327,7 @@ Content consumeDeclarationBlock(Lexer& lex) {
286327 return res;
287328}
288329
330+ // https://www.w3.org/TR/css-syntax-3/#consume-declaration
289331export Opt<Sst> consumeDeclaration (Lexer& lex) {
290332 Sst decl{Sst::DECL};
291333 decl.token = lex.next ();
@@ -303,7 +345,9 @@ export Opt<Sst> consumeDeclaration(Lexer& lex) {
303345 lex.next ();
304346
305347 // Parse the declaration’s value.
306- decl.content = consumeDeclarationValue (lex);
348+ auto [content, important] = consumeDeclarationValue (lex);
349+ decl.content = std::move (content);
350+ decl.important = important;
307351
308352 return decl;
309353}
0 commit comments