Require Import Ascii String List. Require Import List. Import ListNotations. Require Import untyped_syntax micheline_syntax error location. Require Import syntax_type. Require Import Lia. Require Import trie. Require micheline_lexer. Require Coq.Program.Wf. Import error.Notations. Import untyped_syntax.notations. Open Scope string. Inductive string_literal := | S_ABS | S_ADD | S_ADDRESS | S_AMOUNT | S_AND | S_APPLY | S_ASSERT | S_ASSERT_LEFT | S_ASSERT_NONE | S_ASSERT_RIGHT | S_ASSERT_SOME | S_BALANCE | S_BLAKE2B | S_CAR | S_CAST | S_CDR | S_CHAIN_ID | S_CHECK_SIGNATURE | S_COMPARE | S_CONCAT | S_CONS | S_CONTRACT | S_CREATE_CONTRACT | S_DIG | S_DIP | S_DROP | S_DUG | S_DUP | S_EDIV | S_EMPTY_BIG_MAP | S_EMPTY_MAP | S_EMPTY_SET | S_EQ | S_EXEC | S_Elt | S_FAIL | S_FAILWITH | S_False | S_GE | S_GET | S_GT | S_HASH_KEY | S_IF | S_IF_CONS | S_IF_LEFT | S_IF_NIL | S_IF_NONE | S_IF_RIGHT | S_IF_SOME | S_IMPLICIT_ACCOUNT | S_INT | S_ISNAT | S_ITER | S_LAMBDA | S_LE | S_LEFT | S_LOOP | S_LOOP_LEFT | S_LSL | S_LSR | S_LT | S_Left | S_MAP | S_MEM | S_MUL | S_NEG | S_NEQ | S_NIL | S_NONE | S_NOT | S_NOW | S_None | S_OR | S_PACK | S_PAIR | S_PUSH | S_Pair | S_RENAME | S_RIGHT | S_Right | S_SELF | S_SENDER | S_SET_DELEGATE | S_SHA256 | S_SHA512 | S_SIZE | S_SLICE | S_SOME | S_SOURCE | S_SUB | S_SWAP | S_Some | S_TRANSFER_TOKENS | S_True | S_UNIT | S_UNPACK | S_UPDATE | S_Unit | S_XOR | S_address | S_big_map | S_bool | S_bytes | S_chain_id | S_code | S_contract | S_int | S_key | S_key_hash | S_lambda | S_list | S_map | S_mutez | S_nat | S_operation | S_option | S_or | S_pair | S_parameter | S_set | S_signature | S_storage | S_string | S_timestamp | S_unit | S_ : String.string -> string_literal. Definition string_literals := [ ("ABS", S_ABS); ("ADD", S_ADD); ("ADDRESS", S_ADDRESS); ("AMOUNT", S_AMOUNT); ("AND", S_AND); ("APPLY", S_APPLY); ("ASSERT", S_ASSERT); ("ASSERT_LEFT", S_ASSERT_LEFT); ("ASSERT_NONE", S_ASSERT_NONE); ("ASSERT_RIGHT", S_ASSERT_RIGHT); ("ASSERT_SOME", S_ASSERT_SOME); ("BALANCE", S_BALANCE); ("BLAKE2B", S_BLAKE2B); ("CAR", S_CAR); ("CAST", S_CAST); ("CDR", S_CDR); ("CHAIN_ID", S_CHAIN_ID); ("CHECK_SIGNATURE", S_CHECK_SIGNATURE); ("COMPARE", S_COMPARE); ("CONCAT", S_CONCAT); ("CONS", S_CONS); ("CONTRACT", S_CONTRACT); ("CREATE_CONTRACT", S_CREATE_CONTRACT); ("DIG", S_DIG); ("DIP", S_DIP); ("DROP", S_DROP); ("DUG", S_DUG); ("DUP", S_DUP); ("EDIV", S_EDIV); ("EMPTY_BIG_MAP", S_EMPTY_BIG_MAP); ("EMPTY_MAP", S_EMPTY_MAP); ("EMPTY_SET", S_EMPTY_SET); ("EQ", S_EQ); ("EXEC", S_EXEC); ("Elt", S_Elt); ("FAIL", S_FAIL); ("FAILWITH", S_FAILWITH); ("False", S_False); ("GE", S_GE); ("GET", S_GET); ("GT", S_GT); ("HASH_KEY", S_HASH_KEY); ("IF", S_IF); ("IF_CONS", S_IF_CONS); ("IF_LEFT", S_IF_LEFT); ("IF_NIL", S_IF_NIL); ("IF_NONE", S_IF_NONE); ("IF_RIGHT", S_IF_RIGHT); ("IF_SOME", S_IF_SOME); ("IMPLICIT_ACCOUNT", S_IMPLICIT_ACCOUNT); ("INT", S_INT); ("ISNAT", S_ISNAT); ("ITER", S_ITER); ("LAMBDA", S_LAMBDA); ("LE", S_LE); ("LEFT", S_LEFT); ("LOOP", S_LOOP); ("LOOP_LEFT", S_LOOP_LEFT); ("LSL", S_LSL); ("LSR", S_LSR); ("LT", S_LT); ("Left", S_Left); ("MAP", S_MAP); ("MEM", S_MEM); ("MUL", S_MUL); ("NEG", S_NEG); ("NEQ", S_NEQ); ("NIL", S_NIL); ("NONE", S_NONE); ("NOT", S_NOT); ("NOW", S_NOW); ("None", S_None); ("OR", S_OR); ("PACK", S_PACK); ("PAIR", S_PAIR); ("PUSH", S_PUSH); ("Pair", S_Pair); ("RENAME", S_RENAME); ("RIGHT", S_RIGHT); ("Right", S_Right); ("SELF", S_SELF); ("SENDER", S_SENDER); ("SET_DELEGATE", S_SET_DELEGATE); ("SHA256", S_SHA256); ("SHA512", S_SHA512); ("SIZE", S_SIZE); ("SLICE", S_SLICE); ("SOME", S_SOME); ("SOURCE", S_SOURCE); ("SUB", S_SUB); ("SWAP", S_SWAP); ("Some", S_Some); ("TRANSFER_TOKENS", S_TRANSFER_TOKENS); ("True", S_True); ("UNIT", S_UNIT); ("UNPACK", S_UNPACK); ("UPDATE", S_UPDATE); ("Unit", S_Unit); ("XOR", S_XOR); ("address", S_address); ("big_map", S_big_map); ("bool", S_bool); ("bytes", S_bytes); ("chain_id", S_chain_id); ("code", S_code); ("contract", S_contract); ("int", S_int); ("key", S_key); ("key_hash", S_key_hash); ("lambda", S_lambda); ("list", S_list); ("map", S_map); ("mutez", S_mutez); ("nat", S_nat); ("operation", S_operation); ("option", S_option); ("or", S_or); ("pair", S_pair); ("parameter", S_parameter); ("set", S_set); ("signature", S_signature); ("storage", S_storage); ("string", S_string); ("timestamp", S_timestamp); ("unit", S_unit) ]. Definition string_literal_dict_aux : String.string -> Datatypes.option string_literal := Eval cbv in extract (dict string_literals 1000) I. Definition make_string_literal (s : String.string) : string_literal := match string_literal_dict_aux s with | Some l => l | None => S_ s end. Definition loc_pmicheline := loc_gmicheline string_literal. Definition to_pmicheline := map_gmicheline make_string_literal. Definition micheline2michelson_sctype (bem : loc_pmicheline) : M simple_comparable_type := let 'Mk_loc_micheline ((b, e), m) := bem in match m with | PRIM (_, S_string) _ nil => Return string | PRIM (_, S_nat) _ nil => Return nat | PRIM (_, S_int) _ nil => Return int | PRIM (_, S_bytes) _ nil => Return bytes | PRIM (_, S_bool) _ nil => Return bool | PRIM (_, S_mutez) _ nil => Return mutez | PRIM (_, S_key_hash) _ nil => Return key_hash | PRIM (_, S_timestamp) _ nil => Return timestamp | PRIM (_, S_address) _ nil => Return address | _ => Failed _ (Expansion b e) end. Fixpoint micheline2michelson_ctype (bem : loc_pmicheline) : M comparable_type := let 'Mk_loc_micheline ((b, e), m) := bem in match m with | PRIM (_, S_pair) _ (a :: b :: nil) => let! a := micheline2michelson_sctype a in let! b := micheline2michelson_ctype b in Return (Cpair a b) | _ => let! a := micheline2michelson_sctype bem in Return (Comparable_type_simple a) end. Definition extract_one_field_annot_from_list annots : M annot_o := match annots with | nil => Return None | Mk_annot (_, _, annot) :: nil => Return (Some annot) | _ :: Mk_annot (b, e, _) :: _ => Failed _ (Expansion b e) end. Definition is_field_annot annot := match annot with | Mk_annot (_, _, EmptyString) => false | Mk_annot (_, _, String c _) => micheline_lexer.eqb_ascii c "%"%char end. Definition extract_one_field_annot (bem : loc_pmicheline) : M annot_o := let 'Mk_loc_micheline ((b, e), m) := bem in match m with | PRIM p annots args => let filtered_annots := List.filter is_field_annot annots in extract_one_field_annot_from_list filtered_annots | _ => Return None end. Fixpoint micheline2michelson_type (bem : loc_pmicheline) : M type := try (let! ty := micheline2michelson_sctype bem in Return (Comparable_type ty)) (let 'Mk_loc_micheline ((b, e), m) := bem in match m with | PRIM (_, S_key) _ nil => Return key | PRIM (_, S_unit) _ nil => Return unit | PRIM (_, S_signature) _ nil => Return signature | PRIM (_, S_operation) _ nil => Return operation | PRIM (_, S_chain_id) _ nil => Return chain_id | PRIM (_, S_option) _ (a :: nil) => let! a := micheline2michelson_type a in Return (option a) | PRIM (_, S_list) _ (a :: nil) => let! a := micheline2michelson_type a in Return (list a) | PRIM (_, S_contract) _ (a :: nil) => let! a := micheline2michelson_type a in Return (contract a) | PRIM (_, S_set) _ (a :: nil) => let! a := micheline2michelson_ctype a in Return (set a) | PRIM (_, S_pair) _ (a :: b :: nil) => let! a := micheline2michelson_type a in let! b := micheline2michelson_type b in Return (pair a b) | PRIM (_, S_or) _ (a :: b :: nil) => let! an := extract_one_field_annot a in let! bn := extract_one_field_annot b in let! a := micheline2michelson_type a in let! b := micheline2michelson_type b in Return (or a an b bn) | PRIM (_, S_lambda) _ (a :: b :: nil) => let! a := micheline2michelson_type a in let! b := micheline2michelson_type b in Return (lambda a b) | PRIM (_, S_map) _ (a :: b :: nil) => let! a := micheline2michelson_ctype a in let! b := micheline2michelson_type b in Return (map a b) | PRIM (_, S_big_map) _ (a :: b :: nil) => let! a := micheline2michelson_ctype a in let! b := micheline2michelson_type b in Return (big_map a b) | _ => Failed _ (Expansion b e) end). Fixpoint micheline2michelson_data (bem : loc_pmicheline) : M concrete_data := let 'Mk_loc_micheline ((b, e), m) := bem in match m with | SEQ l => let! l := (fix micheline2michelson_data_list (l : Datatypes.list loc_pmicheline) : M (Datatypes.list concrete_data) := match l with | nil => Return nil | m :: l => let! d := micheline2michelson_data m in let! l := micheline2michelson_data_list l in Return (d :: l) end ) l in Return (Concrete_seq l) | STR s => Return (String_constant s) | NUMBER z => Return (Int_constant z) | BYTES s => Return (Bytes_constant s) | PRIM (_, S_Unit) _ nil => Return Unit | PRIM (_, S_True) _ nil => Return True_ | PRIM (_, S_False) _ nil => Return False_ | PRIM (_, S_Pair) _ (a :: b :: nil) => let! a := micheline2michelson_data a in let! b := micheline2michelson_data b in Return (Pair a b) | PRIM (_, S_Elt) _ (a :: b :: nil) => let! a := micheline2michelson_data a in let! b := micheline2michelson_data b in Return (Elt a b) | PRIM (_, S_Left) _ (a :: nil) => let! a := micheline2michelson_data a in Return (Left a) | PRIM (_, S_Right) _ (a :: nil) => let! a := micheline2michelson_data a in Return (Right a) | PRIM (_, S_Some) _ (a :: nil) => let! a := micheline2michelson_data a in Return (Some_ a) | PRIM (_, S_None) _ nil => Return None_ | PRIM _ _ _ => Failed _ (Expansion b e) end. Definition op_of_string (s : string_literal) b e := match s with | S_EQ => Return EQ | S_NEQ => Return NEQ | S_LE => Return LE | S_GE => Return GE | S_LT => Return LT | S_GT => Return GT | _ => Failed _ (Expansion b e) end. Definition FAIL := Instruction_seq {UNIT; FAILWITH}. Definition ASSERT := Instruction_seq {IF_ IF_bool {} {FAIL}}. Definition IF_op_of_string (s : String.string) b e bt bf := match s with | String "I" (String "F" s) => let s := make_string_literal s in let! op := op_of_string s b e in Return (op ;; IF_ IF_bool bt bf ;; NOOP) | _ => Failed _ (Expansion b e) end. Definition ASSERT_op_of_string (s : String.string) b e := match s with | String "A" (String "S" (String "S" (String "E" (String "R" (String "T" (String "_" s)))))) => let s := make_string_literal s in let! op := op_of_string s b e in Return (op ;; ASSERT ;; NOOP) | _ => Failed _ (Expansion b e) end. Definition ASSERT_NONE := Instruction_seq {IF_NONE {} {FAIL}}. Definition ASSERT_SOME := Instruction_seq {IF_NONE {FAIL} {}}. Definition ASSERT_LEFT := Instruction_seq {IF_LEFT {} {FAIL}}. Definition ASSERT_RIGHT := Instruction_seq {IF_LEFT {FAIL} {}}. Fixpoint DUP_Sn n : instruction_seq := match n with | 0 => {DUP} | S n => {DIP 1 (DUP_Sn n); SWAP} end. Definition IF_SOME bt bf := Instruction_seq {IF_NONE bf bt}. Definition IF_RIGHT bt bf := Instruction_seq {IF_LEFT bf bt}. Definition IF_NIL bt bf := Instruction_seq {IF_CONS bf bt}. Inductive cadr : Set := | Cadr_CAR : cadr -> cadr | Cadr_CDR : cadr -> cadr | Cadr_nil : cadr. Fixpoint micheline2michelson_cadr (x : cadr) : instruction_seq := match x with | Cadr_CAR x => CAR ;; micheline2michelson_cadr x | Cadr_CDR x => CDR ;; micheline2michelson_cadr x | Cadr_nil => {} end. Fixpoint micheline2michelson_set_cadr (x : cadr) : instruction_seq := match x with | Cadr_CAR Cadr_nil => {CDR; SWAP; PAIR} | Cadr_CDR Cadr_nil => {CAR; PAIR} | Cadr_CAR x => {DUP; DIP 1 (CAR;; micheline2michelson_set_cadr x); CDR; SWAP; PAIR} | Cadr_CDR x => {DUP; DIP 1 (CDR;; micheline2michelson_set_cadr x); CAR; PAIR} | Cadr_nil => {} (* Should not happen *) end. Fixpoint micheline2michelson_map_cadr (x : cadr) (code : instruction_seq) : instruction_seq := match x with | Cadr_CAR Cadr_nil => {DUP; CDR; DIP 1 (CAR;; code); SWAP; PAIR} | Cadr_CDR Cadr_nil => {DUP; CDR} ;;; code ;;; {SWAP; CAR; PAIR} | Cadr_CAR x => {DUP; DIP 1 (CAR;; micheline2michelson_map_cadr x code); CDR; SWAP; PAIR} | Cadr_CDR x => {DUP; DIP 1 (CDR;; micheline2michelson_map_cadr x code); CAR; PAIR} | Cadr_nil => code (* Should not happen *) end. (* PAPAIR stuff *) Inductive direction := Left | Right. Inductive papair_token := token_P | token_A | token_I. Fixpoint lex_papair (s : String.string) (fail : exception) : M (Datatypes.list papair_token) := match s with | String "P" s => let! l := lex_papair s fail in Return (cons token_P l) | String "A" s => let! l := lex_papair s fail in Return (cons token_A l) | String "I" s => let! l := lex_papair s fail in Return (cons token_I l) | "R"%string => Return nil | _ => Failed _ fail end. Inductive papair_d : direction -> Set := | Papair_d_P d : papair_d Left -> papair_d Right -> papair_d d | Papair_d_A : papair_d Left | Papair_d_I : papair_d Right. Fixpoint parse_papair (d : direction) (s : Datatypes.list papair_token) (fail : exception) (fuel : Datatypes.nat) (Hs : List.length s < fuel) {struct fuel} : M (papair_d d * sig (fun r : Datatypes.list papair_token => List.length r < List.length s)). Proof. destruct fuel. - destruct (PeanoNat.Nat.nlt_0_r _ Hs). - destruct s as [|c s]. + exact (Failed _ fail). + refine (match c, d return M (papair_d d * (sig (fun r : Datatypes.list papair_token => List.length r < S (List.length s)))) with | token_P, d1 => let! (l, exist _ s1 Hl) := parse_papair Left s fail fuel _ in let! (r, exist _ s2 Hr) := parse_papair Right s1 fail fuel _ in Return (Papair_d_P d l r, exist _ s2 _) | token_A, Left => Return (Papair_d_A, exist _ s _) | token_I, Right => Return (Papair_d_I, exist _ s _) | _, _ => Failed _ fail end); simpl in *; lia. Defined. Inductive papair_left : Set := | Papair_l_P : papair_left -> papair_right -> papair_left | Papair_l_A : papair_left with papair_right : Set := | Papair_r_P : papair_left -> papair_right -> papair_right | Papair_r_I : papair_right. Fixpoint papair_l_of_papair_d (x : papair_d Left) : papair_left := match x in papair_d Left return papair_left with | Papair_d_A => Papair_l_A | Papair_d_P Left l r => Papair_l_P (papair_l_of_papair_d l) (papair_r_of_papair_d r) end with papair_r_of_papair_d (x : papair_d Right) : papair_right := match x in papair_d Right return papair_right with | Papair_d_I => Papair_r_I | Papair_d_P Right l r => Papair_r_P (papair_l_of_papair_d l) (papair_r_of_papair_d r) end. Fixpoint size_l (x : papair_left) := match x with | Papair_l_A => 0 | Papair_l_P l r => 1 + size_l l + size_r r end with size_r (y : papair_right) := match y with | Papair_r_I => 0 | Papair_r_P l r => 1 + size_l l + size_r r end. Inductive papair : Set := | Papair_PAIR : papair | Papair_A : papair -> papair | Papair_I : papair -> papair | Papair_P : papair -> papair -> papair. Program Fixpoint papair_of_l_r (x : papair_left) (y : papair_right) {measure (size_l x + size_r y)}: papair := match x, y with | Papair_l_A, Papair_r_I => Papair_PAIR | Papair_l_A, Papair_r_P l r => Papair_A (papair_of_l_r l r) | Papair_l_P l r, Papair_r_I => Papair_I (papair_of_l_r l r) | Papair_l_P xl xr, Papair_r_P yl yr => Papair_P (papair_of_l_r xl xr) (papair_of_l_r yl yr) end. Next Obligation. simpl. lia. Defined. Next Obligation. simpl. lia. Defined. Next Obligation. simpl. lia. Defined. Fixpoint micheline2michelson_papair (x : papair) : instruction_seq := match x with | Papair_PAIR => {PAIR} | Papair_A y => {DIP 1 (micheline2michelson_papair y); PAIR} | Papair_I x => micheline2michelson_papair x ;;; {PAIR} | Papair_P x y => micheline2michelson_papair x ;;; {DIP 1 (micheline2michelson_papair y); PAIR} end. Fixpoint micheline2michelson_unpapair (x : papair) : instruction := match x with | Papair_PAIR => UNPAIR | Papair_A y => Instruction_seq {UNPAIR; DIP 1 { micheline2michelson_unpapair y }} | Papair_I x => Instruction_seq {UNPAIR; micheline2michelson_unpapair x} | Papair_P x y => Instruction_seq {UNPAIR; DIP 1 {micheline2michelson_unpapair y}; micheline2michelson_unpapair x} end. Definition parse_papair_full (s : String.string) (fail : exception) : M instruction_seq := let! toks : Datatypes.list papair_token := lex_papair s fail in let! (l, exist _ toks2 Htoks2) := parse_papair Left toks fail (S (List.length toks)) ltac:(simpl; lia) in let! (r, exist _ toks3 Htoks3) := parse_papair Right toks2 fail (S (List.length toks2)) ltac:(simpl; lia) in match toks3 with | nil => Return (micheline2michelson_papair (papair_of_l_r (papair_l_of_papair_d l) (papair_r_of_papair_d r))) | _ => Failed _ fail end. Definition parse_unpapair_full (s : String.string) (fail : exception) : M instruction := let! toks : Datatypes.list papair_token := lex_papair s fail in let! (l, exist _ toks2 Htoks2) := parse_papair Left toks fail (S (List.length toks)) ltac:(simpl; lia) in let! (r, exist _ toks3 Htoks3) := parse_papair Right toks2 fail (S (List.length toks2)) ltac:(simpl; lia) in match toks3 with | nil => Return (micheline2michelson_unpapair (papair_of_l_r (papair_l_of_papair_d l) (papair_r_of_papair_d r))) | _ => Failed _ fail end. Definition return_instruction (i : instruction) : M instruction_seq := Return {i}%michelson_untyped. Definition return_opcode (op : opcode) : M instruction_seq := return_instruction (instruction_opcode op). Definition return_macro (i : instruction_seq) : M instruction_seq := return_instruction (Instruction_seq i). Fixpoint micheline2michelson_instruction (bem : loc_pmicheline) : M instruction_seq := let 'Mk_loc_micheline ((b, e), m) := bem in match m with | SEQ l => (fix micheline2michelson_instr_seq (l : Datatypes.list loc_pmicheline) : M instruction_seq := match l with | nil => Return NOOP | i1 :: i2 => let! i1 := micheline2michelson_instruction i1 in let! i2 := micheline2michelson_instr_seq i2 in Return (i1 ;;; i2) end) l | PRIM (_, S_FAILWITH) _ nil => return_instruction FAILWITH | PRIM (_, S_EXEC) _ nil => return_instruction EXEC | PRIM (_, S_APPLY) _ nil => return_opcode APPLY | PRIM (_, S_DROP) _ nil => return_opcode (DROP 1) | PRIM (_, S_DROP) _ (Mk_loc_micheline (_, NUMBER n) :: nil) => return_opcode (DROP (BinInt.Z.to_nat n)) | PRIM (_, S_DUP) _ nil => return_opcode DUP | PRIM (_, S_SWAP) _ nil => return_opcode SWAP | PRIM (_, S_UNIT) _ nil => return_opcode UNIT | PRIM (_, S_EQ) _ nil => return_opcode EQ | PRIM (_, S_NEQ) _ nil => return_opcode NEQ | PRIM (_, S_LT) _ nil => return_opcode LT | PRIM (_, S_GT) _ nil => return_opcode GT | PRIM (_, S_LE) _ nil => return_opcode LE | PRIM (_, S_GE) _ nil => return_opcode GE | PRIM (_, S_OR) _ nil => return_opcode OR | PRIM (_, S_AND) _ nil => return_opcode AND | PRIM (_, S_XOR) _ nil => return_opcode XOR | PRIM (_, S_NOT) _ nil => return_opcode NOT | PRIM (_, S_NEG) _ nil => return_opcode NEG | PRIM (_, S_ABS) _ nil => return_opcode ABS | PRIM (_, S_ISNAT) _ nil => return_opcode ISNAT | PRIM (_, S_INT) _ nil => return_opcode INT | PRIM (_, S_ADD) _ nil => return_opcode ADD | PRIM (_, S_SUB) _ nil => return_opcode SUB | PRIM (_, S_MUL) _ nil => return_opcode MUL | PRIM (_, S_EDIV) _ nil => return_opcode EDIV | PRIM (_, S_LSL) _ nil => return_opcode LSL | PRIM (_, S_LSR) _ nil => return_opcode LSR | PRIM (_, S_COMPARE) _ nil => return_opcode COMPARE | PRIM (_, S_CONCAT) _ nil => return_opcode CONCAT | PRIM (_, S_SIZE) _ nil => return_opcode SIZE | PRIM (_, S_SLICE) _ nil => return_opcode SLICE | PRIM (_, S_PAIR) _ nil => return_opcode PAIR | PRIM (_, S_CAR) _ nil => return_opcode CAR | PRIM (_, S_CDR) _ nil => return_opcode CDR | PRIM (_, S_GET) _ nil => return_opcode GET | PRIM (_, S_SOME) _ nil => return_opcode SOME | PRIM (_, S_NONE) _ (ty :: nil) => let! ty := micheline2michelson_type ty in return_opcode (NONE ty) | PRIM (_, S_LEFT) _ (ty :: nil) => let! ty := micheline2michelson_type ty in return_opcode (LEFT ty) | PRIM (_, S_RIGHT) _ (ty :: nil) => let! ty := micheline2michelson_type ty in return_opcode (RIGHT ty) | PRIM (_, S_CONS) _ nil => return_opcode CONS | PRIM (_, S_NIL) _ (ty :: nil) => let! ty := micheline2michelson_type ty in return_opcode (NIL ty) | PRIM (_, S_TRANSFER_TOKENS) _ nil => return_opcode TRANSFER_TOKENS | PRIM (_, S_SET_DELEGATE) _ nil => return_opcode SET_DELEGATE | PRIM (_, S_BALANCE) _ nil => return_opcode BALANCE | PRIM (_, S_ADDRESS) _ nil => return_opcode ADDRESS | PRIM (_, S_CONTRACT) _ (ty :: nil) => let! an := extract_one_field_annot bem in let! ty := micheline2michelson_type ty in return_opcode (CONTRACT an ty) | PRIM (_, S_SOURCE) _ nil => return_opcode SOURCE | PRIM (_, S_SENDER) _ nil => return_opcode SENDER | PRIM (_, S_SELF) _ nil => let! an := extract_one_field_annot bem in return_instruction (SELF an) | PRIM (_, S_AMOUNT) _ nil => return_opcode AMOUNT | PRIM (_, S_IMPLICIT_ACCOUNT) _ nil => return_opcode IMPLICIT_ACCOUNT | PRIM (_, S_NOW) _ nil => return_opcode NOW | PRIM (_, S_PACK) _ nil => return_opcode PACK | PRIM (_, S_UNPACK) _ (ty :: nil) => let! ty := micheline2michelson_type ty in return_opcode (UNPACK ty) | PRIM (_, S_HASH_KEY) _ nil => return_opcode HASH_KEY | PRIM (_, S_BLAKE2B) _ nil => return_opcode BLAKE2B | PRIM (_, S_SHA256) _ nil => return_opcode SHA256 | PRIM (_, S_SHA512) _ nil => return_opcode SHA512 | PRIM (_, S_CHECK_SIGNATURE) _ nil => return_opcode CHECK_SIGNATURE | PRIM (_, S_MEM) _ nil => return_opcode MEM | PRIM (_, S_UPDATE) _ nil => return_opcode UPDATE | PRIM (_, S_CHAIN_ID) _ nil => return_opcode CHAIN_ID | PRIM (_, S_LOOP) _ (i :: nil) => let! i := micheline2michelson_instruction i in return_instruction (LOOP i) | PRIM (_, S_LOOP_LEFT) _ (i :: nil) => let! i := micheline2michelson_instruction i in return_instruction (LOOP_LEFT i) | PRIM (_, S_DIP) _ (i :: nil) => let! i := micheline2michelson_instruction i in return_instruction (DIP 1 i) | PRIM (_, S_DIP) _ (Mk_loc_micheline (_, NUMBER n) :: i :: nil) => let! i := micheline2michelson_instruction i in return_instruction (DIP (BinInt.Z.to_nat n) i) | PRIM (_, S_DIG) _ (Mk_loc_micheline (_, NUMBER n) :: nil) => return_opcode (DIG (BinInt.Z.to_nat n)) | PRIM (_, S_DUG) _ (Mk_loc_micheline (_, NUMBER n) :: nil) => return_opcode (DUG (BinInt.Z.to_nat n)) | PRIM (_, S_ITER) _ (i :: nil) => let! i := micheline2michelson_instruction i in return_instruction (ITER i) | PRIM (_, S_MAP) _ (i :: nil) => let! i := micheline2michelson_instruction i in return_instruction (MAP i) | PRIM (_, S_CREATE_CONTRACT) _ (Mk_loc_micheline (_, SEQ ((Mk_loc_micheline (_, PRIM (_, S_storage) _ (storage_ty :: nil))) :: (Mk_loc_micheline (_, PRIM (_, S_parameter) _ (params_ty :: nil)) as param) :: (Mk_loc_micheline (_, PRIM (_, S_code) _ (i :: nil))) :: nil)) :: nil) => let! an := extract_one_field_annot param in let! i := micheline2michelson_instruction i in let! sty := micheline2michelson_type storage_ty in let! pty := micheline2michelson_type params_ty in return_instruction (CREATE_CONTRACT sty pty an i) | PRIM (_, S_CREATE_CONTRACT) _ (Mk_loc_micheline (_, SEQ ((Mk_loc_micheline (_, PRIM (_, S_parameter) _ (params_ty :: nil)) as param) :: (Mk_loc_micheline (_, PRIM (_, S_storage) _ (storage_ty :: nil))) :: (Mk_loc_micheline (_, PRIM (_, S_code) _ (i :: nil))) :: nil)) :: nil) => let! an := extract_one_field_annot param in let! i := micheline2michelson_instruction i in let! sty := micheline2michelson_type storage_ty in let! pty := micheline2michelson_type params_ty in return_instruction (CREATE_CONTRACT sty pty an i) | PRIM (_, S_EMPTY_SET) _ (cty :: nil) => let! cty := micheline2michelson_ctype cty in return_opcode (EMPTY_SET cty) | PRIM (_, S_EMPTY_MAP) _ (kty :: vty :: nil) => let! kty := micheline2michelson_ctype kty in let! vty := micheline2michelson_type vty in return_opcode (EMPTY_MAP kty vty) | PRIM (_, S_EMPTY_BIG_MAP) _ (kty :: vty :: nil) => let! kty := micheline2michelson_ctype kty in let! vty := micheline2michelson_type vty in return_opcode (EMPTY_BIG_MAP kty vty) | PRIM (_, S_IF) _ (i1 :: i2 :: nil) => let! i1 := micheline2michelson_instruction i1 in let! i2 := micheline2michelson_instruction i2 in return_instruction (IF_ IF_bool i1 i2) | PRIM (_, S_IF_NONE) _ (i1 :: i2 :: nil) => let! i1 := micheline2michelson_instruction i1 in let! i2 := micheline2michelson_instruction i2 in return_instruction (IF_NONE i1 i2) | PRIM (_, S_IF_LEFT) _ (i1 :: i2 :: nil) => let! i1 := micheline2michelson_instruction i1 in let! i2 := micheline2michelson_instruction i2 in return_instruction (IF_LEFT i1 i2) | PRIM (_, S_IF_CONS) _ (i1 :: i2 :: nil) => let! i1 := micheline2michelson_instruction i1 in let! i2 := micheline2michelson_instruction i2 in return_instruction (IF_CONS i1 i2) | PRIM (_, S_LAMBDA) _ (a :: b :: i :: nil) => let! a := micheline2michelson_type a in let! b := micheline2michelson_type b in let! i := micheline2michelson_instruction i in return_instruction (LAMBDA a b i) | PRIM (_, S_PUSH) _ (a :: v :: nil) => let! a := micheline2michelson_type a in let! v := match a with | lambda _ _ => let! i := micheline2michelson_instruction v in Return (Instruction i) | _ => micheline2michelson_data v end in return_instruction (PUSH a v) | PRIM (_, S_RENAME) _ _ => Return NOOP | PRIM (_, S_CAST) _ _ => Return NOOP (* Macros *) | PRIM (_, S_FAIL) _ nil => return_instruction FAIL | PRIM (_, S_ASSERT) _ nil => return_instruction ASSERT | PRIM (_, S_ASSERT_NONE) _ nil => return_instruction ASSERT_NONE | PRIM (_, S_ASSERT_SOME) _ nil => return_instruction ASSERT_SOME | PRIM (_, S_ASSERT_LEFT) _ nil => return_instruction ASSERT_LEFT | PRIM (_, S_ASSERT_RIGHT) _ nil => return_instruction ASSERT_RIGHT | PRIM (_, S_IF_SOME) _ (i1 :: i2 :: nil) => let! i1 := micheline2michelson_instruction i1 in let! i2 := micheline2michelson_instruction i2 in return_instruction (IF_SOME i1 i2) | PRIM (_, S_IF_RIGHT) _ (i1 :: i2 :: nil) => let! i1 := micheline2michelson_instruction i1 in let! i2 := micheline2michelson_instruction i2 in return_instruction (IF_RIGHT i1 i2) | PRIM (_, S_IF_NIL) _ (i1 :: i2 :: nil) => let! i1 := micheline2michelson_instruction i1 in let! i2 := micheline2michelson_instruction i2 in return_instruction (IF_NIL i1 i2) | PRIM (_, S_ (String "C" (String "M" (String "P" s)))) _ nil => let s := make_string_literal s in let! op := op_of_string s b e in return_macro {COMPARE; op} | PRIM (_, S_ (String "I" (String "F" (String "C" (String "M" (String "P" s)))))) _ (i1 :: i2 :: nil) => let! i1 := micheline2michelson_instruction i1 in let! i2 := micheline2michelson_instruction i2 in let s := make_string_literal s in let! op := op_of_string s b e in return_macro {COMPARE; op; IF_ IF_bool i1 i2} | PRIM (_, S_ (String "I" (String "F" s))) _ (i1 :: i2 :: nil) => let! i1 := micheline2michelson_instruction i1 in let! i2 := micheline2michelson_instruction i2 in let s := make_string_literal s in let! op := op_of_string s b e in return_macro {op; IF_ IF_bool i1 i2} | PRIM (_, S_ (String "A" (String "S" (String "S" (String "E" (String "R" (String "T" (String "_" (String "C" (String "M" (String "P" s))))))))))) _ nil => let s := make_string_literal s in let! op := op_of_string s b e in return_macro {COMPARE; op; IF_ IF_bool {} {FAIL}} | PRIM (_, S_ (String "A" (String "S" (String "S" (String "E" (String "R" (String "T" (String "_" s)))))))) _ nil => let s := make_string_literal s in let! op := op_of_string s b e in return_macro {op; IF_ IF_bool {} {FAIL}} | PRIM (_, S_ "CR") _ nil => Failed _ (Expansion_prim b e "CR") | PRIM (_, S_ "SET_CR") _ nil => Failed _ (Expansion_prim b e "SET_CR") | PRIM (_, S_ "MAP_CR") _ nil => Failed _ (Expansion_prim b e "MAP_CR") (* CADAAR *) | PRIM (_, S_ (String "C" s)) _ nil => let prim := String "C" s in let get_cadr := fix get_cadr s := match s with | "R" => Return Cadr_nil | String "A" s => let! x := get_cadr s in Return (Cadr_CAR x) | String "D" s => let! x := get_cadr s in Return (Cadr_CDR x) | _ => Failed _ (Expansion_prim b e prim) end in let! x := get_cadr s in return_macro (micheline2michelson_cadr x) | PRIM (_, S_ (String "S" (String "E"(String "T"(String "_"(String "C" s)))))) _ nil => let prim := String "S" (String "E"(String "T"(String "_"(String "C" s)))) in let get_cadr := fix get_cadr s := match s with | "R" => Return Cadr_nil | String "A" s => let! x := get_cadr s in Return (Cadr_CAR x) | String "D" s => let! x := get_cadr s in Return (Cadr_CDR x) | _ => Failed _ (Expansion_prim b e prim) end in let! x := get_cadr s in return_macro (micheline2michelson_set_cadr x) | PRIM (_, S_ (String "M" (String "A"(String "P"(String "_"(String "C" s)))))) _ (a :: nil) => let prim := String "M" (String "A"(String "P"(String "_"(String "C" s)))) in let get_cadr := fix get_cadr s := match s with | "R" => Return Cadr_nil | String "A" s => let! x := get_cadr s in Return (Cadr_CAR x) | String "D" s => let! x := get_cadr s in Return (Cadr_CDR x) | _ => Failed _ (Expansion_prim b e prim) end in let! x := get_cadr s in let! code := micheline2michelson_instruction a in return_macro (micheline2michelson_map_cadr x code) | PRIM (_, S_ (String "D" (String "I" s))) _ (a :: nil) => let is_diip := fix is_diip s := match s with | "P" => true | String "I" s => is_diip s | _ => false end in if is_diip s then let! a := micheline2michelson_instruction a in return_instruction (DIP (String.length s) a) else Failed _ (Expansion_prim b e (String "D" (String "I" s))) | PRIM (_, S_DUP) _ (Mk_loc_micheline (_, NUMBER n) :: nil) => match BinInt.Z.to_nat n with | S n => return_macro (DUP_Sn n) | O => Failed _ (Expansion b e) end | PRIM (_, S_ (String "D" (String "U" (String "U" s)))) _ nil => let is_duup := fix is_duup s := match s with | "P" => true | String "U" s => is_duup s | _ => false end in if is_duup s then return_macro (DUP_Sn (String.length s)) else Failed _ (Expansion_prim b e (String "D" (String "U" (String "U" s)))) (* PAPAIR *) | PRIM (_, S_ (String "P" s)) _ nil => let prim := String "P" s in let fail := Expansion_prim b e prim in let! full := parse_papair_full s fail in return_macro full (* UNPAPAIR *) | PRIM (_, S_ (String "U" (String "N" (String "P" s)))) _ nil => let prim := String "U" (String "N" (String "P" s)) in let fail := Expansion_prim b e prim in let! full := parse_unpapair_full s fail in return_instruction full (* Unknown case *) | PRIM (_, S_ s) _ _ => Failed _ (Expansion_prim b e s) | _ => Failed _ (Expansion b e) end. Record untyped_michelson_file := Mk_untyped_michelson_file { root_annotation : annot_o; parameter : type; storage : type; code : instruction_seq }. Record untyped_michelson_file_opt := Mk_untyped_michelson_file_opt { root_annot : annot_o; parameter_opt : Datatypes.option type; storage_opt : Datatypes.option type; code_opt : Datatypes.option instruction_seq }. Definition read_parameter (ty : type) (root_annot : annot_o) (f : untyped_michelson_file_opt) := match f.(parameter_opt) with | None => Return {| root_annot := root_annot; parameter_opt := Some ty; storage_opt := f.(storage_opt); code_opt := f.(code_opt) |} | Some _ => Failed _ Parsing end. Definition read_storage (ty : type) (f : untyped_michelson_file_opt) := match f.(storage_opt) with | None => Return {| root_annot := f.(root_annot); parameter_opt := f.(parameter_opt); storage_opt := Some ty; code_opt := f.(code_opt) |} | Some _ => Failed _ Parsing end. Definition read_code (c : instruction_seq) (f : untyped_michelson_file_opt) := match f.(code_opt) with | None => Return {| root_annot := f.(root_annot); parameter_opt := f.(parameter_opt); storage_opt := f.(storage_opt); code_opt := Some c |} | Some _ => Failed _ Parsing end. Definition micheline2michelson_file (m : Datatypes.list loc_micheline) : M untyped_michelson_file := let l := match m with | Mk_loc_micheline (_, SEQ l) :: nil => l | l => l end in let! a := error.list_fold_left (fun (a : untyped_michelson_file_opt) (lm : loc_micheline) => let lm := to_pmicheline lm in let 'Mk_loc_micheline (_, _, m) := lm in match m with | PRIM (_, _, S_parameter) _ (cons param nil) => let! an := extract_one_field_annot lm in let! ty := micheline2michelson_type param in read_parameter ty an a | PRIM (_, _, S_storage) _ (cons storage nil) => let! ty := micheline2michelson_type storage in read_storage ty a | PRIM (_, _, S_code) _ (cons code nil) => let! c := micheline2michelson_instruction code in read_code c a | _ => Failed _ Parsing end) l {| root_annot := None; parameter_opt := None; storage_opt := None; code_opt := None |} in match a.(parameter_opt), a.(storage_opt), a.(code_opt) with | Some param, Some storage, Some code => Return {| root_annotation := a.(root_annot); parameter := param; storage := storage; code := code |} | _, _, _ => Failed _ Parsing end.