From 5c9c9a6a9fb81ea909da227752bec3dd9e5b3caf Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 8 Aug 2012 19:51:19 -0700 Subject: [PATCH] libsyntax: Parse common enum fields --- src/libsyntax/ast.rs | 2 +- src/libsyntax/ext/pipes/pipec.rs | 4 +- src/libsyntax/fold.rs | 73 ++++++------ src/libsyntax/parse/parser.rs | 122 ++++++++++++--------- src/test/run-pass/common-fields-trivial.rs | 14 +++ 5 files changed, 129 insertions(+), 86 deletions(-) create mode 100644 src/test/run-pass/common-fields-trivial.rs diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c33b3e9b6ec..8f4eb98fa7b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -641,7 +641,7 @@ enum variant_kind { } #[auto_serialize] -enum enum_def = { variants: ~[variant] }; +enum enum_def = { variants: ~[variant], common: option<@struct_def> }; #[auto_serialize] type variant_ = {name: ident, attrs: ~[attribute], kind: variant_kind, diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs index a835cbb27a4..f1f8eb4f452 100644 --- a/src/libsyntax/ext/pipes/pipec.rs +++ b/src/libsyntax/ext/pipes/pipec.rs @@ -231,7 +231,9 @@ impl state: to_type_decls { vec::push(items_msg, v); } - ~[cx.item_enum_poly(name, ast::enum_def({ variants: items_msg }), + ~[cx.item_enum_poly(name, + ast::enum_def({ variants: items_msg, + common: none }), self.ty_params)] } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 48d0bf12845..5cce86fd458 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -242,40 +242,13 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ { item_enum(ast::enum_def({ variants: vec::map(enum_definition.variants, |x| fld.fold_variant(x)), + common: option::map(enum_definition.common, + |x| fold_struct_def(x, fld)) }), fold_ty_params(typms, fld)) } item_class(struct_def, typms) => { - let resulting_optional_constructor; - match struct_def.ctor { - none => { - resulting_optional_constructor = none; - } - some(constructor) => { - resulting_optional_constructor = some({ - node: { - body: fld.fold_block(constructor.node.body), - dec: fold_fn_decl(constructor.node.dec, fld), - id: fld.new_id(constructor.node.id) - with constructor.node - } - with constructor - }); - } - } - let dtor = do option::map(struct_def.dtor) |dtor| { - let dtor_body = fld.fold_block(dtor.node.body); - let dtor_id = fld.new_id(dtor.node.id); - {node: {body: dtor_body, - id: dtor_id with dtor.node} - with dtor}}; - item_class(@{ - traits: vec::map(struct_def.traits, - |p| fold_trait_ref(p, fld)), - members: vec::map(struct_def.members, - |x| fld.fold_class_item(x)), - ctor: resulting_optional_constructor, - dtor: dtor}, - /* FIXME (#2543) */ copy typms) + let struct_def = fold_struct_def(struct_def, fld); + item_class(struct_def, /* FIXME (#2543) */ copy typms) } item_impl(tps, ifce, ty, methods) => { item_impl(fold_ty_params(tps, fld), @@ -295,6 +268,39 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ { }; } +fn fold_struct_def(struct_def: @ast::struct_def, fld: ast_fold) + -> @ast::struct_def { + let resulting_optional_constructor; + match struct_def.ctor { + none => { + resulting_optional_constructor = none; + } + some(constructor) => { + resulting_optional_constructor = some({ + node: { + body: fld.fold_block(constructor.node.body), + dec: fold_fn_decl(constructor.node.dec, fld), + id: fld.new_id(constructor.node.id) + with constructor.node + } + with constructor + }); + } + } + let dtor = do option::map(struct_def.dtor) |dtor| { + let dtor_body = fld.fold_block(dtor.node.body); + let dtor_id = fld.new_id(dtor.node.id); + {node: {body: dtor_body, + id: dtor_id with dtor.node} + with dtor}}; + return @{ + traits: vec::map(struct_def.traits, |p| fold_trait_ref(p, fld)), + members: vec::map(struct_def.members, |x| fld.fold_class_item(x)), + ctor: resulting_optional_constructor, + dtor: dtor + }; +} + fn fold_trait_ref(&&p: @trait_ref, fld: ast_fold) -> @trait_ref { @{path: fld.fold_path(p.path), ref_id: fld.new_id(p.ref_id), impl_id: fld.new_id(p.impl_id)} @@ -570,7 +576,10 @@ fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ { enum_variant_kind(enum_definition) => { let variants = vec::map(enum_definition.variants, |x| fld.fold_variant(x)); - kind = enum_variant_kind(ast::enum_def({ variants: variants })); + let common = option::map(enum_definition.common, + |x| fold_struct_def(x, fld)); + kind = enum_variant_kind(ast::enum_def({ variants: variants, + common: common })); } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5141c842335..28768765192 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -46,9 +46,9 @@ import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute, proto_block, proto_box, proto_uniq, provided, public, pure_fn, purity, re_anon, re_named, region, rem, required, ret_style, return_val, self_ty, shl, shr, stmt, stmt_decl, stmt_expr, - stmt_semi, struct_variant_kind, subtract, sty_box, sty_by_ref, - sty_region, sty_static, sty_uniq, sty_value, token_tree, - trait_method, trait_ref, tt_delim, tt_seq, tt_tok, + stmt_semi, struct_def, struct_variant_kind, subtract, sty_box, + sty_by_ref, sty_region, sty_static, sty_uniq, sty_value, + token_tree, trait_method, trait_ref, tt_delim, tt_seq, tt_tok, tt_nonterminal, ty, ty_, ty_bot, ty_box, ty_field, ty_fn, ty_infer, ty_mac, ty_method, ty_nil, ty_param, ty_param_bound, ty_path, ty_ptr, ty_rec, ty_rptr, ty_tup, ty_u32, ty_uniq, @@ -2792,13 +2792,74 @@ class parser { } } - fn parse_enum_def(ty_params: ~[ast::ty_param]) -> enum_def { + fn parse_struct_def(path: @path) -> @struct_def { + let mut the_dtor: option<(blk, ~[attribute], codemap::span)> = none; + let mut ms: ~[@class_member] = ~[]; + while self.token != token::RBRACE { + match self.parse_class_item(path) { + ctor_decl(*) => { + self.span_fatal(copy self.span, + ~"deprecated explicit \ + constructors are not allowed \ + here"); + } + dtor_decl(blk, attrs, s) => { + match the_dtor { + some((_, _, s_first)) => { + self.span_note(s, ~"duplicate destructor \ + declaration"); + self.span_fatal(copy s_first, + ~"first destructor \ + declared here"); + } + none => { + the_dtor = some((blk, attrs, s)); + } + } + } + members(mms) => + ms = vec::append(ms, mms) + } + } + self.bump(); + let mut actual_dtor = do option::map(the_dtor) |dtor| { + let (d_body, d_attrs, d_s) = dtor; + {node: {id: self.get_id(), + attrs: d_attrs, + self_id: self.get_id(), + body: d_body}, + span: d_s} + }; + + return @{ + traits: ~[], + members: ms, + ctor: none, + dtor: actual_dtor + }; + } + + fn parse_enum_def(ident: ast::ident, ty_params: ~[ast::ty_param]) + -> enum_def { let mut variants: ~[variant] = ~[]; let mut all_nullary = true, have_disr = false; + let mut common_fields = none; while self.token != token::RBRACE { let variant_attrs = self.parse_outer_attributes(); let vlo = self.span.lo; + + // Is this a common field declaration? + if self.eat_keyword(~"struct") { + if common_fields.is_some() { + self.fatal(~"duplicate declaration of shared fields"); + } + self.expect(token::LBRACE); + let path = self.ident_to_path_tys(ident, ty_params); + common_fields = some(self.parse_struct_def(path)); + again; + } + let vis = self.parse_visibility(); let ident = self.parse_value_ident(); let mut args = ~[], disr_expr = none; @@ -2807,51 +2868,7 @@ class parser { // Parse a struct variant. all_nullary = false; let path = self.ident_to_path_tys(ident, ty_params); - let mut the_dtor: option<(blk, ~[attribute], codemap::span)> = - none; - let mut ms: ~[@class_member] = ~[]; - while self.token != token::RBRACE { - match self.parse_class_item(path) { - ctor_decl(*) => { - self.span_fatal(copy self.span, - ~"deprecated explicit \ - constructors are not allowed \ - here"); - } - dtor_decl(blk, attrs, s) => { - match the_dtor { - some((_, _, s_first)) => { - self.span_note(s, ~"duplicate destructor \ - declaration"); - self.span_fatal(copy s_first, - ~"first destructor \ - declared here"); - } - none => { - the_dtor = some((blk, attrs, s)); - } - } - } - members(mms) => - ms = vec::append(ms, mms) - } - } - self.bump(); - let mut actual_dtor = do option::map(the_dtor) |dtor| { - let (d_body, d_attrs, d_s) = dtor; - {node: {id: self.get_id(), - attrs: d_attrs, - self_id: self.get_id(), - body: d_body}, - span: d_s} - }; - - kind = struct_variant_kind(@{ - traits: ~[], - members: ms, - ctor: none, - dtor: actual_dtor - }); + kind = struct_variant_kind(self.parse_struct_def(path)); } else if self.token == token::LPAREN { all_nullary = false; let arg_tys = self.parse_unspanned_seq( @@ -2883,7 +2900,7 @@ class parser { enum"); } - return enum_def({ variants: variants }); + return enum_def({ variants: variants, common: common_fields }); } fn parse_item_enum() -> item_info { @@ -2905,12 +2922,13 @@ class parser { id: self.get_id(), disr_expr: none, vis: public}); - return (id, item_enum(enum_def({ variants: ~[variant] }), + return (id, item_enum(enum_def({ variants: ~[variant], + common: none }), ty_params), none); } self.expect(token::LBRACE); - let enum_definition = self.parse_enum_def(ty_params); + let enum_definition = self.parse_enum_def(id, ty_params); (id, item_enum(enum_definition, ty_params), none) } diff --git a/src/test/run-pass/common-fields-trivial.rs b/src/test/run-pass/common-fields-trivial.rs new file mode 100644 index 00000000000..c4feb893c10 --- /dev/null +++ b/src/test/run-pass/common-fields-trivial.rs @@ -0,0 +1,14 @@ +enum Foo { + struct { + x: int; + y: int; + } + + Bar(int), + Baz(int) +} + +fn main() { + let x = Bar(3); +} +