diff --git a/src/parse/mod.rs b/src/parse/mod.rs index c8793bb..81a3422 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -364,6 +364,12 @@ impl<'a> Parser<'a> { found_curly = true; break; } + '\\' => { + string.push('\\'); + if let Some(Token { kind, .. }) = self.toks.next() { + string.push(kind); + } + } '!' => { if peek_ident_no_interpolation(self.toks, false, self.span_before)?.node == "optional" diff --git a/src/utils/peek_until.rs b/src/utils/peek_until.rs index e81ffa3..69de6dc 100644 --- a/src/utils/peek_until.rs +++ b/src/utils/peek_until.rs @@ -133,7 +133,8 @@ pub(crate) fn peek_escape(toks: &mut PeekMoreIterator>) -> SassR toks.peek_forward(1); } } else { - value = toks.peek_forward(1).unwrap().kind as u32; + value = first.kind as u32; + toks.advance_cursor(); } let c = std::char::from_u32(value).ok_or(("Invalid escape sequence.", span))?; diff --git a/tests/error.rs b/tests/error.rs index 7b9a359..ffa3fc1 100644 --- a/tests/error.rs +++ b/tests/error.rs @@ -245,3 +245,4 @@ error!( "a {foo: {bar: red", "Error: Expected identifier." ); error!(toplevel_nullbyte, "\u{0}", "Error: expected selector."); +error!(double_escaped_bang_at_toplevel, "\\!\\!", "Error: expected \"{\"."); diff --git a/tests/selectors.rs b/tests/selectors.rs index 7b415fd..64fb23d 100644 --- a/tests/selectors.rs +++ b/tests/selectors.rs @@ -350,6 +350,11 @@ test!( "ul li#foo {\n foo: bar;\n}\n" ); test!(escaped_space, "a\\ b {\n color: foo;\n}\n"); +test!( + escaped_bang, + "\\! {\n color: red;\n}\n", + "\\! {\n color: red;\n}\n" +); test!( multiple_consecutive_immediate_child, "> > foo {\n color: foo;\n}\n"