Library Prelude.Data.Z


From Coq Require Import Wf Utils ZArith.
From Prelude Require Import Init Text Control.

#[local]
Open Scope Z_scope.
#[local]
Open Scope program_scope.

#[program]
Definition wchar_of_digit (x : Z) (xs : x < 10) : wchar :=
  if x <? 1 then "0"
  else if x <? 2 then "1"
  else if x <? 3 then "2"
  else if x <? 4 then "3"
  else if x <? 5 then "4"
  else if x <? 6 then "5"
  else if x <? 7 then "6"
  else if x <? 8 then "7"
  else if x <? 9 then "8"
  else (if x <? 10 as b return (b = (x <? 10) -> wchar)
  then fun _ => w#"9"
  else _)
         eq_refl.

Next Obligation.
  symmetry in H.
  rewrite Z.ltb_ge in H.
  now apply Zle_not_lt in H.
Defined.

#[program]
Fixpoint text_of_Z_aux (x : Z) (xs : 0 < x) {measure (Z.to_nat x)} : text :=
  let d := x / 10 in
  let r := x mod 10 in
  TCons (wchar_of_digit r _) ((if 0 <? d as b return (0 <? d = b -> text)
                               then fun _ => text_of_Z_aux d _
                               else fun _ => TNil) eq_refl).

Next Obligation.
  apply Z.mod_bound_pos.
  + auto with zarith.
  + reflexivity.
Defined.

Next Obligation.
  now apply Z.ltb_lt in H.
Defined.

Next Obligation.
  apply Z2Nat.inj_lt.
  + apply Z.div_pos.
    ++ auto with zarith.
    ++ reflexivity.
  + auto with zarith.
  + now apply Z.div_lt.
Defined.

#[program]
Definition text_of_Z (x : Z) : text :=
  (if 0 <? x as b return (0 <? x = b -> text)
   then fun _ => text_of_Z_aux x _
   else fun _ => t#"0") eq_refl.

Next Obligation.
  now apply Z.ltb_lt in H.
Defined.

Definition digit_of_wchar (x : wchar) : option Z :=
  match x with
  | w#"0" => Some 0
  | w#"1" => Some 1
  | w#"2" => Some 2
  | w#"3" => Some 3
  | w#"4" => Some 4
  | w#"5" => Some 5
  | w#"6" => Some 6
  | w#"7" => Some 7
  | w#"8" => Some 8
  | w#"9" => Some 9
  | _ => None
  end.

Fixpoint Z_of_text_aux (x : text) (acc : Z) : option Z :=
  match x with
  | TCons x rst => do let* x := digit_of_wchar x in
                      Z_of_text_aux rst (10 * acc + x)
                   end
  | TNil => pure acc
  end.

Definition Z_of_text (x : text) : option Z :=
  match x with
  | TCons w#"-" rst => do (fun x => -1 * x) <$> Z_of_text_aux rst 0 end
  | _ => do (fun x => -1 * x) <$> Z_of_text_aux x 0 end
  end.