Skip to content

Commit

Permalink
Refactor 'parse_enum_item' to use 'parse_delim_comma_seq'
Browse files Browse the repository at this point in the history
  • Loading branch information
VirrageS committed Nov 26, 2019
1 parent 7d761fe commit 5c34a11
Show file tree
Hide file tree
Showing 11 changed files with 124 additions and 92 deletions.
115 changes: 47 additions & 68 deletions src/librustc_parse/parser/item.rs
Expand Up @@ -7,7 +7,7 @@ use syntax::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, An
use syntax::ast::{ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind};
use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, Extern, StrLit};
use syntax::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind};
use syntax::ast::{Ty, TyKind, Generics, TraitRef, EnumDef, VariantData, StructField};
use syntax::ast::{Ty, TyKind, Generics, TraitRef, EnumDef, Variant, VariantData, StructField};
use syntax::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, FnSig, SelfKind, Param};
use syntax::print::pprust;
use syntax::ptr::P;
Expand Down Expand Up @@ -1324,85 +1324,65 @@ impl<'a> Parser<'a> {
let id = self.parse_ident()?;
let mut generics = self.parse_generics()?;
generics.where_clause = self.parse_where_clause()?;
self.expect(&token::OpenDelim(token::Brace))?;

let enum_definition = self.parse_enum_def(&generics).map_err(|e| {
let (variants, _) = self.parse_delim_comma_seq(
token::Brace,
|p| p.parse_enum_item(),
).map_err(|e| {
self.recover_stmt();
self.eat(&token::CloseDelim(token::Brace));
e
})?;

let enum_definition = EnumDef {
variants: variants.into_iter().filter_map(|v| v).collect(),
};
Ok((id, ItemKind::Enum(enum_definition, generics), None))
}

/// Parses the part of an enum declaration following the `{`.
fn parse_enum_def(&mut self, _generics: &Generics) -> PResult<'a, EnumDef> {
let mut variants = Vec::new();
// FIXME: Consider using `parse_delim_comma_seq`.
// We could then remove eating comma in `recover_nested_adt_item`.
while self.token != token::CloseDelim(token::Brace) {
let variant_attrs = self.parse_outer_attributes()?;
let vlo = self.token.span;

let vis = self.parse_visibility(FollowedByType::No)?;
if !self.recover_nested_adt_item(kw::Enum)? {
// Item already parsed, we need to skip this variant.
continue
}
let ident = self.parse_ident()?;
fn parse_enum_item(&mut self) -> PResult<'a, Option<Variant>> {
let variant_attrs = self.parse_outer_attributes()?;
let vlo = self.token.span;

let struct_def = if self.check(&token::OpenDelim(token::Brace)) {
// Parse a struct variant.
let (fields, recovered) = self.parse_record_struct_body()?;
VariantData::Struct(fields, recovered)
} else if self.check(&token::OpenDelim(token::Paren)) {
VariantData::Tuple(
self.parse_tuple_struct_body()?,
DUMMY_NODE_ID,
)
} else {
VariantData::Unit(DUMMY_NODE_ID)
};
let vis = self.parse_visibility(FollowedByType::No)?;
if !self.recover_nested_adt_item(kw::Enum)? {
return Ok(None)
}
let ident = self.parse_ident()?;

let disr_expr = if self.eat(&token::Eq) {
Some(AnonConst {
id: DUMMY_NODE_ID,
value: self.parse_expr()?,
})
} else {
None
};
let struct_def = if self.check(&token::OpenDelim(token::Brace)) {
// Parse a struct variant.
let (fields, recovered) = self.parse_record_struct_body()?;
VariantData::Struct(fields, recovered)
} else if self.check(&token::OpenDelim(token::Paren)) {
VariantData::Tuple(
self.parse_tuple_struct_body()?,
DUMMY_NODE_ID,
)
} else {
VariantData::Unit(DUMMY_NODE_ID)
};

let vr = ast::Variant {
ident,
vis,
let disr_expr = if self.eat(&token::Eq) {
Some(AnonConst {
id: DUMMY_NODE_ID,
attrs: variant_attrs,
data: struct_def,
disr_expr,
span: vlo.to(self.prev_span),
is_placeholder: false,
};
variants.push(vr);
value: self.parse_expr()?,
})
} else {
None
};

if !self.eat(&token::Comma) {
if self.token.is_ident() && !self.token.is_reserved_ident() {
let sp = self.sess.source_map().next_point(self.prev_span);
self.struct_span_err(sp, "missing comma")
.span_suggestion_short(
sp,
"missing comma",
",".to_owned(),
Applicability::MaybeIncorrect,
)
.emit();
} else {
break;
}
}
}
self.expect(&token::CloseDelim(token::Brace))?;
let vr = ast::Variant {
ident,
vis,
id: DUMMY_NODE_ID,
attrs: variant_attrs,
data: struct_def,
disr_expr,
span: vlo.to(self.prev_span),
is_placeholder: false,
};

Ok(ast::EnumDef { variants })
Ok(Some(vr))
}

/// Parses `struct Foo { ... }`.
Expand Down Expand Up @@ -1759,7 +1739,6 @@ impl<'a> Parser<'a> {
let kw_token = self.token.clone();
let kw_str = pprust::token_to_string(&kw_token);
let item = self.parse_item()?;
self.eat(&token::Comma);

self.struct_span_err(
kw_token.span,
Expand Down
22 changes: 20 additions & 2 deletions src/librustc_parse/parser/mod.rs
Expand Up @@ -805,21 +805,39 @@ impl<'a> Parser<'a> {
recovered = true;
break;
}
Err(mut e) => {
Err(mut expect_err) => {
let sp = self.sess.source_map().next_point(self.prev_span);
let token_str = pprust::token_kind_to_string(t);

// Attempt to keep parsing if it was a similar separator.
if let Some(ref tokens) = t.similar_tokens() {
if tokens.contains(&self.token.kind) {
self.bump();
}
}
e.emit();

// Attempt to keep parsing if it was an omitted separator.
match f(self) {
Ok(t) => {
// Parsed successfully, therefore most probably the code only
// misses a separator.
expect_err
.span_suggestion_short(
sp,
&format!("missing `{}`", token_str),
token_str,
Applicability::MaybeIncorrect,
)
.emit();

v.push(t);
continue;
},
Err(mut e) => {
// Parsing failed, therefore it must be something more serious
// than just a missing separator.
expect_err.emit();

e.cancel();
break;
}
Expand Down
Expand Up @@ -2,7 +2,10 @@ error: expected one of `)` or `,`, found `label`
--> $DIR/expected-comma-found-token.rs:9:5
|
LL | message="the message"
| - expected one of `)` or `,`
| -
| |
| expected one of `)` or `,`
| help: missing `,`
LL | label="the label"
| ^^^^^ unexpected token

Expand Down
5 changes: 4 additions & 1 deletion src/test/ui/parser/pat-lt-bracket-6.stderr
Expand Up @@ -2,7 +2,10 @@ error: expected one of `)`, `,`, `@`, or `|`, found `[`
--> $DIR/pat-lt-bracket-6.rs:5:19
|
LL | let Test(&desc[..]) = x;
| ^ expected one of `)`, `,`, `@`, or `|`
| ^
| |
| expected one of `)`, `,`, `@`, or `|`
| help: missing `,`

error[E0658]: subslice patterns are unstable
--> $DIR/pat-lt-bracket-6.rs:5:20
Expand Down
5 changes: 4 additions & 1 deletion src/test/ui/parser/pat-lt-bracket-7.stderr
Expand Up @@ -2,7 +2,10 @@ error: expected one of `)`, `,`, `@`, or `|`, found `[`
--> $DIR/pat-lt-bracket-7.rs:5:16
|
LL | for Thing(x[]) in foo {}
| ^ expected one of `)`, `,`, `@`, or `|`
| ^
| |
| expected one of `)`, `,`, `@`, or `|`
| help: missing `,`

error[E0308]: mismatched types
--> $DIR/pat-lt-bracket-7.rs:9:30
Expand Down
12 changes: 6 additions & 6 deletions src/test/ui/parser/recover-enum.rs
@@ -1,11 +1,11 @@
fn main() {
enum Test {
Very
//~^ ERROR missing comma
Bad(usize)
//~^ ERROR missing comma
Stuff { a: usize }
//~^ ERROR missing comma
Very //~ HELP missing `,`
Bad(usize) //~ HELP missing `,`
//~^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `Bad`
Stuff { a: usize } //~ HELP missing `,`
//~^ ERROR expected one of `,`, `=`, or `}`, found `Stuff`
Here
//~^ ERROR expected one of `,`, `=`, or `}`, found `Here`
}
}
35 changes: 26 additions & 9 deletions src/test/ui/parser/recover-enum.stderr
@@ -1,20 +1,37 @@
error: missing comma
--> $DIR/recover-enum.rs:3:13
error: expected one of `(`, `,`, `=`, `{`, or `}`, found `Bad`
--> $DIR/recover-enum.rs:4:9
|
LL | Very
| ^ help: missing comma
| -
| |
| expected one of `(`, `,`, `=`, `{`, or `}`
| help: missing `,`
LL | Bad(usize)
| ^^^ unexpected token

error: missing comma
--> $DIR/recover-enum.rs:5:19
error: expected one of `,`, `=`, or `}`, found `Stuff`
--> $DIR/recover-enum.rs:6:9
|
LL | Bad(usize)
| ^ help: missing comma
| -
| |
| expected one of `,`, `=`, or `}`
| help: missing `,`
LL |
LL | Stuff { a: usize }
| ^^^^^ unexpected token

error: missing comma
--> $DIR/recover-enum.rs:7:27
error: expected one of `,`, `=`, or `}`, found `Here`
--> $DIR/recover-enum.rs:8:9
|
LL | Stuff { a: usize }
| ^ help: missing comma
| -
| |
| expected one of `,`, `=`, or `}`
| help: missing `,`
LL |
LL | Here
| ^^^^ unexpected token

error: aborting due to 3 previous errors

5 changes: 4 additions & 1 deletion src/test/ui/similar-tokens.stderr
Expand Up @@ -2,7 +2,10 @@ error: expected one of `,`, `::`, `as`, or `}`, found `.`
--> $DIR/similar-tokens.rs:7:10
|
LL | use x::{A. B};
| ^ expected one of `,`, `::`, `as`, or `}`
| ^
| |
| expected one of `,`, `::`, `as`, or `}`
| help: missing `,`

error: aborting due to previous error

4 changes: 3 additions & 1 deletion src/test/ui/tuple/tuple-struct-fields/test.stderr
Expand Up @@ -2,7 +2,9 @@ error: expected one of `)` or `,`, found `(`
--> $DIR/test.rs:4:26
|
LL | struct S2(pub((foo)) ());
| ^ expected one of `)` or `,`
| -^ expected one of `)` or `,`
| |
| help: missing `,`

error[E0412]: cannot find type `foo` in this scope
--> $DIR/test.rs:4:20
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/tuple/tuple-struct-fields/test2.stderr
Expand Up @@ -2,7 +2,9 @@ error: expected one of `)` or `,`, found `(`
--> $DIR/test2.rs:5:26
|
LL | struct S3(pub $t ());
| ^ expected one of `)` or `,`
| -^ expected one of `)` or `,`
| |
| help: missing `,`
...
LL | define_struct! { (foo) }
| ------------------------ in this macro invocation
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/tuple/tuple-struct-fields/test3.stderr
Expand Up @@ -2,7 +2,9 @@ error: expected one of `)` or `,`, found `(`
--> $DIR/test3.rs:5:27
|
LL | struct S3(pub($t) ());
| ^ expected one of `)` or `,`
| -^ expected one of `)` or `,`
| |
| help: missing `,`
...
LL | define_struct! { foo }
| ---------------------- in this macro invocation
Expand Down

0 comments on commit 5c34a11

Please sign in to comment.