Lex attributes in a much more robust way :)
This commit is contained in:
parent
c7efbc7e05
commit
15edae53d6
62
src/lexer.rs
62
src/lexer.rs
@ -127,14 +127,17 @@ impl<'a> Lexer<'a> {
|
||||
TokenKind::Keyword(Keyword::Important)
|
||||
}
|
||||
|
||||
fn devour_whitespace(&mut self) {
|
||||
fn devour_whitespace(&mut self) -> bool {
|
||||
let mut found_whitespace = false;
|
||||
while let Some(c) = self.buf.peek() {
|
||||
if !is_whitespace(*c) {
|
||||
break;
|
||||
return found_whitespace;
|
||||
}
|
||||
found_whitespace = true;
|
||||
self.buf.next();
|
||||
self.pos.next_char();
|
||||
}
|
||||
found_whitespace
|
||||
}
|
||||
|
||||
fn lex_at_rule(&mut self) -> TokenKind {
|
||||
@ -300,21 +303,28 @@ impl<'a> Lexer<'a> {
|
||||
let mut case_sensitive = CaseKind::Sensitive;
|
||||
|
||||
while let Some(c) = self.buf.peek() {
|
||||
if c == &']' && !c.is_whitespace() {
|
||||
if c == &']' || c.is_whitespace() {
|
||||
break;
|
||||
}
|
||||
|
||||
if c == &'i' || c == &'I' {
|
||||
if c == &'i' {
|
||||
case_sensitive = CaseKind::InsensitiveLowercase;
|
||||
} else if c == &'I' {
|
||||
case_sensitive = CaseKind::InsensitiveCapital;
|
||||
}
|
||||
let tok = self
|
||||
.buf
|
||||
.next()
|
||||
.expect("this is impossible because we have already peeked");
|
||||
self.pos.next_char();
|
||||
value.push(tok);
|
||||
}
|
||||
|
||||
if self.devour_whitespace() {
|
||||
let n = self.buf.next();
|
||||
match n {
|
||||
Some('i') | Some('I') => {
|
||||
let case_sensitive = match n {
|
||||
Some('i') => CaseKind::InsensitiveLowercase,
|
||||
Some('I') => CaseKind::InsensitiveCapital,
|
||||
_ => unsafe { std::hint::unreachable_unchecked() },
|
||||
};
|
||||
self.pos.next_char();
|
||||
self.devour_whitespace();
|
||||
match self.buf.next() {
|
||||
Some(']') => {
|
||||
@ -325,27 +335,29 @@ impl<'a> Lexer<'a> {
|
||||
case_sensitive,
|
||||
})
|
||||
}
|
||||
Some(val) => {
|
||||
self.pos.next_char();
|
||||
value.push(tok);
|
||||
value.push(val);
|
||||
Some(_) => todo!("modifier must be 1 character"),
|
||||
None => todo!("unexpected EOF"),
|
||||
}
|
||||
None => todo!("expected something to come after "),
|
||||
}
|
||||
continue;
|
||||
Some(']') => {
|
||||
return TokenKind::Attribute(Attribute {
|
||||
kind,
|
||||
attr,
|
||||
value,
|
||||
case_sensitive,
|
||||
})
|
||||
}
|
||||
|
||||
let tok = self
|
||||
.buf
|
||||
.next()
|
||||
.expect("this is impossible because we have already peeked");
|
||||
self.pos.next_char();
|
||||
value.push(tok);
|
||||
}
|
||||
|
||||
Some(c) => {
|
||||
value.push(' ');
|
||||
value.push(c.clone());
|
||||
self.devour_whitespace();
|
||||
|
||||
assert!(self.buf.next() == Some(']'));
|
||||
}
|
||||
None => todo!(),
|
||||
}
|
||||
} else {
|
||||
assert!(self.buf.next() == Some(']'));
|
||||
}
|
||||
|
||||
TokenKind::Attribute(Attribute {
|
||||
kind,
|
||||
|
@ -348,8 +348,8 @@ pub(crate) enum CaseKind {
|
||||
impl Display for CaseKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::InsensitiveCapital => write!(f, "I"),
|
||||
Self::InsensitiveLowercase => write!(f, "i"),
|
||||
Self::InsensitiveCapital => write!(f, " I"),
|
||||
Self::InsensitiveLowercase => write!(f, " i"),
|
||||
Self::Sensitive => write!(f, ""),
|
||||
}
|
||||
}
|
||||
|
@ -143,10 +143,15 @@ mod test_selectors {
|
||||
selector_attribute_i_in_attr,
|
||||
"[atitr=val] {\n color: red;\n}\n"
|
||||
);
|
||||
// test!(
|
||||
// selector_attribute_i_in_val,
|
||||
// "[attr=vail] {\n color: red;\n}\n"
|
||||
// );
|
||||
test!(
|
||||
selector_attribute_i_in_val,
|
||||
"[attr=vail] {\n color: red;\n}\n"
|
||||
);
|
||||
test!(
|
||||
selector_attribute_whitespace,
|
||||
"[attr *= val ] {\n color: red;\n}\n",
|
||||
"[attr*=val] {\n color: red;\n}\n"
|
||||
);
|
||||
test!(
|
||||
selector_attribute_equals,
|
||||
"[attr=val] {\n color: red;\n}\n"
|
||||
|
Loading…
x
Reference in New Issue
Block a user