Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file ppx_sexp_conv_grammar.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608open!Baseopen!PpxlibopenAst_builder.Defaultletunsupported~locstring=Location.raise_errorf~loc"sexp_grammar: %s are unsupported"string;;letewith_tag~loc~key~valuegrammar=[%expr{key=[%ekey];value=[%evalue];grammar=[%egrammar]}];;leteno_tag~locgrammar=[%exprNo_tag[%egrammar]]letetag~locwith_tag=[%exprTag[%ewith_tag]]letetagged~locwith_tag=[%exprTagged[%ewith_tag]]lettag_of_doc_comment~loccomment=([%exprPpx_sexp_conv_lib.Sexp_grammar.doc_comment_tag],[%exprAtom[%eestring~loccomment]]);;letwith_tagsgrammar~f~loc~tags~comments=lettags=List.concat[List.mapcomments~f:(tag_of_doc_comment~loc);tags]inList.fold_righttags~init:grammar~f:(fun(key,value)grammar->f~loc(ewith_tag~loc~key~valuegrammar));;letwith_tags_as_listgrammar~loc~tags~comments=with_tags(eno_tag~locgrammar)~f:etag~loc~tags~comments;;letwith_tags_as_grammargrammar~loc~tags~comments=with_tagsgrammar~f:etagged~loc~tags~comments;;letgrammar_namename=name^"_sexp_grammar"lettyvar_grammar_namename=grammar_name("_'"^name)letestr{loc;txt}=estring~loctxtletgrammar_type~loccore_type=[%type:[%tcore_type]Sexplib0.Sexp_grammar.t]letabstract_grammar~ctxt~locid=letmodule_name=ctxt|>Expansion_context.Deriver.code_path|>Code_path.fully_qualified_pathin[%exprAny[%eestr{idwithtxt=String.concat~sep:"."[module_name;id.txt]}]];;letarrow_grammar~loc=[%exprSexplib0.Sexp_conv.fun_sexp_grammar.untyped]letopaque_grammar~loc=[%exprSexplib0.Sexp_conv.opaque_sexp_grammar.untyped]letwildcard_grammar~loc=[%exprAny"_"]letlist_grammar~locexpr=[%exprList[%eexpr]]letmany_grammar~locexpr=[%exprMany[%eexpr]]letfields_grammar~locexpr=[%exprFields[%eexpr]]lettyvar_grammar~locexpr=[%exprTyvar[%eexpr]]lettycon_grammar~locnameargs=[%exprTycon([%ename],[%eargs])]letrecursive_grammar~locgrammardefns=[%exprRecursive([%egrammar],[%edefns])]letdefns_type~loc=[%type:Sexplib0.Sexp_grammar.defnStdlib.List.tStdlib.Lazy.t]letuntyped_grammar~locexpr=matchexprwith|[%expr{untyped=[%e?untyped]}]->untyped|_->[%expr[%eexpr].untyped];;lettyped_grammar~locexpr=matchexprwith|[%expr[%e?typed].untyped]->typed|_->[%expr{untyped=[%eexpr]}];;letdefn_expr~loc~tycon~tyvars~grammar=[%expr{tycon=[%etycon];tyvars=[%etyvars];grammar=[%egrammar]}];;letunion_grammar~locexprs=matchexprswith|[]->[%exprUnion[]]|[expr]->expr|_->[%exprUnion[%eelist~locexprs]];;lettuple_grammar~locexprs=List.fold_rightexprs~init:[%exprEmpty]~f:(funexprrest->[%exprCons([%eexpr],[%erest])]);;letatom_clause~loc=[%exprAtom_clause]letlist_clause~locargs=[%exprList_clause{args=[%eargs]}]moduleVariant_clause_type=structtypet={name:labelloc;comments:stringlist;tags:(expression*expression)list;clause_kind:expression}letto_grammar_expr{name;comments;tags;clause_kind}~loc=[%expr{name=[%eestrname];clause_kind=[%eclause_kind]}]|>with_tags_as_list~loc:name.loc~comments~tags;;endletvariant_grammars~loc~case_sensitivity~clauses=matchList.is_emptyclauseswith|true->[]|false->letclause_exprs=List.mapclauses~f:(Variant_clause_type.to_grammar_expr~loc)inletgrammar=[%exprVariant{case_sensitivity=[%ecase_sensitivity];clauses=[%eelist~locclause_exprs]}]in[grammar];;(* Wrap [expr] in [fun a b ... ->] for type parameters. *)lettd_params_funtdexpr=letloc=td.ptype_locinletparams=List.maptd.ptype_params~f:(funparam->let{loc;txt}=get_type_param_nameparaminpvar~loc(tyvar_grammar_nametxt))ineabstract~locparamsexpr;;moduleRow_field_type=structtypet=|Inheritofcore_type|Tag_no_argofstringloc|Tag_with_argofstringloc*core_typeletof_row_field~locrow_field=matchrow_fieldwith|Rinheritcore_type->Inheritcore_type|Rtag(name,possibly_no_arg,possible_type_args)->(matchpossibly_no_arg,possible_type_argswith|true,[]->Tag_no_argname|false,[core_type]->Tag_with_arg(name,core_type)|false,[]->unsupported~loc"empty polymorphic variant types"|true,_::_|false,_::_::_->unsupported~loc"intersection types");;endletattr_doc_commentsattributes~tags_of_doc_comments=matchtags_of_doc_commentswith|false->[]|true->letdoc_pattern=Ast_pattern.(pstr(pstr_eval(estring__)nil^::nil))inList.filter_mapattributes~f:(funattribute->matchattribute.attr_name.txtwith|"ocaml.doc"|"doc"->Ast_pattern.parsedoc_patternattribute.attr_locattribute.attr_payload~on_error:(fun()->None)(fundoc->Somedoc)|_->None);;letgrammar_of_type_tagscore_typegrammar~tags_of_doc_comments=lettags=Attribute.getAttrs.tag_typecore_type|>Option.value~default:[]inletloc=core_type.ptyp_locinletcomments=attr_doc_comments~tags_of_doc_commentscore_type.ptyp_attributesinwith_tags_as_grammargrammar~loc~tags~comments;;letgrammar_of_field_tagsfieldgrammar~tags_of_doc_comments=lettags=Attribute.getAttrs.tag_ldfield|>Option.value~default:[]inletloc=field.pld_locinletcomments=attr_doc_comments~tags_of_doc_commentsfield.pld_attributesinwith_tags_as_listgrammar~loc~tags~comments;;letrecgrammar_of_typecore_type~rec_flag~tags_of_doc_comments=letloc=core_type.ptyp_locinletgrammar=matchAttribute.getAttrs.opaquecore_typewith|Some()->opaque_grammar~loc|None->(matchcore_type.ptyp_descwith|Ptyp_any->wildcard_grammar~loc|Ptyp_varname->(matchrec_flagwith|Recursive->(* For recursive grammars, [grammar_of_type] for any type variables is called
inside a [defn]. The variables should therefore be resolved as [Tyvar]
grammars. *)tyvar_grammar~loc(estring~locname)|Nonrecursive->(* Outside recursive [defn]s, type variables are passed in as function
arguments. *)unapplied_type_constr_conv~loc~f:tyvar_grammar_name(Located.lident~locname)|>untyped_grammar~loc)|Ptyp_arrow_->arrow_grammar~loc|Ptyp_tuplelist->List.map~f:(grammar_of_type~rec_flag~tags_of_doc_comments)list|>tuple_grammar~loc|>list_grammar~loc|Ptyp_constr(id,args)->List.mapargs~f:(funcore_type->letloc=core_type.ptyp_locingrammar_of_type~rec_flag~tags_of_doc_commentscore_type|>typed_grammar~loc)|>type_constr_conv~loc~f:grammar_nameid|>untyped_grammar~loc|Ptyp_object_->unsupported~loc"object types"|Ptyp_class_->unsupported~loc"class types"|Ptyp_alias_->unsupported~loc"type aliases"|Ptyp_variant(rows,closed_flag,(_:stringlistoption))->(matchclosed_flagwith|Open->unsupported~loc"open polymorphic variant types"|Closed->grammar_of_polymorphic_variant~loc~rec_flag~tags_of_doc_commentsrows)|Ptyp_poly_->unsupported~loc"explicitly polymorphic types"|Ptyp_package_->unsupported~loc"first-class module types"|Ptyp_extension_->unsupported~loc"unexpanded ppx extensions")ingrammar_of_type_tagscore_typegrammar~tags_of_doc_commentsandgrammar_of_polymorphic_variant~loc~rec_flag~tags_of_doc_commentsrows=letinherits,clauses=List.partition_maprows~f:(funrow:(_,Variant_clause_type.t)Either.t->lettags=Attribute.getAttrs.tag_polyrow|>Option.value~default:[]inletcomments=attr_doc_comments~tags_of_doc_commentsrow.prf_attributesinmatchAttribute.getAttrs.list_polyrowwith|Some()->(matchRow_field_type.of_row_field~locrow.prf_descwith|Tag_with_arg(name,[%type:[%t?ty]list])->letclause_kind=grammar_of_type~rec_flag~tags_of_doc_commentsty|>many_grammar~loc|>list_clause~locinSecond{name;comments;tags;clause_kind}|_->Attrs.invalid_attribute~locAttrs.list_poly"_ list")|None->(matchRow_field_type.of_row_field~locrow.prf_descwith|Inheritcore_type->First(grammar_of_type~rec_flag~tags_of_doc_commentscore_type|>with_tags_as_grammar~loc~tags~comments)|Tag_no_argname->Second{name;comments;tags;clause_kind=atom_clause~loc}|Tag_with_arg(name,core_type)->letclause_kind=[grammar_of_type~rec_flag~tags_of_doc_commentscore_type]|>tuple_grammar~loc|>list_clause~locinSecond{name;comments;tags;clause_kind}))invariant_grammars~loc~case_sensitivity:[%exprCase_sensitive]~clauses|>List.appendinherits|>union_grammar~loc;;letrecord_expr~loc~rec_flag~tags_of_doc_comments~extra_attrsyntaxfields=letfields=List.mapfields~f:(funfield->letloc=field.pld_locinletfield_kind=Record_field_attrs.Of_sexp.create~locfieldinletrequired=matchfield_kindwith|SpecificRequired->true|Specific(Default_)|Sexp_bool|Sexp_option_|Sexp_array_|Sexp_list_|Omit_nil->falseinletargs=matchfield_kindwith|SpecificRequired|Specific(Default_)|Omit_nil->[%exprCons([%egrammar_of_type~tags_of_doc_comments~rec_flagfield.pld_type],Empty)]|Sexp_bool->[%exprEmpty]|Sexp_optionty->[%exprCons([%egrammar_of_type~tags_of_doc_comments~rec_flagty],Empty)]|Sexp_listty|Sexp_arrayty->[%exprCons(List(Many[%egrammar_of_type~tags_of_doc_comments~rec_flagty]),Empty)]in[%expr{name=[%eestrfield.pld_name];required=[%eebool~locrequired];args=[%eargs]}]|>grammar_of_field_tagsfield~tags_of_doc_comments)inletallow_extra_fields=matchAttribute.getextra_attrsyntaxwith|Some()->true|None->falsein[%expr{allow_extra_fields=[%eebool~locallow_extra_fields];fields=[%eelist~locfields]}];;letgrammar_of_variant~loc~rec_flag~tags_of_doc_commentsclause_decls=letclauses=List.mapclause_decls~f:(funclause:Variant_clause_type.t->letloc=clause.pcd_locinlettags=Attribute.getAttrs.tag_cdclause|>Option.value~default:[]inletcomments=attr_doc_comments~tags_of_doc_commentsclause.pcd_attributesinmatchAttribute.getAttrs.list_variantclausewith|Some()->(matchclause.pcd_argswith|Pcstr_tuple[[%type:[%t?ty]list]]->letargs=many_grammar~loc(grammar_of_typety~rec_flag~tags_of_doc_comments)in{name=clause.pcd_name;comments;tags;clause_kind=list_clause~locargs}|_->Attrs.invalid_attribute~locAttrs.list_variant"_ list")|None->(matchclause.pcd_argswith|Pcstr_tuple[]->{name=clause.pcd_name;comments;tags;clause_kind=atom_clause~loc}|Pcstr_tuple(_::_asargs)->letargs=tuple_grammar~loc(List.mapargs~f:(grammar_of_type~rec_flag~tags_of_doc_comments))in{name=clause.pcd_name;comments;tags;clause_kind=list_clause~locargs}|Pcstr_recordfields->letargs=record_expr~loc~rec_flag~tags_of_doc_comments~extra_attr:Attrs.allow_extra_fields_cdclausefields|>fields_grammar~locin{name=clause.pcd_name;comments;tags;clause_kind=list_clause~locargs}))invariant_grammars~loc~case_sensitivity:[%exprCase_sensitive_except_first_character]~clauses|>union_grammar~loc;;letgrammar_of_td~ctxt~rec_flag~tags_of_doc_commentstd=letloc=td.ptype_locinmatchtd.ptype_kindwith|Ptype_open->unsupported~loc"open types"|Ptype_recordfields->record_expr~loc~rec_flag~tags_of_doc_comments~extra_attr:Attrs.allow_extra_fields_tdtdfields|>fields_grammar~loc|>list_grammar~loc|Ptype_variantclauses->grammar_of_variant~loc~rec_flag~tags_of_doc_commentsclauses|Ptype_abstract->(matchtd.ptype_manifestwith|None->abstract_grammar~ctxt~loctd.ptype_name|Somecore_type->grammar_of_type~rec_flag~tags_of_doc_commentscore_type);;letpattern_of_tdtd=let{loc;txt}=td.ptype_nameinppat_constraint~loc(pvar~loc(grammar_nametxt))(combinator_type_of_type_declarationtd~f:grammar_type);;(* Any grammar expression that is purely a constant does no work, and does not need to be
wrapped in [Lazy]. *)letrecis_preallocated_constantexpr=matchexpr.pexp_descwith|Pexp_constraint(expr,_)|Pexp_coerce(expr,_,_)|Pexp_open(_,expr)->is_preallocated_constantexpr|Pexp_constant_->true|Pexp_tupleargs->List.for_all~f:is_preallocated_constantargs|Pexp_variant(_,maybe_arg)|Pexp_construct(_,maybe_arg)->Option.for_all~f:is_preallocated_constantmaybe_arg|Pexp_record(fields,maybe_template)->List.for_allfields~f:(fun(_,expr)->is_preallocated_constantexpr)&&Option.for_all~f:is_preallocated_constantmaybe_template|_->false;;(* Any grammar expression that just refers to a previously defined grammar also does not
need to be wrapped in [Lazy]. Accessing the previous grammar is work, but building the
closure for a lazy value is at least as much work anyway. *)letrecis_variable_accessexpr=matchexpr.pexp_descwith|Pexp_constraint(expr,_)|Pexp_coerce(expr,_,_)|Pexp_open(_,expr)->is_variable_accessexpr|Pexp_ident_->true|Pexp_field(expr,_)->is_variable_accessexpr|_->false;;letgrammar_needs_lazy_wrapperexpr=not(is_preallocated_constantexpr||is_variable_accessexpr);;letlazy_grammar~loctdexpr=ifList.is_emptytd.ptype_params(* polymorphic types generate functions, so the body does not need a [lazy] wrapper *)&&grammar_needs_lazy_wrapperexprthen[%exprLazy(lazy[%eexpr])]elseexpr;;letforce_expr~locexpr=[%exprStdlib.Lazy.force[%eexpr]](* Definitions of grammars that do not refer to each other. *)letnonrecursive_grammars~ctxt~loc~tags_of_doc_commentstd_lists=List.concat_maptd_lists~f:(funtds->List.maptds~f:(funtd->lettd=name_type_params_in_tdtdinletloc=td.ptype_locinletpat=pattern_of_tdtdinletexpr=grammar_of_td~ctxt~rec_flag:Nonrecursive~tags_of_doc_commentstd|>lazy_grammartd~loc|>typed_grammar~loc|>td_params_funtdinvalue_binding~loc~pat~expr)|>pstr_value_list~locNonrecursive);;(* Type constructor grammars used to "tie the knot" for (mutally) recursive grammars. *)letrecursive_grammar_tyconstds=List.maptds~f:(funtd->lettd=name_type_params_in_tdtdinletloc=td.ptype_locinletpat=pattern_of_tdtdinletexpr=tycon_grammar~loc(estrtd.ptype_name)(List.maptd.ptype_params~f:(funparam->let{loc;txt}=get_type_param_nameparamintyvar_grammar_nametxt|>evar~loc|>untyped_grammar~loc)|>elist~loc)|>typed_grammar~loc|>td_params_funtdinvalue_binding~loc~pat~expr);;(* Recursive grammar definitions, based on the type constructors from above. *)letrecursive_grammar_defns~ctxt~loc~tags_of_doc_commentstds=List.maptds~f:(funtd->lettd=name_type_params_in_tdtdinletloc=td.ptype_locinlettycon=estrtd.ptype_nameinlettyvars=List.maptd.ptype_params~f:(funparam->estr(get_type_param_nameparam))|>elist~locinletgrammar=grammar_of_td~ctxt~rec_flag:Recursive~tags_of_doc_commentstdindefn_expr~loc~tycon~tyvars~grammar)|>elist~loc;;(* Grammar expression using [Recursive] and a shared definition of grammar definitions.
The shared definitions are wrapped in [lazy] to avoid toplevel side effects. *)letrecursive_grammar_expr~defns_nametd=lettd=name_type_params_in_tdtdinletloc=td.ptype_locinletpat=pattern_of_tdtdinletexpr=lettyvars=List.maptd.ptype_params~f:(funparam->let{loc;txt}=get_type_param_nameparamintyvar_grammar_nametxt|>evar~loc|>untyped_grammar~loc)|>elist~locinrecursive_grammar~loc(tycon_grammar~loc(estrtd.ptype_name)tyvars)(evar~locdefns_name|>force_expr~loc)|>lazy_grammartd~loc|>typed_grammar~loc|>td_params_funtdinvalue_binding~loc~pat~expr;;(* Puts together recursive grammar definitions from the parts implemented above. *)letrecursive_grammars~ctxt~loc~tags_of_doc_commentstds=matchList.is_emptytdswith|true->[]|false->letdefns_name=gen_symbol~prefix:"grammars"()inletdefns_item=letexpr=recursive_grammar_defns~ctxt~loc~tags_of_doc_commentstds|>pexp_let~locNonrecursive(recursive_grammar_tyconstds)|>pexp_lazy~locinletpat=ppat_constraint~loc(pvar~locdefns_name)(defns_type~loc)inpstr_value~locNonrecursive[value_binding~loc~pat~expr]inletgrammars_item=List.maptds~f:(recursive_grammar_expr~defns_name)|>pstr_value~locNonrecursivein[%strincludestructopenstruct[%%idefns_item]end[%%igrammars_item]end];;letpartition_recursive_and_nonrecursive~rec_flagtds=match(rec_flag:rec_flag)with|Nonrecursive->[],[tds]|Recursive->(* Pulling out non-recursive references repeatedly means we only "tie the knot" for
variables that actually need it, and we don't have to manually [ignore] the added
bindings in case they are unused. *)letreclooptds~acc=letobj=objectinherittype_is_recursiveRecursivetdsmethodrecursiontd={<type_names=[td.ptype_name.txt]>}#go()endinletrecursive,nonrecursive=List.partition_tftds~f:(funtd->matchobj#recursiontdwith|Recursive->true|Nonrecursive->false)inifList.is_emptyrecursive||List.is_emptynonrecursivethenrecursive,nonrecursive::accelselooprecursive~acc:(nonrecursive::acc)inlooptds~acc:[];;letstr_type_decl~ctxt(rec_flag,tds)tags_of_doc_comments=letloc=Expansion_context.Deriver.derived_item_locctxtinletrecursive,nonrecursive=partition_recursive_and_nonrecursive~rec_flagtdsin[recursive_grammars~ctxt~loc~tags_of_doc_commentsrecursive;nonrecursive_grammars~ctxt~loc~tags_of_doc_commentsnonrecursive]|>List.concat;;letsig_type_decl~ctxt:_(_rec_flag,tds)=List.maptds~f:(funtd->letloc=td.ptype_locinvalue_description~loc~name:(Loc.maptd.ptype_name~f:grammar_name)~type_:(combinator_type_of_type_declarationtd~f:grammar_type)~prim:[]|>psig_value~loc);;letextension_loc~ctxt=letloc=Expansion_context.Extension.extension_point_locctxtin{locwithloc_ghost=true};;letcore_type~tags_of_doc_comments~ctxtcore_type=letloc=extension_loc~ctxtinpexp_constraint~loc(core_type|>grammar_of_type~rec_flag:Nonrecursive~tags_of_doc_comments|>typed_grammar~loc)(core_type|>grammar_type~loc)|>Merlin_helpers.hide_expression;;lettype_extension~ctxtcore_type=assert_no_attributes_in#core_typecore_type;letloc=extension_loc~ctxtincore_type|>grammar_type~loc;;