Expressions
diff --git a/Cargo.toml b/Cargo.toml
index c11e2bf..e7287fc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,6 +11,7 @@
[features]
default = ["parsing", "printing"]
aster = []
+full = []
parsing = []
printing = ["quote"]
visit = []
diff --git a/src/attr.rs b/src/attr.rs
index 2cf9825..e08d9c7 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -22,14 +22,15 @@
/// Name value meta item.
///
/// E.g. `feature = "foo"` as in `#[feature = "foo"]`
- NameValue(Ident, String),
+ NameValue(Ident, Lit),
}
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
- use escape::escaped_string;
use ident::parsing::ident;
+ use lit::{Lit, StrStyle};
+ use lit::parsing::lit;
use nom::multispace;
named!(pub attribute -> Attribute, alt!(
@@ -51,7 +52,10 @@
(Attribute {
value: MetaItem::NameValue(
"doc".into(),
- format!("///{}{}", space, content),
+ Lit::Str(
+ format!("///{}{}", space, content),
+ StrStyle::Cooked,
+ ),
),
is_sugared_doc: true,
})
@@ -68,20 +72,14 @@
)
|
do_parse!(
- id: ident >>
+ name: ident >>
punct!("=") >>
- string: quoted >>
- (MetaItem::NameValue(id, string))
+ value: lit >>
+ (MetaItem::NameValue(name, value))
)
|
map!(ident, MetaItem::Word)
));
-
- named!(quoted -> String, delimited!(
- punct!("\""),
- escaped_string,
- tag!("\"")
- ));
}
#[cfg(feature = "printing")]
diff --git a/src/expr.rs b/src/expr.rs
new file mode 100644
index 0000000..5c31ab9
--- /dev/null
+++ b/src/expr.rs
@@ -0,0 +1,351 @@
+use super::*;
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum Expr {
+ /// A `box x` expression.
+ Box(Box<Expr>),
+ /// First expr is the place; second expr is the value.
+ InPlace(Box<Expr>, Box<Expr>),
+ /// An array (`[a, b, c, d]`)
+ Vec(Vec<Expr>),
+ /// A function call
+ ///
+ /// The first field resolves to the function itself,
+ /// and the second field is the list of arguments
+ Call(Box<Expr>, Vec<Expr>),
+ /// A method call (`x.foo::<Bar, Baz>(a, b, c, d)`)
+ ///
+ /// The `Ident` is the identifier for the method name.
+ /// The vector of `Ty`s are the ascripted type parameters for the method
+ /// (within the angle brackets).
+ ///
+ /// The first element of the vector of `Expr`s is the expression that evaluates
+ /// to the object on which the method is being called on (the receiver),
+ /// and the remaining elements are the rest of the arguments.
+ ///
+ /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
+ /// `ExprKind::MethodCall(foo, [Bar, Baz], [x, a, b, c, d])`.
+ MethodCall(Ident, Vec<Ty>, Vec<Expr>),
+ /// A tuple (`(a, b, c, d)`)
+ Tup(Vec<Expr>),
+ /// A binary operation (For example: `a + b`, `a * b`)
+ Binary(BinOp, Box<Expr>, Box<Expr>),
+ /// A unary operation (For example: `!x`, `*x`)
+ Unary(UnOp, Box<Expr>),
+ /// A literal (For example: `1`, `"foo"`)
+ Lit(Lit),
+ /// A cast (`foo as f64`)
+ Cast(Box<Expr>, Box<Ty>),
+ Type(Box<Expr>, Box<Ty>),
+ /// An `if` block, with an optional else block
+ ///
+ /// `if expr { block } else { expr }`
+ If(Box<Expr>, Box<Block>, Option<Box<Expr>>),
+ /// An `if let` expression with an optional else block
+ ///
+ /// `if let pat = expr { block } else { expr }`
+ ///
+ /// This is desugared to a `match` expression.
+ IfLet(Box<Pat>, Box<Expr>, Box<Block>, Option<Box<Expr>>),
+ /// A while loop, with an optional label
+ ///
+ /// `'label: while expr { block }`
+ While(Box<Expr>, Box<Block>, Option<Ident>),
+ /// A while-let loop, with an optional label
+ ///
+ /// `'label: while let pat = expr { block }`
+ ///
+ /// This is desugared to a combination of `loop` and `match` expressions.
+ WhileLet(Box<Pat>, Box<Expr>, Box<Block>, Option<Ident>),
+ /// A for loop, with an optional label
+ ///
+ /// `'label: for pat in expr { block }`
+ ///
+ /// This is desugared to a combination of `loop` and `match` expressions.
+ ForLoop(Box<Pat>, Box<Expr>, Box<Block>, Option<Ident>),
+ /// Conditionless loop (can be exited with break, continue, or return)
+ ///
+ /// `'label: loop { block }`
+ Loop(Box<Block>, Option<Ident>),
+ /// A `match` block.
+ Match(Box<Expr>, Vec<Arm>),
+ /// A closure (for example, `move |a, b, c| {a + b + c}`)
+ Closure(CaptureBy, Box<FnDecl>, Box<Block>),
+ /// A block (`{ ... }`)
+ Block(Box<Block>),
+
+ /// An assignment (`a = foo()`)
+ Assign(Box<Expr>, Box<Expr>),
+ /// An assignment with an operator
+ ///
+ /// For example, `a += 1`.
+ AssignOp(BinOp, Box<Expr>, Box<Expr>),
+ /// Access of a named struct field (`obj.foo`)
+ Field(Box<Expr>, Ident),
+ /// Access of an unnamed field of a struct or tuple-struct
+ ///
+ /// For example, `foo.0`.
+ TupField(Box<Expr>, usize),
+ /// An indexing operation (`foo[2]`)
+ Index(Box<Expr>, Box<Expr>),
+ /// A range (`1..2`, `1..`, `..2`, `1...2`, `1...`, `...2`)
+ Range(Option<Box<Expr>>, Option<Box<Expr>>, RangeLimits),
+
+ /// Variable reference, possibly containing `::` and/or type
+ /// parameters, e.g. foo::bar::<baz>.
+ ///
+ /// Optionally "qualified",
+ /// E.g. `<Vec<T> as SomeTrait>::SomeType`.
+ Path(Option<QSelf>, Path),
+
+ /// A referencing operation (`&a` or `&mut a`)
+ AddrOf(Mutability, Box<Expr>),
+ /// A `break`, with an optional label to break
+ Break(Option<Ident>),
+ /// A `continue`, with an optional label
+ Continue(Option<Ident>),
+ /// A `return`, with an optional value to be returned
+ Ret(Option<Box<Expr>>),
+
+ /// A macro invocation; pre-expansion
+ Mac(Mac),
+
+ /// A struct literal expression.
+ ///
+ /// For example, `Foo {x: 1, y: 2}`, or
+ /// `Foo {x: 1, .. base}`, where `base` is the `Option<Expr>`.
+ Struct(Path, Vec<Field>, Option<Box<Expr>>),
+
+ /// An array literal constructed from one repeated element.
+ ///
+ /// For example, `[1; 5]`. The first expression is the element
+ /// to be repeated; the second is the number of times to repeat it.
+ Repeat(Box<Expr>, Box<Expr>),
+
+ /// No-op: used solely so we can pretty-print faithfully
+ Paren(Box<Expr>),
+
+ /// `expr?`
+ Try(Box<Expr>),
+}
+
+/// A Block (`{ .. }`).
+///
+/// E.g. `{ .. }` as in `fn foo() { .. }`
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct Block {
+ /// Statements in a block
+ pub stmts: Vec<Stmt>,
+ /// Distinguishes between `unsafe { ... }` and `{ ... }`
+ pub rules: BlockCheckMode,
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum BlockCheckMode {
+ Default,
+ Unsafe,
+}
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum Stmt {
+ /// A local (let) binding.
+ Local(Box<Local>),
+
+ /// An item definition.
+ Item(Box<Item>),
+
+ /// Expr without trailing semi-colon.
+ Expr(Box<Expr>),
+
+ Semi(Box<Expr>),
+
+ Mac(Box<(Mac, MacStmtStyle, Vec<Attribute>)>),
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum MacStmtStyle {
+ /// The macro statement had a trailing semicolon, e.g. `foo! { ... };`
+ /// `foo!(...);`, `foo![...];`
+ Semicolon,
+ /// The macro statement had braces; e.g. foo! { ... }
+ Braces,
+ /// The macro statement had parentheses or brackets and no semicolon; e.g.
+ /// `foo!(...)`. All of these will end up being converted into macro
+ /// expressions.
+ NoBraces,
+}
+
+/// Local represents a `let` statement, e.g., `let <pat>:<ty> = <expr>;`
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct Local {
+ pub pat: Box<Pat>,
+ pub ty: Option<Box<Ty>>,
+ /// Initializer expression to set the value, if any
+ pub init: Option<Box<Expr>>,
+ 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 (`_`)
+ Wild,
+
+ /// A `PatKind::Ident` may either be a new bound variable (`ref mut binding @ OPT_SUBPATTERN`),
+ /// or a unit struct/variant pattern, or a const pattern (in the last two cases the third
+ /// field must be `None`). Disambiguation cannot be done with parser alone, so it happens
+ /// during name resolution.
+ Ident(BindingMode, Ident, Option<Box<Pat>>),
+
+ /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`.
+ /// The `bool` is `true` in the presence of a `..`.
+ Struct(Path, Vec<FieldPat>, bool),
+
+ /// A tuple struct/variant pattern `Variant(x, y, .., z)`.
+ /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
+ /// 0 <= position <= subpats.len()
+ TupleStruct(Path, Vec<Pat>, Option<usize>),
+
+ /// A possibly qualified path pattern.
+ /// Unquailfied path patterns `A::B::C` can legally refer to variants, structs, constants
+ /// or associated constants. Quailfied path patterns `<A>::B::C`/`<A as Trait>::B::C` can
+ /// only legally refer to associated constants.
+ Path(Option<QSelf>, Path),
+
+ /// A tuple pattern `(a, b)`.
+ /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
+ /// 0 <= position <= subpats.len()
+ Tuple(Vec<Pat>, Option<usize>),
+ /// A `box` pattern
+ Box(Box<Pat>),
+ /// A reference pattern, e.g. `&mut (a, b)`
+ Ref(Box<Pat>, Mutability),
+ /// A literal
+ Lit(Box<Expr>),
+ /// A range pattern, e.g. `1...2`
+ Range(Box<Expr>, Box<Expr>),
+ /// `[a, b, ..i, y, z]` is represented as:
+ /// `PatKind::Vec(box [a, b], Some(i), box [y, z])`
+ Vec(Vec<Pat>, Option<Box<Pat>>, Vec<Pat>),
+ /// A macro pattern; pre-expansion
+ Mac(Mac),
+}
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct Arm {
+ pub attrs: Vec<Attribute>,
+ pub pats: Vec<Pat>,
+ pub guard: Option<Box<Expr>>,
+ pub body: Box<Expr>,
+}
+
+/// A capture clause
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum CaptureBy {
+ Value,
+ Ref,
+}
+
+/// Limit types of a range (inclusive or exclusive)
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum RangeLimits {
+ /// Inclusive at the beginning, exclusive at the end
+ HalfOpen,
+ /// Inclusive at the beginning and end
+ Closed,
+}
+
+/// A single field in a struct pattern
+///
+/// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
+/// are treated the same as` x: x, y: ref y, z: ref mut z`,
+/// except is_shorthand is true
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct FieldPat {
+ /// The identifier for the field
+ pub ident: Ident,
+ /// The pattern the field is destructured to
+ pub pat: Box<Pat>,
+ pub is_shorthand: bool,
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum BindingMode {
+ ByRef(Mutability),
+ ByValue(Mutability),
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+ use lit::parsing::lit;
+
+ named!(expr -> Expr, alt!(
+ // TODO other expressions
+ lit => { Expr::Lit }
+ ));
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use quote::{Tokens, ToTokens};
+
+ impl ToTokens for Expr {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ match *self {
+ Expr::Lit(ref lit) => lit.to_tokens(tokens),
+ _ => unimplemented!(),
+ }
+ }
+ }
+}
diff --git a/src/item.rs b/src/item.rs
index 3ed5f8a..4a8a394 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -20,6 +20,8 @@
pub ident: Ident,
pub attrs: Vec<Attribute>,
pub data: VariantData,
+ /// Explicit discriminant, e.g. `Foo = 1`
+ pub discriminant: Option<Discriminant>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
@@ -53,12 +55,19 @@
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::attribute;
use generics::parsing::generics;
use ident::parsing::ident;
+ use lit::parsing::int;
use ty::parsing::ty;
use nom::multispace;
@@ -116,10 +125,12 @@
|
epsilon!() => { |_| VariantData::Unit }
) >>
+ disr: option!(preceded!(punct!("="), discriminant)) >>
(Variant {
ident: id,
attrs: attrs,
data: data,
+ discriminant: disr,
})
));
@@ -174,11 +185,20 @@
|
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 Item {
@@ -230,6 +250,10 @@
}
self.ident.to_tokens(tokens);
variant_data_to_tokens(&self.data, tokens);
+ if let Some(ref disr) = self.discriminant {
+ tokens.append("=");
+ disr.to_tokens(tokens);
+ }
}
}
@@ -249,6 +273,12 @@
}
}
+ impl ToTokens for Discriminant {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ Lit::Int(self.value, self.ty).to_tokens(tokens);
+ }
+ }
+
fn variant_data_to_tokens(data: &VariantData, tokens: &mut Tokens) {
match *data {
VariantData::Struct(ref fields) => {
diff --git a/src/lib.rs b/src/lib.rs
index 2c1be2f..9ebe728 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -16,6 +16,26 @@
MetaItem,
};
+#[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,
+};
+
mod generics;
pub use generics::{
Generics,
@@ -38,6 +58,7 @@
mod item;
pub use item::{
Body,
+ Discriminant,
Field,
Item,
Variant,
@@ -45,6 +66,27 @@
Visibility,
};
+mod lit;
+pub use lit::{
+ FloatTy,
+ IntTy,
+ Lit,
+ StrStyle,
+};
+
+#[cfg(feature = "full")]
+mod mac;
+#[cfg(feature = "full")]
+pub use mac::{
+ BinOpToken,
+ DelimToken,
+ Delimited,
+ Mac,
+ SequenceRepetition,
+ Token,
+ TokenTree,
+};
+
mod ty;
pub use ty::{
AngleBracketedParameterData,
diff --git a/src/lit.rs b/src/lit.rs
new file mode 100644
index 0000000..92d5339
--- /dev/null
+++ b/src/lit.rs
@@ -0,0 +1,167 @@
+/// Literal kind.
+///
+/// E.g. `"foo"`, `42`, `12.34` or `bool`
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum Lit {
+ /// A string literal (`"foo"`)
+ Str(String, StrStyle),
+ /// A byte string (`b"foo"`)
+ ByteStr(Vec<u8>),
+ /// A byte char (`b'f'`)
+ Byte(u8),
+ /// A character literal (`'a'`)
+ Char(char),
+ /// An integer literal (`1`)
+ Int(u64, IntTy),
+ /// A float literal (`1f64` or `1E10f64` or `1.0E10`)
+ Float(String, FloatTy),
+ /// A boolean literal
+ Bool(bool),
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum StrStyle {
+ /// A regular string, like `"foo"`
+ Cooked,
+ /// A raw string, like `r##"foo"##`
+ ///
+ /// The uint is the number of `#` symbols used
+ Raw(usize)
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum IntTy {
+ Isize,
+ I8,
+ I16,
+ I32,
+ I64,
+ Usize,
+ U8,
+ U16,
+ U32,
+ U64,
+ Unsuffixed
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum FloatTy {
+ F32,
+ F64,
+ Unsuffixed,
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+ use escape::escaped_string;
+ use nom::{IResult, multispace};
+
+ named!(pub lit -> Lit, alt!(
+ // TODO other literals
+ quoted => { |q| Lit::Str(q, StrStyle::Cooked) }
+ |
+ int => { |(value, ty)| Lit::Int(value, ty) }
+ ));
+
+ named!(quoted -> String, delimited!(
+ punct!("\""),
+ escaped_string,
+ tag!("\"")
+ ));
+
+ named!(pub int -> (u64, IntTy), preceded!(
+ option!(multispace),
+ tuple!(
+ digits,
+ alt!(
+ tag!("isize") => { |_| IntTy::Isize }
+ |
+ tag!("i8") => { |_| IntTy::I8 }
+ |
+ tag!("i16") => { |_| IntTy::I16 }
+ |
+ tag!("i32") => { |_| IntTy::I32 }
+ |
+ tag!("i64") => { |_| IntTy::I64 }
+ |
+ tag!("usize") => { |_| IntTy::Usize }
+ |
+ tag!("u8") => { |_| IntTy::U8 }
+ |
+ tag!("u16") => { |_| IntTy::U16 }
+ |
+ tag!("u32") => { |_| IntTy::U32 }
+ |
+ tag!("u64") => { |_| IntTy::U64 }
+ |
+ epsilon!() => { |_| IntTy::Unsuffixed }
+ )
+ )
+ ));
+
+ fn digits(input: &str) -> IResult<&str, u64> {
+ let mut value = 0u64;
+ let mut len = 0;
+ let mut bytes = input.bytes().peekable();
+ while let Some(&b) = bytes.peek() {
+ match b {
+ b'0' ... b'9' => {
+ value = match value.checked_mul(10) {
+ Some(value) => value,
+ None => return IResult::Error,
+ };
+ value = match value.checked_add((b - b'0') as u64) {
+ Some(value) => value,
+ None => return IResult::Error,
+ };
+ bytes.next();
+ len += 1;
+ }
+ _ => {
+ return if len > 0 {
+ IResult::Done(&input[len..], value)
+ } else {
+ IResult::Error
+ };
+ },
+ }
+ }
+ IResult::Error
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use quote::{Tokens, ToTokens};
+ use std::fmt::{self, Display};
+
+ impl ToTokens for Lit {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ match *self {
+ Lit::Str(ref s, StrStyle::Cooked) => s.to_tokens(tokens),
+ Lit::Int(value, ty) => tokens.append(&format!("{}{}", value, ty)),
+ _ => unimplemented!(),
+ }
+ }
+ }
+
+ impl Display for IntTy {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ match *self {
+ IntTy::Isize => formatter.write_str("isize"),
+ IntTy::I8 => formatter.write_str("i8"),
+ IntTy::I16 => formatter.write_str("i16"),
+ IntTy::I32 => formatter.write_str("i32"),
+ IntTy::I64 => formatter.write_str("i64"),
+ IntTy::Usize => formatter.write_str("usize"),
+ IntTy::U8 => formatter.write_str("u8"),
+ IntTy::U16 => formatter.write_str("u16"),
+ IntTy::U32 => formatter.write_str("u32"),
+ IntTy::U64 => formatter.write_str("u64"),
+ IntTy::Unsuffixed => Ok(()),
+ }
+ }
+ }
+}
diff --git a/src/mac.rs b/src/mac.rs
new file mode 100644
index 0000000..42d116f
--- /dev/null
+++ b/src/mac.rs
@@ -0,0 +1,148 @@
+use super::*;
+
+/// Represents a macro invocation. The Path indicates which macro
+/// is being invoked, and the vector of token-trees contains the source
+/// of the macro invocation.
+///
+/// NB: the additional ident for a macro_rules-style macro is actually
+/// stored in the enclosing item. Oog.
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct Mac {
+ pub path: Path,
+ pub tts: Vec<TokenTree>,
+}
+
+/// When the main rust parser encounters a syntax-extension invocation, it
+/// parses the arguments to the invocation as a token-tree. This is a very
+/// loose structure, such that all sorts of different AST-fragments can
+/// be passed to syntax extensions using a uniform type.
+///
+/// If the syntax extension is an MBE macro, it will attempt to match its
+/// LHS token tree against the provided token tree, and if it finds a
+/// match, will transcribe the RHS token tree, splicing in any captured
+/// macro_parser::matched_nonterminals into the `SubstNt`s it finds.
+///
+/// The RHS of an MBE macro is the only place `SubstNt`s are substituted.
+/// Nothing special happens to misnamed or misplaced `SubstNt`s.
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum TokenTree {
+ /// A single token
+ Token(Token),
+ /// A delimited sequence of token trees
+ Delimited(Delimited),
+
+ // This only makes sense in MBE macros.
+ /// A kleene-style repetition sequence with a span
+ Sequence(SequenceRepetition),
+}
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct Delimited {
+ /// The type of delimiter
+ pub delim: DelimToken,
+ /// The delimited sequence of token trees
+ pub tts: Vec<TokenTree>,
+}
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct SequenceRepetition {
+ /// The sequence of token trees
+ pub tts: Vec<TokenTree>,
+ /// The optional separator
+ pub separator: Option<Token>,
+ /// Whether the sequence can be repeated zero (*), or one or more times (+)
+ pub op: KleeneOp,
+ /// The number of `MatchNt`s that appear in the sequence (and subsequences)
+ pub num_captures: usize,
+}
+
+/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star)
+/// for token sequences.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum KleeneOp {
+ ZeroOrMore,
+ OneOrMore,
+}
+
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum Token {
+ /* Expression-operator symbols. */
+ Eq,
+ Lt,
+ Le,
+ EqEq,
+ Ne,
+ Ge,
+ Gt,
+ AndAnd,
+ OrOr,
+ Not,
+ Tilde,
+ BinOp(BinOpToken),
+ BinOpEq(BinOpToken),
+
+ /* Structural symbols */
+ At,
+ Dot,
+ DotDot,
+ DotDotDot,
+ Comma,
+ Semi,
+ Colon,
+ ModSep,
+ RArrow,
+ LArrow,
+ FatArrow,
+ Pound,
+ Dollar,
+ Question,
+ /// An opening delimiter, eg. `{`
+ OpenDelim(DelimToken),
+ /// A closing delimiter, eg. `}`
+ CloseDelim(DelimToken),
+
+ /* Literals */
+ Literal(Lit, Option<String>),
+
+ /* Name components */
+ Ident(Ident),
+ Underscore,
+ Lifetime(Ident),
+
+ // Can be expanded into several tokens.
+ /// Doc comment
+ DocComment(String),
+ // In left-hand-sides of MBE macros:
+ /// Parse a nonterminal (name to bind, name of NT)
+ MatchNt(Ident, Ident),
+ // In right-hand-sides of MBE macros:
+ /// A syntactic variable that will be filled in by macro expansion.
+ SubstNt(Ident),
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum BinOpToken {
+ Plus,
+ Minus,
+ Star,
+ Slash,
+ Percent,
+ Caret,
+ And,
+ Or,
+ Shl,
+ Shr,
+}
+
+/// A delimiter token
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum DelimToken {
+ /// A round parenthesis: `(` or `)`
+ Paren,
+ /// A square bracket: `[` or `]`
+ Bracket,
+ /// A curly brace: `{` or `}`
+ Brace,
+ /// An empty delimiter
+ NoDelim,
+}
diff --git a/src/ty.rs b/src/ty.rs
index e87f740..cdfa697 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -40,7 +40,7 @@
pub mutability: Mutability,
}
-#[derive(Debug, Clone, Eq, PartialEq)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Mutability {
Mutable,
Immutable,
diff --git a/tests/test.rs b/tests/test.rs
index c82533a..86a06ca 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -87,6 +87,7 @@
pub enum Result<T, E> {
Ok(T),
Err(E),
+ Surprise = 0isize,
}
";
@@ -97,7 +98,10 @@
Attribute {
value: MetaItem::NameValue(
"doc".into(),
- "/// See the std::result module documentation for details.".into(),
+ Lit::Str(
+ "/// See the std::result module documentation for details.".into(),
+ StrStyle::Cooked,
+ ),
),
is_sugared_doc: true,
},
@@ -136,6 +140,7 @@
ty: simple_ty("T"),
},
]),
+ discriminant: None,
},
Variant {
ident: "Err".into(),
@@ -148,6 +153,16 @@
ty: simple_ty("E"),
},
]),
+ discriminant: None,
+ },
+ Variant {
+ ident: "Surprise".into(),
+ attrs: Vec::new(),
+ data: VariantData::Unit,
+ discriminant: Some(Discriminant {
+ value: 0,
+ ty: IntTy::Isize,
+ }),
},
]),
};