about summary refs log tree commit diff
path: root/src/comp/syntax/parse/parser.rs
diff options
context:
space:
mode:
authorKevin Atkinson <kevina@cs.utah.edu>2012-01-10 14:50:40 -0700
committerGraydon Hoare <graydon@mozilla.com>2012-01-10 15:59:57 -0800
commit08abf8d37fa549ebc67f80d80530f4aa43d716e4 (patch)
treef6c9bce62c494a37d989d07be4661f57c0c7eba3 /src/comp/syntax/parse/parser.rs
parentd0fe6723fc2f431205092bda9ec399d932081bd0 (diff)
downloadrust-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.rs43
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);
 }