# Tuples

()
# There's no (,)

(a) # NOT a tuple
(a,)
(a,b,c)
(a,b,c,)


==>
Program(
  TupleExpression,
  LineComment,
  ParenExpression(Identifier),
  LineComment,
  TupleExpression(Identifier),
  TupleExpression(Identifier, Identifier, Identifier)
  TupleExpression(Identifier, Identifier, Identifier)
)


# Named tuples

(a = 1,)
(a = 1) # NOT a tuple
(a = 1, b = 2)

==>
Program(
  TupleExpression(KwArg(Identifier, AssignmentOp, IntegerLiteral)),
  ParenExpression(Assignment(Identifier, AssignmentOp, IntegerLiteral)),
  LineComment,
  TupleExpression(
    KwArg(Identifier, AssignmentOp, IntegerLiteral),
    KwArg(Identifier, AssignmentOp, IntegerLiteral),
  )
)


# Named tuples with leading semicolon

(;)
(; a)
(; a, b)
(; a = 1)
(; a = 1, b = 2)
(; a, foo.b)

==>
Program(
  TupleExpression(KeywordArguments),
  TupleExpression(KeywordArguments(Identifier)),
  TupleExpression(KeywordArguments(Identifier, Identifier)),
  TupleExpression(KeywordArguments(KwArg(Identifier, AssignmentOp, IntegerLiteral))),
  TupleExpression(KeywordArguments(KwArg(Identifier, AssignmentOp, IntegerLiteral), KwArg(Identifier, AssignmentOp, IntegerLiteral))),
  TupleExpression(KeywordArguments(Identifier, FieldExpression(Identifier, Field(Identifier)))),
)


# Vector arrays

[]
# There's no [,]
[x]
[x,]
[1, 2]

==>
Program(
  VectorExpression,
  LineComment
  VectorExpression(Identifier),
  VectorExpression(Identifier),
  VectorExpression(IntegerLiteral, IntegerLiteral),
)


# Matrix arrays

[x;]
[1 2]

[1 2; 3 4]
[1 2
 3 4]

[1
 2
 3
]
[
 a;
 b;
 c;
]

## this is tecnically parsed incorrectly. `;;` concatenates along the 2nd dimension.
[1;; 2;; 3;;; 4;; 5;; 6;;]

==>
Program(
  MatrixExpression(MatrixRow(Identifier)),
  MatrixExpression(MatrixRow(IntegerLiteral, IntegerLiteral)),

  MatrixExpression(MatrixRow(IntegerLiteral, IntegerLiteral), MatrixRow(IntegerLiteral, IntegerLiteral)),
  MatrixExpression(MatrixRow(IntegerLiteral, IntegerLiteral), MatrixRow(IntegerLiteral, IntegerLiteral)),

  MatrixExpression(MatrixRow(IntegerLiteral), MatrixRow(IntegerLiteral), MatrixRow(IntegerLiteral)),
  MatrixExpression(MatrixRow(Identifier), MatrixRow(Identifier), MatrixRow(Identifier)),

  LineComment,
  MatrixExpression(
    MatrixRow(IntegerLiteral),
    MatrixRow(IntegerLiteral),
    MatrixRow(IntegerLiteral),
    MatrixRow(IntegerLiteral),
    MatrixRow(IntegerLiteral),
    MatrixRow(IntegerLiteral)
  )
)


# Field expressions - typed_ncat

Int[1 2 3 4]

==>
Program(
  IndexExpression(
    Identifier,
    MatrixExpression(MatrixRow(IntegerLiteral, IntegerLiteral, IntegerLiteral, IntegerLiteral)),
  )
)


# Comprehension arrays

[x for x in xs]
UInt[b(c, e) for c in d for e in f]
[
  a(1)
  for a in f
]
[
  a(1)
  for a in f
        ,b in e
]
[
  a(1)
  for a in f
        for b in e
]

==>
Program(
  ComprehensionExpression(
    Generator(
      Identifier,
      GenFor(for, ForBinding(Identifier, AssignmentOp(in), Identifier)),
    )
  ),
  IndexExpression(
    Identifier,
    ComprehensionExpression(
      Generator(
        CallExpression(Identifier, Arguments(Identifier, Identifier)),
        GenFor(for, ForBinding(Identifier, AssignmentOp(in), Identifier), for, ForBinding(Identifier, AssignmentOp(in), Identifier)),
      )
    )
  ),
  ComprehensionExpression(
    Generator(
      CallExpression(Identifier, Arguments(IntegerLiteral)),
      GenFor(for, ForBinding(Identifier, AssignmentOp(in), Identifier)),
    )
  ),
  ComprehensionExpression(
    Generator(
      CallExpression(Identifier, Arguments(IntegerLiteral)),
      GenFor(
        for, 
        ForBinding(Identifier, AssignmentOp(in), Identifier),
        ForBinding(Identifier, AssignmentOp(in), Identifier),
      ),
    )
  ),
  ComprehensionExpression(
    Generator(
      CallExpression(Identifier, Arguments(IntegerLiteral)),
      GenFor(
        for, 
        ForBinding(Identifier, AssignmentOp(in), Identifier),
        for,
        ForBinding(Identifier, AssignmentOp(in), Identifier),
      ),
    )
  ),
)


# Comprehension arrays with compound-statement bodies

[
  try catch end
  for i in 1:10
]
[
  let
    1 + 1
  end
  for i in 1:10
]
[if true; x end for x in xs]
[while false; nothing end for x in xs]
[begin
  a = 1
  a
end for i in xs]

==>
Program(
  ComprehensionExpression(
    Generator(
      TryStatement(try, CatchClause(catch), end),
      GenFor(for, ForBinding(Identifier, AssignmentOp(in), BinaryExpression(IntegerLiteral, Colon, IntegerLiteral))),
    )
  ),
  ComprehensionExpression(
    Generator(
      LetStatement(let, BinaryExpression(IntegerLiteral, UnaryPlusOp, IntegerLiteral), end),
      GenFor(for, ForBinding(Identifier, AssignmentOp(in), BinaryExpression(IntegerLiteral, Colon, IntegerLiteral))),
    )
  ),
  ComprehensionExpression(
    Generator(
      IfStatement(if, Condition(BoolLiteral), Identifier, end),
      GenFor(for, ForBinding(Identifier, AssignmentOp(in), Identifier)),
    )
  ),
  ComprehensionExpression(
    Generator(
      WhileStatement(while, Condition(BoolLiteral), Identifier, end),
      GenFor(for, ForBinding(Identifier, AssignmentOp(in), Identifier)),
    )
  ),
  ComprehensionExpression(
    Generator(
      BeginStatement(begin, Assignment(Identifier, AssignmentOp, IntegerLiteral), Identifier, end),
      GenFor(for, ForBinding(Identifier, AssignmentOp(in), Identifier)),
    )
  ),
)


# Comprehension arrays with begin block bodies - issue #44

[
	begin
		1 + i
	end for i in 1:10
]

==>
Program(
  ComprehensionExpression(
    Generator(
      BeginStatement(begin, BinaryExpression(IntegerLiteral, UnaryPlusOp, Identifier), end),
      GenFor(for, ForBinding(Identifier, AssignmentOp(in), BinaryExpression(IntegerLiteral, Colon, IntegerLiteral))),
    )
  ),
)


# Typed comprehensions - issue #45

Float64[i for i in 1:3]
T[i + j for i in 1:3, j in 1:3]

==>
Program(
  IndexExpression(Identifier, ComprehensionExpression(
    Generator(
      Identifier,
      GenFor(for, ForBinding(Identifier, AssignmentOp(in), BinaryExpression(IntegerLiteral, Colon, IntegerLiteral))),
    )
  )),
  IndexExpression(Identifier, ComprehensionExpression(
    Generator(
      BinaryExpression(Identifier, UnaryPlusOp, Identifier),
      GenFor(
        for,
        ForBinding(Identifier, AssignmentOp(in), BinaryExpression(IntegerLiteral, Colon, IntegerLiteral)),
        ForBinding(Identifier, AssignmentOp(in), BinaryExpression(IntegerLiteral, Colon, IntegerLiteral)),
      ),
    )
  )),
)


# Matrix rows of tilde bindings

eqs = [D(x) ~ a * x
       D(y) ~ b * y]

==>
Program(
  Assignment(Identifier, AssignmentOp, MatrixExpression(
    MatrixRow(Assignment(CallExpression(Identifier, Arguments(Identifier)), TildeOp, BinaryExpression(Identifier, TimesOp, Identifier))),
    MatrixRow(Assignment(CallExpression(Identifier, Arguments(Identifier)), TildeOp, BinaryExpression(Identifier, TimesOp, Identifier))),
  ))
)


# Generator expressions

(b(c, e) for c in d if e)
(b(c, e) for c in d, e = 5)
(b(c, e) for c in d, e = 5 if e)

==>
Program(
  ParenExpression(
    Generator(
      CallExpression(Identifier, Arguments(Identifier, Identifier)),
      GenFor(for, ForBinding(Identifier, AssignmentOp(in), Identifier)),
      GenFilter(if, Identifier),
    )
  ),
  ParenExpression(
    Generator(
      CallExpression(Identifier, Arguments(Identifier, Identifier)),
      GenFor(for, ForBinding(Identifier, AssignmentOp(in), Identifier), ForBinding(Identifier, AssignmentOp, IntegerLiteral)),
    )
  ),
  ParenExpression(
    Generator(
      CallExpression(Identifier, Arguments(Identifier, Identifier)),
      GenFor(for, ForBinding(Identifier, AssignmentOp(in), Identifier), ForBinding(Identifier, AssignmentOp, IntegerLiteral)),
      GenFilter(if, Identifier),
    )
  ),
)


# Generator expressions in function calls

f(i for i in iter)
f(1, 2, x for x = xs)
f(1, 2, x + y for x = xs, y = ys)

==>
Program(
  CallExpression(
    Identifier,
    Arguments(
      Generator(
        Identifier,
        GenFor(for, ForBinding(Identifier, AssignmentOp(in), Identifier)),
      )
    )
  )
  CallExpression(
    Identifier,
    Arguments(
      IntegerLiteral,
      IntegerLiteral,
      Generator(
        Identifier,
        GenFor(for, ForBinding(Identifier, AssignmentOp, Identifier)),
      )
    )
  ),
  CallExpression(
    Identifier,
    Arguments(
      IntegerLiteral,
      IntegerLiteral,
      Generator(
        BinaryExpression(
          Identifier,
          UnaryPlusOp,
          Identifier,
        )
        GenFor(for, ForBinding(Identifier, AssignmentOp, Identifier), ForBinding(Identifier, AssignmentOp, Identifier)),
      )
    )
  )
)
