make parsing of toplevel tokens more robust

This commit is contained in:
ConnorSkees 2020-05-24 07:43:54 -04:00
parent bb89a865d4
commit a01ed981ce
5 changed files with 73 additions and 26 deletions

View File

@ -400,5 +400,12 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
_ => values.push(toks.next().unwrap()),
};
}
// if `values` is not empty, there was an unexpected toplevel token
// that should be part of a selector
if let Some(v) = values.pop() {
return Err(("expected \"{\".", v.pos).into());
}
Ok(None)
}

View File

@ -151,23 +151,40 @@ struct StyleSheetParser<'a> {
path: &'a Path,
}
fn is_selector_char(c: char) -> bool {
c.is_alphanumeric()
|| matches!(
c,
'_' | '-' | '[' | '#' | ':' | '*' | '%' | '.' | '>' | '\\' | '+'
)
}
impl<'a> StyleSheetParser<'a> {
fn parse_toplevel(mut self) -> SassResult<(Vec<Spanned<Stmt>>, Scope)> {
let mut rules: Vec<Spanned<Stmt>> = Vec::new();
devour_whitespace(self.lexer);
while let Some(Token { kind, .. }) = self.lexer.peek() {
match kind {
_ if is_selector_char(*kind) => {
'a'..='z'
| 'A'..='Z'
| '0'..='9'
| '['
| '\\'
| ']'
| '^'
| '_'
| '-'
| '#'
| ':'
| '*'
| '%'
| '.'
| '>'
| '+'
| '='
| ','
| '('
| ')'
| '<'
| '?'
| '~'
| '|'
| '\u{7f}'..=std::char::MAX => {
rules.extend(self.eat_rules(&Selector::new(), &mut Scope::new())?)
}
'\t' | '\n' | ' ' => {
'\t' | '\n' | ' ' | ';' => {
self.lexer.next();
continue;
}
@ -331,20 +348,16 @@ impl<'a> StyleSheetParser<'a> {
)
.into())
}
c if c.is_control() => {
'\u{0}'..='\u{8}' | '\u{b}'..='\u{1f}' => {
return Err(("expected selector.", self.lexer.next().unwrap().pos).into());
}
',' | '!' | '(' | ')' => {
return Err(("expected \"{\".", self.lexer.next().unwrap().pos).into());
}
'{' => {
'{' | '!' => {
return Err(("expected \"}\".", self.lexer.next().unwrap().pos).into());
}
'`' | '\'' | '"' => {
return Err(("expected selector.", self.lexer.next().unwrap().pos).into());
}
'}' => return Err(("unmatched \"}\".", self.lexer.next().unwrap().pos).into()),
_ => todo!("unexpected toplevel token: {:?}", kind),
};
}
Ok((rules, GLOBAL_SCOPE.with(|s| s.borrow().clone())))

View File

@ -83,20 +83,15 @@ error!(
"a {$a", "Error: expected \":\"."
);
error!(toplevel_comma, "a {},", "Error: expected \"{\".");
error!(toplevel_exclamation, "! {}", "Error: expected \"{\".");
error!(toplevel_exclamation_alone, "!", "Error: expected \"}\".");
error!(toplevel_exclamation, "! {}", "Error: expected \"}\".");
error!(toplevel_backtick, "` {}", "Error: expected selector.");
error!(
toplevel_open_curly_brace,
"{ {color: red;}", "Error: expected \"}\"."
);
error!(
toplevel_open_paren,
"(", "Error: expected \"{\"."
);
error!(
toplevel_close_paren,
"(", "Error: expected \"{\"."
);
error!(toplevel_open_paren, "(", "Error: expected \"{\".");
error!(toplevel_close_paren, "(", "Error: expected \"{\".");
error!(
backtick_in_value,
"a {color:`red;}", "Error: Expected expression."
@ -184,3 +179,24 @@ error!(
nothing_after_gt,
"a {color: 1 >", "Error: Expected expression."
);
error!(toplevel_eq_alone, "=", "Error: expected \"{\".");
error!(toplevel_gt_alone, ">", "Error: expected \"{\".");
error!(toplevel_lt_alone, "<", "Error: expected \"{\".");
error!(toplevel_question_alone, "?", "Error: expected \"{\".");
error!(toplevel_caret_alone, "^", "Error: expected \"{\".");
test!(toplevel_gt_as_selector, "> {}", "");
test!(toplevel_tilde_as_selector, "~ {}", "");
error!(toplevel_lt_as_selector, "< {}", "Error: expected selector.");
error!(
toplevel_question_as_selector,
"? {}", "Error: expected selector."
);
error!(
toplevel_caret_as_selector,
"^ {}", "Error: expected selector."
);
error!(toplevel_eq, "= {}", "Error: expected selector.");
error!(value_after_style, "a {}a", "Error: expected \"{\".");
test!(whitespace_after_style, "a {}\t\n ", "");
test!(toplevel_semicolon, ";", "");
test!(toplevel_semicolon_after_style, "a {};", "");

View File

@ -15,7 +15,7 @@ test!(
test!(
same_function_equal,
"@function user-defined() {@return null}
a {b: get-function(user-defined) == get-function(user-defined)}s",
a {b: get-function(user-defined) == get-function(user-defined)}",
"a {\n b: true;\n}\n"
);
test!(

View File

@ -530,3 +530,14 @@ test!(
"+ {\n color: &;\n}\n",
"+ {\n color: +;\n}\n"
);
error!(
#[ignore = "namespaces are not yet parsed correctly"]
empty_namespace,
"| {}", "Error: Expected identifier."
);
test!(
#[ignore = "namespaces are not yet parsed correctly"]
simple_namespace,
"|f {\n color: &;\n}\n",
"|f {\n color: |f;\n}\n"
);