ligo/src/passes/operators/operators.ml

706 lines
23 KiB
OCaml
Raw Normal View History

2019-05-13 00:56:22 +04:00
open Trace
(*
This file is used throughout the pipeline. Its idea is to add a unique place
that you have to modify when you add a new operator/constant to the language.
This file mirrors the LIGO pipeline, starting with Simplify, then Typer and
ending with Compiler. Usually, when adding a new operator, you'll have to add
a new constructor at all those places.
*)
2019-05-13 00:56:22 +04:00
module Simplify = struct
(*
Each front-end has its owns constants.
Constants are special names that have their own case in the AST. E_constant
for regular constants, and T_constant for type constants. Both types are
defined in `Ast_simplified/types.ml`.
For instance, "2 + 2" in Pascaligo is translated to `E_constant ("ADD" , [
E_literal (Literal_int 2) ;
E_literal (Literal_int 2) ;
])`.
They are used to represent what can't expressed in the languages:
- Primitives. Like "int", "string", "unit" for types. Or "+" for values.
- Tezos specific stuff. Like "operation" for types. Or "source" for values.
- What can't be represented in the language yet. Like "list" or "List.fold".
Each constant is expressed as a pair:
- The left-hand-side is the reserved name in the given front-end.
- The right-hand-side is the name that will be used in the AST.
*)
2019-05-13 00:56:22 +04:00
let type_constants = [
2019-05-23 16:16:12 +04:00
("unit" , "unit") ;
("string" , "string") ;
("bytes" , "bytes") ;
("nat" , "nat") ;
("int" , "int") ;
("tez" , "tez") ;
("bool" , "bool") ;
("operation" , "operation") ;
("address" , "address") ;
2019-06-10 05:41:02 +04:00
("key" , "key") ;
("key_hash" , "key_hash") ;
("signature" , "signature") ;
2019-06-07 00:49:36 +04:00
("timestamp" , "timestamp") ;
2019-05-23 16:16:12 +04:00
("contract" , "contract") ;
("list" , "list") ;
("option" , "option") ;
("set" , "set") ;
("map" , "map") ;
("big_map" , "big_map") ;
2019-05-13 00:56:22 +04:00
]
2019-05-23 16:16:12 +04:00
module Pascaligo = struct
let constants = [
("get_force" , "MAP_GET_FORCE") ;
("transaction" , "CALL") ;
("get_contract" , "CONTRACT") ;
("size" , "SIZE") ;
("int" , "INT") ;
("abs" , "ABS") ;
("amount" , "AMOUNT") ;
2019-06-07 00:49:36 +04:00
("now" , "NOW") ;
2019-05-23 16:16:12 +04:00
("unit" , "UNIT") ;
("source" , "SOURCE") ;
2019-06-07 00:49:36 +04:00
("sender" , "SENDER") ;
2019-06-05 21:19:44 +04:00
("failwith" , "FAILWITH") ;
("bitwise_or" , "OR") ;
("bitwise_and" , "AND") ;
("bitwise_xor" , "XOR") ;
("string_concat" , "CONCAT") ;
("string_slice" , "SLICE") ;
2019-09-07 20:42:59 +04:00
("bytes_concat" , "CONCAT") ;
("bytes_slice" , "SLICE") ;
2019-07-19 16:35:47 +04:00
("set_empty" , "SET_EMPTY") ;
("set_mem" , "SET_MEM") ;
("set_add" , "SET_ADD") ;
("set_remove" , "SET_REMOVE") ;
("set_iter" , "SET_ITER") ;
2019-07-20 15:46:42 +04:00
("list_iter" , "LIST_ITER") ;
2019-09-24 01:33:25 +04:00
("list_fold" , "LIST_FOLD") ;
("list_map" , "LIST_MAP") ;
("map_iter" , "MAP_ITER") ;
("map_map" , "MAP_MAP") ;
2019-09-24 01:46:47 +04:00
("map_fold" , "MAP_FOLD") ;
2019-09-07 20:42:59 +04:00
("sha_256" , "SHA256") ;
("sha_512" , "SHA512") ;
("blake2b" , "BLAKE2b") ;
2019-09-08 14:34:29 +04:00
("cons" , "CONS") ;
2019-05-23 16:16:12 +04:00
]
let type_constants = type_constants
end
2019-05-13 00:56:22 +04:00
module Camligo = struct
let constants = [
2019-05-23 16:16:12 +04:00
("Bytes.pack" , "PACK") ;
("Crypto.hash" , "HASH") ;
("Operation.transaction" , "CALL") ;
2019-06-10 05:41:02 +04:00
("Operation.get_contract" , "CONTRACT") ;
2019-05-23 16:16:12 +04:00
("sender" , "SENDER") ;
("unit" , "UNIT") ;
("source" , "SOURCE") ;
2019-05-13 00:56:22 +04:00
]
2019-05-23 16:16:12 +04:00
let type_constants = type_constants
end
module Ligodity = struct
let constants = [
2019-06-11 02:06:00 +04:00
("assert" , "ASSERT") ;
2019-07-19 14:13:09 +04:00
("Current.balance", "BALANCE") ;
("balance", "BALANCE") ;
("Current.time", "NOW") ;
("time", "NOW") ;
("Current.amount" , "AMOUNT") ;
("amount", "AMOUNT") ;
("Current.gas", "STEPS_TO_QUOTA") ;
("gas", "STEPS_TO_QUOTA") ;
("Current.sender" , "SENDER") ;
("sender", "SENDER") ;
2019-06-11 02:06:00 +04:00
("Current.source" , "SOURCE") ;
("source", "SOURCE") ;
("Current.failwith", "FAILWITH") ;
("failwith" , "FAILWITH") ;
("Crypto.hash" , "HASH") ;
("Crypto.black2b", "BLAKE2B") ;
("Crypto.sha256", "SHA256") ;
("Crypto.sha512", "SHA512") ;
("Crypto.hash_key", "HASH_KEY") ;
("Crypto.check", "CHECK_SIGNATURE") ;
("Bytes.pack" , "PACK") ;
("Bytes.unpack", "UNPACK") ;
("Bytes.length", "SIZE") ;
("Bytes.size" , "SIZE") ;
("Bytes.concat", "CONCAT") ;
("Bytes.slice", "SLICE") ;
("Bytes.sub", "SLICE") ;
("Set.mem" , "SET_MEM") ;
("Set.empty" , "SET_EMPTY") ;
("Set.add" , "SET_ADD") ;
("Set.remove" , "SET_REMOVE") ;
("Map.find_opt" , "MAP_FIND_OPT") ;
("Map.find" , "MAP_FIND") ;
("Map.update" , "MAP_UPDATE") ;
("Map.add" , "MAP_ADD") ;
("Map.remove" , "MAP_REMOVE") ;
2019-09-24 01:33:25 +04:00
("Map.iter" , "MAP_ITER") ;
("Map.map" , "MAP_MAP") ;
2019-09-24 01:46:47 +04:00
("Map.fold" , "LIST_FOLD") ;
2019-07-19 14:13:09 +04:00
("String.length", "SIZE") ;
("String.size", "SIZE") ;
("String.slice", "SLICE") ;
("String.sub", "SLICE") ;
("String.concat", "CONCAT") ;
("List.length", "SIZE") ;
("List.size", "SIZE") ;
2019-09-24 01:33:25 +04:00
("List.iter", "LIST_ITER") ;
("List.map" , "LIST_MAP") ;
("List.fold" , "LIST_FOLD") ;
("Operation.transaction" , "CALL") ;
2019-06-10 05:41:02 +04:00
("Operation.get_contract" , "CONTRACT") ;
("int" , "INT") ;
("abs" , "ABS") ;
("unit" , "UNIT") ;
("source" , "SOURCE") ;
]
let type_constants = type_constants
2019-05-13 00:56:22 +04:00
end
end
module Typer = struct
(*
Each constant has its own type.
LIGO's type-system is currently too
weak to express the constant's type. For instance:
- "ADD" has a special kind of type of polymorphism. If "ADD" gets two `int`s,
it will return an `int`. If it gets two `nat`s, it will return a `nat`.
Regular polymorphism wouldn't work because "ADD" only accepts `int`s or
`nat`s.
- "NONE" (from Some/None) requires an annotation.
Instead of a LIGO type, constant types are representend as functions. These
functions take as parameters:
- The list of types of the arguments of the constants. When typing `2 + 2`,
the types might be `[ int ; int ]`.
- The expected type of the whole expression. It is optional. When typing
`[] : list(operation)`, it will be `Some ( list (operation) )`. When
typing `2 + 2` (with no additional context), it will be `None`.
The output is the type of the whole expression. An error is returned through
the Trace monad if it doesn't type-check (`"toto" + 42`).
Various helpers are defined and explaines in `Helpers.Typer`.
*)
open Helpers.Typer
2019-05-23 16:16:12 +04:00
open Ast_typed
let none = typer_0 "NONE" @@ fun tv_opt ->
match tv_opt with
| None -> simple_fail "untyped NONE"
| Some t -> ok t
2019-07-19 16:35:47 +04:00
let set_empty = typer_0 "SET_EMPTY" @@ fun tv_opt ->
match tv_opt with
| None -> simple_fail "untyped SET_EMPTY"
| Some t -> ok t
2019-05-23 16:16:12 +04:00
let sub = typer_2 "SUB" @@ fun a b ->
2019-06-07 00:49:36 +04:00
if (eq_2 (a , b) (t_int ()))
then ok @@ t_int () else
if (eq_2 (a , b) (t_nat ()))
then ok @@ t_int () else
if (eq_2 (a , b) (t_timestamp ()))
then ok @@ t_int () else
2019-07-19 14:13:09 +04:00
if (eq_1 a (t_timestamp ()) && eq_1 b (t_int ()))
then ok @@ t_timestamp () else
2019-06-07 00:49:36 +04:00
if (eq_2 (a , b) (t_tez ()))
then ok @@ t_tez () else
fail (simple_error "Typing substraction, bad parameters.")
2019-05-23 16:16:12 +04:00
let some = typer_1 "SOME" @@ fun a -> ok @@ t_option a ()
2019-09-08 14:34:29 +04:00
let list_cons : typer = typer_2 "CONS" @@ fun hd tl ->
let%bind tl' = get_t_list tl in
let%bind () = assert_type_value_eq (hd , tl') in
ok tl
2019-05-23 16:16:12 +04:00
let map_remove : typer = typer_2 "MAP_REMOVE" @@ fun k m ->
2019-09-11 18:02:06 +04:00
let%bind (src , _) = bind_map_or (get_t_map , get_t_big_map) m in
2019-05-23 16:16:12 +04:00
let%bind () = assert_type_value_eq (src , k) in
ok m
2019-06-07 17:16:24 +04:00
let map_add : typer = typer_3 "MAP_ADD" @@ fun k v m ->
2019-09-11 18:02:06 +04:00
let%bind (src, dst) = bind_map_or (get_t_map , get_t_big_map) m in
2019-05-23 16:16:12 +04:00
let%bind () = assert_type_value_eq (src, k) in
let%bind () = assert_type_value_eq (dst, v) in
ok m
2019-06-11 02:06:00 +04:00
let map_update : typer = typer_3 "MAP_UPDATE" @@ fun k v m ->
2019-09-11 18:02:06 +04:00
let%bind (src, dst) = bind_map_or (get_t_map , get_t_big_map) m in
2019-06-07 17:16:24 +04:00
let%bind () = assert_type_value_eq (src, k) in
let%bind v' = get_t_option v in
let%bind () = assert_type_value_eq (dst, v') in
ok m
2019-07-19 14:13:09 +04:00
let map_mem : typer = typer_2 "MAP_MEM" @@ fun k m ->
2019-09-11 18:02:06 +04:00
let%bind (src, _dst) = bind_map_or (get_t_map , get_t_big_map) m in
2019-06-07 17:16:24 +04:00
let%bind () = assert_type_value_eq (src, k) in
ok @@ t_bool ()
2019-06-11 02:06:00 +04:00
let map_find : typer = typer_2 "MAP_FIND" @@ fun k m ->
2019-09-11 18:02:06 +04:00
let%bind (src, dst) = bind_map_or (get_t_map , get_t_big_map) m in
2019-06-11 02:06:00 +04:00
let%bind () = assert_type_value_eq (src, k) in
ok @@ dst
let map_find_opt : typer = typer_2 "MAP_FIND_OPT" @@ fun k m ->
2019-09-11 18:02:06 +04:00
let%bind (src, dst) = bind_map_or (get_t_map , get_t_big_map) m in
2019-06-07 17:16:24 +04:00
let%bind () = assert_type_value_eq (src, k) in
ok @@ t_option dst ()
2019-07-20 18:42:34 +04:00
let map_iter : typer = typer_2 "MAP_ITER" @@ fun m f ->
2019-09-11 18:02:06 +04:00
let%bind (k, v) = get_t_map m in
2019-07-20 18:42:34 +04:00
let%bind (arg , res) = get_t_function f in
let%bind () = assert_eq_1 arg (t_pair k v ()) in
let%bind () = assert_eq_1 res (t_unit ()) in
2019-07-19 14:13:09 +04:00
ok @@ t_unit ()
2019-06-07 17:16:24 +04:00
2019-07-20 18:42:34 +04:00
let map_map : typer = typer_2 "MAP_MAP" @@ fun m f ->
2019-09-11 18:02:06 +04:00
let%bind (k, v) = get_t_map m in
2019-07-20 18:42:34 +04:00
let%bind (arg , res) = get_t_function f in
let%bind () = assert_eq_1 arg (t_pair k v ()) in
ok @@ t_map k res ()
2019-07-19 14:13:09 +04:00
2019-05-23 16:16:12 +04:00
let size = typer_1 "SIZE" @@ fun t ->
let%bind () =
Assert.assert_true @@
2019-09-11 18:02:06 +04:00
(is_t_map t || is_t_list t || is_t_string t || is_t_bytes t || is_t_set t ) in
2019-05-23 16:16:12 +04:00
ok @@ t_nat ()
2019-06-10 05:41:02 +04:00
let slice = typer_3 "SLICE" @@ fun i j s ->
2019-07-19 14:13:09 +04:00
let%bind () = assert_eq_1 i (t_nat ()) in
let%bind () = assert_eq_1 j (t_nat ()) in
if eq_1 s (t_string ())
then ok @@ t_string ()
else if eq_1 s (t_bytes ())
then ok @@ t_bytes ()
else simple_fail "bad slice"
2019-06-05 21:19:44 +04:00
let failwith_ = typer_1 "FAILWITH" @@ fun t ->
let%bind () =
Assert.assert_true @@
(is_t_string t) in
ok @@ t_unit ()
2019-05-23 16:16:12 +04:00
let get_force = typer_2 "MAP_GET_FORCE" @@ fun i m ->
2019-09-11 18:02:06 +04:00
let%bind (src, dst) = bind_map_or (get_t_map , get_t_big_map) m in
2019-05-23 16:16:12 +04:00
let%bind _ = assert_type_value_eq (src, i) in
ok dst
let int : typer = typer_1 "INT" @@ fun t ->
let%bind () = assert_t_nat t in
ok @@ t_int ()
let bytes_pack : typer = typer_1 "PACK" @@ fun _t ->
ok @@ t_bytes ()
let bytes_unpack = typer_1_opt "UNPACK" @@ fun input output_opt ->
let%bind () = assert_t_bytes input in
trace_option (simple_error "untyped UNPACK") @@
output_opt
2019-06-10 05:41:02 +04:00
let hash256 = typer_1 "SHA256" @@ fun t ->
let%bind () = assert_t_bytes t in
ok @@ t_bytes ()
let hash512 = typer_1 "SHA512" @@ fun t ->
2019-05-23 16:16:12 +04:00
let%bind () = assert_t_bytes t in
ok @@ t_bytes ()
2019-06-10 05:41:02 +04:00
let blake2b = typer_1 "BLAKE2b" @@ fun t ->
let%bind () = assert_t_bytes t in
ok @@ t_bytes ()
let hash_key = typer_1 "HASH_KEY" @@ fun t ->
let%bind () = assert_t_key t in
ok @@ t_key_hash ()
let check_signature = typer_3 "CHECK_SIGNATURE" @@ fun k s b ->
let%bind () = assert_t_key k in
let%bind () = assert_t_signature s in
let%bind () = assert_t_bytes b in
ok @@ t_bool ()
2019-07-19 14:13:09 +04:00
2019-05-23 16:16:12 +04:00
let sender = constant "SENDER" @@ t_address ()
let source = constant "SOURCE" @@ t_address ()
let unit = constant "UNIT" @@ t_unit ()
let amount = constant "AMOUNT" @@ t_tez ()
2019-07-19 14:13:09 +04:00
let balance = constant "BALANCE" @@ t_tez ()
2019-06-10 05:41:02 +04:00
let address = constant "ADDRESS" @@ t_address ()
2019-06-07 00:49:36 +04:00
let now = constant "NOW" @@ t_timestamp ()
2019-05-23 16:16:12 +04:00
let transaction = typer_3 "CALL" @@ fun param amount contract ->
let%bind () = assert_t_tez amount in
let%bind contract_param = get_t_contract contract in
let%bind () = assert_type_value_eq (param , contract_param) in
ok @@ t_operation ()
2019-07-19 14:13:09 +04:00
let originate = typer_6 "ORIGINATE" @@ fun manager delegate_opt spendable delegatable init_balance code ->
let%bind () = assert_eq_1 manager (t_key_hash ()) in
let%bind () = assert_eq_1 delegate_opt (t_option (t_key_hash ()) ()) in
let%bind () = assert_eq_1 spendable (t_bool ()) in
let%bind () = assert_eq_1 delegatable (t_bool ()) in
let%bind () = assert_t_tez init_balance in
let%bind (arg , res) = get_t_function code in
let%bind (_param , storage) = get_t_pair arg in
let%bind (storage' , op_lst) = get_t_pair res in
let%bind () = assert_eq_1 storage storage' in
let%bind () = assert_eq_1 op_lst (t_list (t_operation ()) ()) in
ok @@ (t_pair (t_operation ()) (t_address ()) ())
2019-05-23 16:16:12 +04:00
let get_contract = typer_1_opt "CONTRACT" @@ fun _ tv_opt ->
let%bind tv =
trace_option (simple_error "get_contract needs a type annotation") tv_opt in
let%bind tv' =
trace_strong (simple_error "get_contract has a not-contract annotation") @@
get_t_contract tv in
ok @@ t_contract tv' ()
2019-07-19 14:13:09 +04:00
let set_delegate = typer_1 "SET_DELEGATE" @@ fun delegate_opt ->
let%bind () = assert_eq_1 delegate_opt (t_option (t_key_hash ()) ()) in
ok @@ t_operation ()
2019-05-23 16:16:12 +04:00
let abs = typer_1 "ABS" @@ fun t ->
let%bind () = assert_t_int t in
ok @@ t_nat ()
2019-07-19 14:13:09 +04:00
let neg = typer_1 "NEG" @@ fun t ->
let%bind () = Assert.assert_true (eq_1 t (t_nat ()) || eq_1 t (t_int ())) in
ok @@ t_int ()
2019-06-11 02:06:00 +04:00
let assertion = typer_1 "ASSERT" @@ fun a ->
if eq_1 a (t_bool ())
then ok @@ t_unit ()
else simple_fail "Asserting a non-bool"
2019-07-19 14:13:09 +04:00
2019-05-23 16:16:12 +04:00
let times = typer_2 "TIMES" @@ fun a b ->
if eq_2 (a , b) (t_nat ())
then ok @@ t_nat () else
if eq_2 (a , b) (t_int ())
then ok @@ t_int () else
if (eq_1 a (t_nat ()) && eq_1 b (t_tez ())) || (eq_1 b (t_nat ()) && eq_1 a (t_tez ()))
then ok @@ t_tez () else
simple_fail "Multiplying with wrong types"
let div = typer_2 "DIV" @@ fun a b ->
if eq_2 (a , b) (t_nat ())
then ok @@ t_nat () else
if eq_2 (a , b) (t_int ())
then ok @@ t_int () else
2019-06-07 00:49:36 +04:00
if eq_1 a (t_tez ()) && eq_1 b (t_nat ())
then ok @@ t_tez () else
2019-05-23 16:16:12 +04:00
simple_fail "Dividing with wrong types"
let mod_ = typer_2 "MOD" @@ fun a b ->
if (eq_1 a (t_nat ()) || eq_1 a (t_int ())) && (eq_1 b (t_nat ()) || eq_1 b (t_int ()))
then ok @@ t_nat () else
simple_fail "Computing modulo with wrong types"
let add = typer_2 "ADD" @@ fun a b ->
if eq_2 (a , b) (t_nat ())
then ok @@ t_nat () else
if eq_2 (a , b) (t_int ())
then ok @@ t_int () else
2019-06-07 00:49:36 +04:00
if eq_2 (a , b) (t_tez ())
then ok @@ t_tez () else
2019-05-23 16:16:12 +04:00
if (eq_1 a (t_nat ()) && eq_1 b (t_int ())) || (eq_1 b (t_nat ()) && eq_1 a (t_int ()))
then ok @@ t_int () else
2019-07-19 14:13:09 +04:00
if (eq_1 a (t_timestamp ()) && eq_1 b (t_int ())) || (eq_1 b (t_timestamp ()) && eq_1 a (t_int ()))
then ok @@ t_timestamp () else
2019-06-07 00:49:36 +04:00
simple_fail "Adding with wrong types. Expected nat, int or tez."
2019-05-13 00:56:22 +04:00
2019-06-11 02:06:00 +04:00
let set_mem = typer_2 "SET_MEM" @@ fun elt set ->
let%bind key = get_t_set set in
if eq_1 elt key
then ok @@ t_bool ()
else simple_fail "Set_mem: elt and set don't match"
let set_add = typer_2 "SET_ADD" @@ fun elt set ->
let%bind key = get_t_set set in
if eq_1 elt key
then ok set
else simple_fail "Set_add: elt and set don't match"
let set_remove = typer_2 "SET_REMOVE" @@ fun elt set ->
let%bind key = get_t_set set in
if eq_1 elt key
then ok set
else simple_fail "Set_remove: elt and set don't match"
2019-07-19 14:13:09 +04:00
let set_iter = typer_2 "SET_ITER" @@ fun set body ->
let%bind (arg , res) = get_t_function body in
let%bind () = Assert.assert_true (eq_1 res (t_unit ())) in
let%bind key = get_t_set set in
if eq_1 key arg
then ok (t_unit ())
else simple_fail "bad set iter"
let list_iter = typer_2 "LIST_ITER" @@ fun lst body ->
let%bind (arg , res) = get_t_function body in
let%bind () = Assert.assert_true (eq_1 res (t_unit ())) in
let%bind key = get_t_list lst in
if eq_1 key arg
then ok (t_unit ())
else simple_fail "bad list iter"
let list_map = typer_2 "LIST_MAP" @@ fun lst body ->
let%bind (arg , res) = get_t_function body in
let%bind key = get_t_list lst in
if eq_1 key arg
then ok (t_list res ())
2019-09-24 01:33:25 +04:00
else simple_fail "bad list map"
let list_fold = typer_3 "LIST_FOLD" @@ fun lst init body ->
let%bind (arg , res) = get_t_function body in
let%bind (prec , cur) = get_t_pair arg in
let%bind key = get_t_list lst in
let msg = Format.asprintf "%a vs %a"
Ast_typed.PP.type_value key
Ast_typed.PP.type_value arg
in
trace (simple_error ("bad list fold:" ^ msg)) @@
let%bind () = assert_eq_1 ~msg:"key cur" key cur in
let%bind () = assert_eq_1 ~msg:"prec res" prec res in
let%bind () = assert_eq_1 ~msg:"res init" res init in
ok res
2019-07-19 14:13:09 +04:00
2019-09-24 01:46:47 +04:00
let map_fold = typer_3 "MAP_FOLD" @@ fun map init body ->
let%bind (arg , res) = get_t_function body in
let%bind (prec , cur) = get_t_pair arg in
let%bind (key , value) = get_t_map map in
let msg = Format.asprintf "%a vs %a"
Ast_typed.PP.type_value key
Ast_typed.PP.type_value arg
in
trace (simple_error ("bad list fold:" ^ msg)) @@
let%bind () = assert_eq_1 ~msg:"key cur" (t_pair key value ()) cur in
let%bind () = assert_eq_1 ~msg:"prec res" prec res in
let%bind () = assert_eq_1 ~msg:"res init" res init in
ok res
2019-06-11 02:06:00 +04:00
let not_ = typer_1 "NOT" @@ fun elt ->
if eq_1 elt (t_bool ())
then ok @@ t_bool ()
2019-07-19 14:13:09 +04:00
else if eq_1 elt (t_nat ()) || eq_1 elt (t_int ())
then ok @@ t_int ()
2019-06-11 02:06:00 +04:00
else simple_fail "bad parameter to not"
2019-07-19 14:13:09 +04:00
let or_ = typer_2 "OR" @@ fun a b ->
if eq_2 (a , b) (t_bool ())
then ok @@ t_bool ()
else if eq_2 (a , b) (t_nat ())
then ok @@ t_nat ()
else simple_fail "bad or"
let xor = typer_2 "XOR" @@ fun a b ->
if eq_2 (a , b) (t_bool ())
then ok @@ t_bool ()
else if eq_2 (a , b) (t_nat ())
then ok @@ t_nat ()
else simple_fail "bad xor"
let and_ = typer_2 "AND" @@ fun a b ->
if eq_2 (a , b) (t_bool ())
then ok @@ t_bool ()
else if eq_2 (a , b) (t_nat ()) || (eq_1 b (t_nat ()) && eq_1 a (t_int ()))
then ok @@ t_nat ()
else simple_fail "bad end"
let lsl_ = typer_2 "LSL" @@ fun a b ->
if eq_2 (a , b) (t_nat ())
then ok @@ t_nat ()
else simple_fail "bad lsl"
let lsr_ = typer_2 "LSR" @@ fun a b ->
if eq_2 (a , b) (t_nat ())
then ok @@ t_nat ()
else simple_fail "bad lsr"
let concat = typer_2 "CONCAT" @@ fun a b ->
if eq_2 (a , b) (t_string ())
then ok @@ t_string ()
else if eq_2 (a , b) (t_bytes ())
then ok @@ t_bytes ()
else simple_fail "bad concat"
let cons = typer_2 "CONS" @@ fun hd tl ->
let%bind elt = get_t_list tl in
let%bind () = assert_eq_1 hd elt in
ok tl
let constant_typers = Map.String.of_list [
2019-05-23 16:16:12 +04:00
add ;
2019-05-13 00:56:22 +04:00
times ;
2019-05-23 16:16:12 +04:00
div ;
2019-05-13 00:56:22 +04:00
mod_ ;
sub ;
none ;
some ;
concat ;
slice ;
2019-05-13 00:56:22 +04:00
comparator "EQ" ;
comparator "NEQ" ;
comparator "LT" ;
comparator "GT" ;
comparator "LE" ;
comparator "GE" ;
or_ ;
and_ ;
xor ;
2019-06-11 02:06:00 +04:00
not_ ;
2019-05-13 00:56:22 +04:00
map_remove ;
2019-06-07 17:16:24 +04:00
map_add ;
2019-05-13 00:56:22 +04:00
map_update ;
2019-06-07 17:16:24 +04:00
map_mem ;
map_find ;
map_map ;
map_fold ;
map_iter ;
2019-07-19 16:35:47 +04:00
set_empty ;
2019-06-11 02:06:00 +04:00
set_mem ;
set_add ;
set_remove ;
2019-07-20 15:46:42 +04:00
set_iter ;
list_iter ;
list_map ;
2019-09-24 01:33:25 +04:00
list_fold ;
2019-05-13 00:56:22 +04:00
int ;
size ;
2019-06-05 21:19:44 +04:00
failwith_ ;
2019-05-13 00:56:22 +04:00
get_force ;
bytes_pack ;
bytes_unpack ;
2019-06-10 05:41:02 +04:00
hash256 ;
hash512 ;
blake2b ;
hash_key ;
check_signature ;
2019-05-13 00:56:22 +04:00
sender ;
source ;
unit ;
amount ;
transaction ;
get_contract ;
2019-07-19 14:13:09 +04:00
neg ;
2019-05-13 00:56:22 +04:00
abs ;
2019-06-07 00:49:36 +04:00
now ;
2019-06-10 05:41:02 +04:00
slice ;
address ;
2019-06-11 02:06:00 +04:00
assertion ;
2019-09-08 14:34:29 +04:00
list_cons ;
2019-05-13 00:56:22 +04:00
]
end
module Compiler = struct
(*
Most constants pass through the Transpiler unchanged. So they need to be
compiled down to Michelson. This is the last step.
When compiling the constant, we need to provide its arity (through the type
predicate, defined in `Helpers.Compiler`, and its michelson code.
In the case of an n-ary constant, we assume that the stack has the form:
`x1 :: x2 :: x3 ... :: xn :: _`.
This step requires knowledge of Michelson. Knowledge of
`Tezos_utils.Michelson` will help too, so that no Michelson has to actually
be written by hand.
*)
include Helpers.Compiler
open Tezos_utils.Michelson
2019-05-13 00:56:22 +04:00
2019-09-11 15:56:39 +04:00
let operators = Map.String.of_list [
2019-05-23 16:16:12 +04:00
("ADD" , simple_binary @@ prim I_ADD) ;
("SUB" , simple_binary @@ prim I_SUB) ;
("TIMES" , simple_binary @@ prim I_MUL) ;
("DIV" , simple_binary @@ seq [prim I_EDIV ; i_assert_some_msg (i_push_string "DIV by 0") ; i_car]) ;
2019-05-13 00:56:22 +04:00
("MOD" , simple_binary @@ seq [prim I_EDIV ; i_assert_some_msg (i_push_string "MOD by 0") ; i_cdr]) ;
("NEG" , simple_unary @@ prim I_NEG) ;
("OR" , simple_binary @@ prim I_OR) ;
("AND" , simple_binary @@ prim I_AND) ;
2019-06-10 05:41:02 +04:00
("XOR" , simple_binary @@ prim I_XOR) ;
("NOT" , simple_unary @@ prim I_NOT) ;
2019-05-13 00:56:22 +04:00
("PAIR" , simple_binary @@ prim I_PAIR) ;
("CAR" , simple_unary @@ prim I_CAR) ;
("CDR" , simple_unary @@ prim I_CDR) ;
("EQ" , simple_binary @@ seq [prim I_COMPARE ; prim I_EQ]) ;
("NEQ" , simple_binary @@ seq [prim I_COMPARE ; prim I_NEQ]) ;
("LT" , simple_binary @@ seq [prim I_COMPARE ; prim I_LT]) ;
("LE" , simple_binary @@ seq [prim I_COMPARE ; prim I_LE]) ;
("GT" , simple_binary @@ seq [prim I_COMPARE ; prim I_GT]) ;
("GE" , simple_binary @@ seq [prim I_COMPARE ; prim I_GE]) ;
("UPDATE" , simple_ternary @@ prim I_UPDATE) ;
("SOME" , simple_unary @@ prim I_SOME) ;
2019-05-23 16:16:12 +04:00
("MAP_GET_FORCE" , simple_binary @@ seq [prim I_GET ; i_assert_some_msg (i_push_string "GET_FORCE")]) ;
2019-06-11 04:52:09 +04:00
("MAP_FIND" , simple_binary @@ seq [prim I_GET ; i_assert_some_msg (i_push_string "MAP FIND")]) ;
2019-05-23 16:16:12 +04:00
("MAP_GET" , simple_binary @@ prim I_GET) ;
2019-09-11 18:02:06 +04:00
("MAP_ADD" , simple_ternary @@ seq [dip (i_some) ; prim I_UPDATE]) ;
("MAP_UPDATE" , simple_ternary @@ prim I_UPDATE) ;
2019-05-13 00:56:22 +04:00
("SIZE" , simple_unary @@ prim I_SIZE) ;
("FAILWITH" , simple_unary @@ prim I_FAILWITH) ;
2019-06-11 04:52:09 +04:00
("ASSERT_INFERRED" , simple_binary @@ i_if (seq [i_failwith]) (seq [i_drop ; i_push_unit])) ;
("ASSERT" , simple_unary @@ i_if (seq [i_push_unit ; i_failwith]) (seq [i_push_unit])) ;
2019-05-13 00:56:22 +04:00
("INT" , simple_unary @@ prim I_INT) ;
("ABS" , simple_unary @@ prim I_ABS) ;
("CONS" , simple_binary @@ prim I_CONS) ;
("UNIT" , simple_constant @@ prim I_UNIT) ;
("AMOUNT" , simple_constant @@ prim I_AMOUNT) ;
2019-06-10 05:41:02 +04:00
("ADDRESS" , simple_constant @@ prim I_ADDRESS) ;
2019-06-07 00:49:36 +04:00
("NOW" , simple_constant @@ prim I_NOW) ;
2019-05-23 16:16:12 +04:00
("CALL" , simple_ternary @@ prim I_TRANSFER_TOKENS) ;
2019-05-13 00:56:22 +04:00
("SOURCE" , simple_constant @@ prim I_SOURCE) ;
("SENDER" , simple_constant @@ prim I_SENDER) ;
2019-06-11 04:52:09 +04:00
("SET_MEM" , simple_binary @@ prim I_MEM) ;
("SET_ADD" , simple_binary @@ seq [dip (i_push (prim T_bool) (prim D_True)) ; prim I_UPDATE]) ;
2019-07-19 16:35:47 +04:00
("SET_REMOVE" , simple_binary @@ seq [dip (i_push (prim T_bool) (prim D_False)) ; prim I_UPDATE]) ;
("SLICE" , simple_ternary @@ seq [prim I_SLICE ; i_assert_some_msg (i_push_string "SLICE")]) ;
2019-06-10 05:41:02 +04:00
("SHA256" , simple_unary @@ prim I_SHA256) ;
("SHA512" , simple_unary @@ prim I_SHA512) ;
("BLAKE2B" , simple_unary @@ prim I_BLAKE2B) ;
("CHECK_SIGNATURE" , simple_ternary @@ prim I_CHECK_SIGNATURE) ;
("HASH_KEY" , simple_unary @@ prim I_HASH_KEY) ;
("PACK" , simple_unary @@ prim I_PACK) ;
("CONCAT" , simple_binary @@ prim I_CONCAT) ;
2019-09-08 14:34:29 +04:00
("CONS" , simple_binary @@ prim I_CONS) ;
2019-05-13 00:56:22 +04:00
]
2019-09-11 15:56:39 +04:00
(*
Some complex operators will need to be added in compiler/compiler_program.
All operators whose compilations involve a type are found there.
*)
2019-07-19 14:13:09 +04:00
2019-05-13 00:56:22 +04:00
end