From 476578cdc612c0b25581d6988e882b512814f4a4 Mon Sep 17 00:00:00 2001 From: ConnorSkees <39542938+ConnorSkees@users.noreply.github.com> Date: Thu, 2 Apr 2020 21:44:26 -0400 Subject: [PATCH] fail on modifier with attrkind any --- src/selector/attribute.rs | 34 ++++++++++++++-------------------- src/utils.rs | 4 ++++ tests/selectors.rs | 5 +++++ 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/selector/attribute.rs b/src/selector/attribute.rs index 62f34b6..2bb6cc5 100644 --- a/src/selector/attribute.rs +++ b/src/selector/attribute.rs @@ -5,7 +5,7 @@ use std::string::ToString; use super::{Selector, SelectorKind}; use crate::error::SassResult; use crate::scope::Scope; -use crate::utils::{devour_whitespace, eat_ident, parse_interpolation, parse_quoted_string}; +use crate::utils::{devour_whitespace, eat_ident, parse_interpolation, parse_quoted_string, is_ident_char}; use crate::Token; #[derive(Clone, Debug, Eq, PartialEq)] @@ -23,12 +23,17 @@ impl Attribute { super_selector: &Selector, ) -> SassResult { devour_whitespace(toks); - let attr = match toks.next().ok_or("Expected identifier.")?.kind { - v @ 'a'..='z' | v @ 'A'..='Z' | v @ '-' | v @ '_' => { - format!("{}{}", v, eat_ident(toks, scope, super_selector)?) + let attr = match toks.peek().ok_or("Expected identifier.")?.kind { + c if is_ident_char(c) => { + eat_ident(toks, scope, super_selector)? } - '#' if toks.next().ok_or("Expected expression.")?.kind == '{' => { - parse_interpolation(toks, scope, super_selector)?.to_string() + '#' => { + toks.next(); + if toks.next().ok_or("Expected expression.")?.kind == '{' { + parse_interpolation(toks, scope, super_selector)?.to_string() + } else { + return Err("Expected expression.".into()); + } } q @ '"' | q @ '\'' => parse_quoted_string(toks, scope, q, super_selector)?.to_string(), _ => return Err("Expected identifier.".into()), @@ -37,18 +42,7 @@ impl Attribute { devour_whitespace(toks); let kind = match toks.next().ok_or("expected \"{\".")?.kind { - v @ 'a'..='z' | v @ 'A'..='Z' => { - match toks.next().ok_or("expected \"]\".")?.kind { - ']' => {} - _ => return Err("expected \"]\".".into()), - } - return Ok(SelectorKind::Attribute(Attribute { - kind: AttributeKind::Any, - attr, - value: String::new(), - modifier: Some(v), - })); - } + c if is_ident_char(c) => return Err("expected \"]\".".into()), ']' => { return Ok(SelectorKind::Attribute(Attribute { kind: AttributeKind::Any, @@ -63,7 +57,7 @@ impl Attribute { '^' => AttributeKind::Prefix, '$' => AttributeKind::Suffix, '*' => AttributeKind::Contains, - _ => return Err("Expected \"]\".".into()), + _ => return Err("expected \"]\".".into()), }; if kind != AttributeKind::Equals { @@ -101,7 +95,7 @@ impl Attribute { } Some(v) } - _ => return Err("Expected \"]\".".into()), + _ => return Err("expected \"]\".".into()), }; Ok(SelectorKind::Attribute(Attribute { diff --git a/src/utils.rs b/src/utils.rs index 1b38823..258d125 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -702,3 +702,7 @@ pub(crate) fn read_until_char>( } v } + +pub(crate) fn is_ident_char(c: char) -> bool { + c.is_ascii_alphabetic() || c == '_' || c == '\\' || (!c.is_ascii() && !c.is_control()) +} diff --git a/tests/selectors.rs b/tests/selectors.rs index 88bb482..a020cf0 100644 --- a/tests/selectors.rs +++ b/tests/selectors.rs @@ -318,3 +318,8 @@ test!( test!(escaped_space, "a\\ b {\n color: foo;\n}\n"); // blocked on whitespace // test!(multiple_consecutive_immediate_child,"> > foo {\n color: foo;\n}\n",); +error!( + modifier_on_any_attr, + "[attr i] {color: foo;}", + "Error: expected \"]\"." +); \ No newline at end of file