Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(css/parser): fix declaration parsing #6234

Merged
merged 1 commit into from Oct 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -45,8 +45,7 @@ div {
background: url('\"foo\"');
}
.bar {
background: url(http://example.com/image.svg param(--color var(--primary-color);
));}
background: url(http://example.com/image.svg param(--color var(--primary-color)));}
.baz {
background: url("http://example.com/image.svg" param(--color var(--primary-color)));
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/swc_css_parser/src/error.rs
Expand Up @@ -42,6 +42,7 @@ impl Error {
ErrorKind::Ignore => "Not an error".into(),
ErrorKind::UnexpectedChar(c) => format!("Unexpected character `{:?}`", c).into(),
ErrorKind::Expected(s) => format!("Expected {}", s).into(),
ErrorKind::Unexpected(s) => format!("Unexpected {}", s).into(),
ErrorKind::ExpectedButGot(s) => format!("Expected {}", s).into(),
ErrorKind::ExpectedSelectorText => "Expected a text for selector".into(),
ErrorKind::UnterminatedBlockComment => "Unterminated block comment".into(),
Expand Down Expand Up @@ -91,6 +92,7 @@ pub enum ErrorKind {
Ignore,
UnexpectedChar(char),
Expected(&'static str),
Unexpected(&'static str),
ExpectedButGot(&'static str),
ExpectedSelectorText,
UnterminatedBlockComment,
Expand Down
111 changes: 71 additions & 40 deletions crates/swc_css_parser/src/parser/syntax/mod.rs
@@ -1,4 +1,4 @@
use swc_common::Span;
use swc_common::{Span, Spanned};
use swc_css_ast::*;

use super::{input::ParserInput, PResult, Parser};
Expand Down Expand Up @@ -252,19 +252,33 @@ where
// <semicolon-token>
// Do nothing.
tok!(";") => {
bump!(self);
let token_and_span = self.input.bump().unwrap();

// For recovery mode
// TODO revisit it after refactor parser
if let Some(StyleBlock::ListOfComponentValues(list_of_component_values)) =
declarations.last_mut()
{
list_of_component_values.span = Span::new(
list_of_component_values.span_lo(),
token_and_span.span_hi(),
Default::default(),
);
list_of_component_values
.children
.push(ComponentValue::PreservedToken(token_and_span));
}
}
// <at-keyword-token>
// Reconsume the current input token. Consume an at-rule, and append the result to
// rules.
tok!("@") => {
let ctx = Ctx {
block_contents_grammar: BlockContentsGrammar::StyleBlock,
..self.ctx
};

rules.push(StyleBlock::AtRule(Box::new(
self.with_ctx(ctx).parse_as::<AtRule>()?,
self.with_ctx(Ctx {
block_contents_grammar: BlockContentsGrammar::StyleBlock,
..self.ctx
})
.parse_as::<AtRule>()?,
)));
}
// <ident-token>
Expand All @@ -276,11 +290,12 @@ where
tok!("ident") => {
if self.config.legacy_nesting {
let state = self.input.state();
let ctx = Ctx {
is_trying_legacy_nesting: true,
..self.ctx
};
let legacy_nested = self.with_ctx(ctx).parse_as::<QualifiedRule>();
let legacy_nested = self
.with_ctx(Ctx {
is_trying_legacy_nesting: true,
..self.ctx
})
.parse_as::<QualifiedRule>();

match legacy_nested {
Ok(legacy_nested) => {
Expand All @@ -294,39 +309,36 @@ where
};
}

let state = self.input.state();
let prop = match self.parse() {
Ok(v) => StyleBlock::Declaration(v),
Err(err) => {
self.errors.push(err);
self.input.reset(&state);
let span = self.input.cur_span();
let mut temporary_list = ListOfComponentValues {
span: Default::default(),
children: vec![],
};

let span = self.input.cur_span();
let mut children = vec![];
while !is_one_of!(self, ";", EOF) {
let ctx = Ctx {
block_contents_grammar: BlockContentsGrammar::NoGrammar,
..self.ctx
};

while !is_one_of!(self, EOF) {
if let Some(token_and_span) = self.input.bump() {
children.push(ComponentValue::PreservedToken(token_and_span));
}
let component_value = self.with_ctx(ctx).parse_as::<ComponentValue>()?;

if is!(self, ";") {
if let Some(token_and_span) = self.input.bump() {
children
.push(ComponentValue::PreservedToken(token_and_span));
}
temporary_list.children.push(component_value);
}

break;
}
}
let decl_or_list_of_component_values =
match self.parse_according_to_grammar::<Declaration>(&temporary_list) {
Ok(decl) => StyleBlock::Declaration(Box::new(decl)),
Err(err) => {
self.errors.push(err);

StyleBlock::ListOfComponentValues(ListOfComponentValues {
span: span!(self, span.lo),
children,
})
}
};
temporary_list.span = span!(self, span.lo);

declarations.push(prop);
StyleBlock::ListOfComponentValues(temporary_list)
}
};

declarations.push(decl_or_list_of_component_values);
}

// <delim-token> with a value of "&" (U+0026 AMPERSAND)
Expand Down Expand Up @@ -881,6 +893,25 @@ where
}
}
}

match value.last() {
Some(ComponentValue::PreservedToken(TokenAndSpan {
span,
token: Token::BadUrl { .. },
..
}))
| Some(ComponentValue::PreservedToken(TokenAndSpan {
span,
token: Token::BadString { .. },
..
})) => {
return Err(Error::new(
*span,
ErrorKind::Unexpected("token in <declaration-value>"),
));
}
_ => {}
};
}

// 5. If the last two non-<whitespace-token>s in the declaration’s value are a
Expand Down
4 changes: 1 addition & 3 deletions crates/swc_css_parser/src/parser/values_and_units/mod.rs
Expand Up @@ -25,9 +25,7 @@ where

match cur!(self) {
// ... <bad-string-token>, <bad-url-token>,
tok!("bad-string") | tok!("bad-url") => {
break;
}
tok!("bad-string") | tok!("bad-url") => break,

// ... unmatched <)-token>, <]-token>, or <}-token>,
tok!(")") | tok!("]") | tok!("}") => {
Expand Down
4 changes: 2 additions & 2 deletions crates/swc_css_parser/tests/fixture/csstree/1/output.json
Expand Up @@ -3626,7 +3626,7 @@
"type": "Declaration",
"span": {
"start": 1285,
"end": 1299,
"end": 1298,
"ctxt": 0
},
"name": {
Expand All @@ -3646,7 +3646,7 @@
"type": "Declaration",
"span": {
"start": 1304,
"end": 1315,
"end": 1314,
"ctxt": 0
},
"name": {
Expand Down
12 changes: 6 additions & 6 deletions crates/swc_css_parser/tests/fixture/csstree/1/span.rust-debug
Expand Up @@ -3686,19 +3686,19 @@
x ComponentValue
,-[$DIR/tests/fixture/csstree/1/input.css:52:5]
52 | --empty-var: ;
: ^^^^^^^^^^^^^^
: ^^^^^^^^^^^^^
`----

x StyleBlock
,-[$DIR/tests/fixture/csstree/1/input.css:52:5]
52 | --empty-var: ;
: ^^^^^^^^^^^^^^
: ^^^^^^^^^^^^^
`----

x Declaration
,-[$DIR/tests/fixture/csstree/1/input.css:52:5]
52 | --empty-var: ;
: ^^^^^^^^^^^^^^
: ^^^^^^^^^^^^^
`----

x DeclarationName
Expand All @@ -3716,19 +3716,19 @@
x ComponentValue
,-[$DIR/tests/fixture/csstree/1/input.css:53:5]
53 | --bad-var:;
: ^^^^^^^^^^^
: ^^^^^^^^^^
`----

x StyleBlock
,-[$DIR/tests/fixture/csstree/1/input.css:53:5]
53 | --bad-var:;
: ^^^^^^^^^^^
: ^^^^^^^^^^
`----

x Declaration
,-[$DIR/tests/fixture/csstree/1/input.css:53:5]
53 | --bad-var:;
: ^^^^^^^^^^^
: ^^^^^^^^^^
`----

x DeclarationName
Expand Down
Expand Up @@ -430,7 +430,7 @@
"type": "Declaration",
"span": {
"start": 206,
"end": 216,
"end": 215,
"ctxt": 0
},
"name": {
Expand All @@ -450,7 +450,7 @@
"type": "Declaration",
"span": {
"start": 221,
"end": 236,
"end": 231,
"ctxt": 0
},
"name": {
Expand Down Expand Up @@ -544,7 +544,7 @@
"type": "Declaration",
"span": {
"start": 297,
"end": 322,
"end": 314,
"ctxt": 0
},
"name": {
Expand Down
Expand Up @@ -658,19 +658,19 @@
x ComponentValue
,-[$DIR/tests/fixture/value/custom-property/input.css:10:5]
10 | --empty: ;
: ^^^^^^^^^^
: ^^^^^^^^^
`----

x StyleBlock
,-[$DIR/tests/fixture/value/custom-property/input.css:10:5]
10 | --empty: ;
: ^^^^^^^^^^
: ^^^^^^^^^
`----

x Declaration
,-[$DIR/tests/fixture/value/custom-property/input.css:10:5]
10 | --empty: ;
: ^^^^^^^^^^
: ^^^^^^^^^
`----

x DeclarationName
Expand All @@ -688,19 +688,19 @@
x ComponentValue
,-[$DIR/tests/fixture/value/custom-property/input.css:11:5]
11 | --empty2: /**/;
: ^^^^^^^^^^^^^^^
: ^^^^^^^^^^
`----

x StyleBlock
,-[$DIR/tests/fixture/value/custom-property/input.css:11:5]
11 | --empty2: /**/;
: ^^^^^^^^^^^^^^^
: ^^^^^^^^^^
`----

x Declaration
,-[$DIR/tests/fixture/value/custom-property/input.css:11:5]
11 | --empty2: /**/;
: ^^^^^^^^^^^^^^^
: ^^^^^^^^^^
`----

x DeclarationName
Expand Down Expand Up @@ -802,19 +802,19 @@
x ComponentValue
,-[$DIR/tests/fixture/value/custom-property/input.css:14:5]
14 | --empty5:/* 1 */ /* 2 */;
: ^^^^^^^^^^^^^^^^^^^^^^^^^
: ^^^^^^^^^^^^^^^^^
`----

x StyleBlock
,-[$DIR/tests/fixture/value/custom-property/input.css:14:5]
14 | --empty5:/* 1 */ /* 2 */;
: ^^^^^^^^^^^^^^^^^^^^^^^^^
: ^^^^^^^^^^^^^^^^^
`----

x Declaration
,-[$DIR/tests/fixture/value/custom-property/input.css:14:5]
14 | --empty5:/* 1 */ /* 2 */;
: ^^^^^^^^^^^^^^^^^^^^^^^^^
: ^^^^^^^^^^^^^^^^^
`----

x DeclarationName
Expand Down