123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329moduleOt=Pb_codegen_ocaml_typemoduleF=Pb_codegen_formattingletsp=Pb_codegen_util.spletfield_pattern_match~r_name~rf_labelfield_type=matchfield_typewith|Ot.Ft_basic_typebt->letdecoderuntime_f=sp"Pbrt_options.%s pb_options_value \"%s\" \"%s\""runtime_fr_namerf_labelinletexp=matchbtwith|Ot.Bt_string->decode"string"|Ot.Bt_float->decode"float"|Ot.Bt_int->decode"int"|Ot.Bt_int32->decode"int32"|Ot.Bt_int64->decode"int64"|Ot.Bt_uint32->sp"`unsigned (%s)"(decode"int32")|Ot.Bt_uint64->sp"`unsigned (%s)"(decode"int64")|Ot.Bt_bool->decode"bool"|Ot.Bt_bytes->decode"bytes"in"pb_options_value",exp|Ot.Ft_unit->("pb_options_value",sp"Pbrt_options.unit pb_options_value \"%s\" \"%s\""r_namerf_label)|Ot.Ft_user_defined_typeudt->letf_name=letfunction_prefix="decode_pb_options"inPb_codegen_util.function_name_of_user_defined~function_prefixudtinletvalue_expression="("^f_name^" pb_options_value)"in"pb_options_value",value_expression|_->assertfalseletpb_options_label_of_field_labelrf_label=matchrf_labelwith|"and_"|"as_"|"assert_"|"begin_"|"class_"|"constraint_"|"do_"|"done_"|"downto_"|"else_"|"end_"|"exception_"|"external_"|"false_"|"for_"|"fun_"|"function_"|"functor_"|"if_"|"in_"|"include_"|"inherit_"|"initializer_"|"lazy_"|"let_"|"match_"|"method_"|"module_"|"mutable_"|"new_"|"nonrec_"|"object_"|"of_"|"open_"|"or_"|"private_"|"rec_"|"sig_"|"struct_"|"then_"|"to_"|"true_"|"try_"|"type_"|"unit_"|"val_"|"virtual_"|"when_"|"while_"|"with_"|"mod_"|"land_"|"lor_"|"lxor_"|"lsl_"|"lsr_"|"asr_"->String.subrf_label0(String.lengthrf_label-1)|_->rf_label(* Generate all the pattern matches for a record field *)letgen_rft_nolabelsc~r_name~rf_label(field_type,_,_)=letpb_options_label=pb_options_label_of_field_labelrf_labelinletmatch_variable_name,exp=field_pattern_match~r_name~rf_labelfield_typeinF.linepsc"| (\"%s\", %s) -> "pb_options_labelmatch_variable_name;F.linepsc" %s_set_%s v (%s)"r_namerf_labelexp(* Generate all the pattern matches for a repeated field *)letgen_rft_repeated_fieldsc~r_name~rf_labelrepeated_field=let_,field_type,_,_,_=repeated_fieldinletpb_options_label=pb_options_label_of_field_labelrf_labelinF.linepsc"| (\"%s\", Pbrt_options.List_literal l) -> begin"pb_options_label;F.sub_scopesc(funsc->F.linepsc"%s_set_%s v @@ List.map (function"r_namerf_label;letmatch_variable_name,exp=field_pattern_match~r_name~rf_labelfield_typeinF.linepsc" | %s -> %s"match_variable_nameexp;F.linesc") l;");F.linesc"end"letgen_rft_optional_fieldsc~r_name~rf_labeloptional_field=letfield_type,_,_,_=optional_fieldinletpb_options_label=pb_options_label_of_field_labelrf_labelinletmatch_variable_name,exp=field_pattern_match~r_name~rf_labelfield_typeinF.linepsc"| (\"%s\", %s) -> "pb_options_labelmatch_variable_name;F.linepsc" %s_set_%s v (%s)"r_namerf_labelexp(* Generate pattern match for a variant field *)letgen_rft_variant_fieldsc~r_name~rf_label{Ot.v_constructors;_}=List.iter(fun{Ot.vc_constructor;vc_field_type;_}->letpb_options_label=Pb_codegen_util.camel_case_of_constructorvc_constructorinmatchvc_field_typewith|Ot.Vct_nullary->F.linepsc"| (\"%s\", _) -> %s_set_%s v (%s)"pb_options_labelr_namerf_labelvc_constructor|Ot.Vct_non_nullary_constructorfield_type->letmatch_variable_name,exp=field_pattern_match~r_name~rf_labelfield_typeinF.linepsc"| (\"%s\", %s) -> "pb_options_labelmatch_variable_name;F.linepsc" %s_set_%s v (%s (%s))"r_namerf_labelvc_constructorexp)v_constructorsletgen_rft_assoc_fieldsc~r_name~rf_label~assoc_type~key_type~value_type=letpb_options_label=pb_options_label_of_field_labelrf_labelinF.linepsc"| (\"%s\", Pbrt_options.Message_literal assoc) ->"pb_options_label;F.sub_scopesc(funsc->letvalue_name,value_exp=field_pattern_match~r_name~rf_labelvalue_typeinletkey_name="key"inletkey_exp=matchkey_typewith|Ot.Bt_string->"key"|Ot.Bt_int->"(Int.of_string key)"|Ot.Bt_int32->"(Int32.of_string key)"|Ot.Bt_int64->"(Int64.of_string key)"|Ot.Bt_uint32->"(`unsigned (Int32.of_string key))"|Ot.Bt_uint64->"(`unsigned (Int64.of_string key))"|Ot.Bt_bool->"(Bool.of_string key)"|Ot.Bt_float->Printf.eprintf"float cannot be used as a map key type";exit1|Ot.Bt_bytes->Printf.eprintf"bytes cannot be used as a map key type";exit1inF.linesc"let assoc =";F.sub_scopesc(funsc->F.linesc"assoc";F.linepsc"|> List.map (fun (%s, %s) -> (%s, %s)) "key_namevalue_namekey_expvalue_exp;F.linesc"|> List.to_seq";(* Passing through [Hashtbl.of_seq] even in the [At_list] case ensures that if there
is a repeated key we take the last value associated with it. *)F.linesc"|> Hashtbl.of_seq");F.linesc"in";letassoc_exp=matchassoc_typewith|Ot.At_hashtable->"assoc"|Ot.At_list->"assoc |> Hashtbl.to_seq |> List.of_seq"inF.linepsc"%s_set_%s v (%s)"r_namerf_labelassoc_exp)(* Generate decode function for a record *)letgen_record?and_{Ot.r_name;r_fields}sc=F.linesc@@sp"%s decode_pb_options_%s d ="(Pb_codegen_util.let_decl_of_andand_)r_name;F.sub_scopesc(funsc->F.linepsc"let v = default_%s () in"r_name;F.linesc@@"let assoc = match d with";F.linesc@@" | Pbrt_options.Message_literal assoc -> assoc";F.linesc@@" | _ -> assert(false)";(* TODO raise E *)F.linesc@@"in";F.linesc"List.iter (function ";F.sub_scopesc(funsc->(* Generate pattern match for all the possible message field *)List.iter(fun{Ot.rf_label;rf_field_type;_}->matchrf_field_typewith|Ot.Rft_nolabelnolabel_field->gen_rft_nolabelsc~r_name~rf_labelnolabel_field|Ot.Rft_repeatedrepeated_field->gen_rft_repeated_fieldsc~r_name~rf_labelrepeated_field|Ot.Rft_variantvariant_field->gen_rft_variant_fieldsc~r_name~rf_labelvariant_field|Ot.Rft_optionaloptional_field->gen_rft_optional_fieldsc~r_name~rf_labeloptional_field|Ot.Rft_required_->Printf.eprintf"Only proto3 syntax supported in pb_options encoding";exit1|Ot.Rft_associative(assoc_type,_,(key_type,_),(value_type,_))->gen_rft_assoc_fieldsc~r_name~rf_label~assoc_type~key_type~value_type)r_fields;(* Unknown fields are simply ignored *)F.empty_linesc;F.linesc"| (_, _) -> () (*Unknown fields are ignored*)");F.linesc") assoc;";F.linepsc"(v : %s)"r_name)(* Generate decode function for an empty record *)letgen_unit?and_{Ot.er_name}sc=F.linesc@@sp"%s decode_pb_options_%s d ="(Pb_codegen_util.let_decl_of_andand_)er_name;F.linesc(sp"Pbrt_options.unit d \"%s\" \"%s\""er_name"empty record")(* Generate decode function for a variant type *)letgen_variant?and_{Ot.v_name;v_constructors;v_use_polyvariant=_}sc=(* helper function for each constructor case *)letprocess_v_constructorsc{Ot.vc_constructor;vc_field_type;_}=letpb_options_label=Pb_codegen_util.camel_case_of_constructorvc_constructorinmatchvc_field_typewith|Ot.Vct_nullary->F.linepsc"| (\"%s\", _)::_-> (%s : %s)"pb_options_labelvc_constructorv_name|Ot.Vct_non_nullary_constructorfield_type->letmatch_,exp=letr_name=v_nameandrf_label=vc_constructorinfield_pattern_match~r_name~rf_labelfield_typeinF.linepsc"| (\"%s\", %s)::_ -> "pb_options_labelmatch_;F.linepsc" (%s (%s) : %s)"vc_constructorexpv_nameinF.linepsc"%s decode_pb_options_%s pb_options ="(Pb_codegen_util.let_decl_of_andand_)v_name;F.sub_scopesc(funsc->(* even though a variant should be an object with a single field,
* it is possible other fields are present in the pb_options object. Therefore
* we still need a loop to iterate over the key/value, even if in 99.99%
* of the cases it will be a single iteration *)F.linesc"let assoc = match pb_options with";F.linesc" | Pbrt_options.Message_literal assoc -> assoc";F.linesc" | _ -> assert(false)";(* TODO raise E *)F.linesc"in";F.linesc"let rec loop = function";F.sub_scopesc(funsc->(* termination condition *)F.linepsc"| [] -> Pbrt_options.E.malformed_variant \"%s\""v_name;List.iter(process_v_constructorsc)v_constructors;F.empty_linesc;F.linesc"| _ :: tl -> loop tl");F.linesc"in";F.linesc"loop assoc")letgen_const_variant?and_{Ot.cv_name;cv_constructors}sc=F.linepsc"%s decode_pb_options_%s pb_options ="(Pb_codegen_util.let_decl_of_andand_)cv_name;F.sub_scopesc(funsc->F.linesc"match pb_options with";List.iter(fun{Ot.cvc_name;cvc_string_value;_}->F.linepsc"| Pbrt_options.Scalar_value (Constant_literal \"%s\") -> (%s : %s)"cvc_string_valuecvc_namecv_name)cv_constructors;F.linepsc"| _ -> Pbrt_options.E.malformed_variant \"%s\""cv_name)letgen_struct?and_~modetsc=Pb_codegen_mode.do_decodemode&&let{Ot.spec;_}=tinlethas_encoded=matchspecwith|Ot.Recordr->gen_record?and_rsc;true|Ot.Variantv->gen_variant?and_vsc;true|Ot.Const_variantv->gen_const_variant?and_vsc;true|Ot.Unitu->gen_unit?and_usc;trueinhas_encodedletgen_sig?and_~modetsc=Pb_codegen_mode.do_decodemode&&let_=and_inlet{Ot.spec;_}=tinletftype_name=F.linepsc"val decode_pb_options_%s : Pbrt_options.value -> %s"type_nametype_name;F.linepsc("(** [decode_pb_options_%s decoder] decodes a "^^"[%s] value from [decoder] *)")type_nametype_nameinmatchspecwith|Ot.Record{Ot.r_name;_}->fr_name;true|Ot.Variant{Ot.v_name;_}->fv_name;true|Ot.Const_variant{Ot.cv_name;_}->fcv_name;true|Ot.Unit{Ot.er_name;_}->fer_name;trueletocamldoc_title="Pb_option.set Decoding"letplugin:Pb_codegen_plugin.t=letmoduleP=structletgen_sig=gen_sigletgen_struct=gen_structletocamldoc_title=ocamldoc_titleendin(moduleP)