ConstExpr type for discriminant and array len
diff --git a/src/constant.rs b/src/constant.rs
new file mode 100644
index 0000000..2834539
--- /dev/null
+++ b/src/constant.rs
@@ -0,0 +1,113 @@
+use super::*;
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum ConstExpr {
+    /// A function call
+    ///
+    /// The first field resolves to the function itself,
+    /// and the second field is the list of arguments
+    Call(Box<ConstExpr>, Vec<ConstExpr>),
+    /// A binary operation (For example: `a + b`, `a * b`)
+    Binary(BinOp, Box<ConstExpr>, Box<ConstExpr>),
+    /// A unary operation (For example: `!x`, `*x`)
+    Unary(UnOp, Box<ConstExpr>),
+    /// A literal (For example: `1`, `"foo"`)
+    Lit(Lit),
+    /// A cast (`foo as f64`)
+    Cast(Box<ConstExpr>, Box<Ty>),
+    /// Variable reference, possibly containing `::` and/or type
+    /// parameters, e.g. foo::bar::<baz>.
+    Path(Path),
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+    use super::*;
+    use {BinOp, Ty};
+    use lit::parsing::lit;
+    use op::parsing::{binop, unop};
+    use ty::parsing::{path, ty};
+
+    named!(pub const_expr -> ConstExpr, do_parse!(
+        mut e: alt!(
+            expr_lit
+            |
+            expr_unary
+            |
+            path => { ConstExpr::Path }
+        ) >>
+        many0!(alt!(
+            tap!(args: and_call => {
+                e = ConstExpr::Call(Box::new(e), args);
+            })
+            |
+            tap!(more: and_binary => {
+                let (op, other) = more;
+                e = ConstExpr::Binary(op, Box::new(e), Box::new(other));
+            })
+            |
+            tap!(ty: and_cast => {
+                e = ConstExpr::Cast(Box::new(e), Box::new(ty));
+            })
+        )) >>
+        (e)
+    ));
+
+    named!(and_call -> Vec<ConstExpr>, do_parse!(
+        punct!("(") >>
+        args: separated_list!(punct!(","), const_expr) >>
+        punct!(")") >>
+        (args)
+    ));
+
+    named!(and_binary -> (BinOp, ConstExpr), tuple!(binop, const_expr));
+
+    named!(expr_unary -> ConstExpr, do_parse!(
+        operator: unop >>
+        operand: const_expr >>
+        (ConstExpr::Unary(operator, Box::new(operand)))
+    ));
+
+    named!(expr_lit -> ConstExpr, map!(lit, ConstExpr::Lit));
+
+    named!(and_cast -> Ty, do_parse!(
+        keyword!("as") >>
+        ty: ty >>
+        (ty)
+    ));
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+    use super::*;
+    use quote::{Tokens, ToTokens};
+
+    impl ToTokens for ConstExpr {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            match *self {
+                ConstExpr::Call(ref func, ref args) => {
+                    func.to_tokens(tokens);
+                    tokens.append("(");
+                    tokens.append_separated(args, ",");
+                    tokens.append(")");
+                }
+                ConstExpr::Binary(op, ref left, ref right) => {
+                    left.to_tokens(tokens);
+                    op.to_tokens(tokens);
+                    right.to_tokens(tokens);
+                }
+                ConstExpr::Unary(op, ref expr) => {
+                    op.to_tokens(tokens);
+                    expr.to_tokens(tokens);
+                }
+                ConstExpr::Lit(ref lit) => lit.to_tokens(tokens),
+                ConstExpr::Cast(ref expr, ref ty) => {
+                    expr.to_tokens(tokens);
+                    tokens.append("as");
+                    ty.to_tokens(tokens);
+                }
+                ConstExpr::Path(ref path) => path.to_tokens(tokens),
+            }
+        }
+    }
+}
diff --git a/src/data.rs b/src/data.rs
index 1565794..71d6754 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -6,7 +6,7 @@
     pub attrs: Vec<Attribute>,
     pub data: VariantData,
     /// Explicit discriminant, e.g. `Foo = 1`
-    pub discriminant: Option<Discriminant>,
+    pub discriminant: Option<ConstExpr>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -48,18 +48,12 @@
     Inherited,
 }
 
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub struct Discriminant {
-    pub value: u64,
-    pub ty: IntTy,
-}
-
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
     use attr::parsing::outer_attr;
