# Assignments
a = b
tup = 1, 2, 3
car, cdr... = list

a × b = a * b
c &= d ÷= e
xs .+= ys

A[i] = new_value

==>
Program(
  Assignment(Identifier, AssignmentOp, Identifier),
  Assignment(Identifier, AssignmentOp, OpenTuple(IntegerLiteral, IntegerLiteral, IntegerLiteral)),
  Assignment(OpenTuple(Identifier, SplatExpression(Identifier)), AssignmentOp, Identifier),

  Assignment(BinaryExpression(Identifier, TimesOp, Identifier), AssignmentOp, BinaryExpression(Identifier, TimesOp, Identifier)),
  Assignment(Identifier, UpdateOp, Assignment(Identifier, UpdateOp, Identifier)),
  Assignment(Identifier, UpdateOp, Identifier),

  Assignment(IndexExpression(Identifier, VectorExpression(Identifier)), AssignmentOp, Identifier),
)

# Assignments - Short functions

id(x) = x
add(x, y) = x + y
id(x::T)::T where {T} = x

==>
Program(
  Assignment(
    CallExpression(Identifier, Arguments(Identifier)),
    AssignmentOp,
    Identifier
  ),
  Assignment(
    CallExpression(Identifier, Arguments(Identifier, Identifier)),
    AssignmentOp,
    BinaryExpression(Identifier, UnaryPlusOp, Identifier),
  )
  Assignment(
    BinaryExpression(
      CallExpression(Identifier, Arguments(BinaryExpression(Identifier, SubTypeOp, Type(Identifier)))),
      SubTypeOp,
      Type(
        BinaryExpression(
          Identifier,
          where,
          Type(BraceExpression(Identifier)),
        )
      )
    )
    AssignmentOp,
    Identifier,
  )
)


# Type declarations

x::T
x::Vector{T} where T

==>
Program(
  BinaryExpression(Identifier, SubTypeOp, Type(Identifier)),
  BinaryExpression(
    Identifier,
    SubTypeOp,
    Type(BinaryExpression(ParametrizedExpression(Identifier, BraceExpression(Identifier)), where, Type(Identifier)))
  )
)


# Type declarations - Precedence

a::One + b::Two
a + b::Two

==>
Program(
  BinaryExpression(
    BinaryExpression(Identifier, SubTypeOp, Type(Identifier)),
    UnaryPlusOp,
    BinaryExpression(Identifier, SubTypeOp, Type(Identifier))
  ),
  BinaryExpression(Identifier, UnaryPlusOp, BinaryExpression(Identifier, SubTypeOp, Type(Identifier)))
)


# Arrow function expressions

x -> x ^ 2
(x) -> x + 1
(x, y, z) -> 2 * x + y - z
() -> (sleep(0.1); i += 1; l)
foreach(c -> c.queued = true, cells)

==>
Program(
  ArrowFunctionExpression(
    Identifier,
    BinaryExpression(Identifier, PowerOp, IntegerLiteral),
  ),
  ArrowFunctionExpression(
    TupleExpression(Identifier),
    BinaryExpression(Identifier, UnaryPlusOp, IntegerLiteral),
  ),
  ArrowFunctionExpression(
    TupleExpression(Identifier, Identifier, Identifier),
    BinaryExpression(
      BinaryExpression(
        BinaryExpression(IntegerLiteral, TimesOp, Identifier),
        UnaryPlusOp,
        Identifier
      ),
      UnaryPlusOp,
      Identifier
    )
  ),
  ArrowFunctionExpression(
    TupleExpression,
    ParenExpression(
      CallExpression(Identifier, Arguments(FloatLiteral)),
      Assignment(Identifier, UpdateOp, IntegerLiteral),
      Identifier
    )
  )
  CallExpression(
    Identifier,
    Arguments(
      ArrowFunctionExpression(
        Identifier,
        Assignment(FieldExpression(Identifier, Field(Identifier)), AssignmentOp, BoolLiteral),
      ),
      Identifier,
    )
  )
)


# Juxtaposition expressions - Coefficients

1__1 # Not an integer
2π
2v[i]
3f(x)
4df.a
5u"kg"

==>
Program(
  JuxtapositionExpression(IntegerLiteral, Identifier), LineComment,
  JuxtapositionExpression(IntegerLiteral, Identifier),
  JuxtapositionExpression(IntegerLiteral, IndexExpression(Identifier, VectorExpression(Identifier))),
  JuxtapositionExpression(IntegerLiteral, CallExpression(Identifier, Arguments(Identifier))),
  JuxtapositionExpression(IntegerLiteral, FieldExpression(Identifier, Field(Identifier))),
  JuxtapositionExpression(IntegerLiteral, NsStringLiteral(Identifier)),
)


# Juxtaposition expressions - Monomials # FIXME
## Not parsed with the correct precedence

2x^2 - .3x
1.5x^2 - .5x
2^2x
2(x-1)^2 - 3(x-1)

==>
Program(
  LineComment,
  BinaryExpression(
    BinaryExpression(
      JuxtapositionExpression(IntegerLiteral, Identifier),
      PowerOp,
      IntegerLiteral
    ),
    UnaryPlusOp,
    JuxtapositionExpression(FloatLiteral, Identifier)
  ),
  BinaryExpression(
    BinaryExpression(
      JuxtapositionExpression(FloatLiteral, Identifier),
      PowerOp,
      IntegerLiteral
    ),
    UnaryPlusOp,
    JuxtapositionExpression(FloatLiteral, Identifier)
  ),
  BinaryExpression(
    IntegerLiteral,
    PowerOp,
    JuxtapositionExpression(IntegerLiteral, Identifier)
  ),
  BinaryExpression(
    BinaryExpression(
      JuxtapositionExpression(
        IntegerLiteral,
        ParenExpression(BinaryExpression(Identifier, UnaryPlusOp, IntegerLiteral))
      ),
      PowerOp,
      IntegerLiteral
    ),
    UnaryPlusOp,
    JuxtapositionExpression(
      IntegerLiteral,
      ParenExpression(
        BinaryExpression(Identifier, UnaryPlusOp, IntegerLiteral)
      )
    )
  )
)


# Juxtaposition expressions - Primary LHS

x'x
f()g()h()
A'B:C'D

==>
Program(
  JuxtapositionExpression(AdjointExpression(Identifier), Identifier),
  JuxtapositionExpression(
    CallExpression(Identifier, Arguments),
    CallExpression(Identifier, Arguments),
    CallExpression(Identifier, Arguments),
  ),
  BinaryExpression(
    JuxtapositionExpression(AdjointExpression(Identifier), Identifier),
    Colon,
    JuxtapositionExpression(AdjointExpression(Identifier), Identifier),
  )
)


# Ternary operator

x = batch_size == 1 ?
  rand(10) :
  rand(10, batch_size)

y -> y ? x : 10

==>
Program(
  Assignment(
    Identifier,
    AssignmentOp,
    TernaryExpression(
      BinaryExpression(Identifier, ComparisonOp, IntegerLiteral),
      CallExpression(Identifier, Arguments(IntegerLiteral)),
      CallExpression(Identifier, Arguments(IntegerLiteral, Identifier))
    )
  ),
  ArrowFunctionExpression(
    Identifier,
    TernaryExpression(
      Identifier,
      Identifier,
      IntegerLiteral,
    )
  )
)
