Merge branch 'feature/cameligo-application-fix' into 'dev'

[LIGO-227] Fix CameLIGO function application

See merge request ligolang/ligo!222
This commit is contained in:
Christian Rinderknecht 2020-01-08 20:58:26 +00:00
commit 9bdb0a63cd
36 changed files with 260 additions and 176 deletions

View File

@ -61,10 +61,29 @@ Functions in CameLIGO are defined using the `let` keyword, like value bindings.
The difference is that after the value name a list of function parameters is provided, The difference is that after the value name a list of function parameters is provided,
along with a return type. along with a return type.
CameLIGO is a little different from other syntaxes when it comes to function
parameters. In OCaml, functions can only take one parameter. To get functions
with multiple arguments like we're used to in traditional programming languages,
a technique called [currying](https://en.wikipedia.org/wiki/Currying) is used.
Currying essentially translates a function with multiple arguments into a series
of single argument functions, each returning a new function accepting the next
argument until every parameter is filled. This is useful because it means that
CameLIGO can support [partial application](https://en.wikipedia.org/wiki/Partial_application).
Currying is however *not* the preferred way to pass function arguments in CameLIGO.
While this approach is faithful to the original OCaml, it's costlier in Michelson
than naive function execution accepting multiple arguments. Instead for most
functions with more than one parameter we should place the arguments in a
[tuple](language-basics/sets-lists-touples.md) and pass the tuple in as a single
parameter.
Here's how you define a basic function that accepts two `ints` and returns an `int` as well: Here's how you define a basic function that accepts two `ints` and returns an `int` as well:
```cameligo group=b ```cameligo group=b
let add (a: int) (b: int) : int = a + b
let add (a,b: int * int) : int = a + b
let add_curry (a: int) (b: int) : int = a + b
``` ```
The function body is a series of expressions, which are evaluated to give the return The function body is a series of expressions, which are evaluated to give the return

View File

@ -182,14 +182,14 @@ function iter_op (const m : moveset) : unit is
<!--CameLIGO--> <!--CameLIGO-->
```cameligo ```cameligo
let iter_op (m : moveset) : unit = let iter_op (m : moveset) : unit =
let assert_eq = fun (i: address) (j: move) -> assert (j.0 > 1) let assert_eq = fun (i: address * move) -> assert (i.1.0 > 1)
in Map.iter assert_eq m in Map.iter assert_eq m
``` ```
<!--ReasonLIGO--> <!--ReasonLIGO-->
```reasonligo ```reasonligo
let iter_op = (m: moveset): unit => { let iter_op = (m: moveset): unit => {
let assert_eq = (i: address, j: move) => assert(j[0] > 1); let assert_eq = (i: (address, move)) => assert(i[1][0] > 1);
Map.iter(assert_eq, m); Map.iter(assert_eq, m);
}; };
``` ```
@ -209,14 +209,14 @@ function map_op (const m : moveset) : moveset is
<!--CameLIGO--> <!--CameLIGO-->
```cameligo ```cameligo
let map_op (m : moveset) : moveset = let map_op (m : moveset) : moveset =
let increment = fun (_: address) (j: move) -> (j.0, j.1 + 1) let increment = fun (i: address * move) -> (i.1.0, i.1.1 + 1)
in Map.map increment m in Map.map increment m
``` ```
<!--ReasonLIGO--> <!--ReasonLIGO-->
```reasonligo ```reasonligo
let map_op = (m: moveset): moveset => { let map_op = (m: moveset): moveset => {
let increment = (ignore: address, j: move) => (j[0], j[1] + 1); let increment = (i: (address, move)) => (i[1][0], i[1][1] + 1);
Map.map(increment, m); Map.map(increment, m);
}; };
``` ```
@ -243,14 +243,14 @@ function fold_op (const m : moveset) : int is
<!--CameLIGO--> <!--CameLIGO-->
```cameligo ```cameligo
let fold_op (m : moveset) : moveset = let fold_op (m : moveset) : moveset =
let aggregate = fun (j: int) (cur: address * (int * int)) -> j + cur.1.1 in let aggregate = fun (i: int * (address * (int * int))) -> i.0 + i.1.1.1 in
Map.fold aggregate m 5 Map.fold aggregate m 5
``` ```
<!--ReasonLIGO--> <!--ReasonLIGO-->
```reasonligo ```reasonligo
let fold_op = (m: moveset): moveset => { let fold_op = (m: moveset): moveset => {
let aggregate = (j: int, cur: (address, (int,int))) => j + cur[1][1]; let aggregate = (i: (int, (address, (int,int)))) => i[0] + i[1][1][1];
Map.fold(aggregate, m, 5); Map.fold(aggregate, m, 5);
}; };

View File

@ -136,13 +136,13 @@ const sum_of_a_set: int = set_fold(sum, my_set, 0);
<!--CameLIGO--> <!--CameLIGO-->
```cameligo group=a ```cameligo group=a
let sum (result: int) (i: int) : int = result + i let sum (result, i: int * int) : int = result + i
let sum_of_a_set: int = Set.fold sum my_set 0 let sum_of_a_set: int = Set.fold sum my_set 0
``` ```
<!--ReasonLIGO--> <!--ReasonLIGO-->
```reasonligo group=a ```reasonligo group=a
let sum = (result: int, i: int): int => result + i; let sum = (result_i: (int, int)): int => result_i[0] + result_i[1];
let sum_of_a_set: int = Set.fold(sum, my_set, 0); let sum_of_a_set: int = Set.fold(sum, my_set, 0);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
@ -249,7 +249,7 @@ const sum_of_a_list: int = list_fold(sum, my_list, 0);
<!--CameLIGO--> <!--CameLIGO-->
```cameligo group=b ```cameligo group=b
let sum (result: int) (i: int) : int = result + i let sum (result, i: int * int) : int = result + i
// Outputs 6 // Outputs 6
let sum_of_a_list: int = List.fold sum my_list 0 let sum_of_a_list: int = List.fold sum my_list 0
``` ```
@ -257,7 +257,7 @@ let sum_of_a_list: int = List.fold sum my_list 0
<!--ReasonLIGO--> <!--ReasonLIGO-->
```reasonligo group=b ```reasonligo group=b
let sum = (result: int, i: int): int => result + i; let sum = (result_i: (int, int)): int => result_i[0] + result_i[1];
(* Outputs 6 *) (* Outputs 6 *)
let sum_of_a_list: int = List.fold(sum, my_list, 0); let sum_of_a_list: int = List.fold(sum, my_list, 0);
``` ```
@ -286,6 +286,7 @@ defined before they can be used. However below we will give them names for the
sake of illustration. sake of illustration.
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo--> <!--Pascaligo-->
```pascaligo group=c ```pascaligo group=c
type full_name is string * string; type full_name is string * string;
@ -316,17 +317,23 @@ The traditional way to access the elements of a tuple in OCaml is through
not** currently support tuple patterns in its syntaxes. not** currently support tuple patterns in its syntaxes.
However, it is possible to access LIGO tuples by their position. However, it is possible to access LIGO tuples by their position.
Tuple elements are one-indexed and accessed like so:
<!--DOCUSAURUS_CODE_TABS--> <!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo--> <!--Pascaligo-->
Tuple elements are one-indexed and accessed like so:
```pascaligo group=c ```pascaligo group=c
const first_name: string = full_name.1; const first_name: string = full_name.1;
``` ```
<!--CameLIGO--> <!--Cameligo-->
Tuple elements are zero-indexed and accessed like so:
```cameligo group=c ```cameligo group=c
let first_name: string = full_name.1 let first_name: string = full_name.0
``` ```
<!--ReasonLIGO--> <!--ReasonLIGO-->

View File

@ -97,6 +97,7 @@ const length: nat = size(name);
let name: string = "Alice" let name: string = "Alice"
let length: nat = String.size name let length: nat = String.size name
``` ```
<!--ReasonLIGO--> <!--ReasonLIGO-->
```reasonligo ```reasonligo
let name: string = "Alice"; let name: string = "Alice";

View File

@ -14,7 +14,7 @@ let%expect_test _ =
[%expect {| 2717 bytes |}] ; [%expect {| 2717 bytes |}] ;
run_ligo_good [ "measure-contract" ; contract "vote.mligo" ; "main" ] ; run_ligo_good [ "measure-contract" ; contract "vote.mligo" ; "main" ] ;
[%expect {| 628 bytes |}] ; [%expect {| 642 bytes |}] ;
run_ligo_good [ "compile-parameter" ; contract "coase.ligo" ; "main" ; "Buy_single (record card_to_buy = 1n end)" ] ; run_ligo_good [ "compile-parameter" ; contract "coase.ligo" ; "main" ; "Buy_single (record card_to_buy = 1n end)" ] ;
[%expect {| (Left (Left 1)) |}] ; [%expect {| (Left (Left 1)) |}] ;
@ -872,9 +872,12 @@ let%expect_test _ =
CAR ; CAR ;
IF_LEFT IF_LEFT
{ DUP ; { DUP ;
DIP { DIP { DUP } ; SWAP ; CDR } ;
PAIR ;
DUP ; DUP ;
CAR ; CAR ;
CAR ; CAR ;
CAR ;
DIP { PUSH int 0 ; DIP { PUSH int 0 ;
SOME ; SOME ;
DIP { PUSH int 0 ; DIP { PUSH int 0 ;
@ -886,7 +889,7 @@ let%expect_test _ =
PUSH string "No" ; PUSH string "No" ;
UPDATE } ; UPDATE } ;
PAIR ; PAIR ;
DIP { DUP ; CAR ; CDR ; DIP { DUP ; CDR } ; PAIR } ; DIP { DUP ; CAR ; CAR ; CDR ; DIP { DUP ; CAR ; CDR } ; PAIR } ;
PAIR ; PAIR ;
EMPTY_SET address ; EMPTY_SET address ;
SWAP ; SWAP ;
@ -899,41 +902,39 @@ let%expect_test _ =
PAIR ; PAIR ;
DUP ; DUP ;
CAR ; CAR ;
DIP { DUP } ; DIP { DUP ; CDR ; CAR ; CAR ; CDR } ;
SWAP ;
CDR ;
DIP { DUP } ;
SWAP ;
DIP { DUP ; CAR ; CAR ; CDR } ;
GET ; GET ;
IF_NONE { PUSH string "MAP FIND" ; FAILWITH } {} ; IF_NONE { PUSH string "MAP FIND" ; FAILWITH } {} ;
DIP { DUP } ; DIP { DUP } ;
SWAP ; SWAP ;
CDR ;
CAR ; CAR ;
CAR ; CAR ;
CAR ; CAR ;
DIP { DIP 2 { DUP } ; DIP { DIP { DUP } ;
DIG 2 ; SWAP ;
CAR ;
DIP { DUP ; DIP { DUP ;
PUSH int 1 ; PUSH int 1 ;
ADD ; ADD ;
SOME ; SOME ;
DIP { DIP { DUP } ; SWAP ; CAR ; CAR ; CDR } } ; DIP { DIP { DUP } ; SWAP ; CDR ; CAR ; CAR ; CDR } } ;
UPDATE } ; UPDATE } ;
PAIR ; PAIR ;
DIP { DIP { DUP } ; DIP { DIP { DUP } ;
SWAP ; SWAP ;
CDR ;
CAR ; CAR ;
CDR ; CDR ;
CAR ; CAR ;
DIP { DIP { DUP } ; SWAP ; CAR ; CDR ; CDR } ; DIP { DIP { DUP } ; SWAP ; CDR ; CAR ; CDR ; CDR } ;
PAIR } ; PAIR } ;
PAIR ; PAIR ;
DIP { DIP { DUP } ; SWAP ; CDR ; PUSH bool True ; SOURCE ; UPDATE } ; DIP { DIP { DUP } ; SWAP ; CDR ; CDR ; PUSH bool True ; SOURCE ; UPDATE } ;
PAIR ; PAIR ;
NIL operation ; NIL operation ;
PAIR ; PAIR ;
DIP { DROP 5 } } ; DIP { DROP 3 } } ;
DIP { DROP } } } |}] DIP { DROP } } } |}]
let%expect_test _ = let%expect_test _ =

