add more span information
this resolves a lot of panics that occurred when there was no more input
This commit is contained in:
parent
6e7f1cc319
commit
b58ed29fd0
@ -221,7 +221,7 @@ pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(
|
||||
devour_whitespace(toks);
|
||||
while let Some(Token { kind, pos }) = toks.next() {
|
||||
let name = match kind {
|
||||
'$' => eat_ident(toks, scope, super_selector)?,
|
||||
'$' => eat_ident(toks, scope, super_selector, pos)?,
|
||||
')' => {
|
||||
close_paren_span = pos;
|
||||
break;
|
||||
|
@ -98,7 +98,7 @@ pub(crate) fn parse_each<I: Iterator<Item = Token>>(
|
||||
let next = toks.next().ok_or(("expected \"$\".", span))?;
|
||||
span = next.pos();
|
||||
match next.kind {
|
||||
'$' => vars.push(eat_ident(toks, scope, super_selector)?),
|
||||
'$' => vars.push(eat_ident(toks, scope, super_selector, next.pos)?),
|
||||
_ => return Err(("expected \"$\".", next.pos()).into()),
|
||||
}
|
||||
devour_whitespace(toks);
|
||||
@ -114,10 +114,7 @@ pub(crate) fn parse_each<I: Iterator<Item = Token>>(
|
||||
break;
|
||||
}
|
||||
}
|
||||
if toks.peek().is_none() {
|
||||
todo!()
|
||||
}
|
||||
let i = eat_ident(toks, scope, super_selector)?;
|
||||
let i = eat_ident(toks, scope, super_selector, span)?;
|
||||
if i.node.to_ascii_lowercase() != "in" {
|
||||
return Err(("Expected \"in\".", i.span).into());
|
||||
}
|
||||
|
@ -89,14 +89,17 @@ pub(crate) fn parse_for<I: Iterator<Item = Token>>(
|
||||
span: Span,
|
||||
) -> SassResult<AtRule> {
|
||||
devour_whitespace(toks);
|
||||
let var = match toks.next().ok_or(("expected \"$\".", span))?.kind {
|
||||
'$' => eat_ident(toks, scope, super_selector)?,
|
||||
let next = toks.next().ok_or(("expected \"$\".", span))?;
|
||||
let var = match next.kind {
|
||||
'$' => eat_ident(toks, scope, super_selector, next.pos)?,
|
||||
_ => return Err(("expected \"$\".", span).into()),
|
||||
};
|
||||
devour_whitespace(toks);
|
||||
if toks.peek().is_none()
|
||||
|| eat_ident(toks, scope, super_selector)?.to_ascii_lowercase() != "from"
|
||||
{
|
||||
if toks.peek().is_none() {
|
||||
return Err(("Expected \"from\".", var.span).into());
|
||||
}
|
||||
let span_before = toks.peek().unwrap().pos;
|
||||
if eat_ident(toks, scope, super_selector, span_before)?.to_ascii_lowercase() != "from" {
|
||||
return Err(("Expected \"from\".", var.span).into());
|
||||
}
|
||||
devour_whitespace(toks);
|
||||
|
@ -44,8 +44,9 @@ impl Function {
|
||||
toks: &mut PeekMoreIterator<I>,
|
||||
scope: Scope,
|
||||
super_selector: &Selector,
|
||||
span_before: Span,
|
||||
) -> SassResult<(String, Function)> {
|
||||
let Spanned { node: name, span } = eat_ident(toks, &scope, super_selector)?;
|
||||
let Spanned { node: name, span } = eat_ident(toks, &scope, super_selector, span_before)?;
|
||||
devour_whitespace(toks);
|
||||
let args = match toks.next() {
|
||||
Some(Token { kind: '(', .. }) => eat_func_args(toks, &scope, super_selector)?,
|
||||
|
@ -57,11 +57,13 @@ impl If {
|
||||
if first_char != 'e' && first_char != 'E' {
|
||||
break;
|
||||
}
|
||||
toks.next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
if eat_ident(toks, &Scope::new(), &Selector::new())?.to_ascii_lowercase() == "else"
|
||||
let span_before = toks.next().unwrap().pos;
|
||||
if eat_ident(toks, &Scope::new(), &Selector::new(), span_before)?
|
||||
.to_ascii_lowercase()
|
||||
== "else"
|
||||
{
|
||||
devour_whitespace(toks);
|
||||
if let Some(tok) = toks.next() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::vec::IntoIter;
|
||||
|
||||
use codemap::Spanned;
|
||||
use codemap::{Span, Spanned};
|
||||
|
||||
use peekmore::{PeekMore, PeekMoreIterator};
|
||||
|
||||
@ -34,9 +34,10 @@ impl Mixin {
|
||||
toks: &mut PeekMoreIterator<I>,
|
||||
scope: &Scope,
|
||||
super_selector: &Selector,
|
||||
span_before: Span,
|
||||
) -> SassResult<Spanned<(String, Mixin)>> {
|
||||
devour_whitespace(toks);
|
||||
let Spanned { node: name, span } = eat_ident(toks, scope, super_selector)?;
|
||||
let Spanned { node: name, span } = eat_ident(toks, scope, super_selector, span_before)?;
|
||||
devour_whitespace(toks);
|
||||
let args = match toks.next() {
|
||||
Some(Token { kind: '(', .. }) => eat_func_args(toks, scope, super_selector)?,
|
||||
@ -185,9 +186,10 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
||||
scope: &Scope,
|
||||
super_selector: &Selector,
|
||||
content: Option<&[Spanned<Stmt>]>,
|
||||
span_before: Span,
|
||||
) -> SassResult<Vec<Spanned<Stmt>>> {
|
||||
devour_whitespace_or_comment(toks)?;
|
||||
let name = eat_ident(toks, scope, super_selector)?;
|
||||
let name = eat_ident(toks, scope, super_selector, span_before)?;
|
||||
|
||||
devour_whitespace_or_comment(toks)?;
|
||||
|
||||
|
@ -121,14 +121,15 @@ impl AtRule {
|
||||
let Spanned {
|
||||
node: (name, mixin),
|
||||
span,
|
||||
} = Mixin::decl_from_tokens(toks, scope, super_selector)?;
|
||||
} = Mixin::decl_from_tokens(toks, scope, super_selector, kind_span)?;
|
||||
Spanned {
|
||||
node: AtRule::Mixin(name, Box::new(mixin)),
|
||||
span,
|
||||
}
|
||||
}
|
||||
AtRuleKind::Function => {
|
||||
let (name, func) = Function::decl_from_tokens(toks, scope.clone(), super_selector)?;
|
||||
let (name, func) =
|
||||
Function::decl_from_tokens(toks, scope.clone(), super_selector, kind_span)?;
|
||||
Spanned {
|
||||
node: AtRule::Function(name, Box::new(func)),
|
||||
span: kind_span,
|
||||
@ -236,7 +237,13 @@ impl AtRule {
|
||||
span: kind_span,
|
||||
},
|
||||
AtRuleKind::Include => Spanned {
|
||||
node: AtRule::Include(eat_include(toks, scope, super_selector, content)?),
|
||||
node: AtRule::Include(eat_include(
|
||||
toks,
|
||||
scope,
|
||||
super_selector,
|
||||
content,
|
||||
kind_span,
|
||||
)?),
|
||||
span: kind_span,
|
||||
},
|
||||
AtRuleKind::Import => todo!("@import not yet implemented"),
|
||||
|
25
src/lib.rs
25
src/lib.rs
@ -197,6 +197,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
||||
scope,
|
||||
super_selector,
|
||||
String::new(),
|
||||
tok.unwrap().pos,
|
||||
)?;
|
||||
return Ok(Some(Spanned {
|
||||
node: Style::from_tokens(toks, scope, super_selector, prop)?,
|
||||
@ -207,7 +208,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
||||
}
|
||||
}
|
||||
';' => {
|
||||
toks.next();
|
||||
let span_before = toks.next().unwrap().pos;
|
||||
devour_whitespace(toks);
|
||||
// special edge case where there was no space between the colon
|
||||
// in a style, e.g. `color:red`. todo: refactor
|
||||
@ -223,7 +224,13 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
||||
span,
|
||||
}));
|
||||
}
|
||||
let property = Style::parse_property(&mut v, scope, super_selector, String::new())?;
|
||||
let property = Style::parse_property(
|
||||
&mut v,
|
||||
scope,
|
||||
super_selector,
|
||||
String::new(),
|
||||
span_before,
|
||||
)?;
|
||||
let value = Style::parse_value(&mut v, scope, super_selector)?;
|
||||
return Ok(Some(Spanned {
|
||||
node: Expr::Style(Box::new(Style { property, value })),
|
||||
@ -244,8 +251,13 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
||||
// and no semicolon following the style
|
||||
// in a style `color:red`. todo: refactor
|
||||
let mut v = values.into_iter().peekmore();
|
||||
let property =
|
||||
Style::parse_property(&mut v, scope, super_selector, String::new())?;
|
||||
let property = Style::parse_property(
|
||||
&mut v,
|
||||
scope,
|
||||
super_selector,
|
||||
String::new(),
|
||||
tok.pos,
|
||||
)?;
|
||||
let value = Style::parse_value(&mut v, scope, super_selector)?;
|
||||
return Ok(Some(Spanned {
|
||||
node: Expr::Style(Box::new(Style { property, value })),
|
||||
@ -327,10 +339,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
||||
}
|
||||
'@' => {
|
||||
let span = toks.next().unwrap().pos();
|
||||
if toks.peek().is_none() {
|
||||
return Err(("Expected identifier.", span).into());
|
||||
}
|
||||
let Spanned { node: ident, span } = eat_ident(toks, scope, super_selector)?;
|
||||
let Spanned { node: ident, span } = eat_ident(toks, scope, super_selector, span)?;
|
||||
devour_whitespace(toks);
|
||||
let rule = AtRule::from_tokens(
|
||||
&AtRuleKind::from(ident.as_str()),
|
||||
|
@ -35,15 +35,16 @@ fn attribute_name<I: Iterator<Item = Token>>(
|
||||
return Err(("expected \"|\".", pos).into());
|
||||
}
|
||||
|
||||
toks.next();
|
||||
let span_before = toks.next().unwrap().pos();
|
||||
|
||||
let ident = eat_ident(toks, scope, super_selector)?.node;
|
||||
let ident = eat_ident(toks, scope, super_selector, span_before)?.node;
|
||||
return Ok(QualifiedName {
|
||||
ident,
|
||||
namespace: Some('*'.to_string()),
|
||||
});
|
||||
}
|
||||
let name_or_namespace = eat_ident(toks, scope, super_selector)?;
|
||||
let span_before = next.pos;
|
||||
let name_or_namespace = eat_ident(toks, scope, super_selector, span_before)?;
|
||||
match toks.peek() {
|
||||
Some(v) if v.kind != '|' => {
|
||||
return Ok(QualifiedName {
|
||||
@ -67,8 +68,8 @@ fn attribute_name<I: Iterator<Item = Token>>(
|
||||
}
|
||||
None => return Err(("expected more input.", name_or_namespace.span).into()),
|
||||
}
|
||||
toks.next();
|
||||
let ident = eat_ident(toks, scope, super_selector)?.node;
|
||||
let span_before = toks.next().unwrap().pos();
|
||||
let ident = eat_ident(toks, scope, super_selector, span_before)?.node;
|
||||
Ok(QualifiedName {
|
||||
ident,
|
||||
namespace: Some(name_or_namespace.node),
|
||||
@ -118,7 +119,7 @@ impl Attribute {
|
||||
devour_whitespace(toks);
|
||||
|
||||
let peek = toks.peek().ok_or(("expected more input.", start))?;
|
||||
|
||||
let span_before = peek.pos;
|
||||
let value = match peek.kind {
|
||||
q @ '\'' | q @ '"' => {
|
||||
toks.next();
|
||||
@ -127,7 +128,7 @@ impl Attribute {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
_ => eat_ident(toks, scope, super_selector)?.node,
|
||||
_ => eat_ident(toks, scope, super_selector, span_before)?.node,
|
||||
};
|
||||
devour_whitespace(toks);
|
||||
|
||||
|
13
src/style.rs
13
src/style.rs
@ -1,6 +1,6 @@
|
||||
use peekmore::PeekMoreIterator;
|
||||
|
||||
use codemap::Spanned;
|
||||
use codemap::{Span, Spanned};
|
||||
|
||||
use crate::error::SassResult;
|
||||
use crate::scope::Scope;
|
||||
@ -22,8 +22,9 @@ impl Style {
|
||||
scope: &Scope,
|
||||
super_selector: &Selector,
|
||||
super_property: String,
|
||||
span_before: Span,
|
||||
) -> SassResult<String> {
|
||||
StyleParser::new(scope, super_selector).parse_property(toks, super_property)
|
||||
StyleParser::new(scope, super_selector).parse_property(toks, super_property, span_before)
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> SassResult<String> {
|
||||
@ -95,10 +96,11 @@ impl<'a> StyleParser<'a> {
|
||||
while let Some(tok) = toks.peek() {
|
||||
match tok.kind {
|
||||
'{' => {
|
||||
toks.next();
|
||||
let span_before = toks.next().unwrap().pos;
|
||||
devour_whitespace(toks);
|
||||
loop {
|
||||
let property = self.parse_property(toks, super_property.clone())?;
|
||||
let property =
|
||||
self.parse_property(toks, super_property.clone(), span_before)?;
|
||||
if let Some(tok) = toks.peek() {
|
||||
if tok.kind == '{' {
|
||||
match self.eat_style_group(toks, property, scope)? {
|
||||
@ -194,9 +196,10 @@ impl<'a> StyleParser<'a> {
|
||||
&self,
|
||||
toks: &mut PeekMoreIterator<I>,
|
||||
mut super_property: String,
|
||||
span_before: Span,
|
||||
) -> SassResult<String> {
|
||||
devour_whitespace(toks);
|
||||
let property = eat_ident(toks, self.scope, self.super_selector)?.node;
|
||||
let property = eat_ident(toks, self.scope, self.super_selector, span_before)?.node;
|
||||
devour_whitespace_or_comment(toks)?;
|
||||
if toks.peek().is_some() && toks.peek().unwrap().kind == ':' {
|
||||
toks.next();
|
||||
|
@ -164,8 +164,13 @@ impl<'a> StyleSheetParser<'a> {
|
||||
continue;
|
||||
}
|
||||
'$' => {
|
||||
self.lexer.next();
|
||||
let name = eat_ident(&mut self.lexer, &Scope::new(), &Selector::new())?;
|
||||
let span_before = self.lexer.next().unwrap().pos();
|
||||
let name = eat_ident(
|
||||
&mut self.lexer,
|
||||
&Scope::new(),
|
||||
&Selector::new(),
|
||||
span_before
|
||||
)?;
|
||||
devour_whitespace(&mut self.lexer);
|
||||
let Token { kind, pos } = self
|
||||
.lexer
|
||||
@ -194,8 +199,13 @@ impl<'a> StyleSheetParser<'a> {
|
||||
}
|
||||
}
|
||||
'@' => {
|
||||
self.lexer.next();
|
||||
let Spanned { node: at_rule_kind, span } = eat_ident(&mut self.lexer, &Scope::new(), &Selector::new())?;
|
||||
let span_before = self.lexer.next().unwrap().pos();
|
||||
let Spanned { node: at_rule_kind, span } = eat_ident(
|
||||
&mut self.lexer,
|
||||
&Scope::new(),
|
||||
&Selector::new(),
|
||||
span_before
|
||||
)?;
|
||||
if at_rule_kind.is_empty() {
|
||||
return Err(("Expected identifier.", span).into());
|
||||
}
|
||||
@ -205,6 +215,7 @@ impl<'a> StyleSheetParser<'a> {
|
||||
&Scope::new(),
|
||||
&Selector::new(),
|
||||
None,
|
||||
span
|
||||
)?),
|
||||
AtRuleKind::Import => {
|
||||
devour_whitespace(&mut self.lexer);
|
||||
|
@ -169,9 +169,12 @@ pub(crate) fn eat_ident<I: Iterator<Item = Token>>(
|
||||
toks: &mut PeekMoreIterator<I>,
|
||||
scope: &Scope,
|
||||
super_selector: &Selector,
|
||||
span_before: Span,
|
||||
) -> SassResult<Spanned<String>> {
|
||||
// TODO: take span as param because we use unwrap here
|
||||
let mut span = toks.peek().unwrap().pos();
|
||||
let mut span = toks
|
||||
.peek()
|
||||
.ok_or(("Expected identifier.", span_before))?
|
||||
.pos();
|
||||
let mut text = String::new();
|
||||
if toks.peek().unwrap().kind == '-' {
|
||||
toks.next();
|
||||
|
@ -52,7 +52,7 @@ fn parse_hex<I: Iterator<Item = Token>>(
|
||||
s.push(tok.kind);
|
||||
}
|
||||
} else {
|
||||
let i = eat_ident(toks, scope, super_selector)?;
|
||||
let i = eat_ident(toks, scope, super_selector, span)?;
|
||||
if i.node.chars().all(|c| c.is_ascii_hexdigit()) {
|
||||
s = i.node;
|
||||
span = span.merge(i.span);
|
||||
@ -524,8 +524,9 @@ impl Value {
|
||||
toks: &mut PeekMoreIterator<I>,
|
||||
scope: &Scope,
|
||||
super_selector: &Selector,
|
||||
span_before: Span,
|
||||
) -> SassResult<IntermediateValue> {
|
||||
let Spanned { node: mut s, span } = eat_ident(toks, scope, super_selector)?;
|
||||
let Spanned { node: mut s, span } = eat_ident(toks, scope, super_selector, span_before)?;
|
||||
|
||||
let lower = s.to_ascii_lowercase();
|
||||
|
||||
@ -636,7 +637,7 @@ impl Value {
|
||||
|| (!kind.is_ascii() && !kind.is_control())
|
||||
|| (kind == '-' && next_is_hypen(toks)) =>
|
||||
{
|
||||
return Some(Self::ident(toks, scope, super_selector));
|
||||
return Some(Self::ident(toks, scope, super_selector, span));
|
||||
}
|
||||
'0'..='9' | '.' => {
|
||||
let Spanned {
|
||||
@ -723,9 +724,10 @@ impl Value {
|
||||
})
|
||||
}
|
||||
'#' => {
|
||||
if let Some(Token { kind: '{', .. }) = toks.peek_forward(1) {
|
||||
if let Some(Token { kind: '{', pos }) = toks.peek_forward(1) {
|
||||
let span_before = *pos;
|
||||
toks.reset_view();
|
||||
return Some(Self::ident(toks, scope, super_selector));
|
||||
return Some(Self::ident(toks, scope, super_selector, span_before));
|
||||
}
|
||||
toks.reset_view();
|
||||
toks.next();
|
||||
@ -847,7 +849,7 @@ impl Value {
|
||||
})));
|
||||
}
|
||||
devour_whitespace(toks);
|
||||
let v = match eat_ident(toks, scope, super_selector) {
|
||||
let v = match eat_ident(toks, scope, super_selector, span) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Some(Err(e)),
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user