2020-04-20 14:45:40 -04:00
|
|
|
use std::iter::Iterator;
|
|
|
|
|
|
|
|
use peekmore::PeekMoreIterator;
|
|
|
|
|
2020-06-16 20:00:11 -04:00
|
|
|
use crate::{error::SassResult, Token};
|
2020-04-20 14:45:40 -04:00
|
|
|
|
2020-04-20 14:53:52 -04:00
|
|
|
use super::{devour_whitespace, read_until_newline};
|
2020-04-20 14:45:40 -04:00
|
|
|
|
|
|
|
// Eat tokens until an open curly brace
|
|
|
|
//
|
|
|
|
// Does not consume the open curly brace
|
|
|
|
pub(crate) fn read_until_open_curly_brace<I: Iterator<Item = Token>>(
|
|
|
|
toks: &mut PeekMoreIterator<I>,
|
2020-05-24 10:04:30 -04:00
|
|
|
) -> SassResult<Vec<Token>> {
|
2020-04-22 10:57:57 -04:00
|
|
|
let mut t = Vec::new();
|
2020-04-20 14:45:40 -04:00
|
|
|
let mut n = 0;
|
|
|
|
while let Some(tok) = toks.peek() {
|
|
|
|
match tok.kind {
|
|
|
|
'{' => n += 1,
|
|
|
|
'}' => n -= 1,
|
|
|
|
'/' => {
|
|
|
|
let next = toks.next().unwrap();
|
2020-05-24 10:47:11 -04:00
|
|
|
match toks.peek() {
|
|
|
|
Some(Token { kind: '/', .. }) => read_until_newline(toks),
|
2020-04-22 10:57:57 -04:00
|
|
|
_ => t.push(next),
|
2020-04-20 14:45:40 -04:00
|
|
|
};
|
|
|
|
continue;
|
|
|
|
}
|
2020-04-22 10:57:57 -04:00
|
|
|
'\\' => {
|
|
|
|
t.push(toks.next().unwrap());
|
2020-06-18 03:09:24 -04:00
|
|
|
t.push(match toks.next() {
|
|
|
|
Some(tok) => tok,
|
|
|
|
None => continue,
|
|
|
|
});
|
2020-04-22 10:57:57 -04:00
|
|
|
}
|
2020-05-24 10:04:30 -04:00
|
|
|
q @ '"' | q @ '\'' => {
|
|
|
|
t.push(toks.next().unwrap());
|
|
|
|
t.extend(read_until_closing_quote(toks, q)?);
|
|
|
|
continue;
|
|
|
|
}
|
2020-04-20 14:45:40 -04:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
if n == 1 {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-04-22 10:57:57 -04:00
|
|
|
t.push(toks.next().unwrap());
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|
2020-05-24 10:04:30 -04:00
|
|
|
Ok(t)
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn read_until_closing_curly_brace<I: Iterator<Item = Token>>(
|
|
|
|
toks: &mut PeekMoreIterator<I>,
|
2020-05-24 10:04:30 -04:00
|
|
|
) -> SassResult<Vec<Token>> {
|
2020-04-20 14:45:40 -04:00
|
|
|
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());
|
2020-05-24 10:04:30 -04:00
|
|
|
t.extend(read_until_closing_quote(toks, q)?);
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|
|
|
|
'{' => {
|
|
|
|
nesting += 1;
|
|
|
|
t.push(toks.next().unwrap());
|
|
|
|
}
|
|
|
|
'}' => {
|
|
|
|
if nesting == 0 {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
nesting -= 1;
|
|
|
|
t.push(toks.next().unwrap());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'/' => {
|
|
|
|
let next = toks.next().unwrap();
|
2020-05-25 00:57:59 -04:00
|
|
|
match toks.peek() {
|
|
|
|
Some(Token { kind: '/', .. }) => {
|
2020-05-02 12:49:42 -04:00
|
|
|
read_until_newline(toks);
|
|
|
|
devour_whitespace(toks);
|
|
|
|
}
|
2020-05-25 00:57:59 -04:00
|
|
|
Some(..) | None => t.push(next),
|
2020-04-20 14:45:40 -04:00
|
|
|
};
|
|
|
|
continue;
|
|
|
|
}
|
2020-04-21 04:20:35 -04:00
|
|
|
'(' => {
|
|
|
|
t.push(toks.next().unwrap());
|
2020-05-24 10:04:30 -04:00
|
|
|
t.extend(read_until_closing_paren(toks)?);
|
2020-04-21 04:20:35 -04:00
|
|
|
}
|
2020-04-22 10:57:57 -04:00
|
|
|
'\\' => {
|
|
|
|
t.push(toks.next().unwrap());
|
2020-06-18 03:09:24 -04:00
|
|
|
t.push(match toks.next() {
|
|
|
|
Some(tok) => tok,
|
|
|
|
None => continue,
|
|
|
|
});
|
2020-04-22 10:57:57 -04:00
|
|
|
}
|
2020-04-20 14:45:40 -04:00
|
|
|
_ => t.push(toks.next().unwrap()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
devour_whitespace(toks);
|
2020-05-24 10:04:30 -04:00
|
|
|
Ok(t)
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|
|
|
|
|
2020-05-24 10:04:30 -04:00
|
|
|
/// Read tokens into a vector until a matching closing quote is found
|
|
|
|
///
|
|
|
|
/// The closing quote is included in the output
|
2020-04-20 14:45:40 -04:00
|
|
|
pub(crate) fn read_until_closing_quote<I: Iterator<Item = Token>>(
|
|
|
|
toks: &mut PeekMoreIterator<I>,
|
|
|
|
q: char,
|
2020-05-24 10:04:30 -04:00
|
|
|
) -> SassResult<Vec<Token>> {
|
2020-04-20 14:45:40 -04:00
|
|
|
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);
|
2020-06-18 03:09:24 -04:00
|
|
|
t.push(match toks.next() {
|
|
|
|
Some(tok) => tok,
|
|
|
|
None => return Err((format!("Expected {}.", q), tok.pos).into()),
|
|
|
|
});
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|
|
|
|
'#' => {
|
|
|
|
t.push(tok);
|
2020-06-18 03:09:24 -04:00
|
|
|
match toks.peek() {
|
|
|
|
Some(tok @ Token { kind: '{', .. }) => {
|
|
|
|
t.push(*tok);
|
|
|
|
toks.next();
|
|
|
|
t.append(&mut read_until_closing_curly_brace(toks)?);
|
|
|
|
}
|
|
|
|
Some(..) => continue,
|
|
|
|
None => return Err((format!("Expected {}.", q), tok.pos).into()),
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => t.push(tok),
|
|
|
|
}
|
|
|
|
}
|
2020-05-24 10:04:30 -04:00
|
|
|
if let Some(tok) = t.pop() {
|
|
|
|
if tok.kind != q {
|
|
|
|
return Err((format!("Expected {}.", q), tok.pos).into());
|
|
|
|
}
|
|
|
|
t.push(tok);
|
|
|
|
}
|
|
|
|
Ok(t)
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn read_until_semicolon_or_closing_curly_brace<I: Iterator<Item = Token>>(
|
|
|
|
toks: &mut PeekMoreIterator<I>,
|
2020-05-24 10:04:30 -04:00
|
|
|
) -> SassResult<Vec<Token>> {
|
2020-04-20 14:45:40 -04:00
|
|
|
let mut t = Vec::new();
|
|
|
|
let mut nesting = 0;
|
|
|
|
while let Some(tok) = toks.peek() {
|
|
|
|
match tok.kind {
|
|
|
|
';' => {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
'\\' => {
|
|
|
|
t.push(toks.next().unwrap());
|
2020-06-18 03:09:24 -04:00
|
|
|
t.push(match toks.next() {
|
|
|
|
Some(tok) => tok,
|
|
|
|
None => continue,
|
|
|
|
});
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|
|
|
|
'"' | '\'' => {
|
|
|
|
let quote = toks.next().unwrap();
|
2020-04-21 18:22:26 -04:00
|
|
|
t.push(quote);
|
2020-05-24 10:04:30 -04:00
|
|
|
t.extend(read_until_closing_quote(toks, quote.kind)?);
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|
|
|
|
'{' => {
|
|
|
|
nesting += 1;
|
|
|
|
t.push(toks.next().unwrap());
|
|
|
|
}
|
|
|
|
'}' => {
|
|
|
|
if nesting == 0 {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
nesting -= 1;
|
|
|
|
t.push(toks.next().unwrap());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'/' => {
|
|
|
|
let next = toks.next().unwrap();
|
2020-05-25 00:57:59 -04:00
|
|
|
match toks.peek() {
|
|
|
|
Some(Token { kind: '/', .. }) => {
|
2020-05-02 12:49:42 -04:00
|
|
|
read_until_newline(toks);
|
|
|
|
devour_whitespace(toks);
|
|
|
|
}
|
2020-04-20 14:45:40 -04:00
|
|
|
_ => t.push(next),
|
|
|
|
};
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
_ => t.push(toks.next().unwrap()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
devour_whitespace(toks);
|
2020-05-24 10:04:30 -04:00
|
|
|
Ok(t)
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn read_until_closing_paren<I: Iterator<Item = Token>>(
|
|
|
|
toks: &mut PeekMoreIterator<I>,
|
2020-05-24 10:04:30 -04:00
|
|
|
) -> SassResult<Vec<Token>> {
|
2020-04-22 10:57:57 -04:00
|
|
|
let mut t = Vec::new();
|
2020-04-20 14:45:40 -04:00
|
|
|
let mut scope = 0;
|
|
|
|
while let Some(tok) = toks.next() {
|
|
|
|
match tok.kind {
|
|
|
|
')' => {
|
|
|
|
if scope < 1 {
|
2020-04-22 10:57:57 -04:00
|
|
|
t.push(tok);
|
2020-05-24 10:04:30 -04:00
|
|
|
return Ok(t);
|
2020-04-20 14:45:40 -04:00
|
|
|
} else {
|
|
|
|
scope -= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'(' => scope += 1,
|
|
|
|
'"' | '\'' => {
|
2020-04-22 10:57:57 -04:00
|
|
|
t.push(tok);
|
2020-05-24 10:04:30 -04:00
|
|
|
t.extend(read_until_closing_quote(toks, tok.kind)?);
|
2020-04-22 10:57:57 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
'\\' => {
|
2020-06-18 03:09:24 -04:00
|
|
|
t.push(match toks.next() {
|
|
|
|
Some(tok) => tok,
|
|
|
|
None => continue,
|
|
|
|
});
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2020-04-22 10:57:57 -04:00
|
|
|
t.push(tok)
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|
2020-05-24 10:04:30 -04:00
|
|
|
Ok(t)
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn read_until_closing_square_brace<I: Iterator<Item = Token>>(
|
|
|
|
toks: &mut PeekMoreIterator<I>,
|
2020-05-24 10:04:30 -04:00
|
|
|
) -> SassResult<Vec<Token>> {
|
2020-04-22 10:57:57 -04:00
|
|
|
let mut t = Vec::new();
|
2020-04-20 14:45:40 -04:00
|
|
|
let mut scope = 0;
|
|
|
|
while let Some(tok) = toks.next() {
|
2020-05-02 12:49:42 -04:00
|
|
|
// TODO: comments
|
2020-04-20 14:45:40 -04:00
|
|
|
match tok.kind {
|
|
|
|
']' => {
|
|
|
|
if scope < 1 {
|
2020-04-22 10:57:57 -04:00
|
|
|
t.push(tok);
|
2020-05-24 10:04:30 -04:00
|
|
|
return Ok(t);
|
2020-04-20 14:45:40 -04:00
|
|
|
} else {
|
|
|
|
scope -= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'[' => scope += 1,
|
|
|
|
'"' | '\'' => {
|
2020-04-22 10:57:57 -04:00
|
|
|
t.push(tok);
|
2020-05-24 10:04:30 -04:00
|
|
|
t.extend(read_until_closing_quote(toks, tok.kind)?);
|
2020-04-20 14:45:40 -04:00
|
|
|
continue;
|
|
|
|
}
|
2020-04-22 10:57:57 -04:00
|
|
|
'\\' => {
|
2020-06-18 03:09:24 -04:00
|
|
|
t.push(toks.next().unwrap());
|
|
|
|
t.push(match toks.next() {
|
|
|
|
Some(tok) => tok,
|
|
|
|
None => continue,
|
|
|
|
});
|
2020-04-22 10:57:57 -04:00
|
|
|
}
|
2020-04-20 14:45:40 -04:00
|
|
|
_ => {}
|
|
|
|
}
|
2020-04-22 10:57:57 -04:00
|
|
|
t.push(tok)
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|
2020-05-24 10:04:30 -04:00
|
|
|
Ok(t)
|
2020-04-20 14:45:40 -04:00
|
|
|
}
|