import GolangLean

/-!
# golang-lean Rosetta Stone

Side-by-side comparisons of Go syntax with its Lean encodings.

Two encodings are shown for each construct:

  * **Surface AST** (`GolangLean.Expr`, etc.) — the parser's target.
    Mirrors `go/ast.Node` from the upstream Go reference compiler.
    Faithful to Go's grammar but has no formal semantics yet (the
    surface evaluator is a stub).

  * **Tiny Go Core** (`GolangLean.Core.Term`) — the kernel calculus.
    Smaller, typed, with proven big-step semantics, executable
    evaluator, determinism, and preservation. Real Go programs would
    desugar into this kernel via an elaborator (future work).

Where applicable, `#eval` runs the term through the proven evaluator.
The result is `some (Value, Heap)` on success.
-/

open GolangLean

-- A tiny convenience for running TGC programs.
def runTGC (e : Core.Term) : Option (Core.Value × Core.Heap) :=
  Core.eval 1000 #[] .nil e

/-! ## §1 Literals — atoms of any language. -/

-- Go: `42`
def lit42_AST : Expr      := .intLit 42
def lit42_TGC : Core.Term := .intLit 42
#eval runTGC lit42_TGC                  -- some (vInt 42, [])

-- Go: `true`  (a predeclared identifier in Go)
def litTrue_AST : Expr      := .ident "true"
def litTrue_TGC : Core.Term := .boolLit true
#eval runTGC litTrue_TGC                -- some (vBool true, [])

/-! ## §2 Arithmetic and comparison

Go's binary operators map directly to TGC's `binop`. -/

-- Go: `5 + 3`
def add5_3_AST : Expr      := .binOp .add (.intLit 5) (.intLit 3)
def add5_3_TGC : Core.Term := .binop .add (.intLit 5) (.intLit 3)
#eval runTGC add5_3_TGC                 -- some (vInt 8, [])

-- Go: `(5 + 3) * 2`
def expr_AST : Expr :=
  .binOp .mul (.binOp .add (.intLit 5) (.intLit 3)) (.intLit 2)
def expr_TGC : Core.Term :=
  .binop .mul (.binop .add (.intLit 5) (.intLit 3)) (.intLit 2)
#eval runTGC expr_TGC                   -- some (vInt 16, [])

-- Go: `x < y`
def less_AST : Expr      := .binOp .lss (.ident "x") (.ident "y")
def less_TGC : Core.Term := .binop .lt (.var "x") (.var "y")
-- Needs an env binding x and y — see §4.

-- Go: `x == 5`
def eq_AST : Expr      := .binOp .eql (.ident "x") (.intLit 5)
def eq_TGC : Core.Term := .binop .eq (.var "x") (.intLit 5)

/-! ## §3 Conditionals

Go's `if` statement vs. TGC's `ifte` expression form. -/

-- Go (statement): `if x < 10 { return 1 } else { return 2 }`
-- Go has no ternary expression; TGC's `ifte` is closer to ML's
-- `if ... then ... else ...` for proof-friendliness.
def ifte_TGC : Core.Term :=
  .ifte (.binop .lt (.var "x") (.intLit 10))
        (.intLit 1) (.intLit 2)

/-! ## §4 Variables and let-binding

Go's `x := 42` ↦ TGC's `letIn` (lexical binding, scoped to body).
For *mutating* variables, see §6 (TGC uses `assign` on a heap-allocated
ref). -/

-- Go: `x := 42; x + 1`
def letIn_TGC : Core.Term :=
  .letIn "x" (.intLit 42) (.binop .add (.var "x") (.intLit 1))
#eval runTGC letIn_TGC                  -- some (vInt 43, [])

-- Two bindings: `x := 3; y := 7; x < y`
def less_run : Core.Term :=
  .letIn "x" (.intLit 3)
    (.letIn "y" (.intLit 7)
      (.binop .lt (.var "x") (.var "y")))
#eval runTGC less_run                   -- some (vBool true, [])

/-! ## §5 Functions and application

Go's anonymous function `func(x int) int { return x*2 }` ↦ TGC's
`lam` (a closure). Application is `app`. -/

-- Go: `(func(x int) int { return x*2 })(21)`
def lambda_app_TGC : Core.Term :=
  .app (.lam "x" (.binop .mul (.var "x") (.intLit 2))) (.intLit 21)
#eval runTGC lambda_app_TGC             -- some (vInt 42, [])

-- Higher-order. With `double = func(x) { x*2 }`:
-- `(func(f) func(x) { f(f(x)) })(double)(3)` = double(double(3)) = 12
def higher_order_TGC : Core.Term :=
  .app
    (.app
      (.lam "f"
        (.lam "x" (.app (.var "f") (.app (.var "f") (.var "x")))))
      (.lam "x" (.binop .mul (.var "x") (.intLit 2))))
    (.intLit 3)
#eval runTGC higher_order_TGC           -- some (vInt 12, [])

/-! ## §6 References, dereference, assignment

Go's `&x`, `*p`, `*p = e` ↦ TGC's `refMk`, `deref`, `assign`.
The heap (third tuple component, an `Array Value`) accumulates
allocations. -/

-- Go: `p := &42; *p`
def ref_deref_TGC : Core.Term :=
  .letIn "p" (.refMk (.intLit 42)) (.deref (.var "p"))
#eval runTGC ref_deref_TGC              -- some (vInt 42, #[vInt 42])

-- Go: `p := &42; *p = 100; *p`
def ref_assign_TGC : Core.Term :=
  .letIn "p" (.refMk (.intLit 42))
    (.seq (.assign (.var "p") (.intLit 100))
          (.deref (.var "p")))
#eval runTGC ref_assign_TGC             -- some (vInt 100, #[vInt 100])

/-! ## §7 Sequencing — Go statement separator. -/

-- Go: `_ = 1; 42`
def seq_TGC : Core.Term := .seq (.intLit 1) (.intLit 42)
#eval runTGC seq_TGC                    -- some (vInt 42, [])

/-! ## §8 Theorems applicable to these terms

  * `Core.BigStep.deterministic` — the relation is functional.
  * `Core.eval_sound` — every successful eval is a `BigStep` derivation.
  * `Core.preservation` — well-typed terms produce well-typed values.

Each `#eval` above is a *runtime witness* for a `BigStep` derivation,
which by `eval_sound` is also a proof that the term has the shown
value. Type-check the term and apply `preservation` to get the value's
type for free. -/

-- Demo: a small composition showing TGC's expressive range.
-- `let double = λ x. x*2 in double (double 5)` = 20
def double_twice : Core.Term :=
  .letIn "double" (.lam "x" (.binop .mul (.var "x") (.intLit 2)))
    (.app (.var "double") (.app (.var "double") (.intLit 5)))
#eval runTGC double_twice               -- some (vInt 20, [])
