123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2023 Nomadic Labs <contact@nomadic-labs.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)openTezos_michelineopenProtocolopenAlpha_contexttypelocalized_node={parser_loc:Micheline_parser.locationoption;canonical_loc:Micheline.canonical_location;node:stringMicheline.canonical;}letprint_localized_node_locationfmtlocalized_node=matchlocalized_node.parser_locwith|Someparser_loc->Format.fprintffmt"%s"(Format.kasprintfString.capitalize_ascii"%a"Micheline_parser.print_locationparser_loc)|None->Format.fprintffmt"At position %d"localized_node.canonical_locletprint_localized_nodefmtlocalized_node=Micheline_printer.print_expr_unwrappedfmt(Micheline_printer.printableFun.idlocalized_node.node)letlocalize_node~(parsed:stringMichelson_v1_parser.parser_result)(n:(Micheline.canonical_location,string)Micheline.node):localized_node=letcanonical_loc=Micheline.locationninletparser_loc=letopenOption_syntaxinlet*oloc=List.assoc~equal:Int.equalcanonical_locparsed.unexpansion_tableinlet+ploc,_=List.assoc~equal:Int.equalolocparsed.expansion_tableinplocin{parser_loc;canonical_loc;node=Micheline.strip_locationsn}letlocalized_node_encoding:localized_nodeData_encoding.t=Data_encoding.(conv(fun{parser_loc;canonical_loc;node}->(parser_loc,canonical_loc,node))(fun(parser_loc,canonical_loc,node)->{parser_loc;canonical_loc;node})(obj3(req"parser_location"(optionMicheline_parser.location_encoding))(req"canonical_location"Micheline_encoding.canonical_location_encoding)(req"node"(Micheline_encoding.canonical_encoding~variant:"alpha_client"Data_encoding.string))))typeerror+=|Wrong_stack_itemoflocalized_node|Wrong_stackoflocalized_node|Wrong_other_contracts_itemoflocalized_node|Wrong_other_contractsoflocalized_node|Wrong_extra_big_maps_itemoflocalized_node|Wrong_extra_big_mapsoflocalized_node|Invalid_address_for_smart_contractofstring|Duplicated_tzt_top_primofstring*localized_node|Wrong_tzt_top_prim_arityofstring*localized_node*int|Unknown_tzt_top_primofstring*localized_node|Missing_mandatory_tzt_top_primofstring|Invalid_format_for_tzt_top_primofstring*localized_node|Invalid_tzt_topleveloflocalized_nodelet()=Protocol_client_context.register_error_kind`Permanent~id:"michelson.stack.wrong_stack_item"~title:"Wrong stack item"~description:"Failed to parse an item in a typed stack."~pp:(funppfnode->Format.fprintfppf"%a,@ Unexpected format for an item in a typed stack. Expected: \
Stack_elt <ty> <value>; got %a."print_localized_node_locationnodeprint_localized_nodenode)localized_node_encoding(functionWrong_stack_itemnode->Somenode|_->None)(funnode->Wrong_stack_itemnode);Protocol_client_context.register_error_kind`Permanent~id:"michelson.stack.wrong_stack"~title:"Wrong stack"~description:"Failed to parse a typed stack."~pp:(funppfnode->Format.fprintfppf"%a,@ Unexpected format for a typed stack. Expected a sequence of \
Stack_elt <ty> <value>; got %a."print_localized_node_locationnodeprint_localized_nodenode)localized_node_encoding(functionWrong_stacknode->Somenode|_->None)(funnode->Wrong_stacknode);Protocol_client_context.register_error_kind`Permanent~id:"michelson.wrong_other_contracts_item"~title:"Wrong description of an other contract"~description:"Failed to parse an item in a description of other contracts."~pp:(funppfnode->Format.fprintfppf"%a,@ Unexpected format for an item in a description of other \
contracts. Expected: Contract <address> <ty>; got %a."print_localized_node_locationnodeprint_localized_nodenode)localized_node_encoding(functionWrong_other_contracts_itemnode->Somenode|_->None)(funnode->Wrong_other_contracts_itemnode);Protocol_client_context.register_error_kind`Permanent~id:"michelson.wrong_other_contracts"~title:"Wrong description of a list of other contracts"~description:"Failed to parse a description of other contracts."~pp:(funppfnode->Format.fprintfppf"%a,@ Unexpected format for a description of other contracts. Expected \
a sequence of Contract <address> <ty>; got %a."print_localized_node_locationnodeprint_localized_nodenode)localized_node_encoding(functionWrong_other_contractsnode->Somenode|_->None)(funnode->Wrong_other_contractsnode);Protocol_client_context.register_error_kind`Permanent~id:"michelson.wrong_extra_big_maps_item"~title:"Wrong description of an extra big map"~description:"Failed to parse an item in a description of extra big maps."~pp:(funppfnode->Format.fprintfppf"%a,@ Unexpected format for an item in a description of extra big \
maps. Expected: Big_map <index> <key_type> <value_type> <content>; \
got %a."print_localized_node_locationnodeprint_localized_nodenode)localized_node_encoding(functionWrong_extra_big_maps_itemnode->Somenode|_->None)(funnode->Wrong_extra_big_maps_itemnode);Protocol_client_context.register_error_kind`Permanent~id:"michelson.wrong_extra_big_maps"~title:"Wrong description of a list of extra big maps"~description:"Failed to parse a description of extra big maps."~pp:(funppfnode->Format.fprintfppf"%a,@ Unexpected format for a description of extra big maps. Expected \
a sequence of Big_map <index> <key_type> <value_type> <content>; got \
%a."print_localized_node_locationnodeprint_localized_nodenode)localized_node_encoding(functionWrong_extra_big_mapsnode->Somenode|_->None)(funnode->Wrong_extra_big_mapsnode);Protocol_client_context.register_error_kind`Permanent~id:"InvalidAddressForSmartContract"~title:"Invalid address for smart contract"~description:"Invalid input, expected a smart contract address in base58 check \
notation (KT1...)"Data_encoding.(obj1(req"invalid_address"string))~pp:(funppfliteral->Format.fprintfppf"Bad argument value for a smart contract address. Expected an address \
in base58 checked notation starting with 'KT1', but given '%s'"literal)(functionInvalid_address_for_smart_contractstr->Somestr|_->None)(funstr->Invalid_address_for_smart_contractstr);Protocol_client_context.register_error_kind`Permanent~id:"tzt.wrong_toplevel_arity"~title:"Wrong arity for a TZT toplevel primitive"~description:"A known toplevel TZT primitive was used with a bad arity."~pp:(funppf(prim,node,arity)->Format.fprintfppf"%a,@ Wrong arity for TZT toplevel primitive %s, expected %d \
arguments, got %a"print_localized_node_locationnodeprimarityprint_localized_nodenode)Data_encoding.(obj3(req"prim"string)(req"node"localized_node_encoding)(req"arity"int16))(function|Wrong_tzt_top_prim_arity(prim,node,arity)->Some(prim,node,arity)|_->None)(fun(prim,node,arity)->Wrong_tzt_top_prim_arity(prim,node,arity));Protocol_client_context.register_error_kind`Permanent~id:"tzt.duplicated_toplevel"~title:"Duplicated TZT toplevel primitive"~description:"A toplevel TZT primitive was used several times."~pp:(funppf(prim,node)->Format.fprintfppf"%a,@ The TZT toplevel primitive %s, cannot be used because it has \
already been used. A TZT toplevel primitive can only be used once per \
unit test."print_localized_node_locationnodeprim)Data_encoding.(obj2(req"prim"string)(req"node"localized_node_encoding))(function|Duplicated_tzt_top_prim(prim,node)->Some(prim,node)|_->None)(fun(prim,node)->Duplicated_tzt_top_prim(prim,node));Protocol_client_context.register_error_kind`Permanent~id:"tzt.unknown_toplevel"~title:"Unknown TZT toplevel primitive"~description:"A toplevel TZT primitive was unknown."~pp:(funppf(prim,node)->Format.fprintfppf"%a,@ The TZT toplevel primitive %s is unknown."print_localized_node_locationnodeprim)Data_encoding.(obj2(req"prim"string)(req"node"localized_node_encoding))(function|Unknown_tzt_top_prim(prim,node)->Some(prim,node)|_->None)(fun(prim,node)->Unknown_tzt_top_prim(prim,node));Protocol_client_context.register_error_kind`Permanent~id:"tzt.missing_mandatory"~title:"Missing TZT mandatory toplevel primitive"~description:"A mandatory toplevel TZT primitive was missing."~pp:(funppfprim->Format.fprintfppf"The mandatory TZT toplevel primitive %s is missing."prim)Data_encoding.(obj1(req"prim"string))(functionMissing_mandatory_tzt_top_primprim->Someprim|_->None)(funprim->Missing_mandatory_tzt_top_primprim);Protocol_client_context.register_error_kind`Permanent~id:"tzt.invalid_format"~title:"Invalid format for a TZT toplevel primitive"~description:"Invalid format for a TZT toplevel primitive"~pp:(funppf(prim,node)->Format.fprintfppf"%a,@ Invalid format for TZT toplevel primitive %s."print_localized_node_locationnodeprim)Data_encoding.(obj2(req"prim"string)(req"node"localized_node_encoding))(function|Invalid_format_for_tzt_top_prim(prim,node)->Some(prim,node)|_->None)(fun(prim,node)->Invalid_format_for_tzt_top_prim(prim,node));Protocol_client_context.register_error_kind`Permanent~id:"tzt.invalid_toplevel"~title:"Invalid format for TZT toplevel entry"~description:"Invalid format for a TZT toplevel entry"~pp:(funppfnode->Format.fprintfppf"%a,@ Invalid format for TZT toplevel entry, expected a sequence of \
primitive applications, got %a."print_localized_node_locationnodeprint_localized_nodenode)localized_node_encoding(functionInvalid_tzt_toplevelnode->Somenode|_->None)(funnode->Invalid_tzt_toplevelnode)letparse_expression(node:(_,string)Micheline.node)=Environment.wrap_tzresult@@Michelson_v1_primitives.prims_of_strings(Micheline.strip_locationsnode)letparse_stack_item~parsed=letopenResult_syntaxinfunction|Micheline.Prim(_loc,"Stack_elt",[ty;v],_annot)->let*ty=parse_expressiontyinlet*v=parse_expressionvinreturn(ty,v)|e->tzfail(Wrong_stack_item(localize_node~parsede))letparse_other_contract_item~parsed=letopenResult_syntaxinfunction|Micheline.Prim(_loc,"Contract",[address;ty],_annot)ase->let*address=parse_expressionaddressinlet*address=matchMicheline.rootaddresswith|Micheline.String(_loc,s)->(matchEnvironment.Base58.decodeswith|Some(Contract_hash.Datah)->returnh|Some_|None->tzfail(Invalid_address_for_smart_contracts))|_->tzfail(Wrong_other_contracts_item(localize_node~parsede))inlet*ty=parse_expressiontyinreturnRPC.Scripts.S.{address;ty}|e->tzfail(Wrong_other_contracts_item(localize_node~parsede))letparse_extra_big_map_item~parsed=letopenResult_syntaxinfunction|Micheline.Prim(_loc,"Big_map",[id;kty;vty;items],_annot)ase->let*id=parse_expressionidinlet*id=matchMicheline.rootidwith|Micheline.Int(_loc,id)->return(Big_map.Id.parse_zid)|_->tzfail(Wrong_other_contracts_item(localize_node~parsede))inlet*kty=parse_expressionktyinlet*vty=parse_expressionvtyinlet*items=parse_expressionitemsinreturnRPC.Scripts.S.{id;kty;vty;items}|e->tzfail(Wrong_extra_big_maps_item(localize_node~parsede))letparse_sequence?node~(parsed:stringMichelson_v1_parser.parser_result)~errorparse_item=letnode=Option.value~default:(Micheline.rootparsed.expanded)nodeinleterror()=error(localize_node~parsednode)inmatchnodewith|Micheline.Seq(_loc,l)->record_trace_evalerror@@List.map_e(parse_item~parsed)l|_->Result_syntax.tzfail(error())letparse_stack?nodeparsed=parse_sequence?node~parsed~error:(funnode->Wrong_stacknode)parse_stack_itemletparse_other_contracts?nodeparsed=parse_sequence?node~parsed~error:(funnode->Wrong_other_contractsnode)parse_other_contract_itemletparse_extra_big_maps?nodeparsed=parse_sequence?node~parsed~error:(funnode->Wrong_extra_big_mapsnode)parse_extra_big_map_itemtypeunit_test={input:(Script.expr*Script.expr)list;code:Script.expr;output:(Script.expr*Script.expr)list;}(* Same as unit_test but all fields are optional. Used only during
parsing. *)typetemp_unit_test={temp_input:(Script.expr*Script.expr)listoption;temp_code:Script.exproption;temp_output:(Script.expr*Script.expr)listoption;}letparse_unit_test(parsed:stringMichelson_v1_parser.parser_result)=letopenResult_syntaxinletopenMichelineinletrecparseut=function|[]->returnut|(Prim(_loc,prim,[arg],_annots)ase)::l->(letcheck_duplicated=function|None->return_unit|Some_->tzfail(Duplicated_tzt_top_prim(prim,localize_node~parsede))inletinvalid_format()=Invalid_format_for_tzt_top_prim(prim,localize_node~parsede)inlettrace_invalid_formatres=record_trace_evalinvalid_formatresinmatchprimwith|"input"->let*()=check_duplicatedut.temp_inputinlet*items=trace_invalid_format@@parse_stack~node:argparsedinparse{utwithtemp_input=Someitems}l|"output"->let*()=check_duplicatedut.temp_outputinlet*items=trace_invalid_format@@parse_stack~node:argparsedinparse{utwithtemp_output=Someitems}l|"code"->let*()=check_duplicatedut.temp_codeinlet*c=trace_invalid_format@@parse_expressionarginparse{utwithtemp_code=Somec}l|_->tzfail@@Unknown_tzt_top_prim(prim,localize_node~parsede))|(Prim(_loc,prim,([]|_::_::_),_annots)ase)::_->tzfail@@Wrong_tzt_top_prim_arity(prim,localize_node~parsede,1)|((Seq_|Int_|String_|Bytes_)ase)::_->tzfail@@Invalid_tzt_toplevel(localize_node~parsede)inletnodes=matchMicheline.rootparsed.expandedwith|Seq(_,nodes)->nodes|node->[node]inlet*ut=parse{temp_input=None;temp_code=None;temp_output=None}nodesinletcheck_mandatoryoptprim=Option.value_eopt~error:(TzTrace.make@@Missing_mandatory_tzt_top_primprim)inlet*input=check_mandatoryut.temp_input"input"inlet*code=check_mandatoryut.temp_code"code"inlet*output=check_mandatoryut.temp_output"output"inreturn{input;code;output}