diff --git a/crates/swc_css_parser/src/parser/base.rs b/crates/swc_css_parser/src/parser/base.rs index 1ddaede0c55..04c2fdede43 100644 --- a/crates/swc_css_parser/src/parser/base.rs +++ b/crates/swc_css_parser/src/parser/base.rs @@ -122,6 +122,109 @@ where } } +impl Parse for Parser +where + I: ParserInput, +{ + fn parse(&mut self) -> PResult { + let span = self.input.cur_span()?; + let name = match cur!(self) { + tok!("{") => { + bump!(self); + + '{' + } + tok!("(") => { + bump!(self); + + '(' + } + tok!("[") => { + bump!(self); + + '[' + } + _ => { + unreachable!(); + } + }; + // Create a simple block with its associated token set to the current input + // token and with its value initially set to an empty list. + let mut simple_block = SimpleBlock { + span: Default::default(), + name, + value: vec![], + }; + + // TODO refactor me + self.input.skip_ws()?; + + // Repeatedly consume the next input token and process it as follows: + loop { + // + // This is a parse error. Return the block. + if is!(self, EOF) { + let span = self.input.cur_span()?; + + self.errors.push(Error::new(span, ErrorKind::Eof)); + + break; + } + + match cur!(self) { + // ending token + // Return the block. + tok!("]") if name == '[' => { + bump!(self); + + break; + } + tok!(")") if name == '(' => { + bump!(self); + + break; + } + tok!("}") if name == '{' => { + bump!(self); + + break; + } + // anything else + // Reconsume the current input token. Consume a component value and append it to the + // value of the block. + _ => { + let state = self.input.state(); + let ctx = Ctx { + // TODO refactor me + allow_operation_in_value: name == '(', + ..self.ctx + }; + let parsed = self.with_ctx(ctx).parse_one_value_inner(); + let value = match parsed { + Ok(value) => { + self.input.skip_ws()?; + + value + } + Err(err) => { + self.errors.push(err); + self.input.reset(&state); + + self.parse_component_value()? + } + }; + + simple_block.value.push(value); + } + } + } + + simple_block.span = span!(self, span.lo); + + Ok(simple_block) + } +} + impl Parse for Parser where I: ParserInput, diff --git a/crates/swc_css_parser/src/parser/value/mod.rs b/crates/swc_css_parser/src/parser/value/mod.rs index 7acc2059f1b..4f71a39c213 100644 --- a/crates/swc_css_parser/src/parser/value/mod.rs +++ b/crates/swc_css_parser/src/parser/value/mod.rs @@ -231,7 +231,7 @@ where }) } - fn parse_one_value_inner(&mut self) -> PResult { + pub(super) fn parse_one_value_inner(&mut self) -> PResult { // TODO remove me self.input.skip_ws()?; @@ -270,7 +270,14 @@ where tok!("percentage") | tok!("dimension") | tok!("num") => { let span = self.input.cur_span()?; - let base = self.parse_basical_numeric_value()?; + let base = match cur!(self) { + tok!("percentage") => Value::Percentage(self.parse()?), + tok!("dimension") => Value::Dimension(self.parse()?), + tok!("num") => Value::Number(self.parse()?), + _ => { + unreachable!() + } + }; return self.parse_numeric_value_with_base(span.lo, base); } @@ -287,27 +294,17 @@ where return Ok(Value::Ident(self.parse()?)); } - tok!("[") => return self.parse_square_brackets_value().map(From::from), + tok!("[") => return Ok(Value::SimpleBlock(self.parse()?)), - tok!("(") => return self.parse_round_brackets_value().map(From::from), + tok!("(") => return Ok(Value::SimpleBlock(self.parse()?)), - tok!("{") => { - return self.parse_brace_value().map(From::from); - } + tok!("{") => return Ok(Value::SimpleBlock(self.parse()?)), tok!("#") => return Ok(Value::Color(Color::HexColor(self.parse()?))), _ => {} } - if is_one_of!(self, "", "!", ";") { - let token = self.input.bump()?.unwrap(); - return Ok(Value::Tokens(Tokens { - span, - tokens: vec![token], - })); - } - Err(Error::new(span, ErrorKind::Expected("Declaration value"))) } @@ -352,105 +349,6 @@ where Ok(base) } - fn parse_brace_value(&mut self) -> PResult { - let span = self.input.cur_span()?; - - expect!(self, "{"); - - let brace_start = self.input.cur_span()?.lo; - let mut tokens = vec![]; - - let mut brace_cnt = 1; - loop { - if is!(self, "}") { - brace_cnt -= 1; - if brace_cnt == 0 { - break; - } - } - if is!(self, "{") { - brace_cnt += 1; - } - - let token = self.input.bump()?; - match token { - Some(token) => tokens.push(token), - None => break, - } - } - - let brace_span = span!(self, brace_start); - expect!(self, "}"); - - Ok(SimpleBlock { - span: span!(self, span.lo), - name: '{', - // TODO refactor me - value: vec![Value::Tokens(Tokens { - span: brace_span, - tokens, - })], - }) - } - - fn parse_basical_numeric_value(&mut self) -> PResult { - match cur!(self) { - tok!("percentage") => Ok(Value::Percentage(self.parse()?)), - tok!("dimension") => Ok(Value::Dimension(self.parse()?)), - tok!("num") => Ok(Value::Number(self.parse()?)), - _ => { - unreachable!() - } - } - } - - fn parse_square_brackets_value(&mut self) -> PResult { - let span = self.input.cur_span()?; - - expect!(self, "["); - - self.input.skip_ws()?; - - let value = self.parse_property_values()?.0; - - self.input.skip_ws()?; - - expect!(self, "]"); - - Ok(SimpleBlock { - span: span!(self, span.lo), - name: '[', - value, - }) - } - - fn parse_round_brackets_value(&mut self) -> PResult { - let span = self.input.cur_span()?; - - expect!(self, "("); - - self.input.skip_ws()?; - - let value = if is!(self, ")") { - vec![] - } else { - let ctx = Ctx { - allow_operation_in_value: true, - ..self.ctx - }; - - self.with_ctx(ctx).parse_property_values()?.0 - }; - - expect!(self, ")"); - - Ok(SimpleBlock { - span: span!(self, span.lo), - name: '(', - value, - }) - } - pub fn parse_simple_block(&mut self, ending: char) -> PResult { let start_pos = self.input.last_pos()? - BytePos(1); let mut simple_block = SimpleBlock { diff --git a/crates/swc_css_parser/tests/errors/rome/invalid/fit-content/invalid-call/output.stderr b/crates/swc_css_parser/tests/errors/rome/invalid/fit-content/invalid-call/output.stderr index 8cb6fe2c825..aa435a7544c 100644 --- a/crates/swc_css_parser/tests/errors/rome/invalid/fit-content/invalid-call/output.stderr +++ b/crates/swc_css_parser/tests/errors/rome/invalid/fit-content/invalid-call/output.stderr @@ -1,5 +1,11 @@ error: Expected "}" +error: Expected Declaration value + --> $DIR/tests/errors/rome/invalid/fit-content/invalid-call/input.css:2:45 + | +2 | grid-template-columns: fit-content("broken"; + | ^ + error: Expected Declaration value --> $DIR/tests/errors/rome/invalid/fit-content/invalid-call/input.css:3:1 | diff --git a/crates/swc_css_parser/tests/errors/rome/invalid/grid/repeat/unclosed-lint-name/output.stderr b/crates/swc_css_parser/tests/errors/rome/invalid/grid/repeat/unclosed-lint-name/output.stderr index 18ccafa8b0c..6d3d2c3627e 100644 --- a/crates/swc_css_parser/tests/errors/rome/invalid/grid/repeat/unclosed-lint-name/output.stderr +++ b/crates/swc_css_parser/tests/errors/rome/invalid/grid/repeat/unclosed-lint-name/output.stderr @@ -1,12 +1,28 @@ -error: Expected "]" +error: Expected "}" + +error: Expected Declaration value --> $DIR/tests/errors/rome/invalid/grid/repeat/unclosed-lint-name/input.css:2:45 | 2 | grid-template-columns: repeat(4, [col-start); | ^ +error: Expected Declaration value + --> $DIR/tests/errors/rome/invalid/grid/repeat/unclosed-lint-name/input.css:2:46 + | +2 | grid-template-columns: repeat(4, [col-start); + | ^ + +error: Expected Declaration value + --> $DIR/tests/errors/rome/invalid/grid/repeat/unclosed-lint-name/input.css:3:1 + | +3 | } + | ^ + error: Unexpected end of file --> $DIR/tests/errors/rome/invalid/grid/repeat/unclosed-lint-name/input.css:3:3 | 3 | } | ^ +error: Unexpected end of file + diff --git a/crates/swc_css_parser/tests/errors/rome/invalid/min-or-max/output.stderr b/crates/swc_css_parser/tests/errors/rome/invalid/min-or-max/output.stderr index d73080ea114..83a2f7916df 100644 --- a/crates/swc_css_parser/tests/errors/rome/invalid/min-or-max/output.stderr +++ b/crates/swc_css_parser/tests/errors/rome/invalid/min-or-max/output.stderr @@ -1,5 +1,11 @@ error: Expected "}" +error: Expected Declaration value + --> $DIR/tests/errors/rome/invalid/min-or-max/input.css:2:18 + | +2 | width: min(500px; + | ^ + error: Expected Declaration value --> $DIR/tests/errors/rome/invalid/min-or-max/input.css:3:1 | diff --git a/crates/swc_css_parser/tests/fixture/declaration/output.json b/crates/swc_css_parser/tests/fixture/declaration/output.json index c5e2bf67944..d90ee065628 100644 --- a/crates/swc_css_parser/tests/fixture/declaration/output.json +++ b/crates/swc_css_parser/tests/fixture/declaration/output.json @@ -179,27 +179,14 @@ "name": "{", "value": [ { - "type": "Tokens", + "type": "Ident", "span": { "start": 53, "end": 58, "ctxt": 0 }, - "tokens": [ - { - "span": { - "start": 53, - "end": 58, - "ctxt": 0 - }, - "token": { - "Ident": { - "value": "value", - "raw": "value" - } - } - } - ] + "value": "value", + "raw": "value" } ] } @@ -893,27 +880,14 @@ "name": "{", "value": [ { - "type": "Tokens", + "type": "Ident", "span": { "start": 364, "end": 369, "ctxt": 0 }, - "tokens": [ - { - "span": { - "start": 364, - "end": 369, - "ctxt": 0 - }, - "token": { - "Ident": { - "value": "value", - "raw": "value" - } - } - } - ] + "value": "value", + "raw": "value" } ] }, @@ -927,27 +901,14 @@ "name": "{", "value": [ { - "type": "Tokens", + "type": "Ident", "span": { "start": 371, "end": 376, "ctxt": 0 }, - "tokens": [ - { - "span": { - "start": 371, - "end": 376, - "ctxt": 0 - }, - "token": { - "Ident": { - "value": "value", - "raw": "value" - } - } - } - ] + "value": "value", + "raw": "value" } ] } diff --git a/crates/swc_css_parser/tests/fixture/declaration/span.rust-debug b/crates/swc_css_parser/tests/fixture/declaration/span.rust-debug index f762414219d..f0d38fb65bc 100644 --- a/crates/swc_css_parser/tests/fixture/declaration/span.rust-debug +++ b/crates/swc_css_parser/tests/fixture/declaration/span.rust-debug @@ -197,13 +197,7 @@ error: Value 4 | prop: {value}; | ^^^^^ -error: Tokens - --> $DIR/tests/fixture/declaration/input.css:4:12 - | -4 | prop: {value}; - | ^^^^^ - -error: Ident { value: Atom('value' type=inline), raw: Atom('value' type=inline) } +error: Ident --> $DIR/tests/fixture/declaration/input.css:4:12 | 4 | prop: {value}; @@ -911,13 +905,7 @@ error: Value 17 | prop: {value}{value}; | ^^^^^ -error: Tokens - --> $DIR/tests/fixture/declaration/input.css:17:12 - | -17 | prop: {value}{value}; - | ^^^^^ - -error: Ident { value: Atom('value' type=inline), raw: Atom('value' type=inline) } +error: Ident --> $DIR/tests/fixture/declaration/input.css:17:12 | 17 | prop: {value}{value}; @@ -941,13 +929,7 @@ error: Value 17 | prop: {value}{value}; | ^^^^^ -error: Tokens - --> $DIR/tests/fixture/declaration/input.css:17:19 - | -17 | prop: {value}{value}; - | ^^^^^ - -error: Ident { value: Atom('value' type=inline), raw: Atom('value' type=inline) } +error: Ident --> $DIR/tests/fixture/declaration/input.css:17:19 | 17 | prop: {value}{value}; diff --git a/crates/swc_css_parser/tests/recovery/function/output.json b/crates/swc_css_parser/tests/recovery/function/output.json index e196174748f..79dc7dad88f 100644 --- a/crates/swc_css_parser/tests/recovery/function/output.json +++ b/crates/swc_css_parser/tests/recovery/function/output.json @@ -525,39 +525,24 @@ }, "name": "{", "value": [ + { + "type": "Ident", + "span": { + "start": 166, + "end": 169, + "ctxt": 0 + }, + "value": "foo", + "raw": "foo" + }, { "type": "Tokens", "span": { - "start": 165, - "end": 175, + "start": 169, + "end": 170, "ctxt": 0 }, "tokens": [ - { - "span": { - "start": 165, - "end": 166, - "ctxt": 0 - }, - "token": { - "WhiteSpace": { - "value": " " - } - } - }, - { - "span": { - "start": 166, - "end": 169, - "ctxt": 0 - }, - "token": { - "Ident": { - "value": "foo", - "raw": "foo" - } - } - }, { "span": { "start": 169, @@ -565,45 +550,18 @@ "ctxt": 0 }, "token": "Colon" - }, - { - "span": { - "start": 170, - "end": 171, - "ctxt": 0 - }, - "token": { - "WhiteSpace": { - "value": " " - } - } - }, - { - "span": { - "start": 171, - "end": 174, - "ctxt": 0 - }, - "token": { - "Ident": { - "value": "bar", - "raw": "bar" - } - } - }, - { - "span": { - "start": 174, - "end": 175, - "ctxt": 0 - }, - "token": { - "WhiteSpace": { - "value": " " - } - } } ] + }, + { + "type": "Ident", + "span": { + "start": 171, + "end": 174, + "ctxt": 0 + }, + "value": "bar", + "raw": "bar" } ] } diff --git a/crates/swc_css_parser/tests/recovery/function/output.swc-stderr b/crates/swc_css_parser/tests/recovery/function/output.swc-stderr index 08f064f36b1..1975a113ca9 100644 --- a/crates/swc_css_parser/tests/recovery/function/output.swc-stderr +++ b/crates/swc_css_parser/tests/recovery/function/output.swc-stderr @@ -16,3 +16,9 @@ error: Expected Declaration value 4 | prop: func3( ident.ident ); | ^ +error: Expected Declaration value + --> $DIR/tests/recovery/function/input.css:7:21 + | +7 | prop: func({ foo: bar }); + | ^ +