# Unary operators

+a
-b
√9
-A'         # adjoint > unary
!p === !(p) # unary > call
1 ++ +2

==>
Program(
  UnaryExpression(UnaryPlusOp,Identifier),
  UnaryExpression(UnaryPlusOp,Identifier),
  UnaryExpression(UnaryOp,IntegerLiteral),
  UnaryExpression(UnaryPlusOp,AdjointExpression(Identifier)),
  LineComment,
  BinaryExpression(UnaryExpression(UnaryOp,Identifier),ComparisonOp,UnaryExpression(UnaryOp,ParenExpression("(",Identifier,")"))),
  LineComment,
  BinaryExpression(IntegerLiteral,PlusOp,UnaryExpression(UnaryPlusOp,IntegerLiteral)),
)


# Binary arithmetic operators

x^2
-x^2                # power > unary
a // b
a + b
a ++ 1 × b ⥌ 2      # (++ a (× 1 (⥌ b 2)))
A \ (v × w)

==>
Program(
  BinaryExpression(Identifier,PowerOp,IntegerLiteral),
  UnaryExpression(UnaryPlusOp,BinaryExpression(Identifier,PowerOp,IntegerLiteral)),
  LineComment,
  BinaryExpression(Identifier,RationalOp,Identifier),
  BinaryExpression(Identifier,UnaryPlusOp,Identifier),
  BinaryExpression(Identifier,PlusOp,BinaryExpression(IntegerLiteral,TimesOp,BinaryExpression(Identifier,PowerOp,IntegerLiteral))),
  LineComment,
  BinaryExpression(Identifier,TimesOp,ParenExpression("(",BinaryExpression(Identifier,TimesOp,Identifier),")")),
)


# Binary arithmetic operators - operations spanning multiple lines

1 +
2

==>
Program(
  BinaryExpression(
    IntegerLiteral,
    UnaryPlusOp,
    IntegerLiteral,
  )
)


# Operator broadcasting

a .* b .+ c
.~[x]

==>
Program(
  BinaryExpression(
    BinaryExpression(Identifier, TimesOp, Identifier),
    UnaryPlusOp,
    Identifier
  )
  UnaryExpression(TildeOp, VectorExpression(Identifier)),
)


# Operator suffixes

x +′ y
a^p ≡ₚ a

==>
Program(
  BinaryExpression(Identifier, UnaryPlusOp, Identifier),
  BinaryExpression(
    BinaryExpression(Identifier, PowerOp, Identifier),
    ComparisonOp,
    Identifier
  )
)


# Binary bitwise operators

a & b | c
(x >>> 16, x >>> 8, x) .& 0xff

==>
Program(
  BinaryExpression(BinaryExpression(Identifier, TimesOp, Identifier), PlusOp, Identifier),
  BinaryExpression(
    TupleExpression(
      BinaryExpression(Identifier, BitshiftOp, IntegerLiteral),
      BinaryExpression(Identifier, BitshiftOp, IntegerLiteral),
      Identifier,
    ),
    TimesOp,
    IntegerLiteral
  )
)


# Binary arrow-like operators

Dict(b => c, d => e)

x |>
  f |>
  g

a → b ⇶ c ⭄ d

==>
Program(
  CallExpression(
    Identifier,
    Arguments(
      BinaryExpression(Identifier, PairOp, Identifier),
      BinaryExpression(Identifier, PairOp, Identifier),
    ),
  ),
  BinaryExpression(
    BinaryExpression(
      Identifier,
      PipeRightOp,
      Identifier,
    ),
    PipeRightOp,
    Identifier,
  ),
  BinaryExpression(
    Identifier,
    ArrowOp,
    BinaryExpression(
      Identifier,
      ArrowOp,
      BinaryExpression(Identifier, ArrowOp, Identifier),
    )
  )
)


# Binary ellipsis operators

1:10
x:y+1

==>
Program(
  BinaryExpression(IntegerLiteral, Colon, IntegerLiteral),
  BinaryExpression(Identifier, Colon, BinaryExpression(Identifier, UnaryPlusOp, IntegerLiteral)),
)


# Binary `..` operator - issue #30

1..10
1.0 .. 2.0
a..b
x[2..end]

==>
Program(
  BinaryExpression(IntegerLiteral, EllipsisOp, IntegerLiteral),
  BinaryExpression(FloatLiteral, EllipsisOp, FloatLiteral),
  BinaryExpression(Identifier, EllipsisOp, Identifier),
  IndexExpression(Identifier, VectorExpression(BinaryExpression(IntegerLiteral, EllipsisOp, end))),
)


# Colon quines

:(:)
:(::)
:(:::)
:(:::::)

==>
Program(
  QuoteExpression(ParenExpression(Operator(Colon))),
  QuoteExpression(ParenExpression(Operator(SubTypeOp))),
  QuoteExpression(ParenExpression(UnaryExpression(SubTypeOp, Type(Operator(Colon))))),
  QuoteExpression(ParenExpression(UnaryExpression(SubTypeOp, Type(UnaryExpression(SubTypeOp, Type(Operator(Colon))))))),
)


# Binary comparison operators

a === 1
a! != 0

## NOT an assignment
a!= 1

## Chained comparisons are parsed as a single expression in Julia.  So this isn't 100% correct.
A ⊆ B ⊆ C
x ≥ 0 ≥ z

==>
Program(
  BinaryExpression(Identifier, ComparisonOp, IntegerLiteral),
  BinaryExpression(Identifier, ComparisonOp, IntegerLiteral),
  LineComment,
  BinaryExpression(Identifier, ComparisonOp, IntegerLiteral),
  LineComment,
  BinaryExpression(
    BinaryExpression(Identifier, ComparisonOp, Identifier),
    ComparisonOp,
    Identifier
  ),
  BinaryExpression(
    BinaryExpression(Identifier, ComparisonOp, IntegerLiteral),
    ComparisonOp,
    Identifier
  )
)


# Binary comparison operators - Types

Bool <: Integer

==>
Program(
    BinaryExpression(Identifier, TypeComparisonOp, Identifier),
)


# Binary logic operators

p && q
p && q || r
p .|| q .&& r

==>
Program(
    BinaryExpression(Identifier, LazyAndOp, Identifier),
    BinaryExpression(BinaryExpression(Identifier, LazyAndOp, Identifier), LazyOrOp, Identifier),
    BinaryExpression(Identifier, LazyOrOp, BinaryExpression(Identifier, LazyAndOp, Identifier)),
)


# Operators as values

!
.!

x = +
⪯ = .≤
foo(^, ÷, -)

==>
Program(
  Operator(UnaryOp),
  Operator(UnaryOp),
  Assignment(Identifier, AssignmentOp, Operator(UnaryPlusOp)),
  Assignment(Operator(ComparisonOp), AssignmentOp, Operator(ComparisonOp)),
  CallExpression(Identifier, Arguments(Operator(PowerOp), Operator(TimesOp), Operator(UnaryPlusOp))),
)


# Operators as values - function and macro names

+(1, 2)
.*(xs, ys)
@>:

==>
Program(
  UnaryExpression(UnaryPlusOp, TupleExpression(IntegerLiteral, IntegerLiteral)),
  CallExpression(Operator(TimesOp), Arguments(Identifier, Identifier)),
  MacrocallExpression(MacroIdentifier(Operator(TypeComparisonOp))),
)