+    use constant::parsing::const_expr;
     use ident::parsing::ident;
-    use lit::parsing::int;
     use ty::parsing::ty;
 
     named!(pub struct_body -> VariantData, alt!(
@@ -88,7 +82,7 @@
             |
             epsilon!() => { |_| VariantData::Unit }
         ) >>
-        disr: option!(preceded!(punct!("="), discriminant)) >>
+        disr: option!(preceded!(punct!("="), const_expr)) >>
         (Variant {
             ident: id,
             attrs: attrs,
@@ -144,20 +138,11 @@
         |
         epsilon!() => { |_| Visibility::Inherited }
     ));
-
-    named!(discriminant -> Discriminant, map!(
-        int,
-        |(value, ty)| Discriminant {
-            value: value,
-            ty: ty,
-        }
-    ));
 }
 
 #[cfg(feature = "printing")]
 mod printing {
     use super::*;
-    use lit::Lit;
     use quote::{Tokens, ToTokens};
 
     impl ToTokens for Variant {
@@ -213,10 +198,4 @@
             }
         }
     }
-
-    impl ToTokens for Discriminant {
-        fn to_tokens(&self, tokens: &mut Tokens) {
-            Lit::Int(self.value, self.ty).to_tokens(tokens);
-        }
-    }
 }
diff --git a/src/expr.rs b/src/expr.rs
index f2f96d0..fa7cdf7 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -188,56 +188,6 @@
     pub attrs: Vec<Attribute>,
 }
 
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum BinOp {
-    /// The `+` operator (addition)
-    Add,
-    /// The `-` operator (subtraction)
-    Sub,
-    /// The `*` operator (multiplication)
-    Mul,
-    /// The `/` operator (division)
-    Div,
-    /// The `%` operator (modulus)
-    Rem,
-    /// The `&&` operator (logical and)
-    And,
-    /// The `||` operator (logical or)
-    Or,
-    /// The `^` operator (bitwise xor)
-    BitXor,
-    /// The `&` operator (bitwise and)
-    BitAnd,
-    /// The `|` operator (bitwise or)
-    BitOr,
-    /// The `<<` operator (shift left)
-    Shl,
-    /// The `>>` operator (shift right)
-    Shr,
-    /// The `==` operator (equality)
-    Eq,
-    /// The `<` operator (less than)
-    Lt,
-    /// The `<=` operator (less than or equal to)
-    Le,
-    /// The `!=` operator (not equal to)
-    Ne,
-    /// The `>=` operator (greater than or equal to)
-    Ge,
-    /// The `>` operator (greater than)
-    Gt,
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum UnOp {
-    /// The `*` operator for dereferencing
-    Deref,
-    /// The `!` operator for logical inversion
-    Not,
-    /// The `-` operator for negation
-    Neg,
-}
-
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum Pat {
     /// Represents a wildcard pattern (`_`)
@@ -340,7 +290,7 @@
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
-    use {Delimited, DelimToken, FnArg, FnDecl, FunctionRetTy, Ident, Lifetime, TokenTree, Ty};
+    use {BinOp, Delimited, DelimToken, FnArg, FnDecl, FunctionRetTy, Ident, Lifetime, TokenTree, Ty};
     use attr::parsing::outer_attr;
     use generics::parsing::lifetime;
     use ident::parsing::ident;
@@ -348,6 +298,7 @@
     use lit::parsing::lit;
     use mac::parsing::mac;
     use nom::IResult::Error;
+    use op::parsing::{binop, unop};
     use ty::parsing::{mutability, path, qpath, ty};
 
     named!(pub expr -> Expr, do_parse!(
@@ -482,55 +433,10 @@
         (Expr::Tup(elems))
     ));
 
-    named!(and_binary -> (BinOp, Expr), tuple!(
-        alt!(
-            punct!("&&") => { |_| BinOp::And }
-            |
-            punct!("||") => { |_| BinOp::Or }
-            |
-            punct!("<<") => { |_| BinOp::Shl }
-            |
-            punct!(">>") => { |_| BinOp::Shr }
-            |
-            punct!("==") => { |_| BinOp::Eq }
-            |
-            punct!("<=") => { |_| BinOp::Le }
-            |
-            punct!("!=") => { |_| BinOp::Ne }
-            |
-            punct!(">=") => { |_| BinOp::Ge }
-            |
-            punct!("+") => { |_| BinOp::Add }
-            |
-            punct!("-") => { |_| BinOp::Sub }
-            |
-            punct!("*") => { |_| BinOp::Mul }
-            |
-            punct!("/") => { |_| BinOp::Div }
-            |
-            punct!("%") => { |_| BinOp::Rem }
-            |
-            punct!("^") => { |_| BinOp::BitXor }
-            |
-            punct!("&") => { |_| BinOp::BitAnd }
-            |
-            punct!("|") => { |_| BinOp::BitOr }
-            |
-            punct!("<") => { |_| BinOp::Lt }
-            |
-            punct!(">") => { |_| BinOp::Gt }
-        ),
-        expr
-    ));
+    named!(and_binary -> (BinOp, Expr), tuple!(binop, expr));
 
     named!(expr_unary -> Expr, do_parse!(
-        operator: alt!(
-            punct!("*") => { |_| UnOp::Deref }
-            |
-            punct!("!") => { |_| UnOp::Not }
-            |
-            punct!("-") => { |_| UnOp::Neg }
-        ) >>
+        operator: unop >>
         operand: expr >>
         (Expr::Unary(operator, Box::new(operand)))
     ));
@@ -1206,7 +1112,7 @@
                 }
                 Expr::AssignOp(op, ref var, ref expr) => {
                     var.to_tokens(tokens);
-                    tokens.append(op.assign_op());
+                    tokens.append(op.assign_op().unwrap());
                     expr.to_tokens(tokens);
                 }
                 Expr::Field(ref expr, ref field) => {
@@ -1306,69 +1212,6 @@
         }
     }
 