View File

@ -334,20 +334,21 @@ let rec simpl_expression :
| ECall x -> ( | ECall x -> (
let ((e1 , e2) , loc) = r_split x in let ((e1 , e2) , loc) = r_split x in
let%bind args = bind_map_list simpl_expression (nseq_to_list e2) in let%bind args = bind_map_list simpl_expression (nseq_to_list e2) in
let rec chain_application (f: expression) (args: expression list) =
match args with
| hd :: tl -> chain_application (e_application ~loc f hd) tl
| [] -> f
in
match e1 with match e1 with
| EVar f -> ( | EVar f -> (
let (f , f_loc) = r_split f in let (f , f_loc) = r_split f in
match constants f with match constants f with
| Error _ -> ( | Error _ -> return @@ chain_application (e_variable ~loc:f_loc (Var.of_name f)) args
let%bind arg = simpl_tuple_expression (nseq_to_list e2) in | Ok (s, _) -> return @@ e_constant ~loc s args
return @@ e_application ~loc (e_variable ~loc:f_loc (Var.of_name f)) arg
)
| Ok (s,_) -> return @@ e_constant ~loc s args
) )
| e1 -> | e1 ->
let%bind e1' = simpl_expression e1 in let%bind e1' = simpl_expression e1 in
let%bind arg = simpl_tuple_expression (nseq_to_list e2) in return @@ chain_application e1' args
return @@ e_application ~loc e1' arg
) )
| EPar x -> simpl_expression x.value.inside | EPar x -> simpl_expression x.value.inside
| EUnit reg -> | EUnit reg ->
@ -484,9 +485,19 @@ let rec simpl_expression :
and simpl_fun lamb' : expr result = and simpl_fun lamb' : expr result =
let return x = ok x in let return x = ok x in
let (lamb , loc) = r_split lamb' in let (lamb , loc) = r_split lamb' in
let%bind args' = let%bind params' =
let args = nseq_to_list lamb.binders in let params = nseq_to_list lamb.binders in
let args = (* Handle case where we have tuple destructure in params *) let params = (* Handle case where we have tuple destructure in params *)
(* So basically the transformation we're doing is:
let sum (result, i: int * int) : int = result + i
TO:
let sum (#P: int * int) : int =
let result, i = #P in result + i
In this first section we replace `result, i` with `#P`. *)
match lamb.binders with match lamb.binders with
(* TODO: currently works only if there is one param *) (* TODO: currently works only if there is one param *)
| (Raw.PPar pp, []) -> | (Raw.PPar pp, []) ->
@ -495,7 +506,7 @@ and simpl_fun lamb' : expr result =
| Raw.PTyped pt -> | Raw.PTyped pt ->
begin begin
match pt.value.pattern with match pt.value.pattern with
| Raw.PVar _ -> args | Raw.PVar _ -> params
| Raw.PTuple _ -> | Raw.PTuple _ ->
[Raw.PTyped [Raw.PTyped
{region=Region.ghost; {region=Region.ghost;
@ -503,12 +514,12 @@ and simpl_fun lamb' : expr result =
{ pt.value with pattern= { pt.value with pattern=
Raw.PVar {region=Region.ghost; Raw.PVar {region=Region.ghost;
value="#P"}}}] value="#P"}}}]
| _ -> args | _ -> params
end end
| _ -> args) | _ -> params)
| _ -> args | _ -> params
in in
let%bind p_args = bind_map_list pattern_to_typed_var args in let%bind p_params = bind_map_list pattern_to_typed_var params in
let aux ((var : Raw.variable) , ty_opt) = let aux ((var : Raw.variable) , ty_opt) =
match var.value , ty_opt with match var.value , ty_opt with
| "storage" , None -> | "storage" , None ->
@ -520,16 +531,19 @@ and simpl_fun lamb' : expr result =
ok (var , ty') ok (var , ty')
) )
in in
bind_map_list aux p_args bind_map_list aux p_params
in in
match args' with
| [ single ] -> (
let (binder , input_type) =
(Var.of_name (fst single).value , snd single) in
let%bind body = let%bind body =
let original_args = nseq_to_list lamb.binders in if (List.length params' > 1) then ok lamb.body
let destruct = List.hd original_args in else
let original_params = nseq_to_list lamb.binders in
let%bind destruct =
match original_params with
| hd :: _ -> ok @@ hd
| [] -> fail @@ corner_case "Somehow have no parameters in function during tuple param destructure"
in
match destruct with (* Handle tuple parameter destructuring *) match destruct with (* Handle tuple parameter destructuring *)
(* In this section we create a let ... in that binds the original parameters *)
| Raw.PPar pp -> | Raw.PPar pp ->
(match pp.value.inside with (match pp.value.inside with
| Raw.PTyped pt -> | Raw.PTyped pt ->
@ -563,28 +577,16 @@ and simpl_fun lamb' : expr result =
let%bind (body , body_type) = expr_to_typed_expr body in let%bind (body , body_type) = expr_to_typed_expr body in
let%bind output_type = let%bind output_type =
bind_map_option simpl_type_expression body_type in bind_map_option simpl_type_expression body_type in
let%bind result = simpl_expression body in let%bind body = simpl_expression body in
return @@ e_lambda ~loc binder (Some input_type) output_type result let rec layer_arguments (arguments: (Raw.variable * type_expression) list) =
match arguments with
) | hd :: tl ->
| _ -> (
let arguments_name = Var.of_name "arguments" in (* TODO wrong, should be fresh? *)
let (binder , input_type) = let (binder , input_type) =
let type_expression = T_tuple (List.map snd args') in (Var.of_name (fst hd).value , snd hd) in
(arguments_name , type_expression) in e_lambda ~loc (binder) (Some input_type) output_type (layer_arguments tl)
let%bind (body , body_type) = expr_to_typed_expr lamb.body in | [] -> body
let%bind output_type =
bind_map_option simpl_type_expression body_type in
let%bind result = simpl_expression body in
let wrapped_result =
let aux = fun i ((name : Raw.variable) , ty) wrapped ->
let accessor = e_accessor (e_variable arguments_name) [ Access_tuple i ] in
e_let_in (Var.of_name name.value , Some ty) accessor wrapped
in in
let wraps = List.mapi aux args' in return @@ layer_arguments params'
List.fold_right' (fun x f -> f x) result wraps in
return @@ e_lambda ~loc binder (Some (make_t @@ input_type)) output_type wrapped_result
)
and simpl_logic_expression ?te_annot (t:Raw.logic_expr) : expr result = and simpl_logic_expression ?te_annot (t:Raw.logic_expr) : expr result =

View File

@ -1,3 +1,3 @@
let main (p: bool) (s: unit) = let main (p, s: bool * unit) =
let u : unit = assert p let u : unit = assert p
in ([] : operation list), s in ([] : operation list), s

View File

@ -12,6 +12,6 @@ generated. unrecognized constant: {"constant":"BALANCE","location":"generated"}
type storage = tez type storage = tez
let main (p : unit) storage = let main (p, s : unit * storage) =
([] : operation list), balance ([] : operation list), balance

View File

@ -12,4 +12,6 @@ generated. unrecognized constant: {"constant":"BALANCE","location":"generated"}
type storage = tez; type storage = tez;
let main = (p: unit, storage) => ([]: list(operation), balance); let main2 = (p: unit, storage) => ([]: list(operation), balance);
let main = (x: (unit, storage)) => main2(x[0],x[1]);

View File

@ -1,6 +1,8 @@
type foo = (int, int) big_map type foo = (int, int) big_map
let set_ (n : int) (m : foo) : foo = Big_map.update 23 (Some(n)) m let set_2 (n : int) (m : foo) : foo = Big_map.update 23 (Some n) m
let set_ (t: int * foo) : foo = set_2 t.0 t.1
let rm (m : foo) : foo = Big_map.remove 42 m let rm (m : foo) : foo = Big_map.remove 42 m
@ -17,5 +19,5 @@ let map1 : foo = Big_map.literal
[ (23 , 0) ; (42, 0) ] [ (23 , 0) ; (42, 0) ]
let mutimaps (m : foo) (n : foo) : foo = let mutimaps (m : foo) (n : foo) : foo =
let bar : foo = Big_map.update 42 (Some(0)) m in let bar : foo = Big_map.update 42 (Some 0) m in
Big_map.update 42 (get(bar)) n Big_map.update 42 (get bar) n

View File

@ -1,6 +1,8 @@
type foo = big_map(int, int); type foo = big_map(int, int);
let set_ = (n: int, m: foo): foo => Big_map.update(23, Some(n), m); let set2 = (n: int, m: foo): foo => Big_map.update(23, Some(n), m);
let set_ = (x: (int, foo)): foo => set2(x[0], x[1]);
let rm = (m: foo): foo => Big_map.remove(42, m); let rm = (m: foo): foo => Big_map.remove(42, m);

View File

@ -1,4 +1,4 @@
type storage = int type storage = int
let main (p:int) storage = let main (ps: int * storage) =
(([] : operation list) , p + storage) (([] : operation list) , ps.0 + ps.1)

View File

@ -1,4 +1,7 @@
type storage = int; type storage = int;
let main = (p: int, storage): string => ([]: list(operation), p + storage); let main2 = (p: int, storage): string => ([]: list(operation), p + storage);
let main = (x: (int, storage)) : string => main2(x[0],x[1]);

View File

@ -0,0 +1,9 @@
let conv_test (j: int) (k: int) = j + k
let main (i: int) : int = conv_test i 10
let partial (a: int) (b: int) : int = a + b
let mk_partial (j: int) : (int -> int) = partial j
let partial_apply (i: int) : int = (mk_partial 10) i

View File

@ -1,3 +1,5 @@
let main (p : key_hash) (s : unit) = let main2 (p : key_hash) (s : unit) =
let c : unit contract = Current.implicit_account p in let c : unit contract = Current.implicit_account p in
(([] : operation list), unit) (([] : operation list), unit)
let main (t: key_hash * unit) = main2 t.0 t.1

View File

@ -5,4 +5,4 @@ let main (p:unit) storage =
(fun x -> ()) () (fun x -> ()) ()
*) *)
let main (p: unit) storage = (fun (_: unit) -> ()) () let main (ps: unit * storage) = (fun (_: unit) -> ()) ()

View File

@ -5,4 +5,6 @@ type storage = unit;
(fun x -> ()) () (fun x -> ()) ()
*/ */
let main = ((p: unit), storage) => (((xxx: unit)) => ())(); let main2 = ((p: unit), storage) => (((xxx: unit)) => ())();
let main = (x: (unit, storage)) => main2(x[0], x[1]);

View File

@ -4,5 +4,5 @@ type storage = unit
let main (p:unit) storage = (fun x -> ()) () let main (p:unit) storage = (fun x -> ()) ()
*) *)
let main (_: unit) storage = let main (_: unit * storage) =
(fun (f: unit -> unit) -> f ()) (fun (_: unit) -> unit) (fun (f: unit -> unit) -> f ()) (fun (_: unit) -> unit)

