// This file describes nearly all Rust AST types.  It is used by gen/process_ast.py to generate
// impls of various traits for all AST nodes.
//
// There are three types of declarations that can appear in this file.
//  - `struct`s: Similar to Rust struct declarations, except that only field names are given, not
//    their types.  Both "normal" and tuple structs are supported.  In normal structs declarations,
//    the field names must match the actual names of the fields.  For tuple structs, names must
//    still be provided, but they can be chosen arbitrarily (except they must be valid Rust
//    identifiers, i.e., not keywords).
//  - `enum`s: Similar to Rust enum declarations.  Each variant follows the same format as a struct
//    declaration.  Both tuple-like and struct-like variants are supported.
//  - `flag`s: These indicate types with no interesting internal structure, such as `Mutability` (an
//    enum with two nullary variants, `Mutable` and `Immutable`).  The code generators will either
//    ignore these or use a simple default implementation.
//
// Top-level declarations, enum variants, and struct/variant fields may all be prefixed with
// attributes.  The attribute format is `#[attr]` or `#[key=value]` (where `value` is a single
// word).  Consult the doc comments for the code generator modules for information on the supported
// attributes and their effects.


struct Crate {
    module,
    #[seq_rewrite_outer_span='calc_outer_span(&self.attrs, self.span.shrink_to_lo())']
    attrs,
    span,
}
// Ignore inline because we flip it from false to true when printing (see
// `<Item as PrintParse>::to_string`).
struct Mod { inner, #[mac_table_seq] items, #[rewrite_ignore] inline }


#[rewrite_print_recover] #[rewrite_seq_item] #[rewrite_extra_strategies=item_header]
#[nonterminal] #[extend_span] #[fold_kind=ItemKind] #[boxed]
struct Item { ident, #[match=ignore] attrs, id, kind, vis, span,
              #[match=ignore] #[rewrite_ignore] tokens }
enum ItemKind {
    ExternCrate(name),
    Use(vp),
    Static(ty, mutbl, init),
    Const(ty, init),
    Fn(sig, generics, block),
    Mod(module),
    ForeignMod(fm),
    GlobalAsm(asm),
    TyAlias(ty, generics),
    Enum(def, generics),
    Struct(vd, generics),
    Union(vd, generics),
    Trait(is_auto, unsafety, generics, bounds, #[mac_table_seq] items),
    TraitAlias(generics, bounds),
    Impl(unsafety, polarity, generics, defaultness, trait_ref, ty, #[mac_table_seq] items),
    Mac(mac),
    MacroDef(tts),
}

enum Extern {
    None,
    Implicit,
    Explicit(s),
}

enum UseTreeKind {
    Simple(ident, id1, id2),
    Glob,
    Nested(nested),
}

#[fold_kind=UseTreeKind] #[boxed=both]
struct UseTree { kind, prefix, span }

#[nonterminal] #[extend_span] #[fold_kind=TraitItemKind]
struct TraitItem { id, ident, #[match=ignore] attrs, vis, generics, kind, span,
                   #[match=ignore] #[rewrite_ignore] tokens }
enum TraitItemKind {
    Const(ty, init),
    Method(sig, body),
    Type(bounds, ty),
    Macro(mac),
}

#[nonterminal] #[extend_span] #[fold_item=ImplItemKind]
struct ImplItem { id, ident, vis, defaultness, #[match=ignore] attrs, generics, kind, span,
                  #[match=ignore] #[rewrite_ignore] tokens }
enum ImplItemKind {
    Const(ty, init),
    Method(sig, body),
    TyAlias(ty),
    Macro(mac),
}

struct TraitRef { path, ref_id }

struct EnumDef { variants }
#[extend_span]
struct Variant { ident, #[match=ignore] attrs, id, data, disr_expr, vis, span, is_placeholder }
enum VariantData {
    Struct(fields, id),
    Tuple(fields, id),
    Unit(id),
}

#[extend_span]
struct StructField { span, ident, vis, id, ty, #[match=ignore] attrs, is_placeholder }

struct ForeignMod { abi, #[mac_table_seq] items }
#[rewrite_print_recover] #[rewrite_seq_item] #[nonterminal] #[extend_span]
#[fold_kind=ForeignItemKind]
struct ForeignItem { ident, #[match=ignore] attrs, kind, id, span, vis }
enum ForeignItemKind {
    Fn(decl, generics),
    Static(ty, mutbl),
    Ty,
    Macro(mac),
}


struct Generics { params, where_clause, span }
#[extend_span] #[fold_kind=GenericParamKind]
struct GenericParam { id, ident, attrs, bounds, kind, is_placeholder }
enum GenericParamKind {
    Lifetime,
    Type { default },
    Const { ty },
}
struct WhereClause { predicates, span }
enum WherePredicate {
    BoundPredicate(pred),
    RegionPredicate(pred),
    EqPredicate(pred),
}

struct WhereBoundPredicate { span, bounded_ty, bounds, bound_generic_params }
struct WhereRegionPredicate { span, lifetime, bounds }
struct WhereEqPredicate { id, span, lhs_ty, rhs_ty }

enum TraitBoundModifier {
    None,
    Maybe,
}

#[match=ignore]
enum VisibilityKind {
    Public,
    Crate(crate_sugar),
    Restricted { path, id },
    Inherited,
}

enum CrateSugar {
    PubCrate,
    JustCrate,
}

#[match=custom] #[rewrite_print_recover] #[mac_table_record] #[nonterminal]
#[fold_kind=TyKind] #[boxed]
struct Ty { id, kind, span }
struct MutTy {ty, mutbl}
enum TyKind {
    Slice(ty),
    Array(ty, len),
    Ptr(mty),
    Rptr(lt, mty),
    BareFn(ty),
    Never,
    Tup(tys),
    Path(qself, path),
    TraitObject(bounds, trait_object_syntax),
    ImplTrait(id, bounds),
    Paren(ty),
    Typeof(expr),
    Infer,
    ImplicitSelf,
    #[mac_table_record] Mac(mac),
    Err,
    CVarArgs,
}

enum TraitObjectSyntax {
    Dyn,
    None,
}

enum LitIntType {
    Signed(ty),
    Unsigned(ty),
    Unsuffixed,
}

enum IntTy {
    Isize,
    I8,
    I16,
    I32,
    I64,
    I128,
}

enum UintTy {
    Usize,
    U8,
    U16,
    U32,
    U64,
    U128,
}

enum FloatTy {
    F32,
    F64,
}

#[boxed]
struct BareFnTy { unsafety, ext, decl, generic_params }
struct Lifetime { id, ident }
enum GenericBound {
    Trait(poly_trait_ref, modifier),
    Outlives(lt),
}

struct PolyTraitRef { trait_ref, span, bound_generic_params }

struct FnSig { header, decl }

#[boxed]
struct FnDecl { inputs, output }
struct FnHeader { unsafety, asyncness, constness, ext }
#[rewrite_print]
struct Param { attrs, ty, pat, id, span, is_placeholder }
enum FunctionRetTy {
    Default(sp),
    Ty(ty),
}


#[match=custom] #[rewrite_print_recover] #[rewrite_seq_item] #[nonterminal]
#[fold_kind=StmtKind]
struct Stmt { id, kind, span }
#[no_debug]
enum StmtKind {
    Local(local),
    Item(item),
    Expr(expr),
    Semi(expr),
    Mac(mac),
}

#[extend_span] #[boxed]
struct Local { pat, ty, init, id, span, #[match=ignore] attrs }


#[match=custom] #[rewrite_print_recover] #[extend_span] #[mac_table_record] #[nonterminal]
#[fold_kind=ExprKind] #[boxed]
struct Expr { id, kind, span, #[match=ignore] attrs }
#[prec_contains_expr]
enum ExprKind {
    Box(#[prec=PREFIX] expr),
    Array(#[mac_table_seq] elems),
    Call(#[prec=POSTFIX] #[prec_special=Callee] func, #[mac_table_seq] args),
    MethodCall(path_seg, #[prec_first=POSTFIX] #[mac_table_seq] args),
    Tup(#[mac_table_seq] elems),
    Binary(op, #[prec_left_of_binop=op] a, #[prec_right_of_binop=op] b),
    Unary(op, #[prec=PREFIX] a),
    Lit(lit),
    Cast(#[prec=As] expr, ty),
    Type(#[prec=Colon] expr, ty),
    Let(pats, #[prec_special=Cond] expr),
    If(#[prec_special=Cond] cond, then_body, else_body),
    While(#[prec_special=Cond] cond, body, label),
    ForLoop(pat, #[prec_special=Cond] iter, body, label),
    Loop(body, label),
    Match(#[prec_special=Cond] target, arms),
    Closure(cap, is_async, mov, decl, body, span),
    Block(body, label),
    Async(cap, id, block),
    Await(expr),
    TryBlock(body),
    Assign(#[lvalue_mut] #[prec_inc=Assign] lhs, #[prec=Assign] rhs),
    AssignOp(op, #[lvalue_mut] #[prec_inc=Assign] lhs, #[prec=Assign] rhs),
    Field(#[lr_propagate] #[prec=POSTFIX] expr, ident),
    Index(#[lr_propagate] #[prec=POSTFIX] arr, idx),
    // Special case for `Range`.  `AssocOp` claims that `Range` has higher precedence than
    // `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.  Here we use a
    // fake precedence value so that any child with lower precedence than a "normal" binop gets
    // parenthesized.  (`LOr` is the lowest-precedence binop.)
    Range(#[prec=LOr] lo, #[prec=LOr] hi, limits),
    Path(qself, path),
    AddrOf(borrowkind, mutbl, #[lvalue_kind=mutbl] #[prec=PREFIX] expr),
    Break(label, #[prec=JUMP] expr),
    Continue(label),
    Ret(#[prec=JUMP] expr),
    InlineAsm(asm),
    #[mac_table_record] Mac(mac),
    Struct(path, fields, base),
    Repeat(item, count),
    Paren(expr),
    Try(#[prec=POSTFIX] expr),
    Yield(#[prec=JUMP] expr),
    Err,
}

enum IsAsync {
    Async { closure_id, return_impl_trait_id },
    NotAsync,
}
enum Movability {
    Static,
    Movable,
}

enum UnOp {
    Deref,
    Not,
    Neg,
}
enum BinOpKind {
    Add,
    Sub,
    Mul,
    Div,
    Rem,
    And,
    Or,
    BitXor,
    BitAnd,
    BitOr,
    Shl,
    Shr,
    Eq,
    Lt,
    Le,
    Ne,
    Ge,
    Gt,
}

#[extend_span]
struct Field { id, ident, expr, span, is_shorthand, attrs, is_placeholder }
#[extend_span]
struct Arm { id, attrs, pat, guard, body, span, is_placeholder }
#[match=custom] #[rewrite_print_recover] #[nonterminal] #[boxed]
struct Block { #[mac_table_seq] stmts, id, rules, span }


#[match=custom] #[mac_table_record] #[nonterminal]
#[fold_kind=PatKind] #[boxed]
struct Pat { id, kind, span }
enum PatKind {
    Wild,
    Ident(mode, id, pat),
    Struct(path, fields, dotdot),
    TupleStruct(path, fields),
    Or(paths),
    Path(qself, path),
    Tuple(pats),
    Box(pat),
    Ref(pat, mutbl),
    Lit(expr),
    Range(lo, hi, end),
    Slice(pats),
    Rest,
    Paren(pat),
    #[mac_table_record] Mac(mac),
}

#[extend_span]
struct FieldPat { id, ident, pat, is_shorthand, attrs, span, is_placeholder }

#[match=custom] #[fold_kind=LitKind]
struct Lit { token, kind, span }

struct StrLit { style, symbol, suffix, span, symbol_unescaped }

enum LitKind {
    Str(sym, style),
    ByteStr(bytes),
    Byte(x),
    Char(x),
    Int(x, ty),
    Float(sym, ty),
    Bool(x),
    Err(sym),
}

enum LitFloatType {
    Suffixed(ty),
    Unsuffixed,
}

#[fold_kind=TokenLitKind]
struct TokenLit { kind, symbol, suffix }

enum TokenLitKind {
    Bool,
    Byte,
    Char,
    Integer,
    Float,
    Str,
    StrRaw(n),
    ByteStr,
    ByteStrRaw(n),
    Err,
}

enum Defaultness {
    Default,
    Final,
}

enum Constness {
    Const,
    NotConst,
}

enum ImplPolarity {
    Positive,
    Negative,
}

enum IsAuto {
    Yes,
    No,
}

enum Unsafety {
    Unsafe,
    Normal,
}

#[to_lua_custom] flag Abi;
enum Mutability {
    Mutable,
    Immutable,
}

enum BorrowKind {
    Ref,
    Raw,
}

enum RangeEnd {
    Included(syntax),
    Excluded,
}
enum RangeSyntax {
    DotDotDot,
    DotDotEq,
}
enum BindingMode {
    ByRef(mutbl),
    ByValue(mutbl),
}
enum CaptureBy {
    Value,
    Ref,
}
enum BlockCheckMode {
    Default,
    Unsafe(source),
}
enum UnsafeSource {
    CompilerGenerated,
    UserProvided,
}
enum StrStyle {
    Cooked,
    Raw(n),
}
enum AsmDialect {
    Att,
    Intel,
}
enum RangeLimits {
    HalfOpen,
    Closed,
}


#[no_node_id] #[rewrite_print] #[rewrite_custom=SeqItem]
struct Attribute { id, style, kind, span }
enum AttrKind {
    Normal(item),
    DocComment(symbol),
}
struct AttrItem { path, args }
enum AttrStyle {
    Outer,
    Inner,
}


#[match=custom] #[nonterminal] #[boxed=both]
struct Path { span, segments }
struct PathSegment { ident, id, args }

#[boxed]
enum GenericArgs {
    AngleBracketed(abpd),
    Parenthesized(ppd),
}
struct AngleBracketedArgs { span, args, constraints }
struct ParenthesizedArgs { span, inputs, output }
enum GenericArg {
    Lifetime(lt),
    Type(ty),
    Const(c),
}
struct QSelf { ty, path_span, position }

struct AssocTyConstraint { id, ident, kind, span }
enum AssocTyConstraintKind {
     Equality { ty },
     Bound { bounds },
}


struct Mac { path, args, prior_type_ascription }
enum MacStmtStyle {
    Semicolon,
    Braces,
    NoBraces,
}
#[equiv_mode=ignore]
flag TokenStream;
struct MacroDef { body, legacy }

#[boxed=both]
enum MacArgs {
    Empty,
    Delimited(span, delim, tokens),
    Eq(span, tokens),
}

#[boxed]
struct InlineAsm {
asm, asm_str_style, outputs, inputs, clobbers,
volatile, alignstack, dialect
}

#[boxed]
struct GlobalAsm { asm }
struct InlineAsmOutput { constraint, expr, is_rw, is_indirect }

#[match=custom] struct Label { ident }

enum MacDelimiter {
    Parenthesis,
    Bracket,
    Brace,
}

struct AnonConst {
    id,
    value,
}

#[match=custom] #[equiv_mode=custom] struct Ident { name, span }
#[match=eq] #[to_lua_custom] flag Name;
#[equiv_mode=ignore] #[match=eq] flag SyntaxContext;

#[equiv_mode=ignore] #[rewrite_ignore] #[to_lua_custom]
flag Span;
#[equiv_mode=ignore] #[rewrite_ignore] #[list_node_ids=custom] #[mac_table_custom]
#[to_lua_custom]
flag NodeId;
#[equiv_mode=ignore] #[rewrite_ignore] #[to_lua_custom]
flag AttrId;

#[to_lua_custom] flag usize;
#[match=eq] #[to_lua_custom] flag bool;
#[match=eq] #[to_lua_custom] flag u128;
#[match=eq] #[to_lua_custom] flag u16;
#[match=eq] #[to_lua_custom] flag u8;
#[match=eq] #[to_lua_custom] flag char;


enum Nonterminal {
    NtItem(i),
    NtBlock(b),
    NtStmt(s),
    NtPat(p),
    NtExpr(y),
    NtTy(t),
    NtIdent(i, raw),
    NtLifetime(ident),
    NtLiteral(expr),
    NtMeta(m),
    NtPath(p),
    NtVis(v),
    NtTT(tt),
    NtTraitItem(ti),
    NtImplItem(ii),
    NtForeignItem(fi),
}

enum TokenTree {
    Token(t),
    Delimited(sp, d, tts),
}

struct DelimSpan { open, close }

enum DelimToken {
    Paren,
    Bracket,
    Brace,
    NoDelim,
}

#[fold_kind=TokenKind]
struct Token { kind, span }

enum TokenKind {
    Eq,
    Lt,
    Le,
    EqEq,
    Ne,
    Ge,
    Gt,
    AndAnd,
    OrOr,
    Not,
    Tilde,
    BinOp(op),
    BinOpEq(op),
    At,
    Dot,
    DotDot,
    DotDotDot,
    DotDotEq,
    Comma,
    Semi,
    Colon,
    ModSep,
    RArrow,
    LArrow,
    FatArrow,
    Pound,
    Dollar,
    Question,
    SingleQuote,
    OpenDelim(delim),
    CloseDelim(delim),
    Literal(lit),
    Ident(s, is_raw),
    Lifetime(s),
    Interpolated(nt),
    DocComment(s),
    Whitespace,
    Comment,
    Shebang(s),
    Unknown(s),
    Eof,
}

enum BinOpToken {
    Plus,
    Minus,
    Star,
    Slash,
    Percent,
    Caret,
    And,
    Or,
    Shl,
    Shr,
}

#[fold_kind=MetaItemKind]
struct MetaItem { path, kind, span }
enum MetaItemKind {
    Word,
    List(l),
    NameValue(lit),
}
enum NestedMetaItem {
    MetaItem(mi),
    Literal(lit),
}
