emit proper error on unclosed quote
This commit is contained in:
parent
b653c55ad7
commit
737a6ba90d
@ -262,7 +262,7 @@ pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(
|
|||||||
}
|
}
|
||||||
'(' => {
|
'(' => {
|
||||||
default.push(toks.next().unwrap());
|
default.push(toks.next().unwrap());
|
||||||
default.extend(read_until_closing_paren(toks));
|
default.extend(read_until_closing_paren(toks)?);
|
||||||
}
|
}
|
||||||
_ => default.push(toks.next().unwrap()),
|
_ => default.push(toks.next().unwrap()),
|
||||||
}
|
}
|
||||||
@ -380,15 +380,15 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
|
|||||||
',' => break,
|
',' => break,
|
||||||
'[' => {
|
'[' => {
|
||||||
val.push(tok);
|
val.push(tok);
|
||||||
val.extend(read_until_closing_square_brace(toks));
|
val.extend(read_until_closing_square_brace(toks)?);
|
||||||
}
|
}
|
||||||
'(' => {
|
'(' => {
|
||||||
val.push(tok);
|
val.push(tok);
|
||||||
val.extend(read_until_closing_paren(toks));
|
val.extend(read_until_closing_paren(toks)?);
|
||||||
}
|
}
|
||||||
'"' | '\'' => {
|
'"' | '\'' => {
|
||||||
val.push(tok);
|
val.push(tok);
|
||||||
val.extend(read_until_closing_quote(toks, tok.kind));
|
val.extend(read_until_closing_quote(toks, tok.kind)?);
|
||||||
}
|
}
|
||||||
_ => val.push(tok),
|
_ => val.push(tok),
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ pub(crate) fn parse_each<I: Iterator<Item = Token>>(
|
|||||||
return Err(("Expected \"in\".", i.span).into());
|
return Err(("Expected \"in\".", i.span).into());
|
||||||
}
|
}
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
let iter_val = Value::from_vec(read_until_open_curly_brace(toks), scope, super_selector)?;
|
let iter_val = Value::from_vec(read_until_open_curly_brace(toks)?, scope, super_selector)?;
|
||||||
let iter = match iter_val.node.eval(iter_val.span)?.node {
|
let iter = match iter_val.node.eval(iter_val.span)?.node {
|
||||||
Value::List(v, ..) => v,
|
Value::List(v, ..) => v,
|
||||||
Value::Map(m) => m
|
Value::Map(m) => m
|
||||||
@ -130,7 +130,7 @@ pub(crate) fn parse_each<I: Iterator<Item = Token>>(
|
|||||||
};
|
};
|
||||||
toks.next();
|
toks.next();
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
let mut body = read_until_closing_curly_brace(toks);
|
let mut body = read_until_closing_curly_brace(toks)?;
|
||||||
body.push(toks.next().unwrap());
|
body.push(toks.next().unwrap());
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ pub(crate) fn parse_for<I: Iterator<Item = Token>>(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let to_toks = read_until_open_curly_brace(toks);
|
let to_toks = read_until_open_curly_brace(toks)?;
|
||||||
toks.next();
|
toks.next();
|
||||||
let to_val = Value::from_vec(to_toks, scope, super_selector)?;
|
let to_val = Value::from_vec(to_toks, scope, super_selector)?;
|
||||||
let to = match to_val.node.eval(to_val.span)?.node {
|
let to = match to_val.node.eval(to_val.span)?.node {
|
||||||
@ -164,7 +164,7 @@ pub(crate) fn parse_for<I: Iterator<Item = Token>>(
|
|||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let body = read_until_closing_curly_brace(toks);
|
let body = read_until_closing_curly_brace(toks)?;
|
||||||
toks.next();
|
toks.next();
|
||||||
|
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
|
@ -58,7 +58,7 @@ impl Function {
|
|||||||
|
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
|
|
||||||
let mut body = read_until_closing_curly_brace(toks); //eat_stmts(toks, &mut scope.clone(), super_selector)?;
|
let mut body = read_until_closing_curly_brace(toks)?; //eat_stmts(toks, &mut scope.clone(), super_selector)?;
|
||||||
body.push(toks.next().unwrap());
|
body.push(toks.next().unwrap());
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
|
|
||||||
|
@ -41,13 +41,13 @@ impl If {
|
|||||||
) -> SassResult<If> {
|
) -> SassResult<If> {
|
||||||
devour_whitespace_or_comment(toks)?;
|
devour_whitespace_or_comment(toks)?;
|
||||||
let mut branches = Vec::new();
|
let mut branches = Vec::new();
|
||||||
let init_toks = read_until_open_curly_brace(toks);
|
let init_cond_toks = read_until_open_curly_brace(toks)?;
|
||||||
if init_toks.is_empty() || toks.next().is_none() {
|
if init_cond_toks.is_empty() || toks.next().is_none() {
|
||||||
return Err(("Expected expression.", span_before).into());
|
return Err(("Expected expression.", span_before).into());
|
||||||
}
|
}
|
||||||
let init_cond = Value::from_vec(init_toks, scope, super_selector)?;
|
let init_cond = Value::from_vec(init_cond_toks, scope, super_selector)?;
|
||||||
devour_whitespace_or_comment(toks)?;
|
devour_whitespace_or_comment(toks)?;
|
||||||
let mut init_toks = read_until_closing_curly_brace(toks);
|
let mut init_toks = read_until_closing_curly_brace(toks)?;
|
||||||
if let Some(tok) = toks.next() {
|
if let Some(tok) = toks.next() {
|
||||||
init_toks.push(tok);
|
init_toks.push(tok);
|
||||||
} else {
|
} else {
|
||||||
@ -80,18 +80,18 @@ impl If {
|
|||||||
'i' if toks.next().unwrap().kind.to_ascii_lowercase() == 'f' => {
|
'i' if toks.next().unwrap().kind.to_ascii_lowercase() == 'f' => {
|
||||||
toks.next();
|
toks.next();
|
||||||
let cond = Value::from_vec(
|
let cond = Value::from_vec(
|
||||||
read_until_open_curly_brace(toks),
|
read_until_open_curly_brace(toks)?,
|
||||||
scope,
|
scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
)?;
|
)?;
|
||||||
toks.next();
|
toks.next();
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
branches.push(Branch::new(cond, read_until_closing_curly_brace(toks)));
|
branches.push(Branch::new(cond, read_until_closing_curly_brace(toks)?));
|
||||||
toks.next();
|
toks.next();
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
}
|
}
|
||||||
'{' => {
|
'{' => {
|
||||||
else_ = read_until_closing_curly_brace(toks);
|
else_ = read_until_closing_curly_brace(toks)?;
|
||||||
toks.next();
|
toks.next();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ impl Mixin {
|
|||||||
|
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
|
|
||||||
let mut body = read_until_closing_curly_brace(toks);
|
let mut body = read_until_closing_curly_brace(toks)?;
|
||||||
body.push(toks.next().unwrap());
|
body.push(toks.next().unwrap());
|
||||||
|
|
||||||
Ok(Spanned {
|
Ok(Spanned {
|
||||||
|
@ -69,7 +69,7 @@ impl AtRule {
|
|||||||
node: message,
|
node: message,
|
||||||
span,
|
span,
|
||||||
} = Value::from_vec(
|
} = Value::from_vec(
|
||||||
read_until_semicolon_or_closing_curly_brace(toks),
|
read_until_semicolon_or_closing_curly_brace(toks)?,
|
||||||
scope,
|
scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
)?;
|
)?;
|
||||||
@ -81,7 +81,7 @@ impl AtRule {
|
|||||||
node: message,
|
node: message,
|
||||||
span,
|
span,
|
||||||
} = Value::from_vec(
|
} = Value::from_vec(
|
||||||
read_until_semicolon_or_closing_curly_brace(toks),
|
read_until_semicolon_or_closing_curly_brace(toks)?,
|
||||||
scope,
|
scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
)?;
|
)?;
|
||||||
@ -103,7 +103,7 @@ impl AtRule {
|
|||||||
node: message,
|
node: message,
|
||||||
span,
|
span,
|
||||||
} = Value::from_vec(
|
} = Value::from_vec(
|
||||||
read_until_semicolon_or_closing_curly_brace(toks),
|
read_until_semicolon_or_closing_curly_brace(toks)?,
|
||||||
scope,
|
scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
)?;
|
)?;
|
||||||
@ -139,7 +139,7 @@ impl AtRule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AtRuleKind::Return => {
|
AtRuleKind::Return => {
|
||||||
let v = read_until_semicolon_or_closing_curly_brace(toks);
|
let v = read_until_semicolon_or_closing_curly_brace(toks)?;
|
||||||
if toks.peek().unwrap().kind == ';' {
|
if toks.peek().unwrap().kind == ';' {
|
||||||
toks.next();
|
toks.next();
|
||||||
}
|
}
|
||||||
@ -153,7 +153,7 @@ impl AtRule {
|
|||||||
let mut selector = &Selector::replace(
|
let mut selector = &Selector::replace(
|
||||||
super_selector,
|
super_selector,
|
||||||
Selector::from_tokens(
|
Selector::from_tokens(
|
||||||
&mut read_until_open_curly_brace(toks).into_iter().peekmore(),
|
&mut read_until_open_curly_brace(toks)?.into_iter().peekmore(),
|
||||||
scope,
|
scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
)?,
|
)?,
|
||||||
@ -165,7 +165,7 @@ impl AtRule {
|
|||||||
}
|
}
|
||||||
toks.next();
|
toks.next();
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
let mut body = read_until_closing_curly_brace(toks);
|
let mut body = read_until_closing_curly_brace(toks)?;
|
||||||
body.push(toks.next().unwrap());
|
body.push(toks.next().unwrap());
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
let mut styles = Vec::new();
|
let mut styles = Vec::new();
|
||||||
@ -201,7 +201,7 @@ impl AtRule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AtRuleKind::Charset => {
|
AtRuleKind::Charset => {
|
||||||
read_until_semicolon_or_closing_curly_brace(toks);
|
read_until_semicolon_or_closing_curly_brace(toks)?;
|
||||||
if toks.peek().unwrap().kind == ';' {
|
if toks.peek().unwrap().kind == ';' {
|
||||||
toks.next();
|
toks.next();
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ pub(crate) fn parse_while<I: Iterator<Item = Token>>(
|
|||||||
span: Span,
|
span: Span,
|
||||||
) -> SassResult<Spanned<AtRule>> {
|
) -> SassResult<Spanned<AtRule>> {
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
let cond = read_until_open_curly_brace(toks);
|
let cond = read_until_open_curly_brace(toks)?;
|
||||||
|
|
||||||
if cond.is_empty() {
|
if cond.is_empty() {
|
||||||
return Err(("Expected expression.", span).into());
|
return Err(("Expected expression.", span).into());
|
||||||
@ -58,7 +58,7 @@ pub(crate) fn parse_while<I: Iterator<Item = Token>>(
|
|||||||
|
|
||||||
toks.next();
|
toks.next();
|
||||||
|
|
||||||
let mut body = read_until_closing_curly_brace(toks);
|
let mut body = read_until_closing_curly_brace(toks)?;
|
||||||
|
|
||||||
body.push(toks.next().unwrap());
|
body.push(toks.next().unwrap());
|
||||||
|
|
||||||
|
@ -375,7 +375,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
|||||||
Some(Token { kind: '{', .. }) => {
|
Some(Token { kind: '{', .. }) => {
|
||||||
let next = toks.next().unwrap();
|
let next = toks.next().unwrap();
|
||||||
values.push(next);
|
values.push(next);
|
||||||
values.extend(read_until_closing_curly_brace(toks));
|
values.extend(read_until_closing_curly_brace(toks)?);
|
||||||
if let Some(tok) = toks.next() {
|
if let Some(tok) = toks.next() {
|
||||||
values.push(tok);
|
values.push(tok);
|
||||||
} else {
|
} else {
|
||||||
@ -395,7 +395,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
|||||||
// it is causing us to emit nothing on malformed input
|
// it is causing us to emit nothing on malformed input
|
||||||
'(' => {
|
'(' => {
|
||||||
values.push(toks.next().unwrap());
|
values.push(toks.next().unwrap());
|
||||||
values.extend(read_until_closing_paren(toks));
|
values.extend(read_until_closing_paren(toks)?);
|
||||||
}
|
}
|
||||||
_ => values.push(toks.next().unwrap()),
|
_ => values.push(toks.next().unwrap()),
|
||||||
};
|
};
|
||||||
|
@ -403,7 +403,12 @@ impl Selector {
|
|||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
span_before: Span,
|
span_before: Span,
|
||||||
) -> SassResult<SelectorKind> {
|
) -> SassResult<SelectorKind> {
|
||||||
let is_pseudo_element = if toks.peek().ok_or(("Expected identifier.", span_before))?.kind == ':' {
|
let is_pseudo_element = if toks
|
||||||
|
.peek()
|
||||||
|
.ok_or(("Expected identifier.", span_before))?
|
||||||
|
.kind
|
||||||
|
== ':'
|
||||||
|
{
|
||||||
toks.next();
|
toks.next();
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
@ -419,7 +424,7 @@ impl Selector {
|
|||||||
Ok(
|
Ok(
|
||||||
if toks.peek().is_some() && toks.peek().unwrap().kind == '(' {
|
if toks.peek().is_some() && toks.peek().unwrap().kind == '(' {
|
||||||
toks.next();
|
toks.next();
|
||||||
let mut inner_toks = read_until_closing_paren(toks);
|
let mut inner_toks = read_until_closing_paren(toks)?;
|
||||||
inner_toks.pop();
|
inner_toks.pop();
|
||||||
let inner = Selector::from_tokens(
|
let inner = Selector::from_tokens(
|
||||||
&mut inner_toks.into_iter().peekmore(),
|
&mut inner_toks.into_iter().peekmore(),
|
||||||
|
@ -4,6 +4,7 @@ use peekmore::PeekMoreIterator;
|
|||||||
|
|
||||||
use super::read_until_closing_quote;
|
use super::read_until_closing_quote;
|
||||||
|
|
||||||
|
use crate::error::SassResult;
|
||||||
use crate::Token;
|
use crate::Token;
|
||||||
|
|
||||||
/// Reads until the char is found, consuming the char,
|
/// Reads until the char is found, consuming the char,
|
||||||
@ -11,13 +12,13 @@ use crate::Token;
|
|||||||
pub(crate) fn read_until_char<I: Iterator<Item = Token>>(
|
pub(crate) fn read_until_char<I: Iterator<Item = Token>>(
|
||||||
toks: &mut PeekMoreIterator<I>,
|
toks: &mut PeekMoreIterator<I>,
|
||||||
c: char,
|
c: char,
|
||||||
) -> Vec<Token> {
|
) -> SassResult<Vec<Token>> {
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
while let Some(tok) = toks.next() {
|
while let Some(tok) = toks.next() {
|
||||||
match tok.kind {
|
match tok.kind {
|
||||||
'"' | '\'' => {
|
'"' | '\'' => {
|
||||||
v.push(tok);
|
v.push(tok);
|
||||||
v.extend(read_until_closing_quote(toks, tok.kind));
|
v.extend(read_until_closing_quote(toks, tok.kind)?);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
t if t == c => break,
|
t if t == c => break,
|
||||||
@ -25,7 +26,7 @@ pub(crate) fn read_until_char<I: Iterator<Item = Token>>(
|
|||||||
}
|
}
|
||||||
v.push(tok)
|
v.push(tok)
|
||||||
}
|
}
|
||||||
v
|
Ok(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn hex_char_for(number: u32) -> char {
|
pub(crate) fn hex_char_for(number: u32) -> char {
|
||||||
|
@ -16,7 +16,7 @@ pub(crate) fn parse_interpolation<I: Iterator<Item = Token>>(
|
|||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
) -> SassResult<Spanned<Value>> {
|
) -> SassResult<Spanned<Value>> {
|
||||||
let val = Value::from_vec(read_until_closing_curly_brace(toks), scope, super_selector)?;
|
let val = Value::from_vec(read_until_closing_curly_brace(toks)?, scope, super_selector)?;
|
||||||
toks.next();
|
toks.next();
|
||||||
Ok(Spanned {
|
Ok(Spanned {
|
||||||
node: val.node.eval(val.span)?.node.unquote(),
|
node: val.node.eval(val.span)?.node.unquote(),
|
||||||
|
@ -2,6 +2,7 @@ use std::iter::Iterator;
|
|||||||
|
|
||||||
use peekmore::PeekMoreIterator;
|
use peekmore::PeekMoreIterator;
|
||||||
|
|
||||||
|
use crate::error::SassResult;
|
||||||
use crate::Token;
|
use crate::Token;
|
||||||
|
|
||||||
use super::{devour_whitespace, read_until_newline};
|
use super::{devour_whitespace, read_until_newline};
|
||||||
@ -11,7 +12,7 @@ use super::{devour_whitespace, read_until_newline};
|
|||||||
// Does not consume the open curly brace
|
// Does not consume the open curly brace
|
||||||
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> {
|
) -> SassResult<Vec<Token>> {
|
||||||
let mut t = 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() {
|
||||||
@ -33,6 +34,11 @@ pub(crate) fn read_until_open_curly_brace<I: Iterator<Item = Token>>(
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
q @ '"' | q @ '\'' => {
|
||||||
|
t.push(toks.next().unwrap());
|
||||||
|
t.extend(read_until_closing_quote(toks, q)?);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
if n == 1 {
|
if n == 1 {
|
||||||
@ -41,19 +47,19 @@ pub(crate) fn read_until_open_curly_brace<I: Iterator<Item = Token>>(
|
|||||||
|
|
||||||
t.push(toks.next().unwrap());
|
t.push(toks.next().unwrap());
|
||||||
}
|
}
|
||||||
t
|
Ok(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>>(
|
||||||
toks: &mut PeekMoreIterator<I>,
|
toks: &mut PeekMoreIterator<I>,
|
||||||
) -> Vec<Token> {
|
) -> SassResult<Vec<Token>> {
|
||||||
let mut t = Vec::new();
|
let mut t = Vec::new();
|
||||||
let mut nesting = 0;
|
let mut nesting = 0;
|
||||||
while let Some(tok) = toks.peek() {
|
while let Some(tok) = toks.peek() {
|
||||||
match tok.kind {
|
match tok.kind {
|
||||||
q @ '"' | q @ '\'' => {
|
q @ '"' | q @ '\'' => {
|
||||||
t.push(toks.next().unwrap());
|
t.push(toks.next().unwrap());
|
||||||
t.extend(read_until_closing_quote(toks, q));
|
t.extend(read_until_closing_quote(toks, q)?);
|
||||||
}
|
}
|
||||||
'{' => {
|
'{' => {
|
||||||
nesting += 1;
|
nesting += 1;
|
||||||
@ -80,7 +86,7 @@ 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());
|
t.push(toks.next().unwrap());
|
||||||
@ -92,13 +98,16 @@ pub(crate) fn read_until_closing_curly_brace<I: Iterator<Item = Token>>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
t
|
Ok(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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>>(
|
pub(crate) fn read_until_closing_quote<I: Iterator<Item = Token>>(
|
||||||
toks: &mut PeekMoreIterator<I>,
|
toks: &mut PeekMoreIterator<I>,
|
||||||
q: char,
|
q: char,
|
||||||
) -> Vec<Token> {
|
) -> SassResult<Vec<Token>> {
|
||||||
let mut t = Vec::new();
|
let mut t = Vec::new();
|
||||||
while let Some(tok) = toks.next() {
|
while let Some(tok) = toks.next() {
|
||||||
match tok.kind {
|
match tok.kind {
|
||||||
@ -121,18 +130,24 @@ pub(crate) fn read_until_closing_quote<I: Iterator<Item = Token>>(
|
|||||||
let next = toks.peek().unwrap();
|
let next = toks.peek().unwrap();
|
||||||
if next.kind == '{' {
|
if next.kind == '{' {
|
||||||
t.push(toks.next().unwrap());
|
t.push(toks.next().unwrap());
|
||||||
t.append(&mut read_until_closing_curly_brace(toks));
|
t.append(&mut read_until_closing_curly_brace(toks)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => t.push(tok),
|
_ => t.push(tok),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t
|
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>>(
|
pub(crate) fn read_until_semicolon_or_closing_curly_brace<I: Iterator<Item = Token>>(
|
||||||
toks: &mut PeekMoreIterator<I>,
|
toks: &mut PeekMoreIterator<I>,
|
||||||
) -> Vec<Token> {
|
) -> SassResult<Vec<Token>> {
|
||||||
let mut t = Vec::new();
|
let mut t = Vec::new();
|
||||||
let mut nesting = 0;
|
let mut nesting = 0;
|
||||||
while let Some(tok) = toks.peek() {
|
while let Some(tok) = toks.peek() {
|
||||||
@ -149,7 +164,7 @@ pub(crate) fn read_until_semicolon_or_closing_curly_brace<I: Iterator<Item = Tok
|
|||||||
'"' | '\'' => {
|
'"' | '\'' => {
|
||||||
let quote = toks.next().unwrap();
|
let quote = toks.next().unwrap();
|
||||||
t.push(quote);
|
t.push(quote);
|
||||||
t.extend(read_until_closing_quote(toks, quote.kind));
|
t.extend(read_until_closing_quote(toks, quote.kind)?);
|
||||||
}
|
}
|
||||||
'{' => {
|
'{' => {
|
||||||
nesting += 1;
|
nesting += 1;
|
||||||
@ -178,12 +193,12 @@ pub(crate) fn read_until_semicolon_or_closing_curly_brace<I: Iterator<Item = Tok
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
t
|
Ok(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
) -> SassResult<Vec<Token>> {
|
||||||
let mut t = 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() {
|
||||||
@ -191,7 +206,7 @@ pub(crate) fn read_until_closing_paren<I: Iterator<Item = Token>>(
|
|||||||
')' => {
|
')' => {
|
||||||
if scope < 1 {
|
if scope < 1 {
|
||||||
t.push(tok);
|
t.push(tok);
|
||||||
return t;
|
return Ok(t);
|
||||||
} else {
|
} else {
|
||||||
scope -= 1;
|
scope -= 1;
|
||||||
}
|
}
|
||||||
@ -199,7 +214,7 @@ pub(crate) fn read_until_closing_paren<I: Iterator<Item = Token>>(
|
|||||||
'(' => scope += 1,
|
'(' => scope += 1,
|
||||||
'"' | '\'' => {
|
'"' | '\'' => {
|
||||||
t.push(tok);
|
t.push(tok);
|
||||||
t.extend(read_until_closing_quote(toks, tok.kind));
|
t.extend(read_until_closing_quote(toks, tok.kind)?);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
'\\' => {
|
'\\' => {
|
||||||
@ -213,12 +228,12 @@ pub(crate) fn read_until_closing_paren<I: Iterator<Item = Token>>(
|
|||||||
}
|
}
|
||||||
t.push(tok)
|
t.push(tok)
|
||||||
}
|
}
|
||||||
t
|
Ok(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> {
|
) -> SassResult<Vec<Token>> {
|
||||||
let mut t = 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() {
|
||||||
@ -227,7 +242,7 @@ pub(crate) fn read_until_closing_square_brace<I: Iterator<Item = Token>>(
|
|||||||
']' => {
|
']' => {
|
||||||
if scope < 1 {
|
if scope < 1 {
|
||||||
t.push(tok);
|
t.push(tok);
|
||||||
return t;
|
return Ok(t);
|
||||||
} else {
|
} else {
|
||||||
scope -= 1;
|
scope -= 1;
|
||||||
}
|
}
|
||||||
@ -235,7 +250,7 @@ pub(crate) fn read_until_closing_square_brace<I: Iterator<Item = Token>>(
|
|||||||
'[' => scope += 1,
|
'[' => scope += 1,
|
||||||
'"' | '\'' => {
|
'"' | '\'' => {
|
||||||
t.push(tok);
|
t.push(tok);
|
||||||
t.extend(read_until_closing_quote(toks, tok.kind));
|
t.extend(read_until_closing_quote(toks, tok.kind)?);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
'\\' => {
|
'\\' => {
|
||||||
@ -248,5 +263,5 @@ pub(crate) fn read_until_closing_square_brace<I: Iterator<Item = Token>>(
|
|||||||
}
|
}
|
||||||
t.push(tok)
|
t.push(tok)
|
||||||
}
|
}
|
||||||
t
|
Ok(t)
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ pub(crate) fn eat_variable_value<I: Iterator<Item = Token>>(
|
|||||||
'"' | '\'' => {
|
'"' | '\'' => {
|
||||||
let quote = toks.next().unwrap();
|
let quote = toks.next().unwrap();
|
||||||
val_toks.push(quote);
|
val_toks.push(quote);
|
||||||
val_toks.extend(read_until_closing_quote(toks, quote.kind));
|
val_toks.extend(read_until_closing_quote(toks, quote.kind)?);
|
||||||
}
|
}
|
||||||
'#' => {
|
'#' => {
|
||||||
val_toks.push(toks.next().unwrap());
|
val_toks.push(toks.next().unwrap());
|
||||||
@ -93,7 +93,7 @@ pub(crate) fn eat_variable_value<I: Iterator<Item = Token>>(
|
|||||||
}
|
}
|
||||||
'(' => {
|
'(' => {
|
||||||
val_toks.push(toks.next().unwrap());
|
val_toks.push(toks.next().unwrap());
|
||||||
val_toks.extend(read_until_closing_paren(toks));
|
val_toks.extend(read_until_closing_paren(toks)?);
|
||||||
}
|
}
|
||||||
'!' => {
|
'!' => {
|
||||||
let pos = tok.pos();
|
let pos = tok.pos();
|
||||||
|
@ -189,7 +189,7 @@ fn parse_paren(
|
|||||||
let paren_toks = &mut t.node.into_iter().peekmore();
|
let paren_toks = &mut t.node.into_iter().peekmore();
|
||||||
|
|
||||||
let mut map = SassMap::new();
|
let mut map = SassMap::new();
|
||||||
let key = Value::from_vec(read_until_char(paren_toks, ':'), scope, super_selector)?;
|
let key = Value::from_vec(read_until_char(paren_toks, ':')?, scope, super_selector)?;
|
||||||
|
|
||||||
if paren_toks.peek().is_none() {
|
if paren_toks.peek().is_none() {
|
||||||
return Ok(Spanned {
|
return Ok(Spanned {
|
||||||
@ -198,7 +198,7 @@ fn parse_paren(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let val = Value::from_vec(read_until_char(paren_toks, ','), scope, super_selector)?;
|
let val = Value::from_vec(read_until_char(paren_toks, ',')?, scope, super_selector)?;
|
||||||
|
|
||||||
map.insert(key.node, val.node);
|
map.insert(key.node, val.node);
|
||||||
|
|
||||||
@ -212,9 +212,9 @@ fn parse_paren(
|
|||||||
let mut span = key.span;
|
let mut span = key.span;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let key = Value::from_vec(read_until_char(paren_toks, ':'), scope, super_selector)?;
|
let key = Value::from_vec(read_until_char(paren_toks, ':')?, scope, super_selector)?;
|
||||||
devour_whitespace(paren_toks);
|
devour_whitespace(paren_toks);
|
||||||
let val = Value::from_vec(read_until_char(paren_toks, ','), scope, super_selector)?;
|
let val = Value::from_vec(read_until_char(paren_toks, ',')?, scope, super_selector)?;
|
||||||
span = span.merge(val.span);
|
span = span.merge(val.span);
|
||||||
devour_whitespace(paren_toks);
|
devour_whitespace(paren_toks);
|
||||||
if map.insert(key.node, val.node) {
|
if map.insert(key.node, val.node) {
|
||||||
@ -755,7 +755,10 @@ impl Value {
|
|||||||
}
|
}
|
||||||
'(' => {
|
'(' => {
|
||||||
let mut span = toks.next().unwrap().pos();
|
let mut span = toks.next().unwrap().pos();
|
||||||
let mut inner = read_until_closing_paren(toks);
|
let mut inner = match read_until_closing_paren(toks) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => return Some(Err(e.into())),
|
||||||
|
};
|
||||||
// todo: the above shouldn't eat the closing paren
|
// todo: the above shouldn't eat the closing paren
|
||||||
if let Some(last_tok) = inner.pop() {
|
if let Some(last_tok) = inner.pop() {
|
||||||
if last_tok.kind != ')' {
|
if last_tok.kind != ')' {
|
||||||
@ -794,7 +797,10 @@ impl Value {
|
|||||||
}
|
}
|
||||||
'[' => {
|
'[' => {
|
||||||
let mut span = toks.next().unwrap().pos();
|
let mut span = toks.next().unwrap().pos();
|
||||||
let mut inner = read_until_closing_square_brace(toks);
|
let mut inner = match read_until_closing_square_brace(toks) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => return Some(Err(e.into())),
|
||||||
|
};
|
||||||
if let Some(last_tok) = inner.pop() {
|
if let Some(last_tok) = inner.pop() {
|
||||||
if last_tok.kind != ']' {
|
if last_tok.kind != ']' {
|
||||||
return Some(Err(("expected \"]\".", span).into()));
|
return Some(Err(("expected \"]\".", span).into()));
|
||||||
|
@ -126,3 +126,5 @@ error!(
|
|||||||
nothing_after_escape,
|
nothing_after_escape,
|
||||||
"@if \\", "Error: Expected expression."
|
"@if \\", "Error: Expected expression."
|
||||||
);
|
);
|
||||||
|
error!(unclosed_dbl_quote, "@if true \" {}", "Error: Expected \".");
|
||||||
|
error!(unclosed_sgl_quote, "@if true ' {}", "Error: Expected '.");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user