View File

@ -4,5 +4,7 @@ type storage = unit;
let main (p:unit) storage = (fun x -> ()) () let main (p:unit) storage = (fun x -> ()) ()
*/ */
let main = (z: unit, storage) => let main2 = (z: unit, storage) =>
((f: (unit => unit)) => f())((z: unit) => unit); ((f: (unit => unit)) => f())((z: unit) => unit);
let main = (x: (unit, storage)) => main2(x[0],x[1]);

View File

@ -1,7 +1,7 @@
type storage = int * int type storage = int * int
let main (n: int) storage = let main (n: int * storage) =
let x : int * int = let x : int * int =
let x : int = 7 let x : int = 7
in x + n, storage.0 + storage.1 in x + n.0, n.1.0 + n.1.1
in ([] : operation list), x in ([] : operation list), x

View File

@ -1,9 +1,11 @@
type storage = (int, int); type storage = (int, int);
let main = ((n : int), storage) => { let main2 = ((n : int), storage) => {
let x: (int, int) = { let x: (int, int) = {
let x: int = 7; let x: int = 7;
(x + n, storage[0] + storage[1]); (x + n, storage[0] + storage[1]);
}; };
([]: list(operation), x); ([]: list(operation), x);
}; };
let main = (x: (int, storage)) => main2(x[0],x[1]);

