# Identifiers

fn main() {
  abc;
}

==>

SourceFile(
  FunctionItem(fn,BoundIdentifier, ParamList, Block(
    Identifier)))


# Raw identifiers

fn main() {
  (r#abc as r#Def).r#ghi;
}

==>

SourceFile(
  FunctionItem(fn,
    BoundIdentifier,
    ParamList,
    Block(
      FieldExpression(
        ParenthesizedExpression(
          TypeCastExpression(Identifier, as, TypeIdentifier)),
        FieldIdentifier))))


# Unary operator expressions

-num;
!bits;
*boxed_thing;

==>

SourceFile(
  UnaryExpression(ArithOp, Identifier),
  UnaryExpression(LogicOp, Identifier),
  UnaryExpression(DerefOp, Identifier))


# Reference expressions

&a;
&mut self.name;

==>

SourceFile(
  ReferenceExpression(Identifier),
  ReferenceExpression(mut, FieldExpression(self, FieldIdentifier)))


# Try expressions

a.unwrap()?;

==>

SourceFile(
  TryExpression(CallExpression(FieldExpression(Identifier, FieldIdentifier), ArgList)))


# Binary operator expressions

a * b;
a / b;
a % b;
a + b;
a - b;
a >> b;
a << b;
a == b;
a && b;
a || b;

==>

SourceFile(
  BinaryExpression(Identifier, ArithOp, Identifier),
  BinaryExpression(Identifier, ArithOp, Identifier),
  BinaryExpression(Identifier, ArithOp, Identifier),
  BinaryExpression(Identifier, ArithOp, Identifier),
  BinaryExpression(Identifier, ArithOp, Identifier),
  BinaryExpression(Identifier, BitOp, Identifier),
  BinaryExpression(Identifier, BitOp, Identifier),
  BinaryExpression(Identifier, CompareOp, Identifier),
  BinaryExpression(Identifier, LogicOp, Identifier),
  BinaryExpression(Identifier, LogicOp, Identifier))


# Grouped expressions

(0);
(2 * (3 + 4));

==>

SourceFile(
  ParenthesizedExpression(Integer),
  ParenthesizedExpression(BinaryExpression(
    Integer,
    ArithOp,
    ParenthesizedExpression(BinaryExpression(Integer, ArithOp, Integer)))))


# Range expressions

1..2;
3..;
..4;
..;
1..b;
a..b;

==>

SourceFile(
  RangeExpression(Integer, Integer),
  RangeExpression(Integer),
  RangeExpression(Integer),
  RangeExpression,
  RangeExpression(Integer, Identifier),
  RangeExpression(Identifier, Identifier))


# Assignment expressions

x = y;

==>

SourceFile(
  AssignmentExpression(
    Identifier,
    Identifier))


# Compound assignment expressions

x += 1;
x += y;

==>

SourceFile(
  AssignmentExpression(Identifier, UpdateOp, Integer),
  AssignmentExpression(Identifier, UpdateOp, Identifier))


# Type cast expressions

1000 as u8;
let character = integer as char;
let size: f64 = len(values) as f64;

==>

SourceFile(
  TypeCastExpression(
    Integer,
    as,
    TypeIdentifier),
  LetDeclaration(let,
    BoundIdentifier,
    TypeCastExpression(
      Identifier,
      as,
      TypeIdentifier)),
  LetDeclaration(let,
    BoundIdentifier,
    TypeIdentifier,
    TypeCastExpression(
      CallExpression(
        Identifier,
        ArgList(Identifier)),
      as,
      TypeIdentifier)))


# Call expressions

foo();
add(1i32, 2i32);
add(
    1i32,
    2i32,
);

==>

SourceFile(
  CallExpression(
    Identifier,
    ArgList),
  CallExpression(
    Identifier,
    ArgList(Integer, Integer)),
  CallExpression(
    Identifier,
    ArgList(Integer, Integer)))


# Array expressions

[];
[1, 2, 3];
["a", "b", "c"];
[0; 128];

==>

SourceFile(
  ArrayExpression,
  ArrayExpression(
    Integer,
    Integer,
    Integer),
  ArrayExpression(
    String,
    String,
    String),
  ArrayExpression(
    Integer,
    Integer))


# Tuple expressions

();
(0,);
let (x, y, z) = (1, 2, 3);

==>

SourceFile(
  UnitExpression,
  TupleExpression(Integer),
  LetDeclaration(let,
    TuplePattern(BoundIdentifier, BoundIdentifier, BoundIdentifier),
    TupleExpression(Integer, Integer, Integer)))


# Struct expressions

NothingInMe {};
Point {x: 10.0, y: 20.0};
let a = SomeStruct { field1, field2: expression, field3, };
let u = game::User {name: "Joe", age: 35, score: 100_000};

==>

SourceFile(
  StructExpression(TypeIdentifier,
    FieldInitializerList),
  StructExpression(TypeIdentifier,
    FieldInitializerList(
      FieldInitializer(FieldIdentifier, Float),
      FieldInitializer(FieldIdentifier, Float))),
  LetDeclaration(let,
    BoundIdentifier,
    StructExpression(
      TypeIdentifier,
      FieldInitializerList(
        ShorthandFieldInitializer(
          Identifier),
        FieldInitializer(FieldIdentifier, Identifier),
        ShorthandFieldInitializer(
          Identifier)))),
  LetDeclaration(let,
    BoundIdentifier,
    StructExpression(
      ScopedTypeIdentifier(ScopeIdentifier, TypeIdentifier),
      FieldInitializerList(
        FieldInitializer(FieldIdentifier, String),
        FieldInitializer(FieldIdentifier, Integer),
        FieldInitializer(FieldIdentifier, Integer)))))


# Struct expressions with update initializers

let u = User{name, ..current_user()};

==>

SourceFile(
  LetDeclaration(let,
    BoundIdentifier,
    StructExpression(
      TypeIdentifier,
      FieldInitializerList(
        ShorthandFieldInitializer(
          Identifier),
        BaseFieldInitializer(CallExpression(Identifier, ArgList))))))


# If expressions

fn main() {
  if n == 1 {
  } else if n == 2 {
  } else {
  }
}

let y = if x == 5 { 10 } else { 15 };

==>

SourceFile(
  FunctionItem(fn,
    BoundIdentifier,
    ParamList,
    Block(
      IfExpression(if,
        BinaryExpression(
          Identifier,
          CompareOp,
          Integer),
        Block,
        else,
        IfExpression(if,
          BinaryExpression(
            Identifier,
            CompareOp,
            Integer),
          Block,
          else,
          Block)))),
  LetDeclaration(let,
    BoundIdentifier,
    IfExpression(if,
      BinaryExpression(
        Identifier,
        CompareOp,
        Integer),
      Block(Integer),
      else,
      Block(Integer))))


# If let expressions

if let ("Bacon", b) = dish {
}

==>

SourceFile(
  IfExpression(if, LetDeclaration(let, TuplePattern(String, BoundIdentifier), Identifier), Block))


# While let expressions

while let ("Bacon", b) = dish {
}

==>

SourceFile(
  WhileExpression(while,
    LetDeclaration(let, TuplePattern(String, BoundIdentifier), Identifier),
    Block))


# Match expressions

match x {
    1 => { "one" }
    2 => "two",
    -1 => 1,
    -3.14 => 3,

    #[attr1]
    3 => "three",
    macro!(4) => "four",
    _ => "something else",
}

let msg = match x {
    0 | 1 | 10 => "one of zero, one, or ten",
    y if y < 20 => "less than 20, but not zero, one, or ten",
    y if y == 200 =>
      if a {
        "200 (but this is not very stylish)"
      }
    _ => "something else",
};

==>

SourceFile(
  MatchExpression(match,
    Identifier,
    MatchBlock(
      MatchArm(
        Integer,
        Block(
          String)),
      MatchArm(
        Integer,
        String),
      MatchArm(
        NegatedPattern(ArithOp, Integer),
        Integer),
      MatchArm(
        NegatedPattern(ArithOp, Float),
        Integer),
      MatchArm(
        Attribute(
          MetaItem(
            Identifier)),
        Integer,
        String),
      MatchArm(
        MacroInvocation(
          Identifier,
          ParenthesizedTokens(
            Integer)),
        String),
      MatchArm(_, String))),
  LetDeclaration(let,
    BoundIdentifier,
    MatchExpression(match,
      Identifier,
      MatchBlock(
        MatchArm(
          OrPattern(OrPattern(Integer, Integer), Integer),
          String),
        MatchArm(
          BoundIdentifier,
          Guard(if,
            BinaryExpression(
              Identifier,
              CompareOp,
              Integer)),
          String),
        MatchArm(
          BoundIdentifier,
          Guard(if,
            BinaryExpression(
              Identifier,
              CompareOp,
              Integer)),
          IfExpression(if,
            Identifier,
            Block(
              String))),
        MatchArm(
          _,
          String)))))


# While expressions

while !done {
  done = true;
}

==>

SourceFile(
  WhileExpression(while,
    UnaryExpression(LogicOp, Identifier),
    Block(
      AssignmentExpression(
        Identifier,
        Boolean))))

# Loop expressions

'outer: loop {
  'inner: loop {
    break 'outer;
    break true;
  }
}

==>

SourceFile(
  LoopExpression(LoopLabel, loop, Block(
    LoopExpression(LoopLabel, loop, Block(
      BreakExpression(break,LoopLabel),
      BreakExpression(break,Boolean))))))

# For expressions

for e in v {
  bar(e);
}

for i in 0..256 {
  bar(i);
}

'outer: for x in 0..10 {
    'inner: for y in 0..10 {
        if x % 2 == 0 { continue 'outer; }
        if y % 2 == 0 { continue 'inner; }
    }
}

==>

SourceFile(
  ForExpression(for,BoundIdentifier, in, Identifier, Block(
    CallExpression(Identifier, ArgList(Identifier)))),
  ForExpression(for,BoundIdentifier, in, RangeExpression(Integer, Integer), Block(
    CallExpression(Identifier, ArgList(Identifier)))),
  ForExpression(LoopLabel, for, BoundIdentifier, in, RangeExpression(Integer, Integer), Block(
    ForExpression(LoopLabel, for, BoundIdentifier, in, RangeExpression(Integer, Integer), Block(
      IfExpression(if,BinaryExpression(BinaryExpression(Identifier, ArithOp, Integer), CompareOp, Integer), Block(
        ContinueExpression(continue,LoopLabel))),
      IfExpression(if,BinaryExpression(BinaryExpression(Identifier, ArithOp, Integer), CompareOp, Integer), Block(
        ContinueExpression(continue,LoopLabel))))))))


# Field expressions

mystruct.myfield;
foo().x;
value.0.1.iter();
1.max(2);

==>

SourceFile(
  FieldExpression(Identifier, FieldIdentifier),
  FieldExpression(CallExpression(Identifier, ArgList), FieldIdentifier),
  CallExpression(
    FieldExpression(
      FieldExpression(FieldExpression(Identifier, Integer), Integer),
      FieldIdentifier),
    ArgList),
  CallExpression(
    FieldExpression(Integer, FieldIdentifier), ArgList(Integer)))


# Method call expressions

mystruct.foo();

==>

SourceFile(CallExpression(FieldExpression(Identifier, FieldIdentifier), ArgList))


# Index expressions

([1, 2, 3, 4])[0];
arr[10];
arr[n];

==>

SourceFile(
  IndexExpression(
    ParenthesizedExpression(
      ArrayExpression(Integer, Integer, Integer, Integer)),
    Integer),
  IndexExpression(Identifier, Integer),
  IndexExpression(Identifier, Identifier))


# Scoped functions

a::b();
C::<D>::e();
::f();
::g::h();

==>

SourceFile(
  CallExpression(
    ScopedIdentifier(ScopeIdentifier, Identifier),
    ArgList),
  CallExpression(
    ScopedIdentifier(
      ScopeIdentifier, TypeArgList(TypeIdentifier),
      Identifier),
    ArgList),
  CallExpression(ScopedIdentifier(Identifier), ArgList),
  CallExpression(ScopedIdentifier(ScopeIdentifier, Identifier), ArgList))


# Scoped functions with fully qualified syntax

<Dog as Animal>::eat(d);

==>

SourceFile(
  CallExpression(
    ScopedIdentifier(
      QualifiedScope(TypeIdentifier, as, TypeIdentifier),
      Identifier),
    ArgList(Identifier)))


# Scoped functions with macros as types

<Token![]>::foo();

==>

SourceFile(
  CallExpression(
    ScopedIdentifier(
      QualifiedScope(MacroInvocation(TypeIdentifier, BracketedTokens)),
      Identifier),
    ArgList))


# Generic functions

std::sizeof::<u32>();
foo::<8>();

==>

SourceFile(
  CallExpression(
    GenericFunction(
      ScopedIdentifier(
        ScopeIdentifier,
        Identifier),
      TypeArgList(
        TypeIdentifier)),
    ArgList),
  CallExpression(
    GenericFunction(
      Identifier,
      TypeArgList(
        Integer)),
    ArgList))


# Closures

a.map(|(b, c)| b.push(c));
d.map(move |mut e| {
    f(e);
    g(e)
});
h(|| -> i { j });

==>

SourceFile(
  CallExpression(
    FieldExpression(Identifier, FieldIdentifier),
    ArgList(
      ClosureExpression(
        ParamList(Parameter(TuplePattern(BoundIdentifier, BoundIdentifier))),
        CallExpression(
          FieldExpression(Identifier, FieldIdentifier),
          ArgList(Identifier))))),
  CallExpression(
    FieldExpression(Identifier, FieldIdentifier),
    ArgList(
      ClosureExpression(move,
        ParamList(Parameter(mut, BoundIdentifier)),
        Block(
          CallExpression(Identifier, ArgList(Identifier)),
          CallExpression(Identifier, ArgList(Identifier)))))),
  CallExpression(
    Identifier,
    ArgList(
      ClosureExpression(
        ParamList,
        TypeIdentifier,
        Block(Identifier)))))


# Closures with typed parameteres

a.map(|b: usize| b.push(c));

==>

SourceFile(
  CallExpression(
    FieldExpression(Identifier, FieldIdentifier),
    ArgList(ClosureExpression(
      ParamList(Parameter(BoundIdentifier, TypeIdentifier)),
      CallExpression(FieldExpression(Identifier, FieldIdentifier), ArgList(Identifier))))))


# Unsafe blocks

const a : A = unsafe { foo() };

==>

SourceFile(
  ConstItem(const,
    BoundIdentifier,
    TypeIdentifier,
    UnsafeBlock(unsafe, Block(CallExpression(Identifier, ArgList)))))
