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, [])