Skip to content

Commit

Permalink
refactor(css/parser): Refactor parser (#6395)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait committed Nov 11, 2022
1 parent c1588eb commit 983ab91
Show file tree
Hide file tree
Showing 62 changed files with 5,789 additions and 450 deletions.
6 changes: 3 additions & 3 deletions crates/swc_css_ast/src/base.rs
Expand Up @@ -49,14 +49,14 @@ pub enum QualifiedRulePrelude {
#[ast_node]
#[derive(Eq, Hash, Is, EqIgnoreSpan)]
pub enum StyleBlock {
#[tag("ListOfComponentValues")]
ListOfComponentValues(ListOfComponentValues),
#[tag("AtRule")]
AtRule(Box<AtRule>),
#[tag("Declaration")]
Declaration(Box<Declaration>),
#[tag("QualifiedRule")]
QualifiedRule(Box<QualifiedRule>),
#[tag("ListOfComponentValues")]
ListOfComponentValues(Box<ListOfComponentValues>),
}

#[ast_node("SimpleBlock")]
Expand Down Expand Up @@ -158,7 +158,7 @@ pub enum DeclarationOrAtRule {
AtRule(Box<AtRule>),
// For recovery mode
#[tag("ListOfComponentValues")]
ListOfComponentValues(ListOfComponentValues),
ListOfComponentValues(Box<ListOfComponentValues>),
}

#[ast_node("Declaration")]
Expand Down
114 changes: 59 additions & 55 deletions crates/swc_css_parser/src/parser/syntax/mod.rs
Expand Up @@ -362,10 +362,9 @@ where
// Otherwise, append a <semicolon-token> to the qualified rule’s prelude.
tok!(";") => {
if self.ctx.mixed_with_declarations {
return Err(Error::new(
span!(self, span.lo),
ErrorKind::EofButExpected("'{'"),
));
let span = self.input.cur_span();

return Err(Error::new(span, ErrorKind::Expected("'{'")));
} else {
let component_value = self.parse_as::<ComponentValue>()?;

Expand Down Expand Up @@ -505,19 +504,17 @@ where
temporary_list.children.push(component_value);
}

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

temporary_list.span = span!(self, span.lo);
temporary_list.span = span!(self, span.lo);

StyleBlock::ListOfComponentValues(temporary_list)
}
};
StyleBlock::ListOfComponentValues(Box::new(temporary_list))
}
};

declarations.push(decl_or_list_of_component_values);
}
Expand All @@ -528,6 +525,7 @@ where
let state = self.input.state();
let qualified_rule = self
.with_ctx(Ctx {
block_contents_grammar: BlockContentsGrammar::StyleBlock,
mixed_with_declarations: true,
..self.ctx
})
Expand All @@ -550,7 +548,6 @@ where
children: vec![],
};

// TODO verify error recovery (copied from prev spec)
while !is_one_of!(self, ";", EOF) {
let component_value = self.parse_as::<ComponentValue>()?;

Expand All @@ -559,8 +556,9 @@ where

list_of_component_values.span = span!(self, span.lo);

declarations
.push(StyleBlock::ListOfComponentValues(list_of_component_values));
declarations.push(StyleBlock::ListOfComponentValues(Box::new(
list_of_component_values,
)));
}
};
}
Expand Down Expand Up @@ -615,7 +613,14 @@ where
// Reconsume the current input token. Consume an at-rule. Append the returned rule
// to the list of declarations.
tok!("@") => {
declarations.push(DeclarationOrAtRule::AtRule(self.parse()?));
let at_rule = self
.with_ctx(Ctx {
block_contents_grammar: BlockContentsGrammar::DeclarationList,
..self.ctx
})
.parse_as::<AtRule>()?;

declarations.push(DeclarationOrAtRule::AtRule(Box::new(at_rule)));
}
// <ident-token>
// Initialize a temporary list initially filled with the current input token. As
Expand All @@ -625,9 +630,10 @@ where
// it to the list of declarations.
tok!("ident") => {
let span = self.input.cur_span();
let cur = self.input.bump().unwrap();
let mut temporary_list = ListOfComponentValues {
span: Default::default(),
children: vec![],
children: vec![ComponentValue::PreservedToken(cur)],
};

while !is_one_of!(self, ";", EOF) {
Expand All @@ -636,19 +642,17 @@ where
temporary_list.children.push(component_value);
}

let decl_or_list_of_component_values = match self
.parse_according_to_grammar::<Declaration>(&temporary_list, |parser| {
parser.parse_as()
}) {
Ok(decl) => DeclarationOrAtRule::Declaration(Box::new(decl)),
Err(err) => {
self.errors.push(err);
let decl_or_list_of_component_values =
match self.parse_declaration_from_temporary_list(&temporary_list) {
Ok(decl) => DeclarationOrAtRule::Declaration(Box::new(decl)),
Err(err) => {
self.errors.push(err);

temporary_list.span = span!(self, span.lo);
temporary_list.span = span!(self, span.lo);

DeclarationOrAtRule::ListOfComponentValues(temporary_list)
}
};
DeclarationOrAtRule::ListOfComponentValues(Box::new(temporary_list))
}
};

declarations.push(decl_or_list_of_component_values);
}
Expand All @@ -664,9 +668,7 @@ where

