Skip to content

Commit

Permalink
feat(css_parser): CSS Parser charset #268 (#950)
Browse files Browse the repository at this point in the history
  • Loading branch information
denbezrukov authored Nov 29, 2023
1 parent 3556aa7 commit 5999c74
Show file tree
Hide file tree
Showing 23 changed files with 2,953 additions and 2,039 deletions.
507 changes: 268 additions & 239 deletions crates/biome_css_factory/src/generated/node_factory.rs

Large diffs are not rendered by default.

562 changes: 304 additions & 258 deletions crates/biome_css_factory/src/generated/syntax_factory.rs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions crates/biome_css_parser/src/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ impl<'src> CssLexer<'src> {
CRT => self.consume_ctr(),
COL => self.consume_col(),
AT_ => self.consume_byte(T![@]),
SEM => self.consume_byte(T![;]),
HAS => self.consume_byte(T![#]),
PNO => self.consume_byte(T!['(']),
PNC => self.consume_byte(T![')']),
Expand Down Expand Up @@ -764,6 +765,7 @@ impl<'src> CssLexer<'src> {
b"nth-last-col" => NTHLASTCOL_KW,
b"ltr" => LTR_KW,
b"rtl" => RTL_KW,
b"charset" => CHARSET_KW,
_ => IDENT,
}
}
Expand Down
70 changes: 70 additions & 0 deletions crates/biome_css_parser/src/syntax/at_rule/charset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use crate::parser::CssParser;
use crate::syntax::parse_error::expected_string;
use crate::syntax::parse_string;
use biome_css_syntax::CssSyntaxKind::*;
use biome_css_syntax::{CssSyntaxKind, TextRange, T};
use biome_parser::parse_recovery::ParseRecovery;
use biome_parser::parsed_syntax::ParsedSyntax::Present;
use biome_parser::prelude::ParsedSyntax::Absent;
use biome_parser::prelude::*;
use biome_rowan::SyntaxKind;

#[inline]
pub(crate) fn is_at_charset_rule(p: &mut CssParser) -> bool {
p.at(T![charset])
}

#[inline]
pub(crate) fn parse_at_charset_rule(p: &mut CssParser) -> ParsedSyntax {
if !is_at_charset_rule(p) {
return Absent;
}

let m = p.start();

p.bump(T![charset]);

let kind = match parse_string(p).or_recover(
p,
&ParseRecovery::new(CSS_BOGUS, CHARTSET_RECOVERY_SET).enable_recovery_on_line_break(),
expected_string,
) {
Ok(encoding) if !encoding.kind(p).is_bogus() => {
if eat_or_recover_close_token(p, encoding) {
CSS_CHARSET_AT_RULE
} else {
CSS_BOGUS_AT_RULE
}
}
_ => {
p.expect(T![;]);
CSS_BOGUS_AT_RULE
}
};

Present(m.complete(p, kind))
}

const CHARTSET_RECOVERY_SET: TokenSet<CssSyntaxKind> = token_set![T![;]];

#[inline]
fn eat_or_recover_close_token(p: &mut CssParser, encoding: CompletedMarker) -> bool {
if p.eat(T![;]) {
true
} else {
if let Ok(m) = ParseRecovery::new(CSS_BOGUS, CHARTSET_RECOVERY_SET)
.enable_recovery_on_line_break()
.recover(p)
{
let diagnostic = expected_string(
p,
TextRange::new(encoding.range(p).start(), m.range(p).end()),
);
p.error(diagnostic);
}

p.expect(T![;]);

false
}
}
45 changes: 45 additions & 0 deletions crates/biome_css_parser/src/syntax/at_rule/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
mod charset;

use crate::parser::CssParser;
use crate::syntax::at_rule::charset::{is_at_charset_rule, parse_at_charset_rule};
use crate::syntax::parse_error::expected_any_at_rule;
use biome_css_syntax::CssSyntaxKind::*;
use biome_css_syntax::T;
use biome_parser::prelude::ParsedSyntax::{Absent, Present};
use biome_parser::prelude::*;

#[inline]
pub(crate) fn at_at_rule(p: &mut CssParser) -> bool {
p.at(T![@])
}

#[inline]
pub(crate) fn parse_at_rule(p: &mut CssParser) -> ParsedSyntax {
if !at_at_rule(p) {
return Absent;
}

let m = p.start();

p.bump(T![@]);

let kind = if parse_any_at_rule(p)
.or_add_diagnostic(p, expected_any_at_rule)
.is_some()
{
CSS_AT_RULE
} else {
CSS_BOGUS_RULE
};

Present(m.complete(p, kind))
}

#[inline]
pub(crate) fn parse_any_at_rule(p: &mut CssParser) -> ParsedSyntax {
if is_at_charset_rule(p) {
parse_at_charset_rule(p)
} else {
Absent
}
}
10 changes: 8 additions & 2 deletions crates/biome_css_parser/src/syntax/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
mod at_rule;
mod parse_error;
mod selector;

use crate::lexer::CssLexContext;
use crate::parser::CssParser;
use crate::syntax::at_rule::{at_at_rule, parse_at_rule};
use crate::syntax::parse_error::expected_block;
use crate::syntax::selector::CssSelectorList;
use biome_css_syntax::CssSyntaxKind::*;
Expand Down Expand Up @@ -36,7 +38,11 @@ pub(crate) fn parse_rule_list(p: &mut CssParser) {
while !p.at(EOF) {
progress.assert_progressing(p);

parse_rule(p);
if at_at_rule(p) {
parse_at_rule(p).ok();
} else {
parse_rule(p);
}
}

rules.complete(p, CSS_RULE_LIST);
Expand Down Expand Up @@ -120,7 +126,7 @@ pub(crate) fn parse_number(p: &mut CssParser, context: CssLexContext) -> ParsedS
}

#[inline]
pub(crate) fn parse_css_string(p: &mut CssParser) -> ParsedSyntax {
pub(crate) fn parse_string(p: &mut CssParser) -> ParsedSyntax {
if !p.at(CSS_STRING_LITERAL) {
return Absent;
}
Expand Down
31 changes: 31 additions & 0 deletions crates/biome_css_parser/src/syntax/parse_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ pub(crate) fn expected_number(p: &CssParser, range: TextRange) -> ParseDiagnosti
expected_node("number", range, p)
}

pub(crate) fn expected_string(p: &CssParser, range: TextRange) -> ParseDiagnostic {
expected_node("string", range, p)
}

pub(crate) fn expected_any_pseudo_class_nth(p: &CssParser, range: TextRange) -> ParseDiagnostic {
expected_any(&["even", "odd", "n", "<An+B>", "number"], range, p)
}
Expand Down Expand Up @@ -130,6 +134,33 @@ pub(crate) fn expected_any_pseudo_class(p: &CssParser, range: TextRange) -> Pars
.into_diagnostic(p)
}

pub(crate) fn expected_any_at_rule(p: &CssParser, range: TextRange) -> ParseDiagnostic {
expect_one_of(
&[
"charset",
"color-profile",
"container",
"counter-style",
"document",
"font-face",
"font-feature-values",
"font-palette-values",
"import",
"keyframes",
"layer",
"media",
"namespace",
"page",
"property",
"supports",
"viewport",
"scope",
],
range,
)
.into_diagnostic(p)
}

pub(crate) fn expected_block(p: &CssParser, range: TextRange) -> ParseDiagnostic {
expected_node("body", range, p)
}
4 changes: 2 additions & 2 deletions crates/biome_css_parser/src/syntax/selector/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::syntax::parse_error::{
expected_any_attribute_matcher_name, expected_any_attribute_modifier, expected_identifier,
};
use crate::syntax::selector::{is_at_namespace, parse_namespace, selector_lex_context};
use crate::syntax::{is_at_identifier, parse_css_string, parse_regular_identifier};
use crate::syntax::{is_at_identifier, parse_regular_identifier, parse_string};
use biome_css_syntax::CssSyntaxKind::*;
use biome_css_syntax::{CssSyntaxKind, T};
use biome_parser::diagnostic::expected_token;
Expand Down Expand Up @@ -103,7 +103,7 @@ fn parse_attribute_matcher_value(p: &mut CssParser) -> ParsedSyntax {
let m = p.start();

if p.at(CSS_STRING_LITERAL) {
parse_css_string(p).ok();
parse_string(p).ok();
} else {
parse_regular_identifier(p).ok();
}
Expand Down
6 changes: 5 additions & 1 deletion crates/biome_css_parser/src/syntax/selector/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,10 @@ where
if p.eat_with_context(T![')'], context) {
true
} else {
if let Ok(m) = ParseRecovery::new(CSS_BOGUS, SELECTOR_FUNCTION_RECOVERY_SET).recover(p) {
if let Ok(m) = ParseRecovery::new(CSS_BOGUS, SELECTOR_FUNCTION_RECOVERY_SET)
.enable_recovery_on_line_break()
.recover(p)
{
let diagnostic = error_builder(
p,
TextRange::new(parameter.range(p).start(), m.range(p).end()),
Expand All @@ -362,6 +365,7 @@ where
let start = p.cur_range().start();

let range = ParseRecovery::new(CSS_BOGUS, SELECTOR_FUNCTION_RECOVERY_SET)
.enable_recovery_on_line_break()
.recover(p)
.map(|m| m.range(p))
.unwrap_or_else(|_| p.cur_range());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::parser::CssParser;
use crate::syntax::parse_error::expected_identifier;
use crate::syntax::selector::eat_or_recover_selector_function_close_token;
use crate::syntax::{is_at_identifier, parse_css_string, parse_regular_identifier};
use crate::syntax::{is_at_identifier, parse_regular_identifier, parse_string};
use biome_css_syntax::CssSyntaxKind::*;
use biome_css_syntax::{CssSyntaxKind, T};
use biome_parser::parse_lists::ParseSeparatedList;
Expand Down Expand Up @@ -89,7 +89,7 @@ fn parse_pseudo_value(p: &mut CssParser) -> ParsedSyntax {
}

if p.at(CSS_STRING_LITERAL) {
parse_css_string(p)
parse_string(p)
} else {
parse_regular_identifier(p)
}
Expand Down
10 changes: 7 additions & 3 deletions crates/biome_css_parser/src/syntax/selector/pseudo_class/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,13 @@ pub(crate) fn parse_pseudo_class_selector(p: &mut CssParser) -> ParsedSyntax {

p.bump(T![:]);

let kind = match parse_pseudo_class(p).or_add_diagnostic(p, expected_any_pseudo_class) {
Some(_) => CSS_PSEUDO_CLASS_SELECTOR,
None => CSS_BOGUS_SUB_SELECTOR,
let kind = if parse_pseudo_class(p)
.or_add_diagnostic(p, expected_any_pseudo_class)
.is_some()
{
CSS_PSEUDO_CLASS_SELECTOR
} else {
CSS_BOGUS_SUB_SELECTOR
};

Present(m.complete(p, kind))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@charset dsadsa;
@charset ;
@charset "iso-8859-15"
@charset "UTF-8" 12321321;
@charset "UTF-8" 12321321
@charset

Loading

0 comments on commit 5999c74

Please sign in to comment.