123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214(*
Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2017 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_commonopenC(*
* set json- names if not specified by user
*)(* json name of piqi name *)letjson_name'n=U.dashes_to_underscoresnletjson_namen=Some(json_name'n)(* check name validity *)letcheck_json_names=leterror()=errors"invalid json-name"inifs=""thenerror();(matchs.[0]with|'a'..'z'|'A'..'Z'|'_'->()|_->error());fori=1toString.lengths-1domatchs.[i]with|'a'..'z'|'A'..'Z'|'0'..'9'|'_'->()|_->error()done(* XXX: use name instead of json_name for foreign types? *)lettypedef_json_name=function|`recordt->t.R.json_name|`variantt->t.V.json_name|`enumt->t.E.json_name|`aliast->t.A.json_name|`listt->t.L.json_name|_->(* this function will be called only for named types (i.e. typedefs) *)assertfalseletjson_name_ofnamepiqtype=matchname,piqtypewith|Somen,_->json_namen|None,Somet->typedef_json_namet|_->assertfalseletjson_name_fieldx=letopenFieldinmatchx.json_namewith|None->x.json_name<-json_name_ofx.namex.piqtype|Somen->check_json_namenletjson_name_recordx=letopenRecordin(matchx.json_namewith|None->x.json_name<-json_name(some_ofx.name)|Somen->check_json_namen)letjson_name_optionx=letopenOptioninmatchx.json_namewith|None->x.json_name<-json_name_ofx.namex.piqtype|Somen->check_json_namenletjson_name_variantx=letopenVariantin(matchx.json_namewith|None->x.json_name<-json_name(some_ofx.name)|Somen->check_json_namen)letjson_name_enumx=letopenEnumin(matchx.json_namewith|None->x.json_name<-json_name(some_ofx.name)|Somen->check_json_namen)letjson_name_aliasx=letopenAliasinmatchx.json_namewith|None->x.json_name<-json_name(some_ofx.name)|Somen->check_json_namenletjson_name_listx=letopenLinmatchx.json_namewith|None->x.json_name<-json_name(some_ofx.name)|Somen->check_json_namenletjson_name_typedef=function|`recordx->json_name_recordx|`variantx->json_name_variantx|`enumx->json_name_enumx|`aliasx->json_name_aliasx|`listx->json_name_listx(* name fields and options *)letjson_name_record'x=List.iterjson_name_fieldx.R.fieldletjson_name_variant'x=List.iterjson_name_optionx.V.optionletjson_name_enum'x=List.iterjson_name_optionx.E.optionletjson_name_typedef'=function|`recordx->json_name_record'x|`variantx->json_name_variant'x|`enumx->json_name_enum'x|_->()letjson_name_defsdefs=(* name data structures *)List.iterjson_name_typedefdefs;(* name fields and options *)List.iterjson_name_typedef'defsletjson_name_piqi_idtable(piqi:T.piqi)=letopenPinjson_name_defspiqi.resolved_typedef(* NOTE: this function is called only in case if a JSON-related operation is
* performed. We don't need this startup overhead otherwise *)letinit()=trace"init JSON\n";(* create JSON names in embedded Piqi self-specification *)(* AND add/check JSON names when loading any other Piqi modules *)Piqi.register_processing_hookjson_name_piqi(**)letread_json_objjson_parser=letres=Piqi_json_parser.read_nextjson_parserinres(* for internal use only: read one parsed JSON value from its string
* representation *)letjson_of_strings:Piqi_json_type.json=letjson_parser=Piqi_json_parser.init_from_stringsinletres=tryPiqi_json_parser.read_alljson_parserwithC.Error((_,lnum',cnum'),error)->(* string location can be missing when we parse from JSON embedded in
* Protobuf *)let(fname,lnum,cnum)=tryPiqloc.findswithNot_found->("embedded",1,-1)in(* adjust location column number: add the original column number of the
* '#' character + 1 for the space that follows it; note that this method
* doesn't give 100% guarantee that the offset is correct, but it is
* accurate if all the text literal lines start at the same column *)letloc=(fname,lnum+lnum'-1,cnum+cnum'+1)inC.error_atloc("error parsing embedded JSON: "^error)inmatchreswith|[x]->x|_::o::_->C.erroro"string includes more than one JSON value"|[]->C.errors"string doesn't have JSON data"let_=Piqobj.json_of_string:=(funx->json_of_stringx);Piqobj.string_of_json:=(funx->Piqi_json_gen.pretty_to_stringx~indent:true)