diff options
author | Rutger Broekhoff | 2025-07-07 21:52:08 +0200 |
---|---|---|
committer | Rutger Broekhoff | 2025-07-07 21:52:08 +0200 |
commit | ba61dfd69504ec6263a9dee9931d93adeb6f3142 (patch) | |
tree | d6c9b78e50eeab24e0c1c09ab45909a6ae3fd5db /lib/nix/printer.ml | |
download | verified-dyn-lang-interp-ba61dfd69504ec6263a9dee9931d93adeb6f3142.tar.gz verified-dyn-lang-interp-ba61dfd69504ec6263a9dee9931d93adeb6f3142.zip |
Initialize repository
Diffstat (limited to 'lib/nix/printer.ml')
-rw-r--r-- | lib/nix/printer.ml | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/lib/nix/printer.ml b/lib/nix/printer.ml new file mode 100644 index 0000000..57e81f4 --- /dev/null +++ b/lib/nix/printer.ml | |||
@@ -0,0 +1,176 @@ | |||
1 | open Core | ||
2 | open Types | ||
3 | open PPrint | ||
4 | |||
5 | let rec escape_chlist = function | ||
6 | | [] -> [] | ||
7 | | '$' :: '{' :: l' -> '\\' :: '$' :: '{' :: escape_chlist l' | ||
8 | | '\n' :: l' -> '\\' :: 'n' :: escape_chlist l' | ||
9 | | '\r' :: l' -> '\\' :: 'r' :: escape_chlist l' | ||
10 | | '\t' :: l' -> '\\' :: 't' :: escape_chlist l' | ||
11 | | '\\' :: l' -> '\\' :: '\\' :: escape_chlist l' | ||
12 | | '"' :: l' -> '\\' :: '"' :: escape_chlist l' | ||
13 | | c :: l' -> c :: escape_chlist l' | ||
14 | |||
15 | let escape_string s = s |> String.to_list |> escape_chlist |> String.of_list | ||
16 | let out_width = ref 80 | ||
17 | let set_width i = out_width := i | ||
18 | let indent = ref 2 | ||
19 | let set_indent i = indent := i | ||
20 | |||
21 | let rec doc_of_expr = function | ||
22 | | BinaryOp (op, lhs, rhs) -> | ||
23 | let lhs_doc = maybe_parens_bop op `Left lhs | ||
24 | and rhs_doc = maybe_parens_bop op `Right rhs in | ||
25 | infix !indent 1 (doc_of_bop op) lhs_doc rhs_doc | ||
26 | | UnaryOp (op, e) -> precede (doc_of_uop op) (maybe_parens (prec_of_uop op) e) | ||
27 | | Cond (e1, e2, e3) -> | ||
28 | surround !indent 1 | ||
29 | (soft_surround !indent 1 (string "if") (doc_of_expr e1) (string "then")) | ||
30 | (doc_of_expr e2) | ||
31 | (string "else" ^^ nest !indent (break 1 ^^ doc_of_expr e3)) | ||
32 | | With (e1, e2) -> | ||
33 | flow (break 1) [ string "with"; doc_of_expr e1 ^^ semi; doc_of_expr e2 ] | ||
34 | | Assert (e1, e2) -> | ||
35 | flow (break 1) [ string "assert"; doc_of_expr e1 ^^ semi; doc_of_expr e2 ] | ||
36 | | Test (e, path) -> | ||
37 | maybe_parens 4 e ^^ space ^^ string "?" | ||
38 | ^^ group (break 1 ^^ separate_map dot doc_of_expr path) | ||
39 | | SetLet bs -> | ||
40 | surround !indent 1 | ||
41 | (string "let " ^^ lbrace) | ||
42 | (group (separate_map (break 1) doc_of_binding bs)) | ||
43 | rbrace | ||
44 | | Let (bs, e) -> | ||
45 | surround !indent 1 (string "let") | ||
46 | (separate_map (break 1) doc_of_binding bs) | ||
47 | (prefix !indent 1 (string "in") (doc_of_expr e)) | ||
48 | | Val v -> doc_of_val v | ||
49 | | Id id -> string id | ||
50 | | Select (e, path, oe) -> | ||
51 | maybe_parens 1 e ^^ dot ^^ doc_of_attpath path | ||
52 | ^^ optional | ||
53 | (fun e -> | ||
54 | space ^^ string "or" ^^ nest !indent (break 1 ^^ maybe_parens 1 e)) | ||
55 | oe | ||
56 | | Apply (e1, e2) -> prefix !indent 1 (maybe_parens 2 e1) (maybe_parens 2 e2) | ||
57 | | Aquote e -> surround !indent 0 (string "${") (doc_of_expr e) (string "}") | ||
58 | |||
59 | and maybe_parens lvl e = | ||
60 | if prec_of_expr e >= lvl then surround !indent 0 lparen (doc_of_expr e) rparen | ||
61 | else doc_of_expr e | ||
62 | |||
63 | and maybe_parens_bop op (loc : [ `Left | `Right ]) e = | ||
64 | match (loc, assoc_of_bop op) with | ||
65 | | (`Left, Some Left | `Right, Some Right) | ||
66 | when prec_of_expr e >= prec_of_bop op -> | ||
67 | doc_of_expr e | ||
68 | | _, _ -> maybe_parens (prec_of_bop op) e | ||
69 | |||
70 | and doc_of_attpath path = separate_map dot doc_of_expr path | ||
71 | |||
72 | and doc_of_paramset (params, kind) = | ||
73 | let ps = | ||
74 | List.map ~f:doc_of_param params | ||
75 | @ if Poly.(kind = Loose) then [ string "..." ] else [] | ||
76 | in | ||
77 | surround !indent 0 lbrace (separate (comma ^^ break 1) ps) rbrace | ||
78 | |||
79 | and doc_of_param (id, oe) = | ||
80 | string id ^^ optional (fun e -> qmark ^^ space ^^ doc_of_expr e) oe | ||
81 | |||
82 | and doc_of_binding = function | ||
83 | | AttrPath (path, e) -> | ||
84 | doc_of_attpath path ^^ space ^^ equals ^^ space ^^ doc_of_expr e ^^ semi | ||
85 | | Inherit (oe, ids) -> | ||
86 | let id_docs = | ||
87 | List.map | ||
88 | ~f:(function | ||
89 | | Id x | Val (Str (x, [])) -> string x | _ -> assert false) | ||
90 | ids | ||
91 | in | ||
92 | let xs = | ||
93 | flow (break 1) | ||
94 | (match oe with | ||
95 | | Some e -> parens (doc_of_expr e) :: id_docs | ||
96 | | None -> id_docs) | ||
97 | in | ||
98 | soft_surround !indent 0 (string "inherit" ^^ space) xs semi | ||
99 | |||
100 | and doc_of_bop = function | ||
101 | | Plus -> plus | ||
102 | | Minus -> minus | ||
103 | | Mult -> star | ||
104 | | Div -> slash | ||
105 | | Gt -> rangle | ||
106 | | Lt -> langle | ||
107 | | Lte -> string "<=" | ||
108 | | Gte -> string ">=" | ||
109 | | Eq -> string "==" | ||
110 | | Neq -> string "!=" | ||
111 | | Or -> string "||" | ||
112 | | And -> string "&&" | ||
113 | | Impl -> string "->" | ||
114 | | Merge -> string "//" | ||
115 | | Concat -> string "++" | ||
116 | |||
117 | and doc_of_uop = function Negate -> minus | Not -> bang | ||
118 | |||
119 | and doc_of_val = function | ||
120 | | Str (start, xs) -> | ||
121 | dquotes | ||
122 | (string (escape_string start) | ||
123 | ^^ concat | ||
124 | (List.map | ||
125 | ~f:(fun (e, s) -> | ||
126 | surround !indent 0 (string "${") (doc_of_expr e) | ||
127 | (string "}" ^^ string (escape_string s))) | ||
128 | xs)) | ||
129 | | IStr (i, start, xs) -> | ||
130 | let qq = string "''" in | ||
131 | let str s = | ||
132 | String.split ~on:'\n' s | ||
133 | |> List.map ~f:(fun s -> | ||
134 | let len = String.length s in | ||
135 | let s' = | ||
136 | if len >= i then String.sub s ~pos:i ~len:(len - i) else s | ||
137 | in | ||
138 | string s') | ||
139 | |> separate hardline | ||
140 | in | ||
141 | enclose qq qq | ||
142 | (str start | ||
143 | ^^ concat | ||
144 | (List.map | ||
145 | ~f:(fun (e, s) -> | ||
146 | enclose (string "${") rbrace (doc_of_expr e) ^^ str s) | ||
147 | xs)) | ||
148 | | Int x | Float x | Path x | SPath x | HPath x | Uri x -> string x | ||
149 | | Lambda (pattern, body) -> | ||
150 | let pat = | ||
151 | match pattern with | ||
152 | | Alias id -> string id | ||
153 | | ParamSet (None, ps) -> doc_of_paramset ps | ||
154 | | ParamSet (Some id, ps) -> | ||
155 | doc_of_paramset ps ^^ group (break 1 ^^ at ^^ break 1 ^^ string id) | ||
156 | in | ||
157 | flow (break 1) [ pat ^^ colon; doc_of_expr body ] | ||
158 | | List [] -> lbracket ^^ space ^^ rbracket | ||
159 | | List es -> | ||
160 | surround !indent 1 lbracket | ||
161 | (separate_map (break 1) (maybe_parens 2) es) | ||
162 | rbracket | ||
163 | | AttSet (Nonrec, []) -> lbrace ^^ space ^^ rbrace | ||
164 | | AttSet (Nonrec, bs) -> | ||
165 | surround !indent 1 lbrace | ||
166 | (group (separate_map (break 1) doc_of_binding bs)) | ||
167 | rbrace | ||
168 | | AttSet (Rec, bs) -> | ||
169 | string "rec" ^^ space ^^ doc_of_val (AttSet (Nonrec, bs)) | ||
170 | |||
171 | let print chan expr = ToChannel.pretty 0.7 !out_width chan (doc_of_expr expr) | ||
172 | |||
173 | let to_string expr = | ||
174 | let buf = Stdlib.Buffer.create 0 in | ||
175 | ToBuffer.pretty 0.7 !out_width buf (doc_of_expr expr); | ||
176 | Stdlib.Buffer.contents buf | ||