@@ -920,43 +920,70 @@ let make_type_def env (def : A.type_def) : B.t =
920920 | Wrap (loc , e , an ) -> assert false
921921 | Tvar _ -> assert false
922922
923- let read_case env loc orig_name an opt_e =
923+ let read_case env loc orig_name an opt_e ~ json_sum_repr =
924924 let json_name = Atd.Json. get_json_cons orig_name an in
925925 match opt_e with
926926 | None ->
927+ (* Unit variants are always plain strings, regardless of sum repr. *)
927928 [
928929 Line (sprintf " case '%s':" (single_esc json_name));
929930 Block [
930931 Line (sprintf " return { kind: '%s' }" (single_esc orig_name))
931932 ]
932933 ]
933934 | Some e ->
935+ (* Tagged variants (with payload).
936+ Array repr: the payload is at x[1] in the two-element array.
937+ Object repr: the payload is the value under the constructor's key
938+ e.g. {"Circle": 3.14} -> x['Circle']
939+ The object encoding matches the Rust/Serde default externally-tagged
940+ format and is also natural YAML syntax. *)
941+ let value_expr = match json_sum_repr with
942+ | Atd.Json. Array ->
943+ sprintf " %s(x[1], x)" (json_reader env e)
944+ | Atd.Json. Object ->
945+ sprintf " %s(x['%s'], x)" (json_reader env e) (single_esc json_name)
946+ in
934947 [
935948 Line (sprintf " case '%s':" (single_esc json_name));
936949 Block [
937- Line (sprintf " return { kind: '%s', value: %s(x[1], x) }"
950+ Line (sprintf " return { kind: '%s', value: %s }"
938951 (single_esc orig_name)
939- (json_reader env e) )
952+ value_expr )
940953 ]
941954 ]
942955
943- let write_case env loc orig_name an opt_e =
956+ let write_case env loc orig_name an opt_e ~ json_sum_repr =
944957 let json_name = Atd.Json. get_json_cons orig_name an in
945958 match opt_e with
946959 | None ->
960+ (* Unit variants are always plain strings, regardless of sum repr. *)
947961 [
948962 Line (sprintf " case '%s':" (single_esc orig_name));
949963 Block [
950964 Line (sprintf " return '%s'" (single_esc json_name))
951965 ]
952966 ]
953967 | Some e ->
968+ (* Tagged variants (with payload).
969+ Array repr (default): ["Constructor", payload]
970+ Object repr: {"Constructor": payload}
971+ This is the Rust/Serde externally-tagged default encoding,
972+ and also reads naturally as a YAML single-key mapping. *)
973+ let return_expr = match json_sum_repr with
974+ | Atd.Json. Array ->
975+ sprintf " return ['%s', %s(x.value, x)]"
976+ (single_esc json_name)
977+ (json_writer env e)
978+ | Atd.Json. Object ->
979+ sprintf " return { '%s': %s(x.value, x) }"
980+ (single_esc json_name)
981+ (json_writer env e)
982+ in
954983 [
955984 Line (sprintf " case '%s':" (single_esc orig_name));
956985 Block [
957- Line (sprintf " return ['%s', %s(x.value, x)]"
958- (single_esc json_name)
959- (json_writer env e))
986+ Line return_expr
960987 ]
961988 ]
962989
@@ -967,13 +994,15 @@ let read_root_expr env ~ts_type_name e =
967994 let cases0, cases1 =
968995 List. partition (fun (loc , orig_name , an , opt_e ) -> opt_e = None ) cases
969996 in
997+ (* Determine the encoding for tagged (payload-carrying) variants. *)
998+ let json_sum_repr = (Atd.Json. get_json_sum an).json_sum_repr in
970999 let part0 =
9711000 [
9721001 Line " switch (x) {" ;
9731002 Block (
9741003 List. map
9751004 (fun (loc , orig_name , an , opt_e ) ->
976- read_case env loc orig_name an opt_e
1005+ read_case env loc orig_name an opt_e ~json_sum_repr
9771006 ) cases0
9781007 |> List. flatten
9791008 );
@@ -988,14 +1017,18 @@ let read_root_expr env ~ts_type_name e =
9881017 Line " }" ;
9891018 ]
9901019 in
1020+ (* Build the block that reads tagged variants, switching on encoding. *)
9911021 let part1 =
992- [
1022+ match json_sum_repr with
1023+ | Atd.Json. Array ->
1024+ (* Default: ["Constructor", payload] *)
1025+ [
9931026 Line " _atd_check_json_tuple(2, x, context)" ;
9941027 Line " switch (x[0]) {" ;
9951028 Block (
9961029 List. map
9971030 (fun (loc , orig_name , an , opt_e ) ->
998- read_case env loc orig_name an opt_e
1031+ read_case env loc orig_name an opt_e ~json_sum_repr
9991032 ) cases1
10001033 |> List. flatten
10011034 );
@@ -1008,7 +1041,31 @@ let read_root_expr env ~ts_type_name e =
10081041 ]
10091042 ];
10101043 Line " }" ;
1011- ]
1044+ ]
1045+ | Atd.Json. Object ->
1046+ (* Object encoding: {"Constructor": payload}
1047+ This is the Rust/Serde default externally-tagged encoding
1048+ and reads naturally as a YAML single-key mapping. *)
1049+ [
1050+ Line " const key = Object.keys(x)[0];" ;
1051+ Line " switch (key) {" ;
1052+ Block (
1053+ List. map
1054+ (fun (loc , orig_name , an , opt_e ) ->
1055+ read_case env loc orig_name an opt_e ~json_sum_repr
1056+ ) cases1
1057+ |> List. flatten
1058+ );
1059+ Block [
1060+ Line " default:" ;
1061+ Block [
1062+ Line (sprintf " _atd_bad_json('%s', x, context)"
1063+ (single_esc ts_type_name));
1064+ Line impossible
1065+ ]
1066+ ];
1067+ Line " }" ;
1068+ ]
10121069 in
10131070 (match cases0, cases1 with
10141071 | _ , [] -> (* pure enum *)
@@ -1090,10 +1147,11 @@ let write_root_expr env ~ts_type_name e =
10901147 match e with
10911148 | Sum (loc , variants , an ) ->
10921149 let cases = flatten_variants variants in
1150+ let json_sum_repr = (Atd.Json. get_json_sum an).json_sum_repr in
10931151 [
10941152 Line " switch (x.kind) {" ;
10951153 Block (List. map (fun (loc , orig_name , an , opt_e ) ->
1096- Inline (write_case env loc orig_name an opt_e)
1154+ Inline (write_case env loc orig_name an opt_e ~json_sum_repr )
10971155 ) cases);
10981156 Line " }" ;
10991157 ]
0 commit comments