123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286openBaseopenImportmoduleOf_python=structtype'at={type_name:string;conv:pyobject->'a}letcreate~type_name~conv={type_name;conv}endmoduleArg=structtype'at={name:string;of_python:'aOf_python.t;docstring:string;kind:[`positional|`keywordof'aoption]}endmoduleOpt_arg=structtype'at={name:string;of_python:'aOf_python.t;docstring:string}endmoduleT0=structtype_t=|Return:'a->'at|Map:'at*('a->'b)->'bt|Both:'at*'bt->('a*'b)t|Arg:'aArg.t->'at|Opt_arg:'aOpt_arg.t->'aoptiontletreturnx=Returnxletmapt~f=Map(t,f)letbothtt'=Both(t,t')letapplyfx=bothfx|>map~f:(fun(f,x)->fx)letmap=`CustommapendmoduleT=structincludeT0includeApplicative.Make(T0)endincludeTmoduleOpen_on_rhs_intf=structmoduletypeS=Applicative.SendincludeApplicative.Make_let_syntax(T)(Open_on_rhs_intf)(T)letvalid_charc=Char.(is_alphanumc||c='_')letcheck_valid_arg_namename=ifString.is_emptynamethenfailwith"cannot use an empty name"else(letfirst_char=name.[0]inifChar.(first_char<'a'||first_char>'z')thenPrintf.failwithf"arg name %s does not start with a lowercase letter"name()elseifString.existsname~f:(func->not(valid_charc))thenPrintf.failwithf"arg name %s contains some invalid characters"name()else());;letapply(typea)(t:at)argskwargs=lettry_of_pythonv~of_python~name=tryof_python.Of_python.convvwith|e->value_errorf"error processing arg %s (%s): %s"nameof_python.type_name(Exn.to_stringe)inletkwnames=Hash_set.create(moduleString)inletpositional_arguments()=letrecloop:typea.at->stringlist=function|Return_->[]|Map(t,_)->loopt|Both(t,t')->letargs=looptinletargs'=loopt'inargs@args'|Arg{name;kind=`positional;_}->[name]|Arg{kind=`keyword_;_}->[]|Opt_arg_->[]inlooptinletrecloop:typea.at->pos:int->a*int=funt~pos->matchtwith|Returna->a,pos|Map(t,f)->letv,pos=loopt~posinfv,pos|Both(t,t')->letv,pos=loopt~posinletv',pos=loopt'~posin(v,v'),pos|Arg{name;of_python;docstring=_;kind=`positional}->ifpos>=Array.lengthargsthenvalue_errorf"not enough arguments (got %d, expected %s)"(Array.lengthargs)(positional_arguments()|>String.concat~sep:", ");try_of_pythonargs.(pos)~of_python~name,pos+1|Opt_arg{name;of_python;docstring=_}->ifHash_set.memkwnamesnamethenvalue_errorf"multiple keyword arguments with name %s"name;Hash_set.addkwnamesname;letv=Map.findkwargsnameinOption.mapv~f:(try_of_python~of_python~name),pos|Arg{name;of_python;docstring=_;kind=`keyworddefault}->ifHash_set.memkwnamesnamethenvalue_errorf"multiple keyword arguments with name %s"name;Hash_set.addkwnamesname;(matchMap.findkwargsnamewith|Somev->try_of_pythonv~of_python~name,pos|None->(matchdefaultwith|Somedefault->default,pos|None->value_errorf"missing keyword argument: %s"name))inletv,final_pos=loopt~pos:0inMap.iter_keyskwargs~f:(funkey->ifnot(Hash_set.memkwnameskey)thenvalue_errorf"unexpected keyword argument %s"key);iffinal_pos<>Array.lengthargsthenvalue_errorf"expected %d arguments (%s), got %d"final_pos(positional_arguments()|>String.concat~sep:", ")(Array.lengthargs);v;;letparams_docstringt=letsprintf=Printf.sprintfinletarg_docstringarg~pos=matcharg.Arg.kindwith|`positional->[sprintf" :param %s: (positional %d) %s"arg.nameposarg.docstring;sprintf" :type %s: %s"arg.namearg.of_python.type_name]|>String.concat~sep:"\n"|`keyworddefault->letdefault=matchdefaultwith|None->"mandatory keyword"|Some_->"keyword with default"in[sprintf" :param %s: (%s) %s"arg.namedefaultarg.docstring;sprintf" :type %s: %s"arg.namearg.of_python.type_name]|>String.concat~sep:"\n"inletopt_arg_docstring(arg:_Opt_arg.t)=[sprintf" :param %s: (optional keyword) %s"arg.namearg.docstring;sprintf" :type %s: %s"arg.namearg.of_python.type_name]|>String.concat~sep:"\n"inletrecloop:typea.at->pos:int->stringlist*int=funt~pos->matchtwith|Return_->[],pos|Map(t,_)->loopt~pos|Both(t1,t2)->letparams1,pos=loopt1~posinletparams2,pos=loopt2~posinparams1@params2,pos|Arg({kind=`positional;_}asarg)->[arg_docstringarg~pos],pos+1|Arg({kind=`keyword_;_}asarg)->[arg_docstringarg~pos],pos|Opt_argopt_arg->[opt_arg_docstringopt_arg],posinletparams,_pos=loopt~pos:0inifList.is_emptyparamsthenNoneelseString.concatparams~sep:"\n\n"|>Option.some;;moduleParam=structletpositionalnameof_python~docstring=check_valid_arg_namename;Arg{name;of_python;docstring;kind=`positional};;letkeyword?defaultnameof_python~docstring=check_valid_arg_namename;Arg{name;of_python;docstring;kind=`keyworddefault};;letkeyword_optnameof_python~docstring=check_valid_arg_namename;Opt_arg{name;of_python;docstring};;letint=Of_python.create~type_name:"int"~conv:int_of_pythonletfloat=Of_python.create~type_name:"float"~conv:float_of_pythonletbool=Of_python.create~type_name:"bool"~conv:bool_of_pythonletstring=Of_python.create~type_name:"string"~conv:string_of_pythonletpyobject=Of_python.create~type_name:"obj"~conv:Fn.idletcheck_tuple_lenpyobject~expected_length=ifnot(Py.Tuple.checkpyobject)thenPrintf.failwithf"expected a tuple got %s"(Py.Type.getpyobject|>Py.Type.name)();letlength=Py.Tuple.sizepyobjectinifexpected_length<>lengththenPrintf.failwithf"expected a tuple with %d elements, got %d"expected_lengthlength();;letpair(o1:_Of_python.t)(o2:_Of_python.t)=Of_python.create~type_name:(Printf.sprintf"(%s, %s)"o1.type_nameo2.type_name)~conv:(funpyobject->check_tuple_lenpyobject~expected_length:2;letp1,p2=Py.Tuple.to_tuple2pyobjectino1.convp1,o2.convp2);;lettriple(o1:_Of_python.t)(o2:_Of_python.t)(o3:_Of_python.t)=Of_python.create~type_name:(Printf.sprintf"(%s, %s, %s)"o1.type_nameo2.type_nameo3.type_name)~conv:(funpyobject->check_tuple_lenpyobject~expected_length:3;letp1,p2,p3=Py.Tuple.to_tuple3pyobjectino1.convp1,o2.convp2,o3.convp3);;letlist(o:_Of_python.t)=Of_python.create~type_name:(Printf.sprintf"[%s]"o.type_name)~conv:(funpython_value->(matchPy.Type.getpython_valuewith|List|Tuple->()|otherwise->Printf.failwithf"not a list or a tuple (%s)"(Py.Type.nameotherwise)());Py.List.to_list_mapo.convpython_value);;letlist_or_iter(o:_Of_python.t)=Of_python.create~type_name:(Printf.sprintf"[%s]"o.type_name)~conv:(funp->matchto_iterablepwith|None->Printf.failwithf"not a list/tuple/iter (%s)"(Py.Type.getp|>Py.Type.name)()|Somel->Py.List.to_list_mapo.convl);;letone_or_tuple_or_list(o:_Of_python.t)=Of_python.create~type_name:(Printf.sprintf"[%s]"o.type_name)~conv:(One_or_tuple_or_list.t_of_pythono.conv);;letone_or_tuple_or_list_relaxed(o:_Of_python.t)=Of_python.create~type_name:(Printf.sprintf"[%s] (relaxed)"o.type_name)~conv:(One_or_tuple_or_list_or_error.t_of_pythono.conv~type_name:o.type_name);;letdict~(key:_Of_python.t)~(value:_Of_python.t)=Of_python.create~type_name:(Printf.sprintf"[%s: %s]"key.type_namevalue.type_name)~conv:(Py.Dict.to_bindings_mapkey.convvalue.conv);;end