diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 7e6640c..ded63c9 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -11,11 +11,13 @@ use crate::{Scope, Token}; pub(crate) use chars::*; pub(crate) use comment_whitespace::*; +pub(crate) use read_until::*; pub(crate) use strings::*; pub(crate) use variables::*; mod chars; mod comment_whitespace; +mod read_until; mod strings; mod variables; @@ -32,213 +34,6 @@ pub(crate) fn parse_interpolation>( }) } -// Eat tokens until an open curly brace -// -// Does not consume the open curly brace -pub(crate) fn read_until_open_curly_brace>( - toks: &mut PeekMoreIterator, -) -> Vec { - let mut val = Vec::new(); - let mut n = 0; - while let Some(tok) = toks.peek() { - match tok.kind { - '{' => n += 1, - '}' => n -= 1, - '/' => { - let next = toks.next().unwrap(); - match toks.peek().unwrap().kind { - '/' => read_until_newline(toks), - _ => val.push(next), - }; - continue; - } - _ => {} - } - if n == 1 { - break; - } - - val.push(toks.next().unwrap()); - } - val -} - -pub(crate) fn read_until_closing_curly_brace>( - toks: &mut PeekMoreIterator, -) -> Vec { - let mut t = Vec::new(); - let mut nesting = 0; - while let Some(tok) = toks.peek() { - match tok.kind { - q @ '"' | q @ '\'' => { - t.push(toks.next().unwrap()); - t.extend(read_until_closing_quote(toks, q)); - } - '{' => { - nesting += 1; - t.push(toks.next().unwrap()); - } - '}' => { - if nesting == 0 { - break; - } else { - nesting -= 1; - t.push(toks.next().unwrap()); - } - } - '/' => { - let next = toks.next().unwrap(); - match toks.peek().unwrap().kind { - '/' => read_until_newline(toks), - _ => t.push(next), - }; - continue; - } - _ => t.push(toks.next().unwrap()), - } - } - devour_whitespace(toks); - t -} - -pub(crate) fn read_until_closing_quote>( - toks: &mut PeekMoreIterator, - q: char, -) -> Vec { - let mut t = Vec::new(); - while let Some(tok) = toks.next() { - match tok.kind { - '"' if q == '"' => { - t.push(tok); - break; - } - '\'' if q == '\'' => { - t.push(tok); - break; - } - '\\' => { - t.push(tok); - t.push(toks.next().unwrap()); - } - '#' => { - t.push(tok); - let next = toks.peek().unwrap(); - if next.kind == '{' { - t.push(toks.next().unwrap()); - t.append(&mut read_until_closing_curly_brace(toks)); - } - } - _ => t.push(tok), - } - } - t -} - -pub(crate) fn read_until_semicolon_or_closing_curly_brace>( - toks: &mut PeekMoreIterator, -) -> Vec { - let mut t = Vec::new(); - let mut nesting = 0; - while let Some(tok) = toks.peek() { - match tok.kind { - ';' => { - break; - } - '\\' => { - t.push(toks.next().unwrap()); - t.push(toks.next().unwrap()); - } - '"' | '\'' => { - let quote = toks.next().unwrap(); - t.push(quote.clone()); - t.extend(read_until_closing_quote(toks, quote.kind)); - } - '{' => { - nesting += 1; - t.push(toks.next().unwrap()); - } - '}' => { - if nesting == 0 { - break; - } else { - nesting -= 1; - t.push(toks.next().unwrap()); - } - } - '/' => { - let next = toks.next().unwrap(); - match toks.peek().unwrap().kind { - '/' => read_until_newline(toks), - _ => t.push(next), - }; - continue; - } - _ => t.push(toks.next().unwrap()), - } - } - devour_whitespace(toks); - t -} - -pub(crate) fn read_until_semicolon_or_open_or_closing_curly_brace>( - toks: &mut PeekMoreIterator, -) -> Vec { - let mut t = Vec::new(); - let mut nesting = 0; - while let Some(tok) = toks.peek() { - match tok.kind { - ';' => { - break; - } - '\\' => { - t.push(toks.next().unwrap()); - t.push(toks.next().unwrap()); - } - '"' | '\'' => { - let quote = toks.next().unwrap(); - t.push(quote.clone()); - t.extend(read_until_closing_quote(toks, quote.kind)); - } - '#' => { - t.push(toks.next().unwrap()); - match toks.peek().unwrap().kind { - '{' => nesting += 1, - ';' => break, - '}' => { - if nesting == 0 { - break; - } else { - nesting -= 1; - } - } - _ => {} - } - t.push(toks.next().unwrap()); - } - '{' => break, - '}' => { - if nesting == 0 { - break; - } else { - nesting -= 1; - t.push(toks.next().unwrap()); - } - } - '/' => { - let next = toks.next().unwrap(); - match toks.peek().unwrap().kind { - '/' => read_until_newline(toks), - _ => t.push(next), - }; - continue; - } - _ => t.push(toks.next().unwrap()), - } - } - devour_whitespace(toks); - t -} - pub(crate) fn eat_number>( toks: &mut PeekMoreIterator, ) -> SassResult> { @@ -285,59 +80,3 @@ pub(crate) fn eat_number>( whole.push_str(&dec); Ok(Spanned { node: whole, span }) } - -pub(crate) fn read_until_closing_paren>( - toks: &mut PeekMoreIterator, -) -> Vec { - let mut v = Vec::new(); - let mut scope = 0; - while let Some(tok) = toks.next() { - match tok.kind { - ')' => { - if scope < 1 { - v.push(tok); - return v; - } else { - scope -= 1; - } - } - '(' => scope += 1, - '"' | '\'' => { - v.push(tok.clone()); - v.extend(read_until_closing_quote(toks, tok.kind)); - continue; - } - _ => {} - } - v.push(tok) - } - v -} - -pub(crate) fn read_until_closing_square_brace>( - toks: &mut PeekMoreIterator, -) -> Vec { - let mut v = Vec::new(); - let mut scope = 0; - while let Some(tok) = toks.next() { - match tok.kind { - ']' => { - if scope < 1 { - v.push(tok); - return v; - } else { - scope -= 1; - } - } - '[' => scope += 1, - '"' | '\'' => { - v.push(tok.clone()); - v.extend(read_until_closing_quote(toks, tok.kind)); - continue; - } - _ => {} - } - v.push(tok) - } - v -} diff --git a/src/utils/read_until.rs b/src/utils/read_until.rs new file mode 100644 index 0000000..ef165ca --- /dev/null +++ b/src/utils/read_until.rs @@ -0,0 +1,270 @@ +use std::iter::Iterator; + +use peekmore::PeekMoreIterator; + +use crate::Token; + +use super::*; + +// Eat tokens until an open curly brace +// +// Does not consume the open curly brace +pub(crate) fn read_until_open_curly_brace>( + toks: &mut PeekMoreIterator, +) -> Vec { + let mut val = Vec::new(); + let mut n = 0; + while let Some(tok) = toks.peek() { + match tok.kind { + '{' => n += 1, + '}' => n -= 1, + '/' => { + let next = toks.next().unwrap(); + match toks.peek().unwrap().kind { + '/' => read_until_newline(toks), + _ => val.push(next), + }; + continue; + } + _ => {} + } + if n == 1 { + break; + } + + val.push(toks.next().unwrap()); + } + val +} + +pub(crate) fn read_until_closing_curly_brace>( + toks: &mut PeekMoreIterator, +) -> Vec { + let mut t = Vec::new(); + let mut nesting = 0; + while let Some(tok) = toks.peek() { + match tok.kind { + q @ '"' | q @ '\'' => { + t.push(toks.next().unwrap()); + t.extend(read_until_closing_quote(toks, q)); + } + '{' => { + nesting += 1; + t.push(toks.next().unwrap()); + } + '}' => { + if nesting == 0 { + break; + } else { + nesting -= 1; + t.push(toks.next().unwrap()); + } + } + '/' => { + let next = toks.next().unwrap(); + match toks.peek().unwrap().kind { + '/' => read_until_newline(toks), + _ => t.push(next), + }; + continue; + } + _ => t.push(toks.next().unwrap()), + } + } + devour_whitespace(toks); + t +} + +pub(crate) fn read_until_closing_quote>( + toks: &mut PeekMoreIterator, + q: char, +) -> Vec { + let mut t = Vec::new(); + while let Some(tok) = toks.next() { + match tok.kind { + '"' if q == '"' => { + t.push(tok); + break; + } + '\'' if q == '\'' => { + t.push(tok); + break; + } + '\\' => { + t.push(tok); + t.push(toks.next().unwrap()); + } + '#' => { + t.push(tok); + let next = toks.peek().unwrap(); + if next.kind == '{' { + t.push(toks.next().unwrap()); + t.append(&mut read_until_closing_curly_brace(toks)); + } + } + _ => t.push(tok), + } + } + t +} + +pub(crate) fn read_until_semicolon_or_closing_curly_brace>( + toks: &mut PeekMoreIterator, +) -> Vec { + let mut t = Vec::new(); + let mut nesting = 0; + while let Some(tok) = toks.peek() { + match tok.kind { + ';' => { + break; + } + '\\' => { + t.push(toks.next().unwrap()); + t.push(toks.next().unwrap()); + } + '"' | '\'' => { + let quote = toks.next().unwrap(); + t.push(quote.clone()); + t.extend(read_until_closing_quote(toks, quote.kind)); + } + '{' => { + nesting += 1; + t.push(toks.next().unwrap()); + } + '}' => { + if nesting == 0 { + break; + } else { + nesting -= 1; + t.push(toks.next().unwrap()); + } + } + '/' => { + let next = toks.next().unwrap(); + match toks.peek().unwrap().kind { + '/' => read_until_newline(toks), + _ => t.push(next), + }; + continue; + } + _ => t.push(toks.next().unwrap()), + } + } + devour_whitespace(toks); + t +} + +pub(crate) fn read_until_semicolon_or_open_or_closing_curly_brace>( + toks: &mut PeekMoreIterator, +) -> Vec { + let mut t = Vec::new(); + let mut nesting = 0; + while let Some(tok) = toks.peek() { + match tok.kind { + ';' => { + break; + } + '\\' => { + t.push(toks.next().unwrap()); + t.push(toks.next().unwrap()); + } + '"' | '\'' => { + let quote = toks.next().unwrap(); + t.push(quote.clone()); + t.extend(read_until_closing_quote(toks, quote.kind)); + } + '#' => { + t.push(toks.next().unwrap()); + match toks.peek().unwrap().kind { + '{' => nesting += 1, + ';' => break, + '}' => { + if nesting == 0 { + break; + } else { + nesting -= 1; + } + } + _ => {} + } + t.push(toks.next().unwrap()); + } + '{' => break, + '}' => { + if nesting == 0 { + break; + } else { + nesting -= 1; + t.push(toks.next().unwrap()); + } + } + '/' => { + let next = toks.next().unwrap(); + match toks.peek().unwrap().kind { + '/' => read_until_newline(toks), + _ => t.push(next), + }; + continue; + } + _ => t.push(toks.next().unwrap()), + } + } + devour_whitespace(toks); + t +} + +pub(crate) fn read_until_closing_paren>( + toks: &mut PeekMoreIterator, +) -> Vec { + let mut v = Vec::new(); + let mut scope = 0; + while let Some(tok) = toks.next() { + match tok.kind { + ')' => { + if scope < 1 { + v.push(tok); + return v; + } else { + scope -= 1; + } + } + '(' => scope += 1, + '"' | '\'' => { + v.push(tok.clone()); + v.extend(read_until_closing_quote(toks, tok.kind)); + continue; + } + _ => {} + } + v.push(tok) + } + v +} + +pub(crate) fn read_until_closing_square_brace>( + toks: &mut PeekMoreIterator, +) -> Vec { + let mut v = Vec::new(); + let mut scope = 0; + while let Some(tok) = toks.next() { + match tok.kind { + ']' => { + if scope < 1 { + v.push(tok); + return v; + } else { + scope -= 1; + } + } + '[' => scope += 1, + '"' | '\'' => { + v.push(tok.clone()); + v.extend(read_until_closing_quote(toks, tok.kind)); + continue; + } + _ => {} + } + v.push(tok) + } + v +}