diff --git a/Bytecode/Basic.lean b/Bytecode/Basic.lean index 99415d9..aebaa8f 100644 --- a/Bytecode/Basic.lean +++ b/Bytecode/Basic.lean @@ -1 +1,99 @@ -def hello := "world" +import Batteries.Data.Rat.Basic +import Batteries.Control.Lawful.MonadLift + +inductive Ast +| lit (n : Rat) +| add (l r : Ast) +| sub (l r : Ast) +| mul (l r : Ast) +| div (l r : Ast) + +instance : Coe Rat Ast where coe := .lit +instance : OfScientific Ast where + ofScientific a b c := .lit (.ofScientific a b c) +instance : OfNat Ast n where ofNat := .lit n + +instance : Add Ast where add := .add +instance : Sub Ast where sub := .sub +instance : Mul Ast where mul := .mul +instance : Div Ast where div := .div + +def Ast.interpret : Ast → Rat +| lit n => n +| add l r => l.interpret + r.interpret +| sub l r => l.interpret - r.interpret +| mul l r => l.interpret * r.interpret +| div l r => l.interpret / r.interpret + +#eval Ast.interpret <| 3/2 + 0.5 + +inductive Op +| push (n : Rat) +| add +| sub +| mul +| div + deriving Repr + +-- TODO: prove that the stack manip is all good throughout +def Op.pop_push : Op → Nat × Nat +| push _ => (0, 1) +| _ => (2, 1) + +abbrev Ops := Array Op + +def pushM (x : α) : StateM (Array α) Unit := + modify <| (·.push x) + +def popM? : StateM (Array α) (Option α) := do + let top ← Array.back? <$> get + modify Array.pop + return top + +abbrev M := OptionT (StateM (Array Rat)) +instance : LawfulMonad M := sorry + +def Op.action (op : Op) : M Unit := do + match op with + | .push n => pushM n + | .add => pushM <| (← popM?) + (← popM?) + | .sub => pushM <| (← popM?) - (← popM?) + | .mul => pushM <| (← popM?) * (← popM?) + | .div => pushM <| (← popM?) / (← popM?) + +def Ops.action (ops : Ops) : M Unit := ops.forM Op.action + +def Ops.run (ops : Ops) : Option Rat := + (do + ops.action + popM? + ).run #[] |>.fst + +def Ast.compile : Ast → Ops +| .lit n => #[.push n] +| .add l r => l.compile ++ r.compile ++ #[.add] +| .sub l r => l.compile ++ r.compile ++ #[.sub] +| .mul l r => l.compile ++ r.compile ++ #[.mul] +-- Note that l and r are flipped here. compilation! +| .div l r => r.compile ++ l.compile ++ #[.div] + +#eval (3/2 + 0.5 : Ast) |>.compile.run + +@[simp] +theorem Ops.append_action (a b : Ops) + : (a ++ b).action = (do a.action; b.action) := by + rw [action] + exact Array.forM_append + +@[simp] +theorem Ops.push_action (ops : Ops) (op : Op) + : action (ops.push op) = (do ops.action; op.action) := by + rw [Array.push_eq_append, append_action] + have : op.action = action #[op] := by simp [action] + rw [this] + +theorem Ast.compile_sound (ast : Ast) + : ast.compile.run = some ast.interpret := by + induction ast + · rfl + simp [compile] diff --git a/lake-manifest.json b/lake-manifest.json new file mode 100644 index 0000000..5072ddf --- /dev/null +++ b/lake-manifest.json @@ -0,0 +1,15 @@ +{"version": "1.1.0", + "packagesDir": ".lake/packages", + "packages": + [{"url": "https://github.com/leanprover-community/batteries", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "f1a7afdb343196b33bf9137b232eb69446065925", + "name": "batteries", + "manifestFile": "lake-manifest.json", + "inputRev": "main", + "inherited": false, + "configFile": "lakefile.toml"}], + "name": "bytecode", + "lakeDir": ".lake"} diff --git a/lakefile.toml b/lakefile.toml index afcbbed..ca22313 100644 --- a/lakefile.toml +++ b/lakefile.toml @@ -8,3 +8,8 @@ name = "Bytecode" [[lean_exe]] name = "bytecode" root = "Main" + +[[require]] +name = "batteries" +scope = "leanprover-community" +rev = "main" diff --git a/lean-toolchain b/lean-toolchain index a3edb8f..c7e245c 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.16.0-rc2 +leanprover/lean4:v4.19.0-rc2 \ No newline at end of file