Library PrintPos


Require Import ZArith NArith List Zpower.

Inductive hex_digit : Set :=
| Hx0 | Hx1 | Hx2 | Hx3
| Hx4 | Hx5 | Hx6 | Hx7
| Hx8 | Hx9 | HxA | HxB
| HxC | HxD | HxE | HxF
.

Inductive hex_digit_partial : Set :=
| HDP0 | HDP1 (b: bool)
| HDP2 (b1 b0: bool)
| HDP3 (b2 b1 b0: bool)
.

Definition hex_partial_as_digit (hp: hex_digit_partial) : hex_digit :=
  match hp with
    | HDP0
    | HDP1 false
    | HDP2 false false
    | HDP3 false false falseHx0
    | HDP1 true
    | HDP2 false true
    | HDP3 false false trueHx1
    | HDP2 true false
    | HDP3 false true falseHx2
    | HDP2 true true
    | HDP3 false true trueHx3
    | HDP3 true false falseHx4
    | HDP3 true false trueHx5
    | HDP3 true true falseHx6
    | HDP3 true true trueHx7
  end.

Definition set_next_bit (bh: hex_digit_partial)
  : hex_digit + hex_digit_partial :=
  match bh with
    | HDP0inr _ (HDP1 true)
    | HDP1 binr _ (HDP2 true b)
    | HDP2 b1 b0inr _ (HDP3 true b1 b0)
    | HDP3 b2 b1 b0inl _
      (match b2, b1, b0 with
         | false, false, falseHx8
         | false, false, trueHx9
         | false, true , falseHxA
         | false, true , trueHxB
         | true , false, falseHxC
         | true , false, trueHxD
         | true , true , falseHxE
         | true , true , trueHxF
       end)
  end.

Definition reset_next_bit (bh: hex_digit_partial)
  : hex_digit + hex_digit_partial :=
  match bh with
    | HDP0inr _ (HDP1 false)
    | HDP1 binr _ (HDP2 false b)
    | HDP2 b1 b0inr _ (HDP3 false b1 b0)
    | HDP3 b2 b1 b0inl _
      (match b2, b1, b0 with
         | false, false, falseHx0
         | false, false, trueHx1
         | false, true , falseHx2
         | false, true , trueHx3
         | true , false, falseHx4
         | true , false, trueHx5
         | true , true , falseHx6
         | true , true , trueHx7
       end)
  end.

Definition hex_num : Set := list hex_digit.

Fixpoint hex_of_pos' (p: positive) (curr: hex_digit_partial) (acc: hex_num)
  {struct p} : hex_num :=
  match p with
    | xHmatch set_next_bit curr with
              | inl dd
              | inr hphex_partial_as_digit hp
            end :: acc
    | xO p'match reset_next_bit curr with
                 | inl dhex_of_pos' p' HDP0 (d::acc)
                 | inr hphex_of_pos' p' hp acc
               end
    | xI p'match set_next_bit curr with
                 | inl dhex_of_pos' p' HDP0 (d::acc)
                 | inr hphex_of_pos' p' hp acc
               end
  end.

Definition hex_of_pos (p: positive) : hex_num :=
  hex_of_pos' p HDP0 nil.

Section PRINT.

  Require Import Ascii String.
  Local Open Scope char_scope.

  Definition hex_digit_ascii (hx: hex_digit) : ascii :=
    match hx with
      | Hx0 ⇒ "0" | Hx1 ⇒ "1"
      | Hx2 ⇒ "2" | Hx3 ⇒ "3"
      | Hx4 ⇒ "4" | Hx5 ⇒ "5"
      | Hx6 ⇒ "6" | Hx7 ⇒ "7"
      | Hx8 ⇒ "8" | Hx9 ⇒ "9"
      | HxA ⇒ "A" | HxB ⇒ "B"
      | HxC ⇒ "C" | HxD ⇒ "D"
      | HxE ⇒ "E" | HxF ⇒ "F"
    end.

  Fixpoint hex_num_string (hn: hex_num) {struct hn} : string :=
    match hn with
      | d :: hn'String (hex_digit_ascii d) (hex_num_string hn')
      | nilEmptyString
    end.

  Definition print_pos (p: positive) : string :=
    ("0x" ++ hex_num_string (hex_of_pos p))%string.

  Definition string_of_z (z: Z) : string :=
    (match z with
     | Z0 ⇒ "0"
     | Zpos pprint_pos p
     | Zneg p ⇒ "-" ++ print_pos p
     end)%string.

End PRINT.