From 40e7df701d246faa453003374206014606ca6b6d Mon Sep 17 00:00:00 2001 From: Jonathan Protzenko Date: Thu, 2 Feb 2023 23:36:14 -0800 Subject: WIP --- backends/lean/primitives.lean | 76 ++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 26 deletions(-) (limited to 'backends/lean/primitives.lean') diff --git a/backends/lean/primitives.lean b/backends/lean/primitives.lean index 0a51aacd..79958d94 100644 --- a/backends/lean/primitives.lean +++ b/backends/lean/primitives.lean @@ -1,4 +1,5 @@ import Lean +import Lean.Meta.Tactic.Simp import Init.Data.List.Basic import Mathlib.Tactic.RunCmd @@ -75,7 +76,7 @@ macro "let" h:ident " : " e:term " <-- " f:term : doElem => -- Silly example of the kind of reasoning that this notation enables #eval do let h: y <-- .ret (0: Nat) - let _: y = 0 := by cases h; simp + let _: y = 0 := by cases h; decide let r: { x: Nat // x = 0 } := ⟨ y, by assumption ⟩ .ret r @@ -111,6 +112,23 @@ macro "let" h:ident " : " e:term " <-- " f:term : doElem => -- library_search." Try to settle this with a Lean expert on what is the most -- productive way to go about this? +-- One needs to perform a little bit of reasoning in order to successfully +-- inject constants into USize, so we provide a general-purpose macro + +syntax "intlit" : tactic + +macro_rules + | `(tactic| intlit) => `(tactic| + match USize.size, usize_size_eq with + | _, Or.inl rfl => decide + | _, Or.inr rfl => decide) + +-- This is how the macro is expected to be used +#eval USize.ofNatCore 0 (by intlit) + +-- Also works for other integer types (at the expense of a needless disjunction) +#eval UInt32.ofNatCore 0 (by intlit) + -- Further thoughts: look at what has been done here: -- https://github.com/leanprover-community/mathlib4/blob/master/Mathlib/Data/Fin/Basic.lean -- and @@ -133,7 +151,12 @@ def USize.checked_sub (n: USize) (m: USize): result USize := fail integerOverflow def USize.checked_add (n: USize) (m: USize): result USize := - if h: n.val + m.val < USize.size then + if h: n.val.val + m.val.val <= 4294967295 then + .ret ⟨ n.val.val + m.val.val, by + have h': 4294967295 < USize.size := by intlit + apply Nat.lt_of_le_of_lt h h' + ⟩ + else if h: n.val + m.val < USize.size then .ret ⟨ n.val + m.val, h ⟩ else .fail integerOverflow @@ -149,7 +172,12 @@ def USize.checked_rem (n: USize) (m: USize): result USize := .fail integerOverflow def USize.checked_mul (n: USize) (m: USize): result USize := - if h: n.val * m.val < USize.size then + if h: n.val.val * m.val.val <= 4294967295 then + .ret ⟨ n.val.val * m.val.val, by + have h': 4294967295 < USize.size := by intlit + apply Nat.lt_of_le_of_lt h h' + ⟩ + else if h: n.val * m.val < USize.size then .ret ⟨ n.val * m.val, h ⟩ else .fail integerOverflow @@ -187,22 +215,6 @@ def scalar_cast { src: Type } (dst: Type) [ MachineInteger src ] [ MachineIntege else .fail integerOverflow --- One needs to perform a little bit of reasoning in order to successfully --- inject constants into USize, so we provide a general-purpose macro - -syntax "intlit" : tactic - -macro_rules - | `(tactic| intlit) => `(tactic| - match USize.size, usize_size_eq with - | _, Or.inl rfl => decide - | _, Or.inr rfl => decide) - --- This is how the macro is expected to be used -#eval USize.ofNatCore 0 (by intlit) - --- Also works for other integer types (at the expense of a needless disjunction) -#eval UInt32.ofNatCore 0 (by intlit) -- Test behavior... #eval assert! USize.checked_sub 10 20 == fail integerOverflow; 0 @@ -267,7 +279,14 @@ def vec_push_back_old (α : Type u) (v : vec α) (x : α) : { res: result (vec def vec_push_back (α : Type u) (v : vec α) (x : α) : result (vec α) := - if h : List.length v.val + 1 < USize.size then + if h : List.length v.val + 1 <= 4294967295 then + return ⟨ List.concat v.val x, + by + rw [List.length_concat] + have h': 4294967295 < USize.size := by intlit + apply Nat.lt_of_le_of_lt h h' + ⟩ + else if h: List.length v.val + 1 < USize.size then return ⟨List.concat v.val x, by rw [List.length_concat] @@ -340,10 +359,15 @@ syntax (name := assert) "#assert" term: command @[command_elab assert] def assertImpl : CommandElab := fun (_stx: Syntax) => do - logInfo "Hello World" - -def ignore (a: Prop) (_x: a) := () - -#eval ignore (2 == 2) (by simp) - + logInfo "Reducing and asserting: " + logInfo _stx[1] + runTermElabM (fun _ => do + let e ← Term.elabTerm _stx[1] none + logInfo (Expr.dbgToString e) + -- How to evaluate the term and compare the result to true? + pure ()) + -- logInfo (Expr.dbgToString (``true)) + -- throwError "TODO: assert" + +#eval 2 == 2 #assert (2 == 2) -- cgit v1.2.3