grass/src/utils/read_until.rs

274 lines
7.7 KiB
Rust
Raw Normal View History

use std::iter::Iterator;
use peekmore::PeekMoreIterator;
2020-06-16 20:00:11 -04:00
use crate::{error::SassResult, Token};
2020-04-20 14:53:52 -04:00
use super::{devour_whitespace, read_until_newline};
// 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();
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),
};
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;
}
_ => {}
}
if n == 1 {
break;
}
2020-04-22 10:57:57 -04:00
t.push(toks.next().unwrap());
}
2020-05-24 10:04:30 -04:00
Ok(t)
}
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>> {
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)?);
}
'{' => {
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),
};
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
}
_ => t.push(toks.next().unwrap()),
}
}
devour_whitespace(toks);
2020-05-24 10:04:30 -04:00
Ok(t)
}
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
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>> {
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()),
});
}
'#' => {
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()),
}
}
_ => 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)
}
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>> {
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,
});
}
'"' | '\'' => {
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)?);
}
'{' => {
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);
}
_ => t.push(next),
};
continue;
}
_ => t.push(toks.next().unwrap()),
}
}
devour_whitespace(toks);
2020-05-24 10:04:30 -04:00
Ok(t)
}
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();
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);
} 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-22 10:57:57 -04:00
t.push(tok)
}
2020-05-24 10:04:30 -04:00
Ok(t)
}
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();
let mut scope = 0;
while let Some(tok) = toks.next() {
2020-05-02 12:49:42 -04:00
// TODO: comments
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);
} 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)?);
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-22 10:57:57 -04:00
t.push(tok)
}
2020-05-24 10:04:30 -04:00
Ok(t)
}