-    impl BinOp {
-        fn op(&self) -> &'static str {
-            match *self {
-                BinOp::Add => "+",
-                BinOp::Sub => "-",
-                BinOp::Mul => "*",
-                BinOp::Div => "/",
-                BinOp::Rem => "%",
-                BinOp::And => "&&",
-                BinOp::Or => "||",
-                BinOp::BitXor => "^",
-                BinOp::BitAnd => "&",
-                BinOp::BitOr => "|",
-                BinOp::Shl => "<<",
-                BinOp::Shr => ">>",
-                BinOp::Eq => "==",
-                BinOp::Lt => "<",
-                BinOp::Le => "<=",
-                BinOp::Ne => "!=",
-                BinOp::Ge => ">=",
-                BinOp::Gt => ">",
-            }
-        }
-
-        fn assign_op(&self) -> &'static str {
-            match *self {
-                BinOp::Add => "+=",
-                BinOp::Sub => "-=",
-                BinOp::Mul => "*=",
-                BinOp::Div => "/=",
-                BinOp::Rem => "%=",
-                BinOp::BitXor => "^=",
-                BinOp::BitAnd => "&=",
-                BinOp::BitOr => "|=",
-                BinOp::Shl => "<<=",
-                BinOp::Shr => ">>=",
-                _ => panic!("bad assignment operator"),
-            }
-        }
-    }
-
-    impl ToTokens for BinOp {
-        fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append(self.op());
-        }
-    }
-
-    impl UnOp {
-        fn op(&self) -> &'static str {
-            match *self {
-                UnOp::Deref => "*",
-                UnOp::Not => "!",
-                UnOp::Neg => "-",
-            }
-        }
-    }
-
-    impl ToTokens for UnOp {
-        fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append(self.op());
-        }
-    }
-
     impl ToTokens for FieldValue {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.ident.to_tokens(tokens);
diff --git a/src/lib.rs b/src/lib.rs
index 9e9ffd0..76ca608 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -21,14 +21,17 @@
 mod attr;
 pub use attr::{Attribute, AttrStyle, MetaItem};
 
+mod constant;
+pub use constant::ConstExpr;
+
 mod data;
-pub use data::{Discriminant, Field, Variant, VariantData, Visibility};
+pub use data::{Field, Variant, VariantData, Visibility};
 
 #[cfg(feature = "full")]
 mod expr;
 #[cfg(feature = "full")]
-pub use expr::{Arm, BinOp, BindingMode, Block, BlockCheckMode, CaptureBy, Expr, FieldPat, Local,
-               MacStmtStyle, Pat, RangeLimits, Stmt, UnOp};
+pub use expr::{Arm, BindingMode, Block, BlockCheckMode, CaptureBy, Expr, FieldPat, Local,
+               MacStmtStyle, Pat, RangeLimits, Stmt};
 
 mod generics;
 pub use generics::{Generics, Lifetime, LifetimeDef, TraitBoundModifier, TyParam, TyParamBound,
@@ -60,11 +63,14 @@
 mod macro_input;
 pub use macro_input::{Body, MacroInput};
 
+mod op;
+pub use op::{BinOp, UnOp};
+
 #[cfg(feature = "parsing")]
 mod space;
 
 mod ty;
-pub use ty::{AngleBracketedParameterData, ArrayLen, BareFnArg, BareFnTy, FunctionRetTy, MutTy,
+pub use ty::{AngleBracketedParameterData, BareFnArg, BareFnTy, FunctionRetTy, MutTy,
              Mutability, ParenthesizedParameterData, Path, PathParameters, PathSegment,
              PolyTraitRef, QSelf, Ty, TypeBinding};
 
diff --git a/src/op.rs b/src/op.rs
new file mode 100644
index 0000000..a27f6a2
--- /dev/null
+++ b/src/op.rs
@@ -0,0 +1,169 @@
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum BinOp {
+    /// The `+` operator (addition)
+    Add,
+    /// The `-` operator (subtraction)
+    Sub,
+    /// The `*` operator (multiplication)
+    Mul,
+    /// The `/` operator (division)
+    Div,
+    /// The `%` operator (modulus)
+    Rem,
+    /// The `&&` operator (logical and)
+    And,
+    /// The `||` operator (logical or)
+    Or,
+    /// The `^` operator (bitwise xor)
+    BitXor,
+    /// The `&` operator (bitwise and)
+    BitAnd,
+    /// The `|` operator (bitwise or)
+    BitOr,
+    /// The `<<` operator (shift left)
+    Shl,
+    /// The `>>` operator (shift right)
+    Shr,
+    /// The `==` operator (equality)
+    Eq,
+    /// The `<` operator (less than)
+    Lt,
+    /// The `<=` operator (less than or equal to)
+    Le,
+    /// The `!=` operator (not equal to)
+    Ne,
+    /// The `>=` operator (greater than or equal to)
+    Ge,
+    /// The `>` operator (greater than)
+    Gt,
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum UnOp {
+    /// The `*` operator for dereferencing
+    Deref,
+    /// The `!` operator for logical inversion
+    Not,
+    /// The `-` operator for negation
+    Neg,
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+    use super::*;
+
+    named!(pub binop -> BinOp, alt!(
+        punct!("&&") => { |_| BinOp::And }
+        |
+        punct!("||") => { |_| BinOp::Or }
+        |
+        punct!("<<") => { |_| BinOp::Shl }
+        |
+        punct!(">>") => { |_| BinOp::Shr }
+        |
+        punct!("==") => { |_| BinOp::Eq }
+        |
+        punct!("<=") => { |_| BinOp::Le }
+        |
+        punct!("!=") => { |_| BinOp::Ne }
+        |
+        punct!(">=") => { |_| BinOp::Ge }
+        |
+        punct!("+") => { |_| BinOp::Add }
+        |
+        punct!("-") => { |_| BinOp::Sub }
+        |
+        punct!("*") => { |_| BinOp::Mul }
+        |
+        punct!("/") => { |_| BinOp::Div }
+        |
+        punct!("%") => { |_| BinOp::Rem }
+        |
+        punct!("^") => { |_| BinOp::BitXor }
+        |
+        punct!("&") => { |_| BinOp::BitAnd }
+        |
+        punct!("|") => { |_| BinOp::BitOr }
+        |
+        punct!("<") => { |_| BinOp::Lt }
+        |
+        punct!(">") => { |_| BinOp::Gt }
+    ));
+
+    named!(pub unop -> UnOp, alt!(
+        punct!("*") => { |_| UnOp::Deref }
+        |
+        punct!("!") => { |_| UnOp::Not }
+        |
+        punct!("-") => { |_| UnOp::Neg }
+    ));
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+    use super::*;
+    use quote::{Tokens, ToTokens};
+
+    impl BinOp {
+        pub fn op(&self) -> &'static str {
+            match *self {
+                BinOp::Add => "+",
+                BinOp::Sub => "-",
+                BinOp::Mul => "*",
+                BinOp::Div => "/",
+                BinOp::Rem => "%",
+                BinOp::And => "&&",
+                BinOp::Or => "||",
+                BinOp::BitXor => "^",
+                BinOp::BitAnd => "&",
+                BinOp::BitOr => "|",
+                BinOp::Shl => "<<",
+                BinOp::Shr => ">>",
+                BinOp::Eq => "==",
+                BinOp::Lt => "<",
+                BinOp::Le => "<=",
+                BinOp::Ne => "!=",
+                BinOp::Ge => ">=",
+                BinOp::Gt => ">",
+            }
+        }
+
+        pub fn assign_op(&self) -> Option<&'static str> {
+            match *self {
+                BinOp::Add => Some("+="),
+                BinOp::Sub => Some("-="),
+                BinOp::Mul => Some("*="),
+                BinOp::Div => Some("/="),
+                BinOp::Rem => Some("%="),
+                BinOp::BitXor => Some("^="),
+                BinOp::BitAnd => Some("&="),
+                BinOp::BitOr => Some("|="),
+                BinOp::Shl => Some("<<="),
+                BinOp::Shr => Some(">>="),
+                _ => None,
+            }
+        }
+    }
+
+    impl ToTokens for BinOp {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            tokens.append(self.op());
+        }
+    }
+
+    impl UnOp {
+        pub fn op(&self) -> &'static str {
+            match *self {
+                UnOp::Deref => "*",
+                UnOp::Not => "!",
+                UnOp::Neg => "-",
+            }
+        }
+    }
+
+    impl ToTokens for UnOp {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            tokens.append(self.op());
+        }
+    }
+}
diff --git a/src/ty.rs b/src/ty.rs
index b8aee5a..fb34280 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -6,7 +6,7 @@
     /// A variable-length array (`[T]`)
     Slice(Box<Ty>),
     /// A fixed length array (`[T; n]`)
-    Array(Box<Ty>, ArrayLen),
+    Array(Box<Ty>, ConstExpr),
     /// A raw pointer (`*const T` or `*mut T`)
     Ptr(Box<MutTy>),
     /// A reference (`&'a T` or `&'a mut T`)
@@ -36,15 +36,6 @@
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
-pub enum ArrayLen {
-    /// As in `[T; 0]`.
-    Usize(usize),
-    /// As in `[T; LEN]` or `[T; helper::LEN as usize]`. The boolean indicates
-    /// whether the path is followed by `as usize`.
-    Path(Path, bool),
-}
-
-#[derive(Debug, Clone, Eq, PartialEq)]
 pub struct MutTy {
     pub ty: Ty,
     pub mutability: Mutability,
@@ -204,9 +195,9 @@
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
+    use constant::parsing::const_expr;
     use generics::parsing::{lifetime, lifetime_def, ty_param_bound, bound_lifetimes};
     use ident::parsing::ident;
-    use lit::parsing::int;
     use std::str;
 
     named!(pub ty -> Ty, alt!(
@@ -242,21 +233,11 @@
         punct!("[") >>
         elem: ty >>
         punct!(";") >>
-        len: array_len >>
+        len: const_expr >>
         punct!("]") >>
         (Ty::Array(Box::new(elem), len))
     ));
 
-    named!(array_len -> ArrayLen, alt!(
-        map!(int, |(i, _)| ArrayLen::Usize(i as usize))
-        |
-        do_parse!(
-            path: path >>
-            as_usize: option!(tuple!(keyword!("as"), keyword!("usize"))) >>
-            (ArrayLen::Path(path, as_usize.is_some()))
-        )
-    ));
-
     named!(ty_ptr -> Ty, do_parse!(
         punct!("*") >>
         mutability: alt!(
@@ -527,21 +508,6 @@
         }
     }
 
-    impl ToTokens for ArrayLen {
-        fn to_tokens(&self, tokens: &mut Tokens) {
-            match *self {
-                ArrayLen::Usize(len) => tokens.append(&len.to_string()),
-                ArrayLen::Path(ref path, as_usize) => {
-                    path.to_tokens(tokens);
-                    if as_usize {
-                        tokens.append("as");
-                        tokens.append("usize");
-                    }
-                }
-            }
-        }
-    }
-
     impl ToTokens for Mutability {
         fn to_tokens(&self, tokens: &mut Tokens) {
             if let Mutability::Mutable = *self {