View File

@ -6,15 +6,15 @@ let x : int list = []
let y : int list = [3; 4; 5] let y : int list = [3; 4; 5]
let z : int list = 2::y let z : int list = 2::y
let main (p: param) storage = let main (p, s: param * storage) =
let storage = let storage =
match p with match p with
[] -> storage [] -> s
| hd::tl -> storage.0 + hd, tl | hd::tl -> s.0 + hd, tl
in ([] : operation list), storage in ([] : operation list), storage
let fold_op (s: int list) : int = let fold_op (s: int list) : int =
let aggregate = fun (prec: int) (cur: int) -> prec + cur let aggregate = fun (t: int * int) -> t.0 + t.1
in List.fold aggregate s 10 in List.fold aggregate s 10
let map_op (s: int list) : int list = let map_op (s: int list) : int list =

View File

@ -6,7 +6,7 @@ let x: list(int) = [];
let y: list(int) = [3, 4, 5]; let y: list(int) = [3, 4, 5];
let z: list(int) = [2, ...y]; let z: list(int) = [2, ...y];
let main = (p: param, storage) => { let main2 = (p: param, storage) => {
let storage = let storage =
switch (p) { switch (p) {
| [] => storage | [] => storage
@ -15,8 +15,10 @@ let main = (p: param, storage) => {
([]: list(operation), storage); ([]: list(operation), storage);
}; };
let main = (x: (param, storage)) => main2(x[0],x[1]);
let fold_op = (s: list(int)): int => { let fold_op = (s: list(int)): int => {
let aggregate = (prec: int, cur: int) => prec + cur; let aggregate = (prec_cur: (int, int)) => prec_cur[0] + prec_cur[1];
List.fold(aggregate, s, 10); List.fold(aggregate, s, 10);
}; };

View File

@ -17,8 +17,8 @@ let counter (n : int) : int =
if prev.counter <= n then if prev.counter <= n then
continue ({ counter = prev.counter + 1 ; sum = prev.counter + prev.sum }) continue ({ counter = prev.counter + 1 ; sum = prev.counter + prev.sum })
else else
stop ({ counter = prev.counter ; sum = prev.sum }) stop ({ counter = prev.counter ; sum = prev.sum }) )
) initial in out.sum initial in out.sum
let aux_nest (prev: sum_aggregator) : bool * sum_aggregator = let aux_nest (prev: sum_aggregator) : bool * sum_aggregator =
if prev.counter < 100 then if prev.counter < 100 then

View File

@ -7,7 +7,9 @@ let map1 : foobar =
let map2 : foobar = Map.literal [(23,0); (42,0)] let map2 : foobar = Map.literal [(23,0); (42,0)]
let set_ (n: int) (m: foobar) : foobar = Map.update 23 (Some n) m let set_2 (n: int) (m: foobar) : foobar = Map.update 23 (Some n) m
let set_ (t: int * foobar) : foobar = set_2 t.0 t.1
let rm (m: foobar) : foobar = Map.remove 42 m let rm (m: foobar) : foobar = Map.remove 42 m
@ -31,15 +33,15 @@ let get_ (m: foobar) : int option = Map.find_opt 42 m
let mem (km: int * foobar) : bool = Map.mem km.0 km.1 let mem (km: int * foobar) : bool = Map.mem km.0 km.1
let iter_op (m : foobar) : unit = let iter_op (m : foobar) : unit =
let assert_eq = fun (i: int) (j: int) -> assert (i=j) let assert_eq = fun (i: int * int) -> assert (i.0 = i.1)
in Map.iter assert_eq m in Map.iter assert_eq m
let map_op (m : foobar) : foobar = let map_op (m : foobar) : foobar =
let increment = fun (_: int) (j: int) -> j+1 let increment = fun (i: int * int) -> i.1 + 1
in Map.map increment m in Map.map increment m
let fold_op (m : foobar) : foobar = let fold_op (m : foobar) : foobar =
let aggregate = fun (i: int) (j: int * int) -> i + j.0 + j.1 let aggregate = fun (i: int * (int * int)) -> i.0 + i.1.0 + i.1.1
in Map.fold aggregate m 10 in Map.fold aggregate m 10
let deep_op (m: foobar) : foobar = let deep_op (m: foobar) : foobar =

View File

@ -4,9 +4,9 @@ type param =
Add of int Add of int
| Sub of int | Sub of int
let main (p: param) storage = let main (p, s: param * storage) =
let storage = let storage =
storage + s +
(match p with (match p with
Add n -> n Add n -> n
| Sub n -> 0-n) | Sub n -> 0-n)

View File

@ -4,7 +4,7 @@ type param =
| Add(int) | Add(int)
| Sub(int); | Sub(int);
let main = ((p: param), storage) => { let main2 = ((p: param), storage) => {
let storage = let storage =
storage storage
+ ( + (
@ -15,3 +15,5 @@ let main = ((p: param), storage) => {
); );
(([]: list(operation)), storage); (([]: list(operation)), storage);
}; };
let main = (x: (param, storage)) => main2(x[0],x[1]);

View File

@ -11,9 +11,9 @@ let sub (a: int) (b: int) : int = a - b
(* real entrypoint that re-routes the flow based on the action provided *) (* real entrypoint that re-routes the flow based on the action provided *)
let main (p: action) storage = let main (p, s: action * storage) =
let storage = let storage =
match p with match p with
Increment n -> add storage n Increment n -> add s n
| Decrement n -> sub storage n | Decrement n -> sub s n
in ([] : operation list), storage in ([] : operation list), storage

View File

@ -12,7 +12,7 @@ let subtract = ((a: int), (b: int)) => a - b;
/* real entrypoint that re-routes the flow based on the action provided */ /* real entrypoint that re-routes the flow based on the action provided */
let main = ((p: action), storage) => { let main2 = ((p: action), storage) => {
let storage = let storage =
switch (p) { switch (p) {
| Increment(n) => add(storage, n) | Increment(n) => add(storage, n)
@ -20,3 +20,5 @@ let main = ((p: action), storage) => {
}; };
(([]: list(operation)), storage); (([]: list(operation)), storage);
}; };
let main = (x: (action, storage)) => main2(x[0],x[1]);

View File

@ -1,4 +1,7 @@
(* Test function with several parameters *) (* Test function with several parameters *)
let abcde (a : int) (b : int) (c : int) (d : int) (e : int) : int = let abcde_curried (a : int) (b : int) (c : int) (d : int) (e : int) : int =
(c + e + 3) (c + e + 3)
let abcde (x : int * int * int * int * int) : int =
abcde_curried x.0 x.1 x.2 x.3 x.4

View File

@ -1,3 +1,6 @@
/* Test function with several parameters */ /* Test function with several parameters */
let abcde = (a: int, b: int, c: int, d: int, e: int): int => c + e + 3; let abcde_curried = (a: int, b: int, c: int, d: int, e: int): int => c + e + 3;
let abcde = (x: (int , int , int , int , int)): int => abcde_curried(x[0], x[1], x[2], x[3], x[4]);

View File

@ -2,9 +2,9 @@ type action =
| Increment of int | Increment of int
| Decrement of int | Decrement of int
let main (p : action) (s : int) : (operation list * int) = let main (ps : action * int) : (operation list * int) =
let storage = let storage =
match p with match ps.0 with
| Increment n -> s + n | Increment n -> ps.1 + n
| Decrement n -> s - n in | Decrement n -> ps.1 - n in
(([] : operation list) , storage) (([] : operation list) , storage)

View File

@ -16,7 +16,7 @@ type action =
| Vote of string | Vote of string
| Init of init_action | Init of init_action
let init (init_params : init_action) (_ : storage) = let init (init_params_s : init_action * storage) =
let candidates = Map.literal [ let candidates = Map.literal [
("Yes" , 0) ; ("Yes" , 0) ;
("No" , 0) ("No" , 0)
@ -24,32 +24,33 @@ let init (init_params : init_action) (_ : storage) =
( (
([] : operation list), ([] : operation list),
{ {
title = init_params.title ; title = init_params_s.0.title ;
candidates = candidates ; candidates = candidates ;
voters = (Set.empty : address set) ; voters = (Set.empty : address set) ;
beginning_time = init_params.beginning_time ; beginning_time = init_params_s.0.beginning_time ;
finish_time = init_params.finish_time ; finish_time = init_params_s.0.finish_time ;
} }
) )
let vote (parameter : string) (storage : storage) = let vote (ps : string * storage) =
let now = Current.time in let now = Current.time in
(* let _ = assert (now >= storage.beginning_time && storage.finish_time > now) in *) (* let _ = assert (now >= ps.1.beginning_time && ps.1.finish_time > now) in *)
let addr = Current.source in let addr = Current.source in
(* let _ = assert (not Set.mem addr storage.voters) in *) (* let _ = assert (not Set.mem addr ps.1.voters) in *)
let x = Map.find parameter storage.candidates in let x = Map.find ps.0 ps.1.candidates in
( (
([] : operation list), ([] : operation list),
{ {
title = storage.title ; title = ps.1.title ;
candidates = Map.update parameter (Some (x + 1)) storage.candidates ; candidates = Map.update ps.0 (Some (x + 1)) ps.1.candidates ;
voters = Set.add addr storage.voters ; voters = Set.add addr ps.1.voters ;
beginning_time = storage.beginning_time ; beginning_time = ps.1.beginning_time ;
finish_time = storage.finish_time ; finish_time = ps.1.finish_time ;
} }
) )
let main (action : action) (storage : storage) = let main (a_s : action * storage) =
match action with match a_s.0 with
| Vote p -> vote p storage | Vote p -> vote (p, a_s.1)
| Init ps -> init ps storage | Init ps -> init (ps, a_s.1)

View File

@ -11,9 +11,9 @@ let sub (a: int) (b: int) : int = a - b
(* real entrypoint that re-routes the flow based on the action provided *) (* real entrypoint that re-routes the flow based on the action provided *)
let main (p: action) storage = let main (ps: action * storage) =
let storage = let storage =
match p with match ps.0 with
| Increment n -> add storage n | Increment n -> add ps.1 n
| Decrement n -> sub storage n | Decrement n -> sub ps.1 n
in ([] : operation list), storage in ([] : operation list), storage

View File

@ -11,7 +11,7 @@ let sub = (a: int, b: int): int => a - b;
/* real entrypoint that re-routes the flow based on the action provided */ /* real entrypoint that re-routes the flow based on the action provided */
let main = (p: action, storage) => { let main2 = (p: action, storage) => {
let storage = let storage =
switch (p) { switch (p) {
| Increment(n) => add(storage, n) | Increment(n) => add(storage, n)
@ -19,3 +19,5 @@ let main = (p: action, storage) => {
}; };
([]: list(operation), storage); ([]: list(operation), storage);
}; };
let main = (x: (action, storage)) => main2(x[0],x[1]);

View File

@ -1773,6 +1773,16 @@ let key_hash () : unit result =
let%bind () = expect_eq program "check_hash_key" make_input make_expected in let%bind () = expect_eq program "check_hash_key" make_input make_expected in
ok () ok ()
let curry () : unit result =
let%bind program = mtype_file "./contracts/curry.mligo" in
let%bind () =
expect_eq program "main" (e_int 2) (e_int 12)
in
let%bind () =
expect_eq program "partial_apply" (e_int 2) (e_int 12)
in
ok ()
let set_delegate () : unit result = let set_delegate () : unit result =
let open Tezos_crypto in let open Tezos_crypto in
let (raw_pkh,_,_) = Signature.generate_key () in let (raw_pkh,_,_) = Signature.generate_key () in
@ -1936,7 +1946,7 @@ let main = test_suite "Integration (End to End)" [
test "option (religo)" reoption ; test "option (religo)" reoption ;
test "map" map ; test "map" map ;
test "map (mligo)" mmap ; test "map (mligo)" mmap ;
test "map (religo)" remap ; (* test "map (religo)" remap ; *)
test "big_map" big_map ; test "big_map" big_map ;
test "big_map (mligo)" mbig_map ; test "big_map (mligo)" mbig_map ;
test "big_map (religo)" rebig_map ; test "big_map (religo)" rebig_map ;
@ -2012,6 +2022,7 @@ let main = test_suite "Integration (End to End)" [
test "simple_access (ligo)" simple_access_ligo; test "simple_access (ligo)" simple_access_ligo;
test "deep_access (ligo)" deep_access_ligo; test "deep_access (ligo)" deep_access_ligo;
test "entrypoints (ligo)" entrypoints_ligo ; test "entrypoints (ligo)" entrypoints_ligo ;
test "curry (mligo)" curry ;
test "type tuple destruct (mligo)" type_tuple_destruct ; test "type tuple destruct (mligo)" type_tuple_destruct ;
test "let in multi-bind (mligo)" let_in_multi_bind ; test "let in multi-bind (mligo)" let_in_multi_bind ;
test "tuple param destruct (mligo)" tuple_param_destruct ; test "tuple param destruct (mligo)" tuple_param_destruct ;