///|
pub(all) enum UnaryOp {
  Negate // -x
  Pos // +x
  BitNot // ~x
  LogNot // not x
} derive(Show, Eq, ToJson)

///|
pub(all) enum BinaryOp {
  // Arithmetic
  Add
  Sub
  Mul
  Div
  FloorDiv
  Mod
  // Bitwise
  BitAnd
  BitOr
  BitXor
  LShift
  RShift
  // Comparison
  Eq
  NotEq
  Lt
  Gt
  LtEq
  GtEq
  // Logical
  And
  Or
  // Membership
  In
  NotIn
} derive(Show, Eq, ToJson)

///|
pub(all) enum AssignOp {
  PlusEq
  MinusEq
  StarEq
  SlashEq
  FloorDivEq
  PercentEq
  AmpEq
  PipeEq
  CaretEq
  LShiftEq
  RShiftEq
} derive(Show, Eq, ToJson)

///|
pub(all) enum Argument {
  Positional(Expr) // expr
  Keyword(String, Expr) // name=expr
  Star(Expr) // *expr
  DoubleStar(Expr) // **expr
} derive(Show, Eq, ToJson)

///|
pub(all) enum CompClause {
  For(vars~ : Expr, iterable~ : Expr) // for vars in iterable
  If(Expr) // if condition
} derive(Show, Eq, ToJson)

///|
pub(all) enum Expr {
  NoneLiteral(Span)
  BoolLiteral(Bool, Span)
  IntLiteral(Int64, Span)
  StringLiteral(String, Span)
  Identifier(String, Span)
  UnaryOp(op~ : UnaryOp, operand~ : Expr, span~ : Span)
  BinaryOp(left~ : Expr, op~ : BinaryOp, right~ : Expr, span~ : Span)
  IfExpr(condition~ : Expr, then_expr~ : Expr, else_expr~ : Expr, span~ : Span)
  Call(func~ : Expr, args~ : Array[Argument], span~ : Span)
  Index(object~ : Expr, index~ : Expr, span~ : Span)
  Slice(
    object~ : Expr,
    start~ : Expr?,
    stop~ : Expr?,
    step~ : Expr?,
    span~ : Span
  )
  Dot(object~ : Expr, field~ : String, span~ : Span)
  ListExpr(elements~ : Array[Expr], span~ : Span)
  TupleExpr(elements~ : Array[Expr], span~ : Span)
  DictExpr(entries~ : Array[(Expr, Expr)], span~ : Span)
  ListComp(expr~ : Expr, clauses~ : Array[CompClause], span~ : Span)
  DictComp(
    key~ : Expr,
    value~ : Expr,
    clauses~ : Array[CompClause],
    span~ : Span
  )
} derive(Show, Eq, ToJson)