make parsing of toplevel tokens more robust
This commit is contained in:
parent
bb89a865d4
commit
a01ed981ce
@ -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)
|
||||
}
|
||||
|
@ -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())))
|
||||
|
@ -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 {};", "");
|
||||
|
@ -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!(
|
||||
|
@ -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"
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user