2019-05-13 00:56:22 +04:00
|
|
|
open Trace
|
|
|
|
|
|
|
|
module Simplify = struct
|
|
|
|
|
|
|
|
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") ;
|
|
|
|
("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") ;
|
|
|
|
("unit" , "UNIT") ;
|
|
|
|
("source" , "SOURCE") ;
|
|
|
|
]
|
|
|
|
|
|
|
|
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") ;
|
|
|
|
("Operation.get_contract" , "GET_CONTRACT") ;
|
|
|
|
("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
|
|
|
|
include Pascaligo
|
2019-05-13 00:56:22 +04:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
module Typer = struct
|
2019-05-23 16:16:12 +04:00
|
|
|
|
|
|
|
open Ast_typed
|
|
|
|
|
2019-05-13 00:56:22 +04:00
|
|
|
module Errors = struct
|
2019-05-23 16:16:12 +04:00
|
|
|
let wrong_param_number = fun name expected got ->
|
2019-05-13 00:56:22 +04:00
|
|
|
let title () = "wrong number of params" in
|
2019-05-23 16:16:12 +04:00
|
|
|
let full () = Format.asprintf "constant name: %s\nexpected: %d\ngot: %d\n"
|
|
|
|
name expected (List.length got) in
|
2019-05-13 00:56:22 +04:00
|
|
|
error title full
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
type type_result = string * type_value
|
|
|
|
type typer' = type_value list -> type_value option -> type_result result
|
2019-05-23 16:16:12 +04:00
|
|
|
type typer = string * typer'
|
2019-05-13 00:56:22 +04:00
|
|
|
|
2019-05-23 16:16:12 +04:00
|
|
|
let typer'_0 : name -> (type_value option -> type_value result) -> typer' = fun s f lst tv_opt ->
|
2019-05-13 00:56:22 +04:00
|
|
|
match lst with
|
2019-05-23 16:16:12 +04:00
|
|
|
| [] -> (
|
|
|
|
let%bind tv' = f tv_opt in
|
|
|
|
ok (s , tv')
|
|
|
|
)
|
|
|
|
| _ -> fail @@ Errors.wrong_param_number s 0 lst
|
|
|
|
let typer_0 name f : typer = (name , typer'_0 name f)
|
|
|
|
|
|
|
|
let typer'_1 : name -> (type_value -> type_value result) -> typer' = fun s f lst _ ->
|
2019-05-13 00:56:22 +04:00
|
|
|
match lst with
|
2019-05-23 16:16:12 +04:00
|
|
|
| [ a ] -> (
|
|
|
|
let%bind tv' = f a in
|
|
|
|
ok (s , tv')
|
|
|
|
)
|
|
|
|
| _ -> fail @@ Errors.wrong_param_number s 1 lst
|
|
|
|
let typer_1 name f : typer = (name , typer'_1 name f)
|
2019-05-13 00:56:22 +04:00
|
|
|
|
2019-05-23 16:16:12 +04:00
|
|
|
let typer'_1_opt : name -> (type_value -> type_value option -> type_value result) -> typer' = fun s f lst tv_opt ->
|
2019-05-13 00:56:22 +04:00
|
|
|
match lst with
|
2019-05-23 16:16:12 +04:00
|
|
|
| [ a ] -> (
|
|
|
|
let%bind tv' = f a tv_opt in
|
|
|
|
ok (s , tv')
|
|
|
|
)
|
|
|
|
| _ -> fail @@ Errors.wrong_param_number s 1 lst
|
|
|
|
let typer_1_opt name f : typer = (name , typer'_1_opt name f)
|
2019-05-13 00:56:22 +04:00
|
|
|
|
2019-05-23 16:16:12 +04:00
|
|
|
let typer'_2 : name -> (type_value -> type_value -> type_value result) -> typer' = fun s f lst _ ->
|
2019-05-13 00:56:22 +04:00
|
|
|
match lst with
|
2019-05-23 16:16:12 +04:00
|
|
|
| [ a ; b ] -> (
|
|
|
|
let%bind tv' = f a b in
|
|
|
|
ok (s , tv')
|
|
|
|
)
|
|
|
|
| _ -> fail @@ Errors.wrong_param_number s 2 lst
|
|
|
|
let typer_2 name f : typer = (name , typer'_2 name f)
|
2019-05-13 00:56:22 +04:00
|
|
|
|
2019-05-23 16:16:12 +04:00
|
|
|
let typer'_3 : name -> (type_value -> type_value -> type_value -> type_value result) -> typer' = fun s f lst _ ->
|
2019-05-13 00:56:22 +04:00
|
|
|
match lst with
|
2019-05-23 16:16:12 +04:00
|
|
|
| [ a ; b ; c ] -> (
|
|
|
|
let%bind tv' = f a b c in
|
|
|
|
ok (s , tv')
|
2019-05-13 00:56:22 +04:00
|
|
|
)
|
2019-05-23 16:16:12 +04:00
|
|
|
| _ -> fail @@ Errors.wrong_param_number s 3 lst
|
|
|
|
let typer_3 name f : typer = (name , typer'_3 name f)
|
2019-05-13 00:56:22 +04:00
|
|
|
|
2019-05-23 16:16:12 +04:00
|
|
|
let constant name cst = typer_0 name (fun _ -> ok cst)
|
2019-05-13 00:56:22 +04:00
|
|
|
|
2019-05-23 16:16:12 +04:00
|
|
|
open Combinators
|
2019-05-13 00:56:22 +04:00
|
|
|
|
2019-05-23 16:16:12 +04:00
|
|
|
let eq_1 a cst = type_value_eq (a , cst)
|
|
|
|
let eq_2 (a , b) cst = type_value_eq (a , cst) && type_value_eq (b , cst)
|
|
|
|
|
|
|
|
let comparator : string -> typer = fun s -> typer_2 s @@ fun a b ->
|
|
|
|
let%bind () =
|
|
|
|
trace_strong (simple_error "Types a and b aren't comparable") @@
|
|
|
|
Assert.assert_true @@
|
|
|
|
List.exists (eq_2 (a , b)) [
|
|
|
|
t_int () ;
|
|
|
|
t_nat () ;
|
|
|
|
t_tez () ;
|
|
|
|
t_string () ;
|
|
|
|
t_bytes () ;
|
|
|
|
t_address () ;
|
|
|
|
] in
|
|
|
|
ok @@ t_bool ()
|
|
|
|
|
|
|
|
let boolean_operator_2 : string -> typer = fun s -> typer_2 s @@ fun a b ->
|
|
|
|
let%bind () =
|
|
|
|
trace_strong (simple_error "A isn't of type bool") @@
|
|
|
|
Assert.assert_true @@
|
|
|
|
type_value_eq (t_bool () , a) in
|
|
|
|
let%bind () =
|
|
|
|
trace_strong (simple_error "B isn't of type bool") @@
|
|
|
|
Assert.assert_true @@
|
|
|
|
type_value_eq (t_bool () , b) in
|
|
|
|
ok @@ t_bool ()
|
|
|
|
|
|
|
|
let none = typer_0 "NONE" @@ fun tv_opt ->
|
|
|
|
match tv_opt with
|
|
|
|
| None -> simple_fail "untyped NONE"
|
|
|
|
| Some t -> ok t
|
|
|
|
|
|
|
|
let sub = typer_2 "SUB" @@ fun a b ->
|
|
|
|
let%bind () =
|
|
|
|
trace_strong (simple_error "Types a and b aren't numbers") @@
|
|
|
|
Assert.assert_true @@
|
|
|
|
List.exists (eq_2 (a , b)) [
|
|
|
|
t_int () ;
|
|
|
|
t_nat () ;
|
|
|
|
] in
|
|
|
|
ok @@ t_int ()
|
|
|
|
|
|
|
|
let some = typer_1 "SOME" @@ fun a -> ok @@ t_option a ()
|
|
|
|
|
|
|
|
let map_remove : typer = typer_2 "MAP_REMOVE" @@ fun k m ->
|
|
|
|
let%bind (src , _) = get_t_map m in
|
|
|
|
let%bind () = assert_type_value_eq (src , k) in
|
|
|
|
ok m
|
|
|
|
|
|
|
|
let map_update : typer = typer_3 "MAP_UPDATE" @@ fun k v m ->
|
|
|
|
let%bind (src, dst) = get_t_map m in
|
|
|
|
let%bind () = assert_type_value_eq (src, k) in
|
|
|
|
let%bind () = assert_type_value_eq (dst, v) in
|
|
|
|
ok m
|
|
|
|
|
|
|
|
let size = typer_1 "SIZE" @@ fun t ->
|
|
|
|
let%bind () =
|
|
|
|
Assert.assert_true @@
|
|
|
|
(is_t_map t || is_t_list t) in
|
|
|
|
ok @@ t_nat ()
|
|
|
|
|
|
|
|
let get_force = typer_2 "MAP_GET_FORCE" @@ fun i m ->
|
|
|
|
let%bind (src, dst) = get_t_map m in
|
|
|
|
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
|
|
|
|
|
|
|
|
let crypto_hash = typer_1 "HASH" @@ fun t ->
|
|
|
|
let%bind () = assert_t_bytes t in
|
|
|
|
ok @@ t_bytes ()
|
|
|
|
|
|
|
|
let sender = constant "SENDER" @@ t_address ()
|
|
|
|
|
|
|
|
let source = constant "SOURCE" @@ t_address ()
|
|
|
|
|
|
|
|
let unit = constant "UNIT" @@ t_unit ()
|
|
|
|
|
|
|
|
let amount = constant "AMOUNT" @@ t_tez ()
|
|
|
|
|
|
|
|
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 ()
|
|
|
|
|
|
|
|
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' ()
|
|
|
|
|
|
|
|
let abs = typer_1 "ABS" @@ fun t ->
|
|
|
|
let%bind () = assert_t_int t in
|
|
|
|
ok @@ t_nat ()
|
|
|
|
|
|
|
|
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
|
|
|
|
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
|
|
|
|
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
|
|
|
|
simple_fail "Adding with wrong types"
|
2019-05-13 00:56:22 +04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let constant_typers =
|
2019-05-23 16:16:12 +04:00
|
|
|
let typer_to_kv : typer -> (string * _) = fun x -> x in
|
2019-05-13 00:56:22 +04:00
|
|
|
Map.String.of_list
|
|
|
|
@@ List.map typer_to_kv [
|
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 ;
|
|
|
|
comparator "EQ" ;
|
|
|
|
comparator "NEQ" ;
|
|
|
|
comparator "LT" ;
|
|
|
|
comparator "GT" ;
|
|
|
|
comparator "LE" ;
|
|
|
|
comparator "GE" ;
|
|
|
|
boolean_operator_2 "OR" ;
|
|
|
|
boolean_operator_2 "AND" ;
|
|
|
|
map_remove ;
|
|
|
|
map_update ;
|
|
|
|
int ;
|
|
|
|
size ;
|
|
|
|
get_force ;
|
|
|
|
bytes_pack ;
|
|
|
|
bytes_unpack ;
|
|
|
|
crypto_hash ;
|
|
|
|
sender ;
|
|
|
|
source ;
|
|
|
|
unit ;
|
|
|
|
amount ;
|
|
|
|
transaction ;
|
|
|
|
get_contract ;
|
|
|
|
abs ;
|
|
|
|
]
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
module Compiler = struct
|
|
|
|
|
2019-05-13 16:20:23 +04:00
|
|
|
module Michelson = Tezos_utils.Michelson
|
2019-05-13 00:56:22 +04:00
|
|
|
open Michelson
|
|
|
|
|
|
|
|
type predicate =
|
|
|
|
| Constant of michelson
|
|
|
|
| Unary of michelson
|
|
|
|
| Binary of michelson
|
|
|
|
| Ternary of michelson
|
|
|
|
|
|
|
|
let simple_constant c = Constant c
|
|
|
|
|
|
|
|
let simple_unary c = Unary c
|
|
|
|
|
|
|
|
let simple_binary c = Binary c
|
|
|
|
|
|
|
|
let simple_ternary c = Ternary c
|
|
|
|
|
|
|
|
let predicates = 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) ;
|
|
|
|
("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")]) ;
|
|
|
|
("MAP_GET" , simple_binary @@ prim I_GET) ;
|
2019-05-13 00:56:22 +04:00
|
|
|
("SIZE" , simple_unary @@ prim I_SIZE) ;
|
|
|
|
("FAILWITH" , simple_unary @@ prim I_FAILWITH) ;
|
|
|
|
("ASSERT" , simple_binary @@ i_if (seq [i_failwith]) (seq [i_drop ; i_push_unit])) ;
|
|
|
|
("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-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) ;
|
|
|
|
( "MAP_UPDATE" , simple_ternary @@ seq [dip (i_some) ; prim I_UPDATE ]) ;
|
|
|
|
]
|
|
|
|
|
|
|
|
end
|