import GolangLean.Token

namespace GolangLean

/-! # Go AST — mirrors `go/ast/ast.go`.

The Go reference parser produces nodes from three primary categories:
`Expr`, `Stmt`, `Decl`. We mirror that structure here. The point of mirroring
is that proofs and translations can refer to nodes by the same names that
Go programmers use, and so the eventual cross-language layer can compare
shapes apples-to-apples with octive-lean's `Expr/Stmt`. -/

/-! ## Operator categories (subsets of `Tok`) -/

inductive BinOp where
  | add | sub | mul | quo | rem
  | and | or  | xor | shl | shr | andNot
  | land | lor
  | eql | neq | lss | leq | gtr | geq
  deriving Repr, BEq, Inhabited

inductive UnOp where
  | plus | minus | not | xor | mul        -- `*p`  (deref)
  | and                                    -- `&v`  (addr-of)
  | arrow                                  -- `<-ch` (recv)
  deriving Repr, BEq, Inhabited

/-! ## Channel direction (for `chan T`, `<-chan T`, `chan<- T`) -/

inductive ChanDir where
  | send | recv | both
  deriving Repr, BEq, Inhabited

/-! ## AST nodes (mutually recursive: Expr ↔ Stmt ↔ Decl ↔ Type) -/

mutual

  /-- A Go expression. Types are also expressions in Go's grammar. -/
  inductive Expr where
    | bad
    | ident      : String → Expr
    | intLit     : Int → Expr
    | floatLit   : Float → Expr
    | stringLit  : String → Expr
    | charLit    : Char → Expr
    | imagLit    : Float → Expr
    | binOp      : BinOp → Expr → Expr → Expr
    | unOp       : UnOp → Expr → Expr
    | call       : Expr → Array Expr → Bool → Expr        -- f(args), variadic?
    | selector   : Expr → String → Expr                    -- x.Sel
    | index      : Expr → Expr → Expr                      -- x[i]
    | slice      : Expr → Option Expr → Option Expr → Option Expr → Expr  -- x[lo:hi:max]
    | typeAssert : Expr → Option Expr → Expr               -- x.(T)  (T = none for x.(type))
    | star       : Expr → Expr                             -- *T  or  *p
    | paren      : Expr → Expr
    | composite  : Option Expr → Array Expr → Expr         -- T{elts...}
    | keyValue   : Expr → Expr → Expr                      -- key: value (in composite)
    | funcLit    : FuncType → Array Stmt → Expr            -- func(...) ... { ... }
    | arrayType  : Option Expr → Expr → Expr               -- [N]T  or [...]T (none = ...)
    | sliceType  : Expr → Expr                             -- []T
    | mapType    : Expr → Expr → Expr                      -- map[K]V
    | chanType   : ChanDir → Expr → Expr                   -- chan T / <-chan T / chan<- T
    | structType : Array Field → Expr                      -- struct{ ... }
    | interfaceType : Array Field → Expr                   -- interface{ ... }
    | ellipsis   : Option Expr → Expr                      -- ...T  (variadic param / array len)

  /-- A struct field or method signature in an interface. -/
  inductive Field where
    | mk : Array String → Expr → Option String → Field     -- names, type, tag

  /-- A function-type expression: parameters and results. -/
  inductive FuncType where
    | mk : Array Field → Array Field → FuncType            -- params, results

  /-- A Go statement. -/
  inductive Stmt where
    | bad
    | declS      : Decl → Stmt
    | empty      : Stmt
    | labeled    : String → Stmt → Stmt
    | exprS      : Expr → Stmt
    | sendS      : Expr → Expr → Stmt                      -- ch <- x
    | incDec     : Expr → Bool → Stmt                      -- x++ / x--   (true = inc)
    | assignS    : Array Expr → Tok → Array Expr → Stmt    -- lhs op rhs (op ∈ {=, :=, +=, ...})
    | goS        : Expr → Stmt                             -- go f(...)
    | deferS     : Expr → Stmt                             -- defer f(...)
    | returnS    : Array Expr → Stmt
    | branchS    : Tok → Option String → Stmt              -- break/continue/goto/fallthrough
    | block      : Array Stmt → Stmt
    | ifS        : Option Stmt → Expr → Array Stmt → Option Stmt → Stmt
    | switchS    : Option Stmt → Option Expr → Array Stmt → Stmt
    | typeSwitch : Option Stmt → Stmt → Array Stmt → Stmt
    | caseClause : Array Expr → Array Stmt → Stmt
    | selectS    : Array Stmt → Stmt
    | commClause : Option Stmt → Array Stmt → Stmt
    | forS       : Option Stmt → Option Expr → Option Stmt → Array Stmt → Stmt
    | rangeS     : Option Expr → Option Expr → Tok → Expr → Array Stmt → Stmt  -- key,val := range x

  /-- A top-level or block-scoped declaration. -/
  inductive Decl where
    | bad
    | importD : Array (Option String × String) → Decl       -- (alias, path)
    | constD  : Array (Array String × Option Expr × Array Expr) → Decl  -- (names, type?, values)
    | varD    : Array (Array String × Option Expr × Array Expr) → Decl
    | typeD   : Array (String × Expr × Bool) → Decl         -- (name, type, isAlias)
    | funcD   : Option Field → String → FuncType → Option (Array Stmt) → Decl
                -- receiver?, name, signature, body? (none = forward decl in interface)

end

/-! ## File / Package -/

structure GoFile where
  pkg     : String
  imports : Array (Option String × String)
  decls   : Array Decl
  deriving Inhabited

end GolangLean