self.errors.push(Error::new(
span,
ErrorKind::Expected(
"whitespace, semicolon, EOF, at-keyword or ident token",
),
ErrorKind::Expected("whitespace, ';', '@', ident or EOF"),
));

// For recovery mode
Expand All @@ -683,9 +685,9 @@ where

list_of_component_values.span = span!(self, span.lo);

declarations.push(DeclarationOrAtRule::ListOfComponentValues(
declarations.push(DeclarationOrAtRule::ListOfComponentValues(Box::new(
list_of_component_values,
));
)));
}
}
}
Expand Down Expand Up @@ -718,7 +720,7 @@ where
let is_dashed_ident = match cur!(self) {
Token::Ident { value, .. } => value.starts_with("--"),
_ => {
return Err(Error::new(span, ErrorKind::Expected("Ident")));
return Err(Error::new(span, ErrorKind::Expected("ident")));
}
};
let name = if is_dashed_ident {
Expand Down Expand Up @@ -879,30 +881,31 @@ where
}

// Grammar parsing
let locv = self.create_locv(declaration.value);
let list_of_component_values = self.create_locv(declaration.value);

declaration.value = match self.parse_according_to_grammar(&locv, |parser| {
let mut values = vec![];
declaration.value =
match self.parse_according_to_grammar(&list_of_component_values, |parser| {
let mut values = vec![];

loop {
if is!(parser, EOF) {
break;
loop {
if is!(parser, EOF) {
break;
}

values.push(parser.parse_generic_value()?);
}

values.push(parser.parse_generic_value()?);
}
Ok(values)
}) {
Ok(values) => values,
Err(err) => {
if *err.kind() != ErrorKind::Ignore {
self.errors.push(err);
}

Ok(values)
}) {
Ok(values) => values,
Err(err) => {
if *err.kind() != ErrorKind::Ignore {
self.errors.push(err);
list_of_component_values.children
}

locv.children
}
};
};

// 8. Return the declaration.
Ok(declaration)
Expand Down Expand Up @@ -1098,6 +1101,7 @@ where

function.span = span!(self, span.lo);

// Grammar parsing
match self.ctx.block_contents_grammar {
BlockContentsGrammar::DeclarationList => {}
_ => {
Expand Down
9 changes: 9 additions & 0 deletions crates/swc_css_parser/src/parser/util.rs
Expand Up @@ -7,6 +7,7 @@ use super::{
input::{Input, InputType, ParserInput},
Ctx, Error, PResult, Parse, Parser,
};
use crate::parser::BlockContentsGrammar;

impl<I> Parser<I>
where
Expand Down Expand Up @@ -77,6 +78,7 @@ where
let state = self.input.state();
let qualified_rule = self
.with_ctx(Ctx {
block_contents_grammar: BlockContentsGrammar::StyleBlock,
mixed_with_declarations: true,
..self.ctx
})
Expand Down Expand Up @@ -114,6 +116,13 @@ where
Err(_) => None,
}
}

pub(super) fn parse_declaration_from_temporary_list(
&mut self,
temporary_list: &ListOfComponentValues,
) -> PResult<Declaration> {
self.parse_according_to_grammar::<Declaration>(temporary_list, |parser| parser.parse_as())
}
}

pub(super) struct WithCtx<'w, I: 'w + ParserInput> {
Expand Down
24 changes: 24 additions & 0 deletions crates/swc_css_parser/tests/fixture/style-block/input.css
Expand Up @@ -113,3 +113,27 @@ a/**/
}
;
}

