refactor errors using Parser::expect_char

This commit is contained in:
Connor Skees 2020-08-06 21:36:11 -04:00
parent 074d679cbd
commit 0254517095
10 changed files with 73 additions and 129 deletions

View File

@ -72,19 +72,12 @@ impl<'a> Parser<'a> {
}
}
'.' => {
let next = self.toks.next().ok_or(("expected \".\".", span))?;
if next.kind != '.' {
return Err(("expected \".\".", next.pos()).into());
}
let next = self.toks.next().ok_or(("expected \".\".", next.pos()))?;
if next.kind != '.' {
return Err(("expected \".\".", next.pos()).into());
}
self.expect_char('.')?;
self.expect_char('.')?;
self.whitespace_or_comment();
let next = self.toks.next().ok_or(("expected \")\".", next.pos()))?;
if next.kind != ')' {
return Err(("expected \")\".", next.pos()).into());
}
self.expect_char(')')?;
is_variadic = true;
@ -119,6 +112,7 @@ impl<'a> Parser<'a> {
}
self.whitespace_or_comment();
// TODO: this should NOT eat the opening curly brace
// todo: self.expect_char('{')?;
match self.toks.next() {
Some(v) if v.kind == '{' => {}
Some(..) | None => return Err(("expected \"{\".", close_paren_span).into()),
@ -225,11 +219,7 @@ impl<'a> Parser<'a> {
return Err(("expected \")\".", pos).into());
}
self.toks.next();
if let Some(Token { kind: '.', .. }) = self.toks.peek() {
self.toks.next();
} else {
return Err(("expected \".\".", pos).into());
}
self.expect_char('.')?;
} else {
return Err(("expected \")\".", pos).into());
}
@ -323,23 +313,16 @@ impl<'a> Parser<'a> {
self.whitespace_or_comment();
continue;
}
Some(Token { kind: '.', pos }) => {
let pos = *pos;
Some(Token { kind: '.', .. }) => {
self.toks.next();
if let Some(Token { kind: '.', pos }) = self.toks.peek().cloned() {
if !name.is_empty() {
return Err(("expected \")\".", pos).into());
}
self.toks.next();
if let Some(Token { kind: '.', .. }) = self.toks.peek() {
self.toks.next();
} else {
return Err(("expected \".\".", pos).into());
}
} else {
return Err(("expected \")\".", pos).into());
self.expect_char('.')?;
if !name.is_empty() {
return Err(("expected \")\".", self.span_before).into());
}
self.expect_char('.')?;
}
Some(Token { pos, .. }) => {
return Err(("expected \")\".", *pos).into());

View File

@ -24,14 +24,10 @@ impl<'a> Parser<'a> {
let init_cond = self.parse_value(true, &|_| false)?.node;
// consume the open curly brace
let span_before = match self.toks.next() {
Some(Token { kind: '{', pos }) => pos,
Some(..) | None => return Err(("expected \"{\".", self.span_before).into()),
};
self.expect_char('{')?;
if self.toks.peek().is_none() {
return Err(("expected \"}\".", span_before).into());
return Err(("expected \"}\".", self.span_before).into());
}
self.whitespace_or_comment();
@ -89,12 +85,7 @@ impl<'a> Parser<'a> {
false
} else {
let v = self.parse_value(true, &|_| false)?.node.is_true();
match self.toks.next() {
Some(Token { kind: '{', .. }) => {}
Some(..) | None => {
return Err(("expected \"{\".", self.span_before).into())
}
}
self.expect_char('{')?;
v
};
if cond {
@ -164,17 +155,15 @@ impl<'a> Parser<'a> {
}
pub(super) fn parse_for(&mut self) -> SassResult<Vec<Stmt>> {
// todo: whitespace or comment
self.whitespace();
let next = self
.toks
.next()
.ok_or(("expected \"$\".", self.span_before))?;
let var: Spanned<Identifier> = match next.kind {
'$' => self
.parse_identifier_no_interpolation(false)?
.map_node(|i| i.into()),
_ => return Err(("expected \"$\".", self.span_before).into()),
};
// todo: test for error here
self.expect_char('$')?;
let var = self
.parse_identifier_no_interpolation(false)?
.map_node(|n| n.into());
self.whitespace();
self.span_before = match self.toks.peek() {
Some(tok) => tok.pos,
@ -278,11 +267,7 @@ impl<'a> Parser<'a> {
}
};
// consume the open curly brace
match self.toks.next() {
Some(Token { kind: '{', pos }) => pos,
Some(..) | None => return Err(("expected \"{\".", to_val.span).into()),
};
self.expect_char('{')?;
let body = read_until_closing_curly_brace(self.toks)?;
self.toks.next();
@ -443,15 +428,11 @@ impl<'a> Parser<'a> {
let mut vars: Vec<Spanned<Identifier>> = Vec::new();
loop {
let next = self
.toks
.next()
.ok_or(("expected \"$\".", self.span_before))?;
self.expect_char('$')?;
match next.kind {
'$' => vars.push(self.parse_identifier()?.map_node(|i| i.into())),
_ => return Err(("expected \"$\".", next.pos()).into()),
}
vars.push(self.parse_identifier()?.map_node(|i| i.into()));
// todo: whitespace or comment
self.whitespace();
if self
.toks

View File

@ -40,11 +40,9 @@ impl<'a> Parser<'a> {
}
self.whitespace_or_comment();
let args = match self.toks.next() {
Some(Token { kind: '(', .. }) => self.parse_func_args()?,
Some(Token { pos, .. }) => return Err(("expected \"(\".", pos).into()),
None => return Err(("expected \"(\".", span).into()),
};
self.expect_char('(')?;
let args = self.parse_func_args()?;
self.whitespace();

View File

@ -63,9 +63,8 @@ impl<'a, 'b> KeyframesSelectorParser<'a, 'b> {
num.push_str(&eat_whole_number(self.parser.toks));
}
if !matches!(self.parser.toks.next(), Some(Token { kind: '%', .. })) {
return Err(("expected \"%\".", tok.pos).into());
}
self.parser.expect_char('%')?;
selectors.push(KeyframesSelector::Percent(num.into_boxed_str()));
}
'{' => break,

View File

@ -104,9 +104,7 @@ impl<'a> Parser<'a> {
ident.node.make_ascii_lowercase();
if ident.node == "using" {
self.whitespace_or_comment();
if !matches!(self.toks.next(), Some(Token { kind: '(', .. })) {
return Err(("expected \"(\".", ident.span).into());
}
self.expect_char('(')?;
Some(self.parse_func_args()?)
} else {

View File

@ -903,9 +903,7 @@ impl<'a> Parser<'a> {
self.whitespace();
if !matches!(self.toks.next(), Some(Token { kind: '{', .. })) {
return Err(("expected \"{\".", self.span_before).into());
}
self.expect_char('{')?;
let raw_body = self.parse_stmt()?;

View File

@ -598,6 +598,7 @@ impl<'a> Parser<'a> {
};
// todo: the above shouldn't eat the closing paren
if let Some(last_tok) = inner.pop() {
// todo: we should remove this like we did for square braces
if last_tok.kind != ')' {
return Some(Err(("expected \")\".", span).into()));
}

View File

@ -29,9 +29,9 @@ impl<'a> Parser<'a> {
assert!(matches!(self.toks.next(), Some(Token { kind: '$', .. })));
let ident: Identifier = self.parse_identifier_no_interpolation(false)?.node.into();
self.whitespace();
if !matches!(self.toks.next(), Some(Token { kind: ':', .. })) {
return Err(("expected \":\".", self.span_before).into());
}
self.expect_char(':')?;
let VariableValue {
val_toks,
global,

View File

@ -5,7 +5,9 @@ use std::{
use codemap::Span;
use crate::{common::QuoteKind, error::SassResult, parse::Parser, utils::is_ident, value::Value};
use crate::{
common::QuoteKind, error::SassResult, parse::Parser, utils::is_ident, value::Value, Token,
};
use super::{Namespace, QualifiedName};
@ -41,13 +43,8 @@ impl Hash for Attribute {
fn attribute_name(parser: &mut Parser<'_>, start: Span) -> SassResult<QualifiedName> {
let next = parser.toks.peek().ok_or(("Expected identifier.", start))?;
if next.kind == '*' {
let pos = next.pos;
parser.toks.next();
if parser.toks.peek().ok_or(("expected \"|\".", pos))?.kind != '|' {
return Err(("expected \"|\".", pos).into());
}
parser.span_before = parser.toks.next().unwrap().pos();
parser.expect_char('|')?;
let ident = parser.parse_identifier()?.node;
return Ok(QualifiedName {
@ -89,19 +86,18 @@ fn attribute_name(parser: &mut Parser<'_>, start: Span) -> SassResult<QualifiedN
}
fn attribute_operator(parser: &mut Parser<'_>) -> SassResult<AttributeOp> {
let start = parser.span_before;
let op = match parser.toks.next().ok_or(("Expected \"]\".", start))?.kind {
'=' => return Ok(AttributeOp::Equals),
'~' => AttributeOp::Include,
'|' => AttributeOp::Dash,
'^' => AttributeOp::Prefix,
'$' => AttributeOp::Suffix,
'*' => AttributeOp::Contains,
_ => return Err(("Expected \"]\".", start).into()),
let op = match parser.toks.next() {
Some(Token { kind: '=', .. }) => return Ok(AttributeOp::Equals),
Some(Token { kind: '~', .. }) => AttributeOp::Include,
Some(Token { kind: '|', .. }) => AttributeOp::Dash,
Some(Token { kind: '^', .. }) => AttributeOp::Prefix,
Some(Token { kind: '$', .. }) => AttributeOp::Suffix,
Some(Token { kind: '*', .. }) => AttributeOp::Contains,
Some(..) | None => return Err(("Expected \"]\".", parser.span_before).into()),
};
if parser.toks.next().ok_or(("expected \"=\".", start))?.kind != '=' {
return Err(("expected \"=\".", start).into());
}
parser.expect_char('=')?;
Ok(op)
}
impl Attribute {
@ -145,25 +141,23 @@ impl Attribute {
};
parser.whitespace();
let peek = parser.toks.peek().ok_or(("expected more input.", start))?;
let modifier = match peek.kind {
c if c.is_alphabetic() => Some(c),
let modifier = match parser.toks.peek().cloned() {
Some(Token {
kind: c @ 'a'..='z',
..
})
| Some(Token {
kind: c @ 'A'..='Z',
..
}) => {
parser.toks.next();
parser.whitespace();
Some(c)
}
_ => None,
};
let pos = peek.pos();
if modifier.is_some() {
parser.toks.next();
parser.whitespace();
}
if parser.toks.peek().ok_or(("expected \"]\".", pos))?.kind != ']' {
return Err(("expected \"]\".", pos).into());
}
parser.toks.next();
parser.expect_char(']')?;
Ok(Attribute {
op,

View File

@ -317,14 +317,14 @@ impl<'a, 'b> SelectorParser<'a, 'b> {
if SELECTOR_PSEUDO_ELEMENTS.contains(&unvendored) {
selector = Some(Box::new(self.parse_selector_list()?));
self.parser.whitespace();
self.expect_closing_paren()?;
self.parser.expect_char(')')?;
} else {
argument = Some(self.declaration_value()?.into_boxed_str());
}
} else if SELECTOR_PSEUDO_CLASSES.contains(&unvendored) {
selector = Some(Box::new(self.parse_selector_list()?));
self.parser.whitespace();
self.expect_closing_paren()?;
self.parser.expect_char(')')?;
} else if unvendored == "nth-child" || unvendored == "nth-last-child" {
let mut this_arg = self.parse_a_n_plus_b()?;
let found_whitespace = self.parser.whitespace();
@ -339,7 +339,7 @@ impl<'a, 'b> SelectorParser<'a, 'b> {
}
_ => {}
}
self.expect_closing_paren()?;
self.parser.expect_char(')')?;
argument = Some(this_arg.into_boxed_str());
} else {
argument = Some(
@ -541,14 +541,6 @@ impl<'a, 'b> SelectorParser<'a, 'b> {
Err((format!("Expected \"{}\".", s), self.span).into())
}
}
fn expect_closing_paren(&mut self) -> SassResult<()> {
if let Some(Token { kind: ')', .. }) = self.parser.toks.next() {
Ok(())
} else {
Err(("expected \")\".", self.span).into())
}
}
}
/// Returns whether `c` can start a simple selector other than a type