tangled
alpha
login
or
join now
futur.blue
/
pegasus
57
fork
atom
objective categorical abstract machine language personal data server
57
fork
atom
overview
issues
2
pulls
pipelines
hermes: Better names for union types
futur.blue
2 months ago
c9c049f2
befa211a
verified
This commit was signed with the committer's
known signature
.
futur.blue
SSH Key Fingerprint:
SHA256:QHGqHWNpqYyw9bt8KmPuJIyeZX9SZewBZ0PR1COtKQ0=
+47
-15
1 changed file
expand all
collapse all
unified
split
hermes-cli
lib
codegen.ml
+47
-15
hermes-cli/lib/codegen.ml
···
3
3
type output =
4
4
{ mutable imports: string list
5
5
; mutable generated_unions: string list
6
6
+
; mutable union_names: (string list * string) list (* refs -> context name *)
6
7
; buf: Buffer.t }
7
8
8
8
-
let make_output () = {imports= []; generated_unions= []; buf= Buffer.create 4096}
9
9
+
let make_output () =
10
10
+
{imports= []; generated_unions= []; union_names= []; buf= Buffer.create 4096}
9
11
10
12
let add_import out module_name =
11
13
if not (List.mem module_name out.imports) then
···
16
18
out.generated_unions <- union_name :: out.generated_unions
17
19
18
20
let is_union_generated out union_name = List.mem union_name out.generated_unions
21
21
+
22
22
+
(* register a context-based name for a union based on its refs *)
23
23
+
let register_union_name out refs context_name =
24
24
+
let sorted_refs = List.sort String.compare refs in
25
25
+
if not (List.exists (fun (r, _) -> r = sorted_refs) out.union_names) then
26
26
+
out.union_names <- (sorted_refs, context_name) :: out.union_names
27
27
+
28
28
+
(* look up a union's context-based name, or return None *)
29
29
+
let lookup_union_name out refs =
30
30
+
let sorted_refs = List.sort String.compare refs in
31
31
+
List.assoc_opt sorted_refs out.union_names
19
32
20
33
let emit out s = Buffer.add_string out.buf s
21
34
···
53
66
"object_todo"
54
67
| Ref {ref_; _} ->
55
68
gen_ref_type nsid out ref_
56
56
-
| Union {refs; _} ->
57
57
-
(* generate inline union reference *)
58
58
-
gen_union_type_name refs
69
69
+
| Union {refs; _} -> (
70
70
+
(* generate inline union reference, using registered name if available *)
71
71
+
match lookup_union_name out refs with
72
72
+
| Some name ->
73
73
+
name
74
74
+
| None ->
75
75
+
gen_union_type_name refs )
59
76
| Token _ ->
60
77
"string"
61
78
| Unknown _ ->
···
97
114
(* external ref, use as-is *)
98
115
ref_str
99
116
100
100
-
(* collect inline union specs from object properties *)
101
101
-
let rec collect_inline_unions acc type_def =
117
117
+
(* collect inline union specs from object properties with context *)
118
118
+
let rec collect_inline_unions_with_context context acc type_def =
102
119
match type_def with
103
120
| Union spec ->
104
104
-
(spec.refs, spec) :: acc
121
121
+
(context, spec.refs, spec) :: acc
105
122
| Array {items; _} ->
106
106
-
collect_inline_unions acc items
123
123
+
(* for array items, append _item to context *)
124
124
+
collect_inline_unions_with_context (context ^ "_item") acc items
107
125
| _ ->
108
126
acc
109
127
110
128
let collect_inline_unions_from_properties properties =
111
129
List.fold_left
112
112
-
(fun acc (_, (prop : property)) -> collect_inline_unions acc prop.type_def)
130
130
+
(fun acc (prop_name, (prop : property)) ->
131
131
+
collect_inline_unions_with_context prop_name acc prop.type_def )
113
132
[] properties
114
133
115
134
(* generate inline union types that appear in object properties *)
116
135
let gen_inline_unions nsid out properties =
117
136
let inline_unions = collect_inline_unions_from_properties properties in
118
137
List.iter
119
119
-
(fun (refs, spec) ->
120
120
-
let type_name = Naming.union_type_name refs in
138
138
+
(fun (context, refs, spec) ->
139
139
+
(* register and use context-based name *)
140
140
+
let context_name = Naming.type_name context in
141
141
+
register_union_name out refs context_name ;
142
142
+
let type_name = context_name in
121
143
(* skip if already generated *)
122
144
if not (is_union_generated out type_name) then begin
123
145
mark_union_generated out type_name ;
···
162
184
let full_type_uri = gen_type_uri nsid ref_str in
163
185
let payload_type = gen_ref_type nsid out ref_str in
164
186
emitln out (Printf.sprintf " | %s v ->" variant_name) ;
165
165
-
emitln out (Printf.sprintf " (match %s_to_yojson v with" payload_type) ;
166
166
-
emitln out (Printf.sprintf " | `Assoc fields -> `Assoc ((\"$type\", `String \"%s\") :: fields)" full_type_uri) ;
187
187
+
emitln out
188
188
+
(Printf.sprintf " (match %s_to_yojson v with" payload_type) ;
189
189
+
emitln out
190
190
+
(Printf.sprintf
191
191
+
" | `Assoc fields -> `Assoc ((\"$type\", `String \
192
192
+
\"%s\") :: fields)"
193
193
+
full_type_uri ) ;
167
194
emitln out " | other -> other)" )
168
195
refs ;
169
196
if not is_closed then emitln out " | Unknown j -> j" ;
···
253
280
let full_type_uri = gen_type_uri nsid ref_str in
254
281
let payload_type = gen_ref_type nsid out ref_str in
255
282
emitln out (Printf.sprintf " | %s v ->" variant_name) ;
256
256
-
emitln out (Printf.sprintf " (match %s_to_yojson v with" payload_type) ;
257
257
-
emitln out (Printf.sprintf " | `Assoc fields -> `Assoc ((\"$type\", `String \"%s\") :: fields)" full_type_uri) ;
283
283
+
emitln out
284
284
+
(Printf.sprintf " (match %s_to_yojson v with" payload_type) ;
285
285
+
emitln out
286
286
+
(Printf.sprintf
287
287
+
" | `Assoc fields -> `Assoc ((\"$type\", `String \"%s\") :: \
288
288
+
fields)"
289
289
+
full_type_uri ) ;
258
290
emitln out " | other -> other)" )
259
291
spec.refs ;
260
292
if not is_closed then emitln out " | Unknown j -> j" ;