add more span information

this resolves a lot of panics that occurred when there was no more input
This commit is contained in:
ConnorSkees 2020-05-17 00:35:07 -04:00
parent 6e7f1cc319
commit b58ed29fd0
13 changed files with 93 additions and 52 deletions

View File

@ -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;

View File

@ -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());
}

View File

@ -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);

View File

@ -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)?,

View File

@ -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() {

View File

@ -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)?;

View File

@ -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"),

View File

@ -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()),

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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)),
};