diff --git a/src/args.rs b/src/args.rs index c02ddae..8a86a1c 100644 --- a/src/args.rs +++ b/src/args.rs @@ -335,7 +335,7 @@ pub(crate) fn eat_call_args>( match toks.peek().unwrap().kind { '$' => { let Token { pos, .. } = toks.next().unwrap(); - let v = eat_ident_no_interpolation(toks, false)?; + let v = eat_ident_no_interpolation(toks, false, pos)?; let whitespace = devour_whitespace_or_comment(toks)?; if toks.peek().unwrap().kind == ':' { toks.next(); diff --git a/src/selector/mod.rs b/src/selector/mod.rs index 65c7443..9417824 100644 --- a/src/selector/mod.rs +++ b/src/selector/mod.rs @@ -290,10 +290,11 @@ impl Selector { let mut iter = sel_toks.into_iter().peekmore(); while let Some(tok) = iter.peek() { - inner.push(match tok.kind { - _ if is_selector_name_char(tok.kind) => { + let Token { kind, pos } = *tok; + inner.push(match kind { + _ if is_selector_name_char(kind) => { inner.push(SelectorKind::Element( - eat_ident_no_interpolation(&mut iter, false)?.node, + eat_ident_no_interpolation(&mut iter, false, pos)?.node, )); continue; } @@ -304,14 +305,14 @@ impl Selector { '.' => { iter.next(); inner.push(SelectorKind::Class( - eat_ident_no_interpolation(&mut iter, false)?.node, + eat_ident_no_interpolation(&mut iter, false, pos)?.node, )); continue; } '#' => { iter.next(); inner.push(SelectorKind::Id( - eat_ident_no_interpolation(&mut iter, false)?.node, + eat_ident_no_interpolation(&mut iter, false, pos)?.node, )); continue; } @@ -319,7 +320,7 @@ impl Selector { iter.next(); is_invisible = true; inner.push(SelectorKind::Placeholder( - eat_ident_no_interpolation(&mut iter, false)?.node, + eat_ident_no_interpolation(&mut iter, false, pos)?.node, )); continue; } @@ -405,8 +406,13 @@ impl Selector { } else { false }; - if is_selector_name_char(toks.peek().unwrap().kind) { - let name = eat_ident_no_interpolation(toks, false)?.node; + let t = if let Some(tok) = toks.peek() { + *tok + } else { + todo!() + }; + if is_selector_name_char(t.kind) { + let name = eat_ident_no_interpolation(toks, false, t.pos)?.node; Ok( if toks.peek().is_some() && toks.peek().unwrap().kind == '(' { toks.next(); @@ -425,7 +431,7 @@ impl Selector { }, ) } else { - todo!() + return Err(("Expected identifier.", t.pos).into()); } } diff --git a/src/utils/strings.rs b/src/utils/strings.rs index 2fc43a6..8a55284 100644 --- a/src/utils/strings.rs +++ b/src/utils/strings.rs @@ -232,8 +232,12 @@ pub(crate) fn eat_ident>( pub(crate) fn eat_ident_no_interpolation>( toks: &mut PeekMoreIterator, unit: bool, + span_before: Span, ) -> SassResult> { - let mut span = toks.peek().unwrap().pos(); + let mut span = toks + .peek() + .ok_or(("Expected identifier.", span_before))? + .pos(); let mut text = String::new(); if toks.peek().unwrap().kind == '-' { toks.next(); diff --git a/src/value/parse.rs b/src/value/parse.rs index a8b4957..53e54b1 100644 --- a/src/value/parse.rs +++ b/src/value/parse.rs @@ -679,9 +679,10 @@ impl Value { Err(e) => return Some(Err(e)), }; let unit = if let Some(tok) = toks.peek() { - match tok.kind { + let Token { kind, pos } = *tok; + match kind { 'a'..='z' | 'A'..='Z' | '_' | '\\' => { - let u = match eat_ident_no_interpolation(toks, true) { + let u = match eat_ident_no_interpolation(toks, true, pos) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -804,7 +805,7 @@ impl Value { } '$' => { toks.next(); - let val = match eat_ident_no_interpolation(toks, false) { + let val = match eat_ident_no_interpolation(toks, false, span) { Ok(v) => v, Err(e) => return Some(Err(e)), }; diff --git a/tests/if.rs b/tests/if.rs index ee5c85b..e0d3c87 100644 --- a/tests/if.rs +++ b/tests/if.rs @@ -109,6 +109,10 @@ test!( "a {\n color: red;\n}\n" ); error!(nothing_after_if, "@if", "Error: Expected expression."); +error!( + nothing_after_dollar, + "@if ${}", "Error: Expected identifier." +); error!(no_condition, "@if{}", "Error: Expected expression."); error!( nothing_after_open_curly, diff --git a/tests/selectors.rs b/tests/selectors.rs index 606827c..31efb7f 100644 --- a/tests/selectors.rs +++ b/tests/selectors.rs @@ -541,3 +541,11 @@ test!( "|f {\n color: &;\n}\n", "|f {\n color: |f;\n}\n" ); +error!(nothing_after_period, ". {}", "Error: Expected identifier."); +error!(nothing_after_hash, "# {}", "Error: Expected identifier."); +error!(nothing_after_percent, "% {}", "Error: Expected identifier."); +error!(nothing_after_colon, ": {}", "Error: Expected identifier."); +error!( + non_ident_after_colon, + ":#ab {}", "Error: Expected identifier." +);