diff options
| author | Kevin Atkinson <kevina@cs.utah.edu> | 2012-01-10 14:50:40 -0700 |
|---|---|---|
| committer | Graydon Hoare <graydon@mozilla.com> | 2012-01-10 15:59:57 -0800 |
| commit | 08abf8d37fa549ebc67f80d80530f4aa43d716e4 (patch) | |
| tree | f6c9bce62c494a37d989d07be4661f57c0c7eba3 /src/comp/syntax/parse/parser.rs | |
| parent | d0fe6723fc2f431205092bda9ec399d932081bd0 (diff) | |
| download | rust-08abf8d37fa549ebc67f80d80530f4aa43d716e4.tar.gz rust-08abf8d37fa549ebc67f80d80530f4aa43d716e4.zip | |
Support explicit discriminant numbers on tag variants.
Addresses issue #1393. For now disallow disr. values unless all variants use nullary contractors (i.e. "enum-like"). Disr. values are now encoded in the crate metadata, but only when it will differ from the inferred value based on the order.
Diffstat (limited to 'src/comp/syntax/parse/parser.rs')
| -rw-r--r-- | src/comp/syntax/parse/parser.rs | 43 |
1 files changed, 41 insertions, 2 deletions
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index ca14bf6e870..a27209424ae 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -2072,11 +2072,16 @@ fn parse_item_tag(p: parser, attrs: [ast::attribute]) -> @ast::item { spanned(ty.span.lo, ty.span.hi, {name: id, args: [{ty: ty, id: p.get_id()}], - id: p.get_id()}); + id: p.get_id(), + disr_val: 0, + disr_expr: none}); ret mk_item(p, lo, ty.span.hi, id, ast::item_tag([variant], ty_params), attrs); } expect(p, token::LBRACE); + let all_nullary = true; + let have_disr = false; + let disr_val = 0; while p.peek() != token::RBRACE { let tok = p.peek(); alt tok { @@ -2086,8 +2091,10 @@ fn parse_item_tag(p: parser, attrs: [ast::attribute]) -> @ast::item { p.bump(); let args: [ast::variant_arg] = []; let vhi = p.get_hi_pos(); + let disr_expr = none; alt p.peek() { token::LPAREN. { + all_nullary = false; let arg_tys = parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA), {|p| parse_ty(p, false)}, p); @@ -2096,12 +2103,41 @@ fn parse_item_tag(p: parser, attrs: [ast::attribute]) -> @ast::item { } vhi = arg_tys.span.hi; } + token::EQ. { + have_disr = true; + p.bump(); + let e = parse_expr(p); + // FIXME: eval_const_expr does no error checking, nor do I. + // Also, the parser is not the right place to do this; likely + // somewhere in the middle end so that constants can be + // refereed to, even if they are after the declaration for the + // type. Finally, eval_const_expr probably shouldn't exist as + // it Graydon puts it: "[I] am a little worried at its + // presence since it quasi-duplicates stuff that trans should + // probably be doing." (See issue #1417) + alt syntax::ast_util::eval_const_expr(e) { + syntax::ast_util::const_int(val) { + disr_val = val as int; + // FIXME: check that value is in range + } + } + if option::is_some + (vec::find + (variants, {|v| v.node.disr_val == disr_val})) + { + p.fatal("discriminator value " + /* str(disr_val) + */ + "already exists."); + } + disr_expr = some(e); + } _ {/* empty */ } } expect(p, token::SEMI); p.get_id(); - let vr = {name: p.get_str(name), args: args, id: p.get_id()}; + let vr = {name: p.get_str(name), args: args, id: p.get_id(), + disr_val: disr_val, disr_expr: disr_expr}; variants += [spanned(vlo, vhi, vr)]; + disr_val += 1; } token::RBRACE. {/* empty */ } _ { @@ -2111,6 +2147,9 @@ fn parse_item_tag(p: parser, attrs: [ast::attribute]) -> @ast::item { } } let hi = p.get_hi_pos(); + if (have_disr && !all_nullary) { + p.fatal("discriminator values can only be used with enum-like tag"); + } p.bump(); ret mk_item(p, lo, hi, id, ast::item_tag(variants, ty_params), attrs); } |