a {
color: red;

.class {
color: green;
}

color: blue;
}

.foo {
color: red;

+ .bar {
color: blue;
}
}

article {
color: green;
& { color: blue; }
color: red;
}

1 comment on commit 983ab91

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 983ab91 Previous: ec2c021 Ratio
es/full/bugs-1 356255 ns/iter (± 24408) 334786 ns/iter (± 16748) 1.06
es/full/minify/libraries/antd 2003249507 ns/iter (± 211392434) 1824535495 ns/iter (± 35894667) 1.10
es/full/minify/libraries/d3 454571424 ns/iter (± 9989609) 408326702 ns/iter (± 26978303) 1.11
es/full/minify/libraries/echarts 1737998805 ns/iter (± 98652919) 1552193114 ns/iter (± 20086071) 1.12
es/full/minify/libraries/jquery 126268406 ns/iter (± 12250100) 99772654 ns/iter (± 1004242) 1.27
es/full/minify/libraries/lodash 145958685 ns/iter (± 24379533) 139744559 ns/iter (± 7001730) 1.04
es/full/minify/libraries/moment 68587180 ns/iter (± 3556299) 60782910 ns/iter (± 2667101) 1.13
es/full/minify/libraries/react 22890375 ns/iter (± 1376615) 20541130 ns/iter (± 831642) 1.11
es/full/minify/libraries/terser 389607601 ns/iter (± 29163082) 316565708 ns/iter (± 24688809) 1.23
es/full/minify/libraries/three 703295293 ns/iter (± 42922780) 575697083 ns/iter (± 27222102) 1.22
es/full/minify/libraries/typescript 4166372931 ns/iter (± 131962044) 3270780317 ns/iter (± 24562878) 1.27
es/full/minify/libraries/victory 1003754335 ns/iter (± 84374129) 798110882 ns/iter (± 15674171) 1.26
es/full/minify/libraries/vue 198735824 ns/iter (± 4721656) 151323074 ns/iter (± 5163757) 1.31
es/full/codegen/es3 44902 ns/iter (± 9074) 33110 ns/iter (± 2709) 1.36
es/full/codegen/es5 41655 ns/iter (± 7610) 33108 ns/iter (± 1105) 1.26
es/full/codegen/es2015 41805 ns/iter (± 7207) 32870 ns/iter (± 1052) 1.27
es/full/codegen/es2016 39963 ns/iter (± 6657) 33526 ns/iter (± 832) 1.19
es/full/codegen/es2017 37192 ns/iter (± 6196) 33418 ns/iter (± 604) 1.11
es/full/codegen/es2018 42498 ns/iter (± 6707) 33606 ns/iter (± 359) 1.26
es/full/codegen/es2019 42543 ns/iter (± 7398) 33648 ns/iter (± 703) 1.26
es/full/codegen/es2020 42383 ns/iter (± 6476) 33647 ns/iter (± 823) 1.26
es/full/all/es3 256975639 ns/iter (± 30629428) 189247676 ns/iter (± 5197430) 1.36
es/full/all/es5 211682658 ns/iter (± 31223245) 180338464 ns/iter (± 5069777) 1.17
es/full/all/es2015 164726057 ns/iter (± 12589875) 141966737 ns/iter (± 4502041) 1.16
es/full/all/es2016 195908805 ns/iter (± 23808681) 142717290 ns/iter (± 3849932) 1.37
es/full/all/es2017 177297202 ns/iter (± 17993106) 140641379 ns/iter (± 4392570) 1.26
es/full/all/es2018 165575616 ns/iter (± 24198719) 139091794 ns/iter (± 5812591) 1.19
es/full/all/es2019 160172709 ns/iter (± 13845862) 138970966 ns/iter (± 4446261) 1.15
es/full/all/es2020 157364425 ns/iter (± 17619799) 133953990 ns/iter (± 4780667) 1.17
es/full/parser 789448 ns/iter (± 110821) 694599 ns/iter (± 33529) 1.14
es/full/base/fixer 29180 ns/iter (± 3957) 26481 ns/iter (± 892) 1.10
es/full/base/resolver_and_hygiene 98298 ns/iter (± 14349) 90863 ns/iter (± 3283) 1.08
serialization of ast node 254 ns/iter (± 43) 213 ns/iter (± 5) 1.19
serialization of serde 243 ns/iter (± 41) 215 ns/iter (± 2) 1.13

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.