[@@@warning "-42"] open AST module Region = Simple_utils.Region open! Region open! PPrint let pp_par printer {value; _} = string "(" ^^ nest 1 (printer value.inside ^^ string ")") let rec print ast = let app decl = group (pp_declaration decl) in let decl = Utils.nseq_to_list ast.decl in separate_map (hardline ^^ hardline) app decl and pp_declaration = function Let decl -> pp_let_decl decl | TypeDecl decl -> pp_type_decl decl and pp_let_decl {value; _} = let _, rec_opt, binding, attr = value in let let_str = match rec_opt with None -> "let " | Some _ -> "let rec " in let binding = pp_let_binding binding and attr = pp_attributes attr in string let_str ^^ binding ^^ attr and pp_attributes = function [] -> empty | attr -> let make s = string "[@@" ^^ string s.value ^^ string "]" in group (nest 2 (break 1 ^^ separate_map (break 0) make attr)) and pp_ident {value; _} = string value and pp_string s = string "\"" ^^ pp_ident s ^^ string "\"" and pp_verbatim s = string "{|" ^^ pp_ident s ^^ string "|}" and pp_let_binding (binding : let_binding) = let {binders; lhs_type; let_rhs; _} = binding in let head, tail = binders in let patterns = group (nest 2 (separate_map (break 1) pp_pattern (head::tail))) in let lhs = patterns ^^ match lhs_type with None -> empty | Some (_,e) -> group (break 1 ^^ string ": " ^^ pp_type_expr e) in prefix 2 1 (lhs ^^ string " =") (pp_expr let_rhs) and pp_pattern = function PConstr p -> pp_pconstr p | PUnit _ -> string "()" | PFalse _ -> string "false" | PTrue _ -> string "true" | PVar v -> pp_ident v | PInt i -> pp_int i | PNat n -> pp_nat n | PBytes b -> pp_bytes b | PString s -> pp_string s | PVerbatim s -> pp_verbatim s | PWild _ -> string "_" | PList l -> pp_plist l | PTuple t -> pp_ptuple t | PPar p -> pp_ppar p | PRecord r -> pp_precord r | PTyped t -> pp_ptyped t and pp_pconstr = function PNone _ -> string "None" | PSomeApp p -> pp_patt_some p | PConstrApp a -> pp_pconstr_app a and pp_pconstr_app {value; _} = match value with constr, None -> pp_ident constr | constr, Some pat -> prefix 4 1 (pp_ident constr) (pp_pattern pat) and pp_patt_some {value; _} = prefix 4 1 (string "Some") (pp_pattern (snd value)) and pp_int {value; _} = string (Z.to_string (snd value)) and pp_nat {value; _} = string (Z.to_string (snd value) ^ "n") and pp_bytes {value; _} = string ("0x" ^ Hex.show (snd value)) and pp_ppar p = pp_par pp_pattern p and pp_plist = function PListComp cmp -> pp_list_comp cmp | PCons cons -> pp_pcons cons and pp_list_comp e = group (pp_injection pp_pattern e) and pp_pcons {value; _} = let patt1, _, patt2 = value in prefix 2 1 (pp_pattern patt1 ^^ string " ::") (pp_pattern patt2) and pp_ptuple {value; _} = let head, tail = value in let rec app = function [] -> empty | [p] -> group (break 1 ^^ pp_pattern p) | p::items -> group (break 1 ^^ pp_pattern p ^^ string ",") ^^ app items in if tail = [] then pp_pattern head else pp_pattern head ^^ string "," ^^ app (List.map snd tail) and pp_precord fields = pp_ne_injection pp_field_pattern fields and pp_field_pattern {value; _} = let {field_name; pattern; _} = value in prefix 2 1 (pp_ident field_name ^^ string " =") (pp_pattern pattern) and pp_ptyped {value; _} = let {pattern; type_expr; _} = value in group (pp_pattern pattern ^^ string " :" ^/^ pp_type_expr type_expr) and pp_type_decl decl = let {name; type_expr; _} = decl.value in let padding = match type_expr with TSum _ -> 0 | _ -> 2 in string "type " ^^ string name.value ^^ string " =" ^^ group (nest padding (break 1 ^^ pp_type_expr type_expr)) and pp_expr = function ECase e -> pp_case_expr e | ECond e -> group (pp_cond_expr e) | EAnnot e -> pp_annot_expr e | ELogic e -> group (pp_logic_expr e) | EArith e -> group (pp_arith_expr e) | EString e -> pp_string_expr e | EList e -> group (pp_list_expr e) | EConstr e -> pp_constr_expr e | ERecord e -> pp_record_expr e | EProj e -> pp_projection e | EUpdate e -> pp_update e | EVar v -> pp_ident v | ECall e -> pp_call_expr e | EBytes e -> pp_bytes e | EUnit _ -> string "()" | ETuple e -> pp_tuple_expr e | EPar e -> pp_par_expr e | ELetIn e -> pp_let_in e | EFun e -> pp_fun e | ESeq e -> pp_seq e | ECodeInj e -> pp_code_inj e and pp_case_expr {value; _} = let {expr; cases; _} = value in group (string "match " ^^ nest 6 (pp_expr expr) ^/^ string "with") ^^ hardline ^^ pp_cases cases and pp_cases {value; _} = let head, tail = value in let head = pp_clause head in let head = if tail = [] then head else blank 2 ^^ head in let rest = List.map snd tail in let app clause = break 1 ^^ string "| " ^^ pp_clause clause in head ^^ concat_map app rest and pp_clause {value; _} = let {pattern; rhs; _} = value in pp_pattern pattern ^^ prefix 4 1 (string " ->") (pp_expr rhs) and pp_cond_expr {value; _} = let {test; ifso; kwd_else; ifnot; _} = value in let test = string "if " ^^ group (nest 3 (pp_expr test)) and ifso = string "then" ^^ group (nest 2 (break 1 ^^ pp_expr ifso)) and ifnot = string "else" ^^ group (nest 2 (break 1 ^^ pp_expr ifnot)) in if kwd_else#is_ghost then test ^/^ ifso else test ^/^ ifso ^/^ ifnot and pp_annot_expr {value; _} = let expr, _, type_expr = value.inside in group (string "(" ^^ nest 1 (pp_expr expr ^/^ string ": " ^^ pp_type_expr type_expr ^^ string ")")) and pp_logic_expr = function BoolExpr e -> pp_bool_expr e | CompExpr e -> pp_comp_expr e and pp_bool_expr = function Or e -> pp_bin_op "||" e | And e -> pp_bin_op "&&" e | Not e -> pp_un_op "not" e | True _ -> string "true" | False _ -> string "false" and pp_bin_op op {value; _} = let {arg1; arg2; _} = value and length = String.length op + 1 in pp_expr arg1 ^/^ string (op ^ " ") ^^ nest length (pp_expr arg2) and pp_un_op op {value; _} = string (op ^ " ") ^^ pp_expr value.arg and pp_comp_expr = function Lt e -> pp_bin_op "<" e | Leq e -> pp_bin_op "<=" e | Gt e -> pp_bin_op ">" e | Geq e -> pp_bin_op ">=" e | Equal e -> pp_bin_op "=" e | Neq e -> pp_bin_op "<>" e and pp_arith_expr = function Add e -> pp_bin_op "+" e | Sub e -> pp_bin_op "-" e | Mult e -> pp_bin_op "*" e | Div e -> pp_bin_op "/" e | Mod e -> pp_bin_op "mod" e | Neg e -> string "-" ^^ pp_expr e.value.arg | Int e -> pp_int e | Nat e -> pp_nat e | Mutez e -> pp_mutez e and pp_mutez {value; _} = Z.to_string (snd value) ^ "mutez" |> string and pp_string_expr = function Cat e -> pp_bin_op "^" e | String e -> pp_string e | Verbatim e -> pp_verbatim e and pp_list_expr = function ECons e -> pp_bin_op "::" e | EListComp e -> group (pp_injection pp_expr e) and pp_injection : 'a.('a -> document) -> 'a injection reg -> document = fun printer {value; _} -> let {compound; elements; _} = value in let sep = string ";" ^^ break 1 in let elements = Utils.sepseq_to_list elements in let elements = separate_map sep printer elements in match pp_compound compound with None -> elements | Some (opening, closing) -> string opening ^^ nest 1 elements ^^ string closing and pp_compound = function BeginEnd (start, _) -> if start#is_ghost then None else Some ("begin","end") | Braces (start, _) -> if start#is_ghost then None else Some ("{","}") | Brackets (start, _) -> if start#is_ghost then None else Some ("[","]") and pp_constr_expr = function ENone _ -> string "None" | ESomeApp a -> pp_some a | EConstrApp a -> pp_constr_app a and pp_some {value=_, e; _} = prefix 4 1 (string "Some") (pp_expr e) and pp_constr_app {value; _} = let constr, arg = value in let constr = string constr.value in match arg with None -> constr | Some e -> prefix 2 1 constr (pp_expr e) and pp_record_expr ne_inj = group (pp_ne_injection pp_field_assign ne_inj) and pp_field_assign {value; _} = let {field_name; field_expr; _} = value in prefix 2 1 (pp_ident field_name ^^ string " =") (pp_expr field_expr) and pp_ne_injection : 'a.('a -> document) -> 'a ne_injection reg -> document = fun printer {value; _} -> let {compound; ne_elements; _} = value in let elements = pp_nsepseq ";" printer ne_elements in match pp_compound compound with None -> elements | Some (opening, closing) -> string opening ^^ nest 1 elements ^^ string closing and pp_nsepseq : 'a.string -> ('a -> document) -> ('a, t) Utils.nsepseq -> document = fun sep printer elements -> let elems = Utils.nsepseq_to_list elements and sep = string sep ^^ break 1 in separate_map sep printer elems and pp_nseq : 'a.('a -> document) -> 'a Utils.nseq -> document = fun printer (head, tail) -> separate_map (break 1) printer (head::tail) and pp_projection {value; _} = let {struct_name; field_path; _} = value in let fields = Utils.nsepseq_to_list field_path and sep = string "." ^^ break 0 in let fields = separate_map sep pp_selection fields in group (pp_ident struct_name ^^ string "." ^^ break 0 ^^ fields) and pp_selection = function FieldName v -> string v.value | Component cmp -> cmp.value |> snd |> Z.to_string |> string and pp_update {value; _} = let {record; updates; _} = value in let updates = group (pp_ne_injection pp_field_path_assign updates) and record = pp_path record in string "{" ^^ record ^^ string " with" ^^ nest 2 (break 1 ^^ updates ^^ string "}") and pp_code_inj {value; _} = let {language; code; _} = value in let language = pp_string language.value and code = pp_expr code in string "[%" ^^ language ^/^ code ^^ string "]" and pp_field_path_assign {value; _} = let {field_path; field_expr; _} = value in let path = pp_path field_path in prefix 2 1 (path ^^ string " =") (pp_expr field_expr) and pp_path = function Name v -> pp_ident v | Path p -> pp_projection p and pp_call_expr {value; _} = let lambda, arguments = value in let arguments = pp_nseq pp_expr arguments in group (pp_expr lambda ^^ nest 2 (break 1 ^^ arguments)) and pp_tuple_expr {value; _} = let head, tail = value in let rec app = function [] -> empty | [e] -> group (break 1 ^^ pp_expr e) | e::items -> group (break 1 ^^ pp_expr e ^^ string ",") ^^ app items in if tail = [] then pp_expr head else pp_expr head ^^ string "," ^^ app (List.map snd tail) and pp_par_expr e = pp_par pp_expr e and pp_let_in {value; _} = let {binding; kwd_rec; body; attributes; _} = value in let let_str = match kwd_rec with None -> "let " | Some _ -> "let rec " in let binding = pp_let_binding binding and attr = pp_attributes attributes in string let_str ^^ binding ^^ attr ^^ hardline ^^ group (string "in " ^^ nest 3 (pp_expr body)) and pp_fun {value; _} = let {binders; lhs_type; body; _} = value in let binders = pp_nseq pp_pattern binders and annot = match lhs_type with None -> empty | Some (_,e) -> group (break 1 ^^ string ": " ^^ nest 2 (break 1 ^^ pp_type_expr e)) in group (string "fun " ^^ nest 4 binders ^^ annot ^^ string " ->" ^^ nest 2 (break 1 ^^ pp_expr body)) and pp_seq {value; _} = let {compound; elements; _} = value in let sep = string ";" ^^ hardline in let elements = Utils.sepseq_to_list elements in let elements = separate_map sep pp_expr elements in match pp_compound compound with None -> elements | Some (opening, closing) -> string opening ^^ nest 2 (hardline ^^ elements) ^^ hardline ^^ string closing and pp_type_expr = function TProd t -> pp_cartesian t | TSum t -> pp_variants t | TRecord t -> pp_fields t | TApp t -> pp_type_app t | TFun t -> pp_fun_type t | TPar t -> pp_type_par t | TVar t -> pp_ident t | TString s -> pp_string s and pp_cartesian {value; _} = let head, tail = value in let rec app = function [] -> empty | [e] -> group (break 1 ^^ pp_type_expr e) | e::items -> group (break 1 ^^ pp_type_expr e ^^ string " *") ^^ app items in pp_type_expr head ^^ string " *" ^^ app (List.map snd tail) and pp_variants {value; _} = let head, tail = value in let head = pp_variant head in let head = if tail = [] then head else ifflat head (blank 2 ^^ head) in let rest = List.map snd tail in let app variant = break 1 ^^ string "| " ^^ pp_variant variant in head ^^ concat_map app rest and pp_variant {value; _} = let {constr; arg} = value in match arg with None -> pp_ident constr | Some (_, e) -> prefix 4 1 (pp_ident constr ^^ string " of") (pp_type_expr e) and pp_fields fields = group (pp_ne_injection pp_field_decl fields) and pp_field_decl {value; _} = let {field_name; field_type; _} = value in let name = pp_ident field_name in let t_expr = pp_type_expr field_type in prefix 2 1 (name ^^ string " :") t_expr and pp_type_app {value = ctor, tuple; _} = pp_type_tuple tuple ^^ group (nest 2 (break 1 ^^ pp_type_constr ctor)) and pp_type_tuple {value; _} = let head, tail = value.inside in let rec app = function [] -> empty | [e] -> group (break 1 ^^ pp_type_expr e) | e::items -> group (break 1 ^^ pp_type_expr e ^^ string ",") ^^ app items in if tail = [] then pp_type_expr head else let components = pp_type_expr head ^^ string "," ^^ app (List.map snd tail) in string "(" ^^ nest 1 (components ^^ string ")") and pp_type_constr ctor = string ctor.value and pp_fun_type {value; _} = let lhs, _, rhs = value in group (pp_type_expr lhs ^^ string " ->" ^/^ pp_type_expr rhs) and pp_type_par t = pp_par pp_type_expr t