summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/parse/mod.rs16
-rw-r--r--src/parse/parser.rs15
-rw-r--r--src/parse/tests.rs20
-rw-r--r--src/parse/tokens.rs6
-rw-r--r--src/syntax/token.rs6
5 files changed, 39 insertions, 24 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 33de5c24..61c90f6c 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -85,8 +85,9 @@ fn node(p: &mut Parser, at_start: bool) -> Option<Spanned<SynNode>> {
}
// Bad tokens.
- token => {
- p.diag_unexpected(token.span_with(start .. p.pos()));
+ _ => {
+ p.jump(start);
+ p.diag_unexpected();
return None;
}
};
@@ -233,6 +234,7 @@ fn paren_call(p: &mut Parser, name: Spanned<Ident>) -> ExprCall {
fn dict_contents(p: &mut Parser) -> (LitDict, bool) {
let mut dict = LitDict::new();
let mut comma_and_keyless = true;
+ let mut expected_comma = None;
loop {
p.skip_white();
@@ -243,10 +245,15 @@ fn dict_contents(p: &mut Parser) -> (LitDict, bool) {
let entry = if let Some(entry) = dict_entry(p) {
entry
} else {
- p.diag_expected("value");
+ expected_comma = None;
+ p.diag_unexpected();
continue;
};
+ if let Some(pos) = expected_comma.take() {
+ p.diag_expected_at("comma", pos);
+ }
+
if let Some(key) = &entry.key {
comma_and_keyless = false;
p.deco(Deco::DictKey.span_with(key.span));
@@ -261,7 +268,7 @@ fn dict_contents(p: &mut Parser) -> (LitDict, bool) {
}
if !p.eat_if(Token::Comma) {
- p.diag_expected_at("comma", behind);
+ expected_comma = Some(behind);
}
comma_and_keyless = false;
@@ -286,6 +293,7 @@ fn dict_entry(p: &mut Parser) -> Option<LitDictEntry> {
expr,
})
} else {
+ p.diag_expected("value");
None
}
}
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 047f6e4c..a8e5883a 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -38,7 +38,7 @@ impl<'s> Parser<'s> {
self.f.diags.push(diag);
}
- /// Eat the next token and add a diagnostic that it was not the expected
+ /// Eat the next token and add a diagnostic that it is not the expected
/// `thing`.
pub fn diag_expected(&mut self, thing: &str) {
let before = self.pos();
@@ -60,9 +60,16 @@ impl<'s> Parser<'s> {
self.diag(error!(pos, "expected {}", thing));
}
- /// Add a diagnostic that the given `token` was unexpected.
- pub fn diag_unexpected(&mut self, token: Spanned<Token>) {
- self.diag(error!(token.span, "unexpected {}", token.v.name()));
+ /// Eat the next token and add a diagnostic that it is unexpected.
+ pub fn diag_unexpected(&mut self) {
+ let before = self.pos();
+ if let Some(found) = self.eat() {
+ let after = self.pos();
+ self.diag(match found {
+ Token::Invalid(_) => error!(before .. after, "invalid token"),
+ _ => error!(before .. after, "unexpected {}", found.name()),
+ });
+ }
}
/// Add a decoration to the feedback.
diff --git a/src/parse/tests.rs b/src/parse/tests.rs
index 172b1d15..2fd6d0b1 100644
--- a/src/parse/tests.rs
+++ b/src/parse/tests.rs
@@ -415,6 +415,7 @@ fn test_parse_values() {
// Simple.
v!("_" => Id("_"));
v!("name" => Id("name"));
+ v!("ke-bab" => Id("ke-bab"));
v!("α" => Id("α"));
v!("\"hi\"" => Str("hi"));
v!("true" => Bool(true));
@@ -457,6 +458,7 @@ fn test_parse_expressions() {
// Operations.
v!("-1" => Unary(Neg, Int(1)));
v!("-- 1" => Unary(Neg, Unary(Neg, Int(1))));
+ v!("--css" => Unary(Neg, Unary(Neg, Id("css"))));
v!("3.2in + 6pt" => Binary(Add, Length(3.2, In), Length(6.0, Pt)));
v!("5 - 0.01" => Binary(Sub, Int(5), Float(0.01)));
v!("(3mm * 2)" => Binary(Mul, Length(3.0, Mm), Int(2)));
@@ -547,7 +549,7 @@ fn test_parse_dicts_compute_func_calls() {
// Invalid name.
v!("👠(\"abc\", 13e-5)" => Dict!(Str("abc"), Float(13.0e-5)));
- e!("[val: 👠(\"abc\", 13e-5)]" => s(6, 10, "expected value, found invalid token"));
+ e!("[val: 👠(\"abc\", 13e-5)]" => s(6, 10, "invalid token"));
}
#[test]
@@ -567,12 +569,12 @@ fn test_parse_dicts_nested() {
#[test]
fn test_parse_dicts_errors() {
// Expected value.
- e!("[val: (=)]" => s(7, 8, "expected value, found equals sign"));
- e!("[val: (,)]" => s(7, 8, "expected value, found comma"));
+ e!("[val: (=)]" => s(7, 8, "unexpected equals sign"));
+ e!("[val: (,)]" => s(7, 8, "unexpected comma"));
v!("(\x07 abc,)" => Dict![Id("abc")]);
- e!("[val: (\x07 abc,)]" => s(7, 8, "expected value, found invalid token"));
+ e!("[val: (\x07 abc,)]" => s(7, 8, "invalid token"));
e!("[val: (key=,)]" => s(11, 12, "expected value, found comma"));
- e!("[val: hi,)]" => s(9, 10, "expected value, found closing paren"));
+ e!("[val: hi,)]" => s(9, 10, "unexpected closing paren"));
// Expected comma.
v!("(true false)" => Dict![Bool(true), Bool(false)]);
@@ -586,13 +588,9 @@ fn test_parse_dicts_errors() {
// Bad key.
v!("true=you" => Bool(true), Id("you"));
- e!("[val: true=you]" =>
- s(10, 10, "expected comma"),
- s(10, 11, "expected value, found equals sign"));
+ e!("[val: true=you]" => s(10, 11, "unexpected equals sign"));
// Unexpected equals sign.
v!("z=y=4" => "z" => Id("y"), Int(4));
- e!("[val: z=y=4]" =>
- s(9, 9, "expected comma"),
- s(9, 10, "expected value, found equals sign"));
+ e!("[val: z=y=4]" => s(9, 10, "unexpected equals sign"));
}
diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs
index 91477eb9..3dcc6460 100644
--- a/src/parse/tokens.rs
+++ b/src/parse/tokens.rs
@@ -75,7 +75,7 @@ impl<'s> Iterator for Tokens<'s> {
// Comments.
'/' if self.s.eat_if('/') => self.line_comment(),
'/' if self.s.eat_if('*') => self.block_comment(),
- '*' if self.s.eat_if('/') => Token::Invalid("*/"),
+ '*' if self.s.eat_if('/') => Token::StarSlash,
// Functions and blocks.
'[' => Token::LeftBracket,
@@ -779,8 +779,8 @@ mod tests {
#[test]
fn test_tokenize_invalid() {
// Test invalidly closed block comments.
- t!(Both: "*/" => Invalid("*/"));
- t!(Both: "/**/*/" => BC(""), Invalid("*/"));
+ t!(Both: "*/" => StarSlash);
+ t!(Both: "/**/*/" => BC(""), StarSlash);
// Test invalid expressions.
t!(Header: r"\" => Invalid(r"\"));
diff --git a/src/syntax/token.rs b/src/syntax/token.rs
index 21a56004..e105ad2f 100644
--- a/src/syntax/token.rs
+++ b/src/syntax/token.rs
@@ -19,6 +19,8 @@ pub enum Token<'s> {
///
/// The comment can contain nested block comments.
BlockComment(&'s str),
+ /// An end of a block comment that was not started.
+ StarSlash,
/// A star: `*`.
Star,
@@ -83,7 +85,7 @@ pub enum Token<'s> {
/// A quoted string: `"..."`.
Str(TokenStr<'s>),
- /// Things that are not valid in the context they appeared in.
+ /// Things that are not valid tokens.
Invalid(&'s str),
}
@@ -129,6 +131,7 @@ impl<'s> Token<'s> {
Self::LineComment(_) => "line comment",
Self::BlockComment(_) => "block comment",
+ Self::StarSlash => "end of block comment",
Self::Star => "star",
Self::Underscore => "underscore",
@@ -162,7 +165,6 @@ impl<'s> Token<'s> {
Self::Hex(_) => "hex value",
Self::Str { .. } => "string",
- Self::Invalid("*/") => "end of block comment",
Self::Invalid(_) => "invalid token",
}
}