# Tuple struct patterns

match x {
  Some(x) => "some",
  std::None() => "none"
}

==>

SourceFile(
  ExpressionStatement(MatchExpression(match,Identifier, MatchBlock(
    MatchArm(
      TuplePattern(TypeIdentifier, BoundIdentifier),
      String),
    MatchArm(
      TuplePattern(ScopedTypeIdentifier(ScopeIdentifier, TypeIdentifier)),
      String)))))


# Reference patterns

match x {
  A(ref x) => x.0,
  ref mut y => y,
  & mut z => z,
}

==>

SourceFile(
  ExpressionStatement(MatchExpression(match,Identifier, MatchBlock(
    MatchArm(
      TuplePattern(TypeIdentifier, RefPattern(ref, BoundIdentifier)),
      FieldExpression(Identifier, Integer)),
    MatchArm(
      RefPattern(ref, MutPattern(mut, BoundIdentifier)),
      Identifier),
    MatchArm(
      ReferencePattern(mut, BoundIdentifier),
      Identifier)))))

# Struct patterns

match x {
  Person{name, age} if age < 5 => ("toddler", name),
  Person{name: adult_name, age: _} => ("adult", adult_name),
}

==>

SourceFile(
  ExpressionStatement(MatchExpression(match,Identifier, MatchBlock(
    MatchArm(
      StructPattern(
        TypeIdentifier,
        FieldPatternList(FieldPattern(BoundIdentifier), FieldPattern(BoundIdentifier))),
      Guard(if, BinaryExpression(Identifier, CompareOp, Integer)),
      TupleExpression(String, Identifier)),
    MatchArm(
      StructPattern(
        TypeIdentifier,
        FieldPatternList(
          FieldPattern(FieldIdentifier, BoundIdentifier),
          FieldPattern(FieldIdentifier, _))),
      TupleExpression(String, Identifier))))))

# Ignored patterns

match x {
  (a, ..) => a,
  B(..) => c,
  D::E{f: g, ..} => g
}

==>

SourceFile(
  ExpressionStatement(MatchExpression(match,Identifier, MatchBlock(
    MatchArm(
      TuplePattern(BoundIdentifier),
      Identifier),
    MatchArm(
      TuplePattern(TypeIdentifier),
      Identifier),
    MatchArm(
      StructPattern(
        ScopedTypeIdentifier(ScopeIdentifier, TypeIdentifier),
        FieldPatternList(FieldPattern(FieldIdentifier, BoundIdentifier))),
      Identifier)))))

# Captured patterns

match x {
  a @ A(_) | b @ B(..) => a,
  a @ 1 ... 5 => a,
  Some(1 ... 5) => a,
  a @ b...c => a,
  a @ b..=c => a,
}

==>

SourceFile(
  ExpressionStatement(MatchExpression(match,
    Identifier,
    MatchBlock(
      MatchArm(
        OrPattern(
          CapturedPattern(
            BoundIdentifier,
            TuplePattern(TypeIdentifier, _)),
          CapturedPattern(
            BoundIdentifier,
            TuplePattern(TypeIdentifier))),
        Identifier),
      MatchArm(
        CapturedPattern(
          BoundIdentifier,
          RangePattern(Integer, Integer)),
        Identifier),
      MatchArm(
        TuplePattern(
          TypeIdentifier,
          RangePattern(Integer, Integer)),
        Identifier),
      MatchArm(
        CapturedPattern(
          BoundIdentifier,
          RangePattern(Identifier, Identifier)),
        Identifier),
      MatchArm(
        CapturedPattern(
          BoundIdentifier,
          RangePattern(Identifier, Identifier)),
        Identifier)))))


# Or patterns

if let A(x) | B(x) = expr {
    do_stuff_with(x);
}

while let A(x) | B(x) = expr {
    do_stuff_with(x);
}

let Ok(index) | Err(index) = slice.binary_search(&x);

for ref a | b in c {}

let Ok(x) | Err(x) = binary_search(x);

for A | B | C in c {}

|(Ok(x) | Err(x))| expr();

let ref mut x @ (A | B | C);

fn foo((1 | 2 | 3): u8) {}

==>

SourceFile(
  ExpressionStatement(IfExpression(if,
    LetDeclaration(let,
      OrPattern(
        TuplePattern(TypeIdentifier, BoundIdentifier),
        TuplePattern(TypeIdentifier, BoundIdentifier)),
      Identifier),
    Block(
      ExpressionStatement(CallExpression(Identifier, ArgList(Identifier)))))),
  ExpressionStatement(WhileExpression(while,
    LetDeclaration(let, 
      OrPattern(
        TuplePattern(TypeIdentifier, BoundIdentifier),
        TuplePattern(TypeIdentifier, BoundIdentifier)),
      Identifier),
    Block(
      ExpressionStatement(CallExpression(Identifier,ArgList(Identifier)))))),
  LetDeclaration(let,
    OrPattern(
      TuplePattern(TypeIdentifier, BoundIdentifier),
      TuplePattern(TypeIdentifier, BoundIdentifier)),
    CallExpression(FieldExpression(Identifier, FieldIdentifier),
      ArgList(ReferenceExpression(Identifier)))),
  ExpressionStatement(ForExpression(for,
    OrPattern(RefPattern(ref, BoundIdentifier), BoundIdentifier),
    in, Identifier,
    Block)),
  LetDeclaration(let,
    OrPattern(
      TuplePattern(TypeIdentifier, BoundIdentifier),
      TuplePattern(TypeIdentifier, BoundIdentifier)),
    CallExpression(Identifier, ArgList(Identifier))),
  ExpressionStatement(ForExpression(for,
    OrPattern(OrPattern(BoundIdentifier, BoundIdentifier), BoundIdentifier),
    in, Identifier,
    Block)),
  ExpressionStatement(ClosureExpression(
    ParamList(Parameter(TuplePattern(
        OrPattern(
          TuplePattern(TypeIdentifier, BoundIdentifier),
          TuplePattern(TypeIdentifier, BoundIdentifier))))),
    CallExpression(Identifier, ArgList))),
  LetDeclaration(let,
    RefPattern(ref,
      MutPattern(
        mut,
        CapturedPattern(
          BoundIdentifier,
          TuplePattern(
            OrPattern(OrPattern(BoundIdentifier, BoundIdentifier), BoundIdentifier)))))),
  FunctionItem(fn,
    BoundIdentifier,
    ParamList(
      Parameter(
        TuplePattern(
          OrPattern(OrPattern(LiteralPattern(Integer), LiteralPattern(Integer)), LiteralPattern(Integer))),
        TypeIdentifier)),
    Block))
