Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file piqobj_of_json.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309(*
Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2017, 2018 Anton Lavrik
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*)moduleC=Piqi_commonopenCopenPiqobj_commontypejson=Piqi_json_type.jsonleterror_duplicateobjname=errorobj("duplicate field: "^U.quotename)lethandle_unknown_field((n,_))=letf=if!Config.flag_strictthenerrorelsewarninginfn("unknown field: "^U.quoten)letparse_int(obj:json)=matchobjwith|`Intx->`intx|`Uintx->`uintx|o->erroro"int constant expected"letparse_float(x:json)=matchxwith|`Intx->Int64.to_floatx|`Uintx->Piqobj_of_piq.uint64_to_floatx|`Floatx->x|`String"NaN"->Pervasives.nan|`String"Infinity"->Pervasives.infinity|`String"-Infinity"->Pervasives.neg_infinity|o->erroro"float constant expected"letparse_bool(x:json)=matchxwith|`Boolx->x|o->erroro"bool constant expected"letparse_string(x:json)=matchxwith|`Stringx->x|o->erroro"string constant expected"letparse_binary(x:json)=matchxwith|`Stringx->(tryPiqi_base64.decodexwithInvalid_argument_->errorx"invalid base64-encoded string")|o->erroro"string constant expected"letrecparse_obj(t:T.piqtype)(x:json):Piqobj.obj=matchtwith(* built-in types *)|`int->parse_intx|`float->`float(parse_floatx)|`bool->`bool(parse_boolx)|`string->`string(parse_stringx)|`binary->`binary(parse_binaryx)|`any->`any(parse_anyx)(* custom types *)|`recordt->`record(parse_recordtx)|`variantt->`variant(parse_varianttx)|`enumt->`enum(parse_enumtx)|`listt->`list(parse_listtx)|`aliast->`alias(parse_aliastx)andparse_any(x:json):Piqobj.any=(* detect extended piqi-any format *)matchxwith|`Assoc(("piqi_type",`String"piqi-any")::rem)->(* extended piqi-any format *)(* manually parsing the piqi-any record, so that we could extract the
* symbolic json representation *)(* XXX: check correspondence between typed protobuf and typed json? *)lettypename_obj,rem=parse_optional_field"type"`stringNonereminletprotobuf_obj,rem=parse_optional_field"protobuf"`binaryNonereminletjson_obj,rem=parse_optional_field"json"`anyNonereminletpiq_obj,rem=parse_optional_field"piq"`stringNoneremin(* issue warnings on unparsed fields *)List.iterhandle_unknown_fieldrem;lettypename=matchtypename_objwith|Some(`stringx)->Somex|_->Noneinletprotobuf=matchprotobuf_objwith|Some(`binaryx)->Somex|_->Noneinletjson_ast=matchjson_objwith|Some(`any{Any.json_ast=json_ast})->json_ast|_->Noneinletpiq_ast=matchpiq_objwith|Some(`stringx)->letpiq_ast=!Piqobj.piq_of_stringxinSomepiq_ast|_->NoneinAny.({Piqobj.default_anywithtypename=typename;pb=protobuf;json_ast=json_ast;piq_ast=piq_ast;})|json_ast->(* regular symbolic piqi-any *)(* TODO: preserve the original int, float and string literals -- see
* Piqobj.json_of_any *)Any.({Piqobj.default_anywithjson_ast=Somejson_ast;})andparse_recordt=function|(`Assocl)asx->(* NOTE: passing locating information as a separate parameter since empty
* list is unboxed and doesn't provide correct location information *)letloc=xindo_parse_recordloctl|o->erroro"object expected"anddo_parse_recordloctl=debug"do_parse_record: %s\n"(some_oft.T.Record.name);letfields_spec=t.T.Record.fieldinletfields,rem=List.fold_left(parse_fieldloc)([],l)fields_specin(* issue warnings on unparsed fields *)List.iterhandle_unknown_fieldrem;(* put required fields back at the top *)R.({t=t;field=List.revfields;unparsed_piq_fields_ref=None})andparse_fieldloc(accu,rem)t=letfields,rem=do_parse_fieldloctremin(List.rev_appendfieldsaccu,rem)anddo_parse_fieldloctl=letopenT.Fieldinletname=some_oft.json_nameindebug"do_parse_field: %s\n"name;letfield_type=some_oft.piqtypeinletvalues,rem=matcht.modewith|`required->letx,rem=parse_required_fieldlocnamefield_typelin[x],rem|`optional->letx,rem=parse_optional_fieldnamefield_typet.defaultlinletres=(matchxwithSomex->[x]|None->[])inres,rem|`repeated->parse_repeated_fieldnamefield_typelinletfields=List.map(funx->F.({t=t;obj=Somex}))valuesinfields,remandparse_required_fieldlocnamefield_typel=letres,rem=find_fieldsnamelinmatchreswith|[]->errorloc("missing field "^U.quotename)|[x]->parse_objfield_typex,rem|_::o::_->error_duplicateoname(* find field by name, return found fields and remaining fields *)andfind_fields(name:string)(l:(string*json)list):(jsonlist*(string*json)list)=letrecauxaccurem=function|[]->List.revaccu,List.revrem|(n,v)::twhenn=name->aux(v::accu)remt|h::t->auxaccu(h::rem)tinaux[][]landparse_optional_fieldnamefield_typedefaultl=letres,rem=find_fieldsnamelinmatchreswith|[]->Piqobj_common.parse_defaultfield_typedefault,rem|[`Null()]->None,rem|[x]->Some(parse_objfield_typex),rem|_::o::_->error_duplicateoname(* parse repeated variant field allowing variant names if field name is
* unspecified *)andparse_repeated_fieldnamefield_typel=letres,rem=find_fieldsnamelinmatchreswith|[]->[],rem(* XXX: allowing repeated field to be actually missing *)|[`Listl]->letres=List.map(parse_objfield_type)linres,rem|[x]->errorx"array expected"|_::o::_->error_duplicateonameandparse_varianttx=debug"parse_variant: %s\n"(some_oft.T.Variant.name);matchxwith|`Assoc[name,value]->letoptions=t.T.Variant.optioninletoption=tryleto=List.find(funo->some_ofo.T.Option.json_name=name)optionsinparse_optionovaluewithNot_found->errorx("unknown variant option: "^U.quotename)inV.({t=t;option=option})|`Assocl->letl=List.filter(fun(n,v)->v<>`Null())lin(matchlwith|[_]->parse_variantt(`Assocl)|_->errorx"exactly one non-null option field expected")|_->errorx"object expected"andparse_optiontx=letopenT.Optioninmatcht.piqtype,xwith|None,`Booltrue->O.({t=t;obj=None})|None,_->errorx"true value expected"|Someoption_type,_->letobj=parse_objoption_typexinO.({t=t;obj=Someobj})andparse_enumtx=debug"parse_enum: %s\n"(some_oft.T.Enum.name);matchxwith|`Stringname->letoptions=t.T.Enum.optioninletoption=tryleto=List.find(funo->some_ofo.T.Option.json_name=name)optionsinO.({t=o;obj=None})withNot_found->errorx("unknown enum option: "^U.quotename)inE.({t=t;option=option})|_->errorx"string enum value expected"andparse_listtx=matchxwith|`Listl->debug"parse_list: %s\n"(some_oft.T.Piqi_list.name);letobj_type=some_oft.T.Piqi_list.piqtypeinletcontents=List.map(parse_objobj_type)linL.({t=t;obj=contents})|_->errorx"array expected"(* XXX: roll-up multiple enclosed aliases into one? *)andparse_aliastx=letopenT.Aliasinletobj_type=some_oft.piqtypeindebug"parse_alias: %s\n"(some_oft.T.Alias.name);letobj=parse_objobj_typexinA.({t=t;obj=obj})let_=Piqobj.of_json:=parse_obj