remove most remaining unwraps

This commit is contained in:
ConnorSkees 2020-06-18 03:09:24 -04:00
parent de8e7048d8
commit 5fc3748472
17 changed files with 159 additions and 79 deletions

View File

@ -15,7 +15,10 @@ use super::Parser;
impl<'a> Parser<'a> {
pub(super) fn parse_func_args(&mut self) -> SassResult<FuncArgs> {
let mut args: Vec<FuncArg> = Vec::new();
let mut close_paren_span: Span = self.toks.peek().unwrap().pos();
let mut close_paren_span: Span = match self.toks.peek() {
Some(Token { pos, .. }) => *pos,
None => return Err(("expected \")\".", self.span_before).into()),
};
self.whitespace();
while let Some(Token { kind, pos }) = self.toks.next() {
@ -130,9 +133,10 @@ impl<'a> Parser<'a> {
.ok_or(("expected \")\".", self.span_before))?
.pos();
loop {
match self.toks.peek() {
Some(Token { kind: '$', .. }) => {
let Token { pos, .. } = self.toks.next().unwrap();
match self.toks.peek().cloned() {
Some(Token { kind: '$', pos }) => {
span = span.merge(pos);
self.toks.next();
let v = self.parse_identifier_no_interpolation(false)?;
let whitespace = self.whitespace_or_comment();
if let Some(Token { kind: ':', .. }) = self.toks.peek() {

View File

@ -35,7 +35,10 @@ impl<'a> Parser<'a> {
self.whitespace();
let mut body = read_until_closing_curly_brace(self.toks)?;
body.push(self.toks.next().unwrap());
body.push(match self.toks.next() {
Some(tok) => tok,
None => return Err(("expected \"}\".", self.span_before).into()),
});
self.whitespace();
let function = Function::new(self.scopes.last().clone(), args, body, span);

View File

@ -29,7 +29,10 @@ impl<'a> Parser<'a> {
self.whitespace();
let mut body = read_until_closing_curly_brace(self.toks)?;
body.push(self.toks.next().unwrap());
body.push(match self.toks.next() {
Some(tok) => tok,
None => return Err(("expected \"}\".", self.span_before).into()),
});
// todo: `@include` can only give content when `@content` is present within the body
// if `@content` is *not* present and `@include` attempts to give a body, we throw an error

View File

@ -171,8 +171,9 @@ impl<'a> Parser<'a> {
span,
} = self.parse_value_from_vec(toks)?;
span.merge(kind_string.span);
if let Some(Token { kind: ';', .. }) = self.toks.peek() {
kind_string.span.merge(self.toks.next().unwrap().pos());
if let Some(Token { kind: ';', pos }) = self.toks.peek() {
kind_string.span.merge(*pos);
self.toks.next();
}
self.warn(&Spanned {
node: message.to_css_string(span)?,
@ -186,8 +187,9 @@ impl<'a> Parser<'a> {
span,
} = self.parse_value_from_vec(toks)?;
span.merge(kind_string.span);
if let Some(Token { kind: ';', .. }) = self.toks.peek() {
kind_string.span.merge(self.toks.next().unwrap().pos());
if let Some(Token { kind: ';', pos }) = self.toks.peek() {
kind_string.span.merge(*pos);
self.toks.next();
}
self.debug(&Spanned {
node: message.inspect(span)?,
@ -529,7 +531,11 @@ impl<'a> Parser<'a> {
if let Some(tok) = self.toks.next() {
self.whitespace();
match tok.kind.to_ascii_lowercase() {
'i' if self.toks.next().unwrap().kind.to_ascii_lowercase() == 'f' => {
'i' if matches!(
self.toks.peek(),
Some(Token { kind: 'f', .. }) | Some(Token { kind: 'F', .. })
) =>
{
self.toks.next();
let cond = read_until_open_curly_brace(self.toks)?;
self.toks.next();
@ -610,10 +616,10 @@ impl<'a> Parser<'a> {
_ => return Err(("expected \"$\".", self.span_before).into()),
};
self.whitespace();
if self.toks.peek().is_none() {
return Err(("Expected \"from\".", var.span).into());
}
self.span_before = self.toks.peek().unwrap().pos;
self.span_before = match self.toks.peek() {
Some(tok) => tok.pos,
None => return Err(("Expected \"from\".", var.span).into()),
};
if self.parse_identifier()?.node.to_ascii_lowercase() != "from" {
return Err(("Expected \"from\".", var.span).into());
}
@ -644,7 +650,10 @@ impl<'a> Parser<'a> {
'{' => {
return Err(("Expected \"to\" or \"through\".", tok.pos()).into());
}
_ => from_toks.push(self.toks.next().unwrap()),
_ => {
from_toks.push(tok);
self.toks.next();
}
}
}
self.whitespace();
@ -766,7 +775,10 @@ impl<'a> Parser<'a> {
let mut body = read_until_closing_curly_brace(self.toks)?;
body.push(self.toks.next().unwrap());
body.push(match self.toks.next() {
Some(tok) => tok,
None => return Err(("expected \"}\".", self.span_before).into()),
});
self.whitespace();
@ -860,7 +872,10 @@ impl<'a> Parser<'a> {
self.toks.next();
self.whitespace();
let mut body = read_until_closing_curly_brace(self.toks)?;
body.push(self.toks.next().unwrap());
body.push(match self.toks.next() {
Some(tok) => tok,
None => return Err(("expected \"}\".", self.span_before).into()),
});
self.whitespace();
let mut stmts = Vec::new();
@ -1102,7 +1117,10 @@ impl<'a> Parser<'a> {
self.whitespace();
let mut body = read_until_closing_curly_brace(self.toks)?;
body.push(self.toks.next().unwrap());
body.push(match self.toks.next() {
Some(tok) => tok,
None => return Err(("expected \"}\".", self.span_before).into()),
});
self.whitespace();

View File

@ -710,7 +710,7 @@ impl<'a> Parser<'a> {
}
fn peek_interpolation(&mut self) -> SassResult<(Spanned<Value>, usize)> {
let vec = peek_until_closing_curly_brace(self.toks);
let vec = peek_until_closing_curly_brace(self.toks)?;
let peek_counter = vec.len();
self.toks.move_forward(1);
let val = self.parse_value_from_vec(vec)?;

View File

@ -51,11 +51,7 @@ pub(crate) fn eat_number<I: Iterator<Item = Token>>(
) -> SassResult<Spanned<ParsedNumber>> {
let mut whole = String::with_capacity(1);
// TODO: merge this span with chars
let span = if let Some(tok) = toks.peek() {
tok.pos()
} else {
todo!()
};
let span = toks.peek().unwrap().pos;
eat_whole_number(toks, &mut whole);
if toks.peek().is_none() {

View File

@ -8,19 +8,19 @@ use super::{as_hex, hex_char_for, is_name, is_name_start, IsWhitespace};
pub(crate) fn peek_until_closing_curly_brace<I: Iterator<Item = Token>>(
toks: &mut PeekMoreIterator<I>,
) -> Vec<Token> {
) -> SassResult<Vec<Token>> {
let mut t = Vec::new();
let mut nesting = 0;
while let Some(tok) = toks.peek() {
while let Some(tok) = toks.peek().cloned() {
match tok.kind {
q @ '"' | q @ '\'' => {
t.push(*toks.peek().unwrap());
t.push(tok);
toks.move_forward(1);
t.extend(peek_until_closing_quote(toks, q));
t.extend(peek_until_closing_quote(toks, q)?);
}
'{' => {
nesting += 1;
t.push(*toks.peek().unwrap());
t.push(tok);
toks.move_forward(1);
}
'}' => {
@ -28,62 +28,71 @@ pub(crate) fn peek_until_closing_curly_brace<I: Iterator<Item = Token>>(
break;
} else {
nesting -= 1;
t.push(*toks.peek().unwrap());
t.push(tok);
toks.move_forward(1);
}
}
'/' => {
let next = *toks.peek_forward(1).unwrap();
match toks.peek().unwrap().kind {
'/' => peek_until_newline(toks),
let next = *toks
.peek_forward(1)
.ok_or(("Expected expression.", tok.pos))?;
match toks.peek() {
Some(Token { kind: '/', .. }) => peek_until_newline(toks),
_ => t.push(next),
};
continue;
}
_ => {
t.push(*toks.peek().unwrap());
t.push(tok);
toks.move_forward(1);
}
}
}
peek_whitespace(toks);
t
Ok(t)
}
fn peek_until_closing_quote<I: Iterator<Item = Token>>(
toks: &mut PeekMoreIterator<I>,
q: char,
) -> Vec<Token> {
) -> SassResult<Vec<Token>> {
let mut t = Vec::new();
while let Some(tok) = toks.peek() {
while let Some(tok) = toks.peek().cloned() {
match tok.kind {
'"' if q == '"' => {
t.push(*tok);
t.push(tok);
toks.move_forward(1);
break;
}
'\'' if q == '\'' => {
t.push(*tok);
t.push(tok);
toks.move_forward(1);
break;
}
'\\' => {
t.push(*tok);
t.push(*toks.peek_forward(1).unwrap());
t.push(tok);
t.push(match toks.peek_forward(1) {
Some(tok) => *tok,
None => return Err((format!("Expected {}.", q), tok.pos).into()),
});
}
'#' => {
t.push(*tok);
let next = toks.peek().unwrap();
t.push(tok);
let next = match toks.peek() {
Some(tok) => tok,
None => return Err((format!("Expected {}.", q), tok.pos).into()),
};
if next.kind == '{' {
t.push(*toks.peek_forward(1).unwrap());
t.append(&mut peek_until_closing_curly_brace(toks));
t.push(*next);
toks.peek_forward(1);
t.append(&mut peek_until_closing_curly_brace(toks)?);
}
}
_ => t.push(*tok),
_ => t.push(tok),
}
toks.move_forward(1);
}
t
Ok(t)
}
fn peek_until_newline<I: Iterator<Item = Token>>(toks: &mut PeekMoreIterator<I>) {
@ -166,13 +175,13 @@ pub(crate) fn peek_ident_no_interpolation<I: Iterator<Item = Token>>(
.ok_or(("Expected identifier.", span_before))?
.pos();
let mut text = String::new();
if toks.peek().unwrap().kind == '-' {
if let Some(Token { kind: '-', .. }) = toks.peek() {
toks.peek_forward(1);
text.push('-');
if toks.peek().is_none() {
return Ok(Spanned { node: text, span });
}
if toks.peek().unwrap().kind == '-' {
if let Some(Token { kind: '-', .. }) = toks.peek() {
toks.peek_forward(1);
text.push('-');
text.push_str(&peek_ident_body_no_interpolation(toks, unit, span)?.node);

View File

@ -28,10 +28,10 @@ pub(crate) fn read_until_open_curly_brace<I: Iterator<Item = Token>>(
}
'\\' => {
t.push(toks.next().unwrap());
if toks.peek().is_some() {
t.push(toks.next().unwrap());
}
continue;
t.push(match toks.next() {
Some(tok) => tok,
None => continue,
});
}
q @ '"' | q @ '\'' => {
t.push(toks.next().unwrap());
@ -89,9 +89,10 @@ pub(crate) fn read_until_closing_curly_brace<I: Iterator<Item = Token>>(
}
'\\' => {
t.push(toks.next().unwrap());
if toks.peek().is_some() {
t.push(toks.next().unwrap());
}
t.push(match toks.next() {
Some(tok) => tok,
None => continue,
});
}
_ => t.push(toks.next().unwrap()),
}
@ -120,17 +121,22 @@ pub(crate) fn read_until_closing_quote<I: Iterator<Item = Token>>(
}
'\\' => {
t.push(tok);
if toks.peek().is_some() {
t.push(toks.next().unwrap());
}
t.push(match toks.next() {
Some(tok) => tok,
None => return Err((format!("Expected {}.", q), tok.pos).into()),
});
}
'#' => {
t.push(tok);
let next = toks.peek().unwrap();
if next.kind == '{' {
t.push(toks.next().unwrap());
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),
}
@ -156,9 +162,10 @@ pub(crate) fn read_until_semicolon_or_closing_curly_brace<I: Iterator<Item = Tok
}
'\\' => {
t.push(toks.next().unwrap());
if toks.peek().is_some() {
t.push(toks.next().unwrap());
}
t.push(match toks.next() {
Some(tok) => tok,
None => continue,
});
}
'"' | '\'' => {
let quote = toks.next().unwrap();
@ -217,11 +224,11 @@ pub(crate) fn read_until_closing_paren<I: Iterator<Item = Token>>(
continue;
}
'\\' => {
t.push(tok);
if toks.peek().is_some() {
t.push(toks.next().unwrap());
}
continue;
t.push(match toks.next() {
Some(tok) => tok,
None => continue,
});
}
_ => {}
}
@ -253,10 +260,11 @@ pub(crate) fn read_until_closing_square_brace<I: Iterator<Item = Token>>(
continue;
}
'\\' => {
t.push(tok);
if toks.peek().is_some() {
t.push(toks.next().unwrap());
}
t.push(match toks.next() {
Some(tok) => tok,
None => continue,
});
}
_ => {}
}

View File

@ -148,7 +148,7 @@ impl Value {
Self::List(vals, sep, brackets) => match brackets {
Brackets::None => Cow::owned(
vals.iter()
.filter(|x| !x.clone().is_null(span).unwrap_or(false))
.filter(|x| !x.is_null(span).unwrap_or(false))
.map(|x| x.to_css_string(span))
.collect::<SassResult<Vec<Cow<'static, str>>>>()?
.join(sep.as_str()),

View File

@ -46,7 +46,11 @@ test!(
"a {\n color: 2;\n}\n"
);
error!(
#[ignore = "does not fail"]
#[ignore = "expects incorrect char, '{'"]
nothing_after_open,
"a { color:rgb(; }", "Error: expected \")\"."
);
error!(
nothing_after_open_paren_in_fn_args,
"@function foo(", "Error: expected \")\"."
);

View File

@ -68,3 +68,7 @@ test!(
"a {}\n\n@at-root {\n @-ms-viewport { width: device-width; }\n}\n",
"@-ms-viewport {\n width: device-width;\n}\n"
);
error!(
missing_closing_curly_brace,
"@at-root {", "Error: expected \"}\"."
);

View File

@ -48,3 +48,7 @@ test!(
"a {\n @each $i in 1 2 3 {\n color: type-of($i);\n }\n}\n",
"a {\n color: number;\n color: number;\n color: number;\n}\n"
);
error!(
missing_closing_curly_brace,
"@each $i in 1 {", "Error: expected \"}\"."
);

View File

@ -95,3 +95,7 @@ error!(
double_comma_args,
"@function foo($a,$b,,) {}", "Error: expected \")\"."
);
error!(
body_missing_closing_curly_brace,
"@function foo() {", "Error: expected \"}\"."
);

View File

@ -149,3 +149,7 @@ error!(unclosed_sgl_quote, "@if true ' {}", "Error: Expected '.");
error!(unclosed_call_args, "@if a({}", "Error: expected \")\".");
error!(nothing_after_div, "@if a/", "Error: Expected expression.");
error!(multiline_error, "@if \"\n\"{}", "Error: Expected \".");
error!(
nothing_after_i_after_else,
"@if true {} @else i", "Error: expected \"{\"."
);

View File

@ -233,6 +233,10 @@ error!(
undefined_mixin,
"a {@include foo;}", "Error: Undefined mixin."
);
error!(
body_missing_closing_curly_brace,
"@mixin foo() {", "Error: expected \"}\"."
);
test!(
include_empty_args_no_semicolon,
"@mixin c {}\n\na {\n @include c()\n}\n",

View File

@ -134,3 +134,15 @@ test!(
"a {\n color: UrL(http://foo);\n}\n",
"a {\n color: url(http://foo);\n}\n"
);
error!(
url_nothing_after_forward_slash_in_interpolation,
"a { color: url(#{/", "Error: Expected expression."
);
error!(
url_nothing_after_backslash_in_interpolation_in_quote,
"a { color: url(#{\"\\", "Error: Expected \"."
);
error!(
url_nothing_after_hash_in_interpolation_in_quote,
"a { color: url(#{\"#", "Error: Expected \"."
);

View File

@ -107,7 +107,6 @@ test!(
}",
"result {\n root_default: initial;\n root_implicit: inner;\n root_explicit: inner;\n}\n"
);
test!(
if_inside_while,
"$continue_outer: true;
@ -126,3 +125,7 @@ test!(
}",
"a {\n color: red;\n}\n\na {\n color: blue;\n}\n"
);
error!(
missing_closing_curly_brace,
"@while true {", "Error: expected \"}\"."
);