Contents:
Library ConCert.Extraction.PrettyPrinterMonad
From Coq Require Import List.
From Coq Require Import Ascii.
From Coq Require Import String.
From MetaCoq.Utils Require Import monad_utils.
From MetaCoq.SafeChecker Require Import PCUICErrors.
From MetaCoq.Erasure.Typed Require Import ResultMonad.
From ConCert.Extraction Require Import Common.
Import monad_utils.MCMonadNotation.
Import ListNotations.
Local Open Scope string.
Import Kernames.
Record PrettyPrinterState :=
{
indent_stack : list nat;
used_names : list ident;
output_lines : list (nat * string);
cur_output_line : nat * string;
}.
Notation bs_to_s := bytestring.String.to_string.
Notation s_to_bs := bytestring.String.of_string.
Local Coercion bs_to_s : bytestring.string >-> string.
Definition PrettyPrinter A :=
PrettyPrinterState -> result (A * PrettyPrinterState) string.
#[export]
Instance Monad_PrettyPrinter : Monad PrettyPrinter :=
{| ret _ a pps := Ok (a, pps);
bind _ _ m f pps :=
match m pps with
| Ok (a, pps) => f a pps
| Err err => Err err
end |}.
Definition map_pps
(f : list nat -> list nat)
(g : list ident -> list ident)
(h : list (nat * string) -> list (nat * string))
(i : nat * string -> nat * string) : PrettyPrinter unit :=
fun pps =>
Ok (tt,
let (a, b, c, d) := pps in
Build_PrettyPrinterState (f a) (g b) (h c) (i d)).
Fixpoint prefix_spaces n s :=
match n with
| 0 => s
| S n => prefix_spaces n (String " "%char s)
end.
Definition collect_output_lines pps :=
MCList.rev_map (fun '(n, l) => prefix_spaces n l) (cur_output_line pps :: output_lines pps).
Definition result_string_err A := result A string.
Definition finish_print_lines {A} (pp : PrettyPrinter A) : result_string_err (A * list string) :=
'(a, pps) <- pp {| indent_stack := [];
used_names := [];
output_lines := [];
cur_output_line := (0, "") |};;
ret (a, collect_output_lines pps).
Definition collect_output pps :=
concat nl (collect_output_lines pps).
Definition printer_fail {A} (str : string) : PrettyPrinter A :=
fun pps => Err (str ++ nl ++ "failed after printing" ++ nl ++ collect_output pps).
Definition finish_print {A} (pp : PrettyPrinter A) : result (A * string) string :=
'(a, lines) <- finish_print_lines pp;;
ret (a, concat nl lines).
Definition get_indent : PrettyPrinter nat :=
fun pps => Ok (hd 0 (indent_stack pps), pps).
Definition map_indent_stack (f : list nat -> list nat) : PrettyPrinter unit :=
map_pps f id id id.
Definition push_indent (n : nat) : PrettyPrinter unit :=
map_indent_stack (cons n).
Definition pop_indent : PrettyPrinter unit :=
map_indent_stack (@tl nat).
Definition get_used_names : PrettyPrinter (list ident) :=
fun pps => Ok (used_names pps, pps).
Definition map_used_names (f : list ident -> list ident) : PrettyPrinter unit :=
map_pps id f id id.
Definition push_use (n : ident) : PrettyPrinter unit :=
map_used_names (cons n).
Definition pop_use : PrettyPrinter unit :=
map_used_names (@tl _).
Definition get_current_line_length : PrettyPrinter nat :=
fun pps => Ok ((fst (cur_output_line pps)) + String.length (snd (cur_output_line pps)), pps).
Definition map_cur_output_line (f : nat * string -> nat * string) : PrettyPrinter unit :=
map_pps id id id f.
Definition append (s : string) : PrettyPrinter unit :=
map_cur_output_line (fun '(n, prev) => (n, prev ++ s)).
Definition append_nl : PrettyPrinter unit :=
fun pps =>
Ok (tt,
{| indent_stack := indent_stack pps;
used_names := used_names pps;
output_lines := cur_output_line pps :: output_lines pps;
cur_output_line := (hd 0 (indent_stack pps), "") |}).
Definition monad_append_join
(sep : PrettyPrinter unit)
(xs : list (PrettyPrinter unit)) : PrettyPrinter unit :=
monad_fold_left (fun sep' x => sep';; x;; ret sep) xs (ret tt);;
ret tt.
Definition append_join (sep : string) (s : list string) : PrettyPrinter unit :=
monad_append_join (append sep) (map append s).
Definition monad_append_concat (xs : list (PrettyPrinter unit)) : PrettyPrinter unit :=
monad_map id xs;;
ret tt.
Definition append_concat (xs : list string) : PrettyPrinter unit :=
monad_append_concat (map append xs).
Definition fresh_name (name : ident) (extra_used : list ident) : PrettyPrinter ident :=
used <- get_used_names;;
let used := (extra_used ++ used)%list in
if existsb (bytestring.String.eqb name) used then
(fix f n i :=
match n with
| 0 => ret (s_to_bs "unreachable")
| S n =>
let numbered_name := bytestring.String.append name (MCString.string_of_nat i) in
if existsb (bytestring.String.eqb numbered_name) used then
f n (S i)
else
ret numbered_name
end) (S (List.length used)) 2
else
ret name.
Definition string_of_env_error Σ e :=
match e with
| IllFormedDecl s e =>
("IllFormedDecl " ++ s ++ "\nType error: " ++ string_of_type_error Σ e)%string
| AlreadyDeclared s => "Alreadydeclared " ++ s
end%string.
Definition wrap_EnvCheck {astr A} f (ec : EnvCheck astr A) : PrettyPrinter A :=
match ec with
| CorrectDecl a => ret a
| EnvError Σ err =>
printer_fail ("EnvError: " ++ string_of_env_error (f Σ) err)
end.
Module P := PCUICAst.
Definition wrap_typing_result {A} (Σ : P.PCUICEnvironment.global_env)
(tr : typing_result A) : PrettyPrinter A :=
match tr with
| Checked et => ret et
| TypeError te =>
printer_fail ("TypeError: " ++ string_of_type_error (P.PCUICEnvironment.empty_ext Σ) te)
end.
Definition wrap_option {A} (o : option A) (err : string) : PrettyPrinter A :=
match o with
| Some a => ret a
| None => printer_fail err
end.
Definition wrap_result {T E} (r : result T E) (err_string : E -> string) : PrettyPrinter T :=
match r with
| Ok t => ret t
| Err e => printer_fail (err_string e)
end.
From Coq Require Import Ascii.
From Coq Require Import String.
From MetaCoq.Utils Require Import monad_utils.
From MetaCoq.SafeChecker Require Import PCUICErrors.
From MetaCoq.Erasure.Typed Require Import ResultMonad.
From ConCert.Extraction Require Import Common.
Import monad_utils.MCMonadNotation.
Import ListNotations.
Local Open Scope string.
Import Kernames.
Record PrettyPrinterState :=
{
indent_stack : list nat;
used_names : list ident;
output_lines : list (nat * string);
cur_output_line : nat * string;
}.
Notation bs_to_s := bytestring.String.to_string.
Notation s_to_bs := bytestring.String.of_string.
Local Coercion bs_to_s : bytestring.string >-> string.
Definition PrettyPrinter A :=
PrettyPrinterState -> result (A * PrettyPrinterState) string.
#[export]
Instance Monad_PrettyPrinter : Monad PrettyPrinter :=
{| ret _ a pps := Ok (a, pps);
bind _ _ m f pps :=
match m pps with
| Ok (a, pps) => f a pps
| Err err => Err err
end |}.
Definition map_pps
(f : list nat -> list nat)
(g : list ident -> list ident)
(h : list (nat * string) -> list (nat * string))
(i : nat * string -> nat * string) : PrettyPrinter unit :=
fun pps =>
Ok (tt,
let (a, b, c, d) := pps in
Build_PrettyPrinterState (f a) (g b) (h c) (i d)).
Fixpoint prefix_spaces n s :=
match n with
| 0 => s
| S n => prefix_spaces n (String " "%char s)
end.
Definition collect_output_lines pps :=
MCList.rev_map (fun '(n, l) => prefix_spaces n l) (cur_output_line pps :: output_lines pps).
Definition result_string_err A := result A string.
Definition finish_print_lines {A} (pp : PrettyPrinter A) : result_string_err (A * list string) :=
'(a, pps) <- pp {| indent_stack := [];
used_names := [];
output_lines := [];
cur_output_line := (0, "") |};;
ret (a, collect_output_lines pps).
Definition collect_output pps :=
concat nl (collect_output_lines pps).
Definition printer_fail {A} (str : string) : PrettyPrinter A :=
fun pps => Err (str ++ nl ++ "failed after printing" ++ nl ++ collect_output pps).
Definition finish_print {A} (pp : PrettyPrinter A) : result (A * string) string :=
'(a, lines) <- finish_print_lines pp;;
ret (a, concat nl lines).
Definition get_indent : PrettyPrinter nat :=
fun pps => Ok (hd 0 (indent_stack pps), pps).
Definition map_indent_stack (f : list nat -> list nat) : PrettyPrinter unit :=
map_pps f id id id.
Definition push_indent (n : nat) : PrettyPrinter unit :=
map_indent_stack (cons n).
Definition pop_indent : PrettyPrinter unit :=
map_indent_stack (@tl nat).
Definition get_used_names : PrettyPrinter (list ident) :=
fun pps => Ok (used_names pps, pps).
Definition map_used_names (f : list ident -> list ident) : PrettyPrinter unit :=
map_pps id f id id.
Definition push_use (n : ident) : PrettyPrinter unit :=
map_used_names (cons n).
Definition pop_use : PrettyPrinter unit :=
map_used_names (@tl _).
Definition get_current_line_length : PrettyPrinter nat :=
fun pps => Ok ((fst (cur_output_line pps)) + String.length (snd (cur_output_line pps)), pps).
Definition map_cur_output_line (f : nat * string -> nat * string) : PrettyPrinter unit :=
map_pps id id id f.
Definition append (s : string) : PrettyPrinter unit :=
map_cur_output_line (fun '(n, prev) => (n, prev ++ s)).
Definition append_nl : PrettyPrinter unit :=
fun pps =>
Ok (tt,
{| indent_stack := indent_stack pps;
used_names := used_names pps;
output_lines := cur_output_line pps :: output_lines pps;
cur_output_line := (hd 0 (indent_stack pps), "") |}).
Definition monad_append_join
(sep : PrettyPrinter unit)
(xs : list (PrettyPrinter unit)) : PrettyPrinter unit :=
monad_fold_left (fun sep' x => sep';; x;; ret sep) xs (ret tt);;
ret tt.
Definition append_join (sep : string) (s : list string) : PrettyPrinter unit :=
monad_append_join (append sep) (map append s).
Definition monad_append_concat (xs : list (PrettyPrinter unit)) : PrettyPrinter unit :=
monad_map id xs;;
ret tt.
Definition append_concat (xs : list string) : PrettyPrinter unit :=
monad_append_concat (map append xs).
Definition fresh_name (name : ident) (extra_used : list ident) : PrettyPrinter ident :=
used <- get_used_names;;
let used := (extra_used ++ used)%list in
if existsb (bytestring.String.eqb name) used then
(fix f n i :=
match n with
| 0 => ret (s_to_bs "unreachable")
| S n =>
let numbered_name := bytestring.String.append name (MCString.string_of_nat i) in
if existsb (bytestring.String.eqb numbered_name) used then
f n (S i)
else
ret numbered_name
end) (S (List.length used)) 2
else
ret name.
Definition string_of_env_error Σ e :=
match e with
| IllFormedDecl s e =>
("IllFormedDecl " ++ s ++ "\nType error: " ++ string_of_type_error Σ e)%string
| AlreadyDeclared s => "Alreadydeclared " ++ s
end%string.
Definition wrap_EnvCheck {astr A} f (ec : EnvCheck astr A) : PrettyPrinter A :=
match ec with
| CorrectDecl a => ret a
| EnvError Σ err =>
printer_fail ("EnvError: " ++ string_of_env_error (f Σ) err)
end.
Module P := PCUICAst.
Definition wrap_typing_result {A} (Σ : P.PCUICEnvironment.global_env)
(tr : typing_result A) : PrettyPrinter A :=
match tr with
| Checked et => ret et
| TypeError te =>
printer_fail ("TypeError: " ++ string_of_type_error (P.PCUICEnvironment.empty_ext Σ) te)
end.
Definition wrap_option {A} (o : option A) (err : string) : PrettyPrinter A :=
match o with
| Some a => ret a
| None => printer_fail err
end.
Definition wrap_result {T E} (r : result T E) (err_string : E -> string) : PrettyPrinter T :=
match r with
| Ok t => ret t
| Err e => printer_fail (err_string e)
end.