Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
PPrintOCaml.ml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166(**************************************************************************) (* *) (* PPrint *) (* *) (* François Pottier, Inria Paris *) (* Nicolas Pouillard *) (* *) (* Copyright 2007-2019 Inria. All rights reserved. This file is *) (* distributed under the terms of the GNU Library General Public *) (* License, with an exception, as described in the file LICENSE. *) (**************************************************************************) open Printf open PPrintEngine open PPrintCombinators type constructor = string type type_name = string type record_field = string type tag = int (* ------------------------------------------------------------------------- *) (* This internal [sprintf]-like function produces a document. We use [string], as opposed to [arbitrary_string], because the strings that we produce will never contain a newline character. *) let dsprintf format = ksprintf string format (* ------------------------------------------------------------------------- *) (* Nicolas prefers using this code as opposed to just [sprintf "%g"] or [sprintf "%f"]. The latter print [inf] and [-inf], whereas OCaml understands [infinity] and [neg_infinity]. [sprintf "%g"] does not add a trailing dot when the number happens to be an integral number. [sprintf "%F"] seems to lose precision and ignores the precision modifier. *) let valid_float_lexeme (s : string) : string = let l = String.length s in let rec loop i = if i >= l then (* If we reach the end of the string and have found only characters in the set '0' .. '9' and '-', then this string will be considered as an integer literal by OCaml. Adding a trailing dot makes it a float literal. *) s ^ "." else match s.[i] with | '0' .. '9' | '-' -> loop (i + 1) | _ -> s in loop 0 (* This function constructs a string representation of a floating point number. This representation is supposed to be accepted by OCaml as a valid floating point literal. *) let float_representation (f : float) : string = match classify_float f with | FP_nan -> "nan" | FP_infinite -> if f < 0.0 then "neg_infinity" else "infinity" | _ -> (* Try increasing precisions and validate. *) let s = sprintf "%.12g" f in if f = float_of_string s then valid_float_lexeme s else let s = sprintf "%.15g" f in if f = float_of_string s then valid_float_lexeme s else sprintf "%.18g" f (* ------------------------------------------------------------------------- *) (* A few constants and combinators, used below. *) let some = string "Some" let none = string "None" let lbracketbar = string "[|" let rbracketbar = string "|]" let seq1 opening separator closing = surround_separate 2 0 (opening ^^ closing) opening (separator ^^ break 1) closing let seq2 opening separator closing = surround_separate_map 2 1 (opening ^^ closing) opening (separator ^^ break 1) closing (* ------------------------------------------------------------------------- *) (* The following functions are printers for many types of OCaml values. *) (* There is no protection against cyclic values. *) type representation = document let tuple = seq1 lparen comma rparen let variant _ cons _ args = match args with | [] -> !^cons | _ :: _ -> !^cons ^^ tuple args let record _ fields = seq2 lbrace semi rbrace (fun (k, v) -> infix 2 1 equals !^k v) fields let option f = function | None -> none | Some x -> some ^^ tuple [f x] let list f xs = seq2 lbracket semi rbracket f xs let flowing_list f xs = group (lbracket ^^ space ^^ nest 2 ( flow_map (semi ^^ break 1) f xs ) ^^ space ^^ rbracket) let array f xs = seq2 lbracketbar semi rbracketbar f (Array.to_list xs) let flowing_array f xs = group (lbracketbar ^^ space ^^ nest 2 ( flow_map (semi ^^ break 1) f (Array.to_list xs) ) ^^ space ^^ rbracketbar) let ref f x = record "ref" ["contents", f !x] let float f = string (float_representation f) let int = dsprintf "%d" let int32 = dsprintf "%ld" let int64 = dsprintf "%Ld" let nativeint = dsprintf "%nd" let char = dsprintf "%C" let bool = dsprintf "%B" let string = dsprintf "%S" let unknown tyname _ = dsprintf "<abstr:%s>" tyname