more robustly handle escaping

This commit is contained in:
ConnorSkees 2020-04-22 10:57:57 -04:00
parent 680790c49a
commit 34b886b758
3 changed files with 65 additions and 40 deletions

View File

@ -99,7 +99,7 @@ use crate::style::Style;
pub(crate) use crate::token::Token; pub(crate) use crate::token::Token;
use crate::utils::{ use crate::utils::{
devour_whitespace, eat_comment, eat_ident, eat_ident_no_interpolation, eat_variable_value, 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; use crate::value::Value;
@ -676,7 +676,8 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
values.push(toks.next().unwrap()); values.push(toks.next().unwrap());
if toks.peek().unwrap().kind == '{' { if toks.peek().unwrap().kind == '{' {
values.push(toks.next().unwrap()); 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<I: Iterator<Item = Token>>(
Ok(None) Ok(None)
} }
fn eat_interpolation<I: Iterator<Item = Token>>(toks: &mut PeekMoreIterator<I>) -> Vec<Token> {
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 /// Functions that print to stdout or stderr
impl<'a> StyleSheetParser<'a> { impl<'a> StyleSheetParser<'a> {
fn debug(&self, span: Span, message: &str) { fn debug(&self, span: Span, message: &str) {

View File

@ -12,7 +12,7 @@ use super::{devour_whitespace, read_until_newline};
pub(crate) fn read_until_open_curly_brace<I: Iterator<Item = Token>>( pub(crate) fn read_until_open_curly_brace<I: Iterator<Item = Token>>(
toks: &mut PeekMoreIterator<I>, toks: &mut PeekMoreIterator<I>,
) -> Vec<Token> { ) -> Vec<Token> {
let mut val = Vec::new(); let mut t = Vec::new();
let mut n = 0; let mut n = 0;
while let Some(tok) = toks.peek() { while let Some(tok) = toks.peek() {
match tok.kind { match tok.kind {
@ -22,19 +22,25 @@ pub(crate) fn read_until_open_curly_brace<I: Iterator<Item = Token>>(
let next = toks.next().unwrap(); let next = toks.next().unwrap();
match toks.peek().unwrap().kind { match toks.peek().unwrap().kind {
'/' => read_until_newline(toks), '/' => read_until_newline(toks),
_ => val.push(next), _ => t.push(next),
}; };
continue; continue;
} }
'\\' => {
t.push(toks.next().unwrap());
if toks.peek().is_some() {
t.push(toks.next().unwrap());
}
}
_ => {} _ => {}
} }
if n == 1 { if n == 1 {
break; break;
} }
val.push(toks.next().unwrap()); t.push(toks.next().unwrap());
} }
val t
} }
pub(crate) fn read_until_closing_curly_brace<I: Iterator<Item = Token>>( pub(crate) fn read_until_closing_curly_brace<I: Iterator<Item = Token>>(
@ -72,6 +78,12 @@ pub(crate) fn read_until_closing_curly_brace<I: Iterator<Item = Token>>(
t.push(toks.next().unwrap()); t.push(toks.next().unwrap());
t.extend(read_until_closing_paren(toks)); 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()), _ => t.push(toks.next().unwrap()),
} }
} }
@ -96,8 +108,10 @@ pub(crate) fn read_until_closing_quote<I: Iterator<Item = Token>>(
} }
'\\' => { '\\' => {
t.push(tok); t.push(tok);
if toks.peek().is_some() {
t.push(toks.next().unwrap()); t.push(toks.next().unwrap());
} }
}
'#' => { '#' => {
t.push(tok); t.push(tok);
let next = toks.peek().unwrap(); let next = toks.peek().unwrap();
@ -124,8 +138,10 @@ pub(crate) fn read_until_semicolon_or_closing_curly_brace<I: Iterator<Item = Tok
} }
'\\' => { '\\' => {
t.push(toks.next().unwrap()); t.push(toks.next().unwrap());
if toks.peek().is_some() {
t.push(toks.next().unwrap()); t.push(toks.next().unwrap());
} }
}
'"' | '\'' => { '"' | '\'' => {
let quote = toks.next().unwrap(); let quote = toks.next().unwrap();
t.push(quote); t.push(quote);
@ -170,8 +186,10 @@ pub(crate) fn read_until_semicolon_or_open_or_closing_curly_brace<I: Iterator<It
} }
'\\' => { '\\' => {
t.push(toks.next().unwrap()); t.push(toks.next().unwrap());
if toks.peek().is_some() {
t.push(toks.next().unwrap()); t.push(toks.next().unwrap());
} }
}
'"' | '\'' => { '"' | '\'' => {
let quote = toks.next().unwrap(); let quote = toks.next().unwrap();
t.push(quote); t.push(quote);
@ -224,55 +242,68 @@ pub(crate) fn read_until_semicolon_or_open_or_closing_curly_brace<I: Iterator<It
pub(crate) fn read_until_closing_paren<I: Iterator<Item = Token>>( pub(crate) fn read_until_closing_paren<I: Iterator<Item = Token>>(
toks: &mut PeekMoreIterator<I>, toks: &mut PeekMoreIterator<I>,
) -> Vec<Token> { ) -> Vec<Token> {
let mut v = Vec::new(); let mut t = Vec::new();
let mut scope = 0; let mut scope = 0;
while let Some(tok) = toks.next() { while let Some(tok) = toks.next() {
match tok.kind { match tok.kind {
')' => { ')' => {
if scope < 1 { if scope < 1 {
v.push(tok); t.push(tok);
return v; return t;
} else { } else {
scope -= 1; scope -= 1;
} }
} }
'(' => scope += 1, '(' => scope += 1,
'"' | '\'' => { '"' | '\'' => {
v.push(tok); t.push(tok);
v.extend(read_until_closing_quote(toks, tok.kind)); t.extend(read_until_closing_quote(toks, tok.kind));
continue;
}
'\\' => {
t.push(tok);
if toks.peek().is_some() {
t.push(toks.next().unwrap());
}
continue; continue;
} }
_ => {} _ => {}
} }
v.push(tok) t.push(tok)
} }
v t
} }
pub(crate) fn read_until_closing_square_brace<I: Iterator<Item = Token>>( pub(crate) fn read_until_closing_square_brace<I: Iterator<Item = Token>>(
toks: &mut PeekMoreIterator<I>, toks: &mut PeekMoreIterator<I>,
) -> Vec<Token> { ) -> Vec<Token> {
let mut v = Vec::new(); let mut t = Vec::new();
let mut scope = 0; let mut scope = 0;
while let Some(tok) = toks.next() { while let Some(tok) = toks.next() {
match tok.kind { match tok.kind {
']' => { ']' => {
if scope < 1 { if scope < 1 {
v.push(tok); t.push(tok);
return v; return t;
} else { } else {
scope -= 1; scope -= 1;
} }
} }
'[' => scope += 1, '[' => scope += 1,
'"' | '\'' => { '"' | '\'' => {
v.push(tok); t.push(tok);
v.extend(read_until_closing_quote(toks, tok.kind)); t.extend(read_until_closing_quote(toks, tok.kind));
continue; continue;
} }
'\\' => {
t.push(tok);
if toks.peek().is_some() {
t.push(toks.next().unwrap());
}
}
_ => {} _ => {}
} }
v.push(tok) t.push(tok)
} }
v t
} }

View File

@ -58,3 +58,13 @@ test!(
"a {\n color: #{\"\\a\"};\n}\n", "a {\n color: #{\"\\a\"};\n}\n",
"a {\n color: ;\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"
);