diff --git a/src/lib.rs b/src/lib.rs index 23fce73..15b032a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,7 +99,7 @@ use crate::style::Style; pub(crate) use crate::token::Token; use crate::utils::{ devour_whitespace, eat_comment, eat_ident, eat_ident_no_interpolation, eat_variable_value, - parse_quoted_string, read_until_newline, VariableDecl, + parse_quoted_string, read_until_closing_curly_brace, read_until_newline, VariableDecl, }; use crate::value::Value; @@ -676,7 +676,8 @@ pub(crate) fn eat_expr>( values.push(toks.next().unwrap()); if toks.peek().unwrap().kind == '{' { values.push(toks.next().unwrap()); - values.extend(eat_interpolation(toks)); + values.extend(read_until_closing_curly_brace(toks)); + values.push(toks.next().unwrap()); } } '\\' => { @@ -689,23 +690,6 @@ pub(crate) fn eat_expr>( Ok(None) } -fn eat_interpolation>(toks: &mut PeekMoreIterator) -> Vec { - let mut vals = Vec::new(); - let mut n = 1; - for tok in toks { - match tok.kind { - '{' => n += 1, - '}' => n -= 1, - _ => {} - } - vals.push(tok); - if n == 0 { - break; - } - } - vals -} - /// Functions that print to stdout or stderr impl<'a> StyleSheetParser<'a> { fn debug(&self, span: Span, message: &str) { diff --git a/src/utils/read_until.rs b/src/utils/read_until.rs index 5216d00..c450e54 100644 --- a/src/utils/read_until.rs +++ b/src/utils/read_until.rs @@ -12,7 +12,7 @@ use super::{devour_whitespace, read_until_newline}; pub(crate) fn read_until_open_curly_brace>( toks: &mut PeekMoreIterator, ) -> Vec { - let mut val = Vec::new(); + let mut t = Vec::new(); let mut n = 0; while let Some(tok) = toks.peek() { match tok.kind { @@ -22,19 +22,25 @@ pub(crate) fn read_until_open_curly_brace>( let next = toks.next().unwrap(); match toks.peek().unwrap().kind { '/' => read_until_newline(toks), - _ => val.push(next), + _ => t.push(next), }; continue; } + '\\' => { + t.push(toks.next().unwrap()); + if toks.peek().is_some() { + t.push(toks.next().unwrap()); + } + } _ => {} } if n == 1 { break; } - val.push(toks.next().unwrap()); + t.push(toks.next().unwrap()); } - val + t } pub(crate) fn read_until_closing_curly_brace>( @@ -72,6 +78,12 @@ pub(crate) fn read_until_closing_curly_brace>( t.push(toks.next().unwrap()); t.extend(read_until_closing_paren(toks)); } + '\\' => { + t.push(toks.next().unwrap()); + if toks.peek().is_some() { + t.push(toks.next().unwrap()); + } + } _ => t.push(toks.next().unwrap()), } } @@ -96,7 +108,9 @@ pub(crate) fn read_until_closing_quote>( } '\\' => { t.push(tok); - t.push(toks.next().unwrap()); + if toks.peek().is_some() { + t.push(toks.next().unwrap()); + } } '#' => { t.push(tok); @@ -124,7 +138,9 @@ pub(crate) fn read_until_semicolon_or_closing_curly_brace { t.push(toks.next().unwrap()); - t.push(toks.next().unwrap()); + if toks.peek().is_some() { + t.push(toks.next().unwrap()); + } } '"' | '\'' => { let quote = toks.next().unwrap(); @@ -170,7 +186,9 @@ pub(crate) fn read_until_semicolon_or_open_or_closing_curly_brace { t.push(toks.next().unwrap()); - t.push(toks.next().unwrap()); + if toks.peek().is_some() { + t.push(toks.next().unwrap()); + } } '"' | '\'' => { let quote = toks.next().unwrap(); @@ -224,55 +242,68 @@ pub(crate) fn read_until_semicolon_or_open_or_closing_curly_brace>( toks: &mut PeekMoreIterator, ) -> Vec { - let mut v = Vec::new(); + let mut t = Vec::new(); let mut scope = 0; while let Some(tok) = toks.next() { match tok.kind { ')' => { if scope < 1 { - v.push(tok); - return v; + t.push(tok); + return t; } else { scope -= 1; } } '(' => scope += 1, '"' | '\'' => { - v.push(tok); - v.extend(read_until_closing_quote(toks, tok.kind)); + t.push(tok); + t.extend(read_until_closing_quote(toks, tok.kind)); + continue; + } + '\\' => { + t.push(tok); + if toks.peek().is_some() { + t.push(toks.next().unwrap()); + } continue; } _ => {} } - v.push(tok) + t.push(tok) } - v + t } pub(crate) fn read_until_closing_square_brace>( toks: &mut PeekMoreIterator, ) -> Vec { - let mut v = Vec::new(); + let mut t = Vec::new(); let mut scope = 0; while let Some(tok) = toks.next() { match tok.kind { ']' => { if scope < 1 { - v.push(tok); - return v; + t.push(tok); + return t; } else { scope -= 1; } } '[' => scope += 1, '"' | '\'' => { - v.push(tok); - v.extend(read_until_closing_quote(toks, tok.kind)); + t.push(tok); + t.extend(read_until_closing_quote(toks, tok.kind)); continue; } + '\\' => { + t.push(tok); + if toks.peek().is_some() { + t.push(toks.next().unwrap()); + } + } _ => {} } - v.push(tok) + t.push(tok) } - v + t } diff --git a/tests/interpolation.rs b/tests/interpolation.rs index 1bfce7e..7e0ebcb 100644 --- a/tests/interpolation.rs +++ b/tests/interpolation.rs @@ -58,3 +58,13 @@ test!( "a {\n color: #{\"\\a\"};\n}\n", "a {\n color: ;\n}\n" ); +test!( + interpolate_escaped_quotes, + "a {\n color: #{\\\"\\'};\n}\n", + "a {\n color: \\\"\\';\n}\n" +); +test!( + interpolate_escaped_quotes_in_quotes, + "a {\n color: \"#{\\\"\\'}\";\n}\n", + "a {\n color: \"\\\\\\\"\\\\'\";\n}\n" +);