Merge branch 'feature/pascaligo-anon-functions' into 'dev'

Feature/pascaligo anon functions

See merge request ligolang/ligo!201
This commit is contained in:
John David Pressman 2019-11-19 08:33:54 +00:00
commit bbcacc253b
34 changed files with 342 additions and 261 deletions

View File

@ -36,7 +36,9 @@ Here's how you define a basic function that accepts two `ints` and returns a sin
```pascaligo ```pascaligo
function add(const a: int; const b: int): int is function add(const a: int; const b: int): int is
block { skip } with a + b begin
const result: int = a + b;
end with result;
``` ```
The function body consists of two parts: The function body consists of two parts:
@ -44,9 +46,14 @@ The function body consists of two parts:
- `block {<code>}` - logic of the function - `block {<code>}` - logic of the function
- `with <value>` - the return value of the function - `with <value>` - the return value of the function
> 💡 `skip` can be used as a placeholder for empty function blocks, when all the neccessary logic fits into `with` at the end. It is also possible to omit `block { skip } with` #### Blockless functions
in the above example, leaving only `a + b`.
Functions that can contain all of their logic into a single instruction/expression, can be defined without the surrounding `block`.
Instead, you can inline the necessary logic directly, like this:
```pascaligo
function add(const a: int; const b: int): int is a + b
```
<!--Cameligo--> <!--Cameligo-->
@ -65,3 +72,25 @@ value.
<!--END_DOCUSAURUS_CODE_TABS--> <!--END_DOCUSAURUS_CODE_TABS-->
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const increment : (int -> int) = (function (const i : int) : int is i + 1);
// a = 2
const a: int = increment(1);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Anonymous functions
Functions without a name, also known as anonymous functions are useful in cases when you want to pass the function as an argument or assign it to a key in a record/map.
Here's how to define an anonymous function assigned to a variable `increment`, with it's appropriate function type signature.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const increment : (int -> int) = (function (const i : int) : int is i + 1);
// a = 2
const a: int = increment(1);
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -0,0 +1,4 @@
function add(const a: int; const b: int): int is
begin
const result: int = a + b;
end with result;

View File

@ -0,0 +1,3 @@
const increment : (int -> int) = (function (const i : int) : int is i + 1);
// a = 2
const a: int = increment(1);

View File

@ -0,0 +1 @@
function add(const a: int; const b: int): int is a + b

View File

@ -43,6 +43,9 @@ Variables, unlike constants, are mutable. They can't be used in a *global scope*
> 💡 Don't worry if you don't understand the function syntax yet. We'll get to it in upcoming sections of the docs. > 💡 Don't worry if you don't understand the function syntax yet. We'll get to it in upcoming sections of the docs.
> ⚠️ Please be wary that mutation only works within the function scope itself, values outside of the function scope will not be affected.
```pascaligo ```pascaligo
// won't work, use const for global values instead // won't work, use const for global values instead

View File

@ -18,55 +18,25 @@ const GridBlock = CompLibrary.GridBlock;
const pre = "```"; const pre = "```";
const pascaligoExampleSmall = `${pre}pascaligo const pascaligoExampleSmall = `${pre}pascaligo
// variant defining pseudo multi-entrypoint
// actions
type action is
| Increment of int
| Decrement of int
function add
(const a: int; const b: int): int is
block { skip } with a + b
function subtract
(const a: int; const b: int): int
is block { skip } with a - b
// real entrypoint that re-routes the flow
// based on the action provided
function main
(const p: action; const s: int):
(list(operation) * int) is
block { skip }
with ((nil : list(operation)),
case p of
| Increment(n) -> add(s, n)
| Decrement(n) -> subtract(s, n)
end)
${pre}`;
const pascaligoExample = `${pre}pascaligo
// variant defining pseudo multi-entrypoint actions // variant defining pseudo multi-entrypoint actions
type action is type action is
| Increment of int | Increment of int
| Decrement of int | Decrement of int
function add (const a : int ; const b : int) : int is function add (const a : int ; const b : int) : int is a + b
block { skip } with a + b
function subtract (const a : int ; const b : int) : int is function subtract (const a : int ; const b : int) : int is a - b
block { skip } with a - b
// real entrypoint that re-routes the flow based // real entrypoint that re-routes the flow based on the action provided
// on the action provided function main (const p : action ; const s : int) : (list(operation) * int) is
function main (const p : action ; const s : int) : ((nil : list(operation)),
(list(operation) * int) is
block { skip } with ((nil : list(operation)),
case p of case p of
| Increment(n) -> add(s, n) | Increment (n) -> add (s, n)
| Decrement(n) -> subtract(s, n) | Decrement (n) -> subtract (s, n)
end) end)
${pre}`; ${pre}`;
const pascaligoExample = pascaligoExampleSmall;
const cameligoExampleSmall = `${pre}ocaml const cameligoExampleSmall = `${pre}ocaml
type storage = int type storage = int

View File

@ -210,9 +210,9 @@ and type_tuple = (type_expr, comma) nsepseq par reg
(* Function and procedure declarations *) (* Function and procedure declarations *)
and fun_decl = { and fun_expr = {
kwd_function : kwd_function; kwd_function : kwd_function;
name : variable; name : variable option;
param : parameters; param : parameters;
colon : colon; colon : colon;
ret_type : type_expr; ret_type : type_expr;
@ -221,7 +221,11 @@ and fun_decl = {
block : block reg option; block : block reg option;
kwd_with : kwd_with option; kwd_with : kwd_with option;
return : expr; return : expr;
terminator : semi option }
and fun_decl = {
fun_expr : fun_expr reg ;
terminator : semi option ;
} }
and parameters = (param_decl, semi) nsepseq par reg and parameters = (param_decl, semi) nsepseq par reg
@ -266,12 +270,12 @@ and statement =
| Data of data_decl | Data of data_decl
and local_decl = and local_decl =
LocalFun of fun_decl reg
| LocalData of data_decl | LocalData of data_decl
and data_decl = and data_decl =
LocalConst of const_decl reg LocalConst of const_decl reg
| LocalVar of var_decl reg | LocalVar of var_decl reg
| LocalFun of fun_decl reg
and var_decl = { and var_decl = {
kwd_var : kwd_var; kwd_var : kwd_var;
@ -464,6 +468,7 @@ and expr =
| EUnit of c_Unit | EUnit of c_Unit
| ETuple of tuple_expr | ETuple of tuple_expr
| EPar of expr par reg | EPar of expr par reg
| EFun of fun_expr reg
and annot_expr = (expr * type_expr) and annot_expr = (expr * type_expr)
@ -644,7 +649,8 @@ let rec expr_to_region = function
| EUnit region | EUnit region
| ECase {region;_} | ECase {region;_}
| ECond {region; _} | ECond {region; _}
| EPar {region; _} -> region | EPar {region; _}
| EFun {region; _} -> region
and tuple_expr_to_region {region; _} = region and tuple_expr_to_region {region; _} = region
@ -752,7 +758,7 @@ let pattern_to_region = function
| PTuple {region; _} -> region | PTuple {region; _} -> region
let local_decl_to_region = function let local_decl_to_region = function
LocalFun {region; _} | LocalData LocalFun {region; _}
| LocalData LocalConst {region; _} | LocalData LocalConst {region; _}
| LocalData LocalVar {region; _} -> region | LocalData LocalVar {region; _} -> region

View File

@ -201,9 +201,9 @@ and type_tuple = (type_expr, comma) nsepseq par reg
(* Function declarations *) (* Function declarations *)
and fun_decl ={ and fun_expr = {
kwd_function : kwd_function; kwd_function : kwd_function;
name : variable; name : variable option;
param : parameters; param : parameters;
colon : colon; colon : colon;
ret_type : type_expr; ret_type : type_expr;
@ -212,7 +212,12 @@ and fun_decl ={
block : block reg option; block : block reg option;
kwd_with : kwd_with option; kwd_with : kwd_with option;
return : expr; return : expr;
terminator : semi option } }
and fun_decl = {
fun_expr : fun_expr reg ;
terminator : semi option ;
}
and parameters = (param_decl, semi) nsepseq par reg and parameters = (param_decl, semi) nsepseq par reg
@ -256,12 +261,12 @@ and statement =
| Data of data_decl | Data of data_decl
and local_decl = and local_decl =
LocalFun of fun_decl reg
| LocalData of data_decl | LocalData of data_decl
and data_decl = and data_decl =
LocalConst of const_decl reg LocalConst of const_decl reg
| LocalVar of var_decl reg | LocalVar of var_decl reg
| LocalFun of fun_decl reg
and var_decl = { and var_decl = {
kwd_var : kwd_var; kwd_var : kwd_var;
@ -454,6 +459,7 @@ and expr =
| EUnit of c_Unit | EUnit of c_Unit
| ETuple of tuple_expr | ETuple of tuple_expr
| EPar of expr par reg | EPar of expr par reg
| EFun of fun_expr reg
and annot_expr = (expr * type_expr) and annot_expr = (expr * type_expr)

View File

@ -239,17 +239,11 @@ field_decl:
and value = {field_name = $1; colon = $2; field_type = $3} and value = {field_name = $1; colon = $2; field_type = $3}
in {region; value} } in {region; value} }
(* Function declarations *) fun_expr:
Function option(fun_name) parameters COLON type_expr Is
fun_decl:
Function fun_name parameters COLON type_expr Is
seq(local_decl)
block block
With expr option(SEMI) { With expr {
let stop = let stop = expr_to_region $9 in
match $11 with
Some region -> region
| None -> expr_to_region $10 in
let region = cover $1 stop let region = cover $1 stop
and value = { and value = {
kwd_function = $1; kwd_function = $1;
@ -258,18 +252,15 @@ fun_decl:
colon = $4; colon = $4;
ret_type = $5; ret_type = $5;
kwd_is = $6; kwd_is = $6;
local_decls = $7; local_decls = [];
block = Some $8; block = Some $7;
kwd_with = Some $9; kwd_with = Some $8;
return = $10; return = $9;
terminator = $11} }
in {region;value}} in {region;value}}
| Function fun_name parameters COLON type_expr Is | Function option(fun_name) parameters COLON type_expr Is
expr option(SEMI) { expr {
let stop = let stop = expr_to_region $7 in
match $8 with
Some region -> region
| None -> expr_to_region $7 in
let region = cover $1 stop let region = cover $1 stop
and value = { and value = {
kwd_function = $1; kwd_function = $1;
@ -282,10 +273,36 @@ fun_decl:
block = None; block = None;
kwd_with = None; kwd_with = None;
return = $7; return = $7;
terminator = $8;
} }
in {region;value}} in {region;value}}
(* Function declarations *)
fun_decl:
fun_expr option(SEMI) {
let stop =
match $2 with
Some region -> region
| None -> $1.region in
let region = cover $1.region stop
and value = {
fun_expr = $1;
terminator = $2;
}
in {region;value}}
open_fun_decl:
fun_expr {
let region = $1.region
and value = {
fun_expr = $1;
terminator = None;
}
in {region;value}}
parameters: parameters:
par(nsepseq(param_decl,SEMI)) { $1 } par(nsepseq(param_decl,SEMI)) { $1 }
@ -341,6 +358,7 @@ statement:
open_data_decl: open_data_decl:
open_const_decl { LocalConst $1 } open_const_decl { LocalConst $1 }
| open_var_decl { LocalVar $1 } | open_var_decl { LocalVar $1 }
| open_fun_decl { LocalFun $1 }
open_const_decl: open_const_decl:
Const unqualified_decl(EQ) { Const unqualified_decl(EQ) {
@ -370,14 +388,6 @@ open_var_decl:
terminator = None} terminator = None}
in {region; value}} in {region; value}}
local_decl:
fun_decl { LocalFun $1 }
| data_decl { LocalData $1 }
data_decl:
const_decl { LocalConst $1 }
| var_decl { LocalVar $1 }
unqualified_decl(OP): unqualified_decl(OP):
var COLON type_expr OP expr { var COLON type_expr OP expr {
let region = expr_to_region $5 let region = expr_to_region $5
@ -390,12 +400,6 @@ const_decl:
} }
| open_const_decl { $1 } | open_const_decl { $1 }
var_decl:
open_var_decl SEMI {
let var_decl : AST.var_decl = $1.value in
{$1 with value = {var_decl with terminator = Some $2}}
}
| open_var_decl { $1 }
instruction: instruction:
conditional { Cond $1 } conditional { Cond $1 }
@ -683,6 +687,7 @@ expr:
case(expr) { ECase ($1 expr_to_region) } case(expr) { ECase ($1 expr_to_region) }
| cond_expr { $1 } | cond_expr { $1 }
| disj_expr { $1 } | disj_expr { $1 }
| fun_expr { EFun $1 }
cond_expr: cond_expr:
If expr Then expr option(SEMI) Else expr { If expr Then expr option(SEMI) Else expr {

View File

@ -156,12 +156,13 @@ and print_type_tuple buffer {value; _} =
print_nsepseq buffer "," print_type_expr inside; print_nsepseq buffer "," print_type_expr inside;
print_token buffer rpar ")" print_token buffer rpar ")"
and print_fun_decl buffer {value; _} = and print_fun_expr buffer {value; _} =
let {kwd_function; name; param; colon; let {kwd_function; name; param; colon;
ret_type; kwd_is; local_decls; ret_type; kwd_is; local_decls;
block; kwd_with; return; terminator} = value in block; kwd_with; return;} = value in
let anonymous_name = Region.wrap_ghost "#anonymous" in
print_token buffer kwd_function "function"; print_token buffer kwd_function "function";
print_var buffer name; print_var buffer @@ Simple_utils.Option.unopt ~default:anonymous_name name;
print_parameters buffer param; print_parameters buffer param;
print_token buffer colon ":"; print_token buffer colon ":";
print_type_expr buffer ret_type; print_type_expr buffer ret_type;
@ -173,7 +174,11 @@ and print_fun_decl buffer {value; _} =
print_token buffer kwd_with "with"; print_token buffer kwd_with "with";
| None -> (); | None -> ();
print_expr buffer return; print_expr buffer return;
print_terminator buffer terminator
and print_fun_decl buffer {value; _} =
let {fun_expr ; terminator;} = value in
print_fun_expr buffer fun_expr;
print_terminator buffer terminator;
and print_parameters buffer {value; _} = and print_parameters buffer {value; _} =
let {lpar; inside; rpar} = value in let {lpar; inside; rpar} = value in
@ -225,12 +230,12 @@ and print_local_decls buffer sequence =
List.iter (print_local_decl buffer) sequence List.iter (print_local_decl buffer) sequence
and print_local_decl buffer = function and print_local_decl buffer = function
LocalFun decl -> print_fun_decl buffer decl
| LocalData decl -> print_data_decl buffer decl | LocalData decl -> print_data_decl buffer decl
and print_data_decl buffer = function and print_data_decl buffer = function
LocalConst decl -> print_const_decl buffer decl LocalConst decl -> print_const_decl buffer decl
| LocalVar decl -> print_var_decl buffer decl | LocalVar decl -> print_var_decl buffer decl
| LocalFun decl -> print_fun_decl buffer decl
and print_var_decl buffer {value; _} = and print_var_decl buffer {value; _} =
let {kwd_var; name; colon; var_type; let {kwd_var; name; colon; var_type;
@ -402,6 +407,7 @@ and print_expr buffer = function
| EUnit r -> print_token buffer r "Unit" | EUnit r -> print_token buffer r "Unit"
| ETuple e -> print_tuple_expr buffer e | ETuple e -> print_tuple_expr buffer e
| EPar e -> print_par_expr buffer e | EPar e -> print_par_expr buffer e
| EFun e -> print_fun_expr buffer e
and print_annot_expr buffer (expr , type_expr) = and print_annot_expr buffer (expr , type_expr) =
print_expr buffer expr; print_expr buffer expr;
@ -795,7 +801,7 @@ and pp_declaration buffer ~pad:(_,pc as pad) = function
pp_const_decl buffer ~pad value pp_const_decl buffer ~pad value
| FunDecl {value; region} -> | FunDecl {value; region} ->
pp_loc_node buffer ~pad "FunDecl" region; pp_loc_node buffer ~pad "FunDecl" region;
pp_fun_decl buffer ~pad value pp_fun_expr buffer ~pad value.fun_expr.value
and pp_const_decl buffer ~pad:(_,pc) decl = and pp_const_decl buffer ~pad:(_,pc) decl =
pp_ident buffer ~pad:(mk_pad 3 0 pc) decl.name; pp_ident buffer ~pad:(mk_pad 3 0 pc) decl.name;
@ -861,12 +867,13 @@ and pp_type_tuple buffer ~pad:(_,pc) {value; _} =
pp_type_expr buffer ~pad:(mk_pad len rank pc) pp_type_expr buffer ~pad:(mk_pad len rank pc)
in List.iteri (List.length components |> apply) components in List.iteri (List.length components |> apply) components
and pp_fun_decl buffer ~pad:(_,pc) decl = and pp_fun_expr buffer ~pad:(_,pc) decl =
let fields = let fields =
if decl.local_decls = [] then 5 else 6 in if decl.local_decls = [] then 5 else 6 in
let () = let () =
let pad = mk_pad fields 0 pc in let pad = mk_pad fields 0 pc in
pp_ident buffer ~pad decl.name in let anonymous_name = Region.wrap_ghost "#anonymous" in
pp_ident buffer ~pad @@ Simple_utils.Option.unopt ~default:anonymous_name decl.name in
let () = let () =
let pad = mk_pad fields 1 pc in let pad = mk_pad fields 1 pc in
pp_node buffer ~pad "<parameters>"; pp_node buffer ~pad "<parameters>";
@ -1294,9 +1301,6 @@ and pp_local_decls buffer ~pad:(_,pc) decls =
in List.iteri (List.length decls |> apply) decls in List.iteri (List.length decls |> apply) decls
and pp_local_decl buffer ~pad:(_,pc as pad) = function and pp_local_decl buffer ~pad:(_,pc as pad) = function
LocalFun {value; region} ->
pp_loc_node buffer ~pad "LocalFun" region;
pp_fun_decl buffer ~pad value
| LocalData data -> | LocalData data ->
pp_node buffer ~pad "LocalData"; pp_node buffer ~pad "LocalData";
pp_data_decl buffer ~pad:(mk_pad 1 0 pc) data pp_data_decl buffer ~pad:(mk_pad 1 0 pc) data
@ -1308,6 +1312,9 @@ and pp_data_decl buffer ~pad = function
| LocalVar {value; region} -> | LocalVar {value; region} ->
pp_loc_node buffer ~pad "LocalVar" region; pp_loc_node buffer ~pad "LocalVar" region;
pp_var_decl buffer ~pad value pp_var_decl buffer ~pad value
| LocalFun {value; region} ->
pp_loc_node buffer ~pad "LocalFun" region;
pp_fun_expr buffer ~pad value.fun_expr.value
and pp_var_decl buffer ~pad:(_,pc) decl = and pp_var_decl buffer ~pad:(_,pc) decl =
pp_ident buffer ~pad:(mk_pad 3 0 pc) decl.name; pp_ident buffer ~pad:(mk_pad 3 0 pc) decl.name;
@ -1368,6 +1375,9 @@ and pp_expr buffer ~pad:(_,pc as pad) = function
| EPar {value; region} -> | EPar {value; region} ->
pp_loc_node buffer ~pad "EPar" region; pp_loc_node buffer ~pad "EPar" region;
pp_expr buffer ~pad:(mk_pad 1 0 pc) value.inside pp_expr buffer ~pad:(mk_pad 1 0 pc) value.inside
| EFun {value; region} ->
pp_loc_node buffer ~pad "EFun" region;
pp_fun_expr ~pad buffer value;
and pp_list_expr buffer ~pad:(_,pc as pad) = function and pp_list_expr buffer ~pad:(_,pc as pad) = function
ECons {value; region} -> ECons {value; region} ->

View File

@ -117,6 +117,22 @@ module Errors = struct
] in ] in
error ~data title message error ~data title message
let unexpected_anonymous_function loc =
let title () = "unexpected anonymous function" in
let message () = "you provided a function declaration without name" in
let data = [
("loc" , fun () -> Format.asprintf "%a" Location.pp @@ loc)
] in
error ~data title message
let unexpected_named_function loc =
let title () = "unexpected named function" in
let message () = "you provided a function expression with a name (remove it)" in
let data = [
("loc" , fun () -> Format.asprintf "%a" Location.pp @@ loc)
] in
error ~data title message
(* Logging *) (* Logging *)
let simplifying_instruction t = let simplifying_instruction t =
@ -410,6 +426,13 @@ let rec simpl_expression (t:Raw.expr) : expr result =
let%bind index = simpl_expression lu.index.value.inside in let%bind index = simpl_expression lu.index.value.inside in
return @@ e_look_up ~loc path index return @@ e_look_up ~loc path index
) )
| EFun f -> (
let (f , loc) = r_split f in
let%bind ((name_opt , _ty_opt) , f') = simpl_fun_expression ~loc f in
match name_opt with
| None -> return @@ f'
| Some _ -> fail @@ unexpected_named_function loc
)
and simpl_logic_expression (t:Raw.logic_expr) : expression result = and simpl_logic_expression (t:Raw.logic_expr) : expression result =
let return x = ok x in let return x = ok x in
@ -497,10 +520,6 @@ and simpl_local_declaration : Raw.local_decl -> _ result = fun t ->
match t with match t with
| LocalData d -> | LocalData d ->
simpl_data_declaration d simpl_data_declaration d
| LocalFun f ->
let (f , loc) = r_split f in
let%bind (name , e) = simpl_fun_declaration ~loc f in
return_let_in ~loc name e
and simpl_data_declaration : Raw.data_decl -> _ result = fun t -> and simpl_data_declaration : Raw.data_decl -> _ result = fun t ->
match t with match t with
@ -516,6 +535,11 @@ and simpl_data_declaration : Raw.data_decl -> _ result = fun t ->
let%bind t = simpl_type_expression x.const_type in let%bind t = simpl_type_expression x.const_type in
let%bind expression = simpl_expression x.init in let%bind expression = simpl_expression x.init in
return_let_in ~loc (name , Some t) expression return_let_in ~loc (name , Some t) expression
| LocalFun f ->
let (f , loc) = r_split f in
let%bind ((name_opt , ty_opt) , e) = simpl_fun_expression ~loc f.fun_expr.value in
let%bind name = trace_option (unexpected_anonymous_function loc) name_opt in
return_let_in ~loc (name , ty_opt) e
and simpl_param : Raw.param_decl -> (type_name * type_expression) result = and simpl_param : Raw.param_decl -> (type_name * type_expression) result =
fun t -> fun t ->
@ -531,11 +555,11 @@ and simpl_param : Raw.param_decl -> (type_name * type_expression) result =
let%bind type_expression = simpl_type_expression c.param_type in let%bind type_expression = simpl_type_expression c.param_type in
ok (type_name , type_expression) ok (type_name , type_expression)
and simpl_fun_declaration : and simpl_fun_expression :
loc:_ -> Raw.fun_decl -> ((name * type_expression option) * expression) result = loc:_ -> Raw.fun_expr -> ((name option * type_expression option) * expression) result =
fun ~loc x -> fun ~loc x ->
let open! Raw in let open! Raw in
let {name;param;ret_type;local_decls;block;return} : fun_decl = x in let {name;param;ret_type;local_decls;block;return} : fun_expr = x in
let statements = let statements =
match block with match block with
| Some block -> npseq_to_list block.value.statements | Some block -> npseq_to_list block.value.statements
@ -544,7 +568,7 @@ and simpl_fun_declaration :
(match param.value.inside with (match param.value.inside with
a, [] -> ( a, [] -> (
let%bind input = simpl_param a in let%bind input = simpl_param a in
let name = name.value in let name = Option.map (fun (x : _ reg) -> x.value) name in
let (binder , input_type) = input in let (binder , input_type) = input in
let%bind local_declarations = let%bind local_declarations =
bind_map_list simpl_local_declaration local_decls in bind_map_list simpl_local_declaration local_decls in
@ -591,7 +615,8 @@ and simpl_fun_declaration :
let expression = let expression =
e_lambda ~loc binder (Some input_type) (Some output_type) result in e_lambda ~loc binder (Some input_type) (Some output_type) result in
let type_annotation = Some (T_function (input_type, output_type)) in let type_annotation = Some (T_function (input_type, output_type)) in
ok ((name.value , type_annotation) , expression) let name = Option.map (fun (x : _ reg) -> x.value) name in
ok ((name , type_annotation) , expression)
) )
) )
and simpl_declaration : Raw.declaration -> declaration Location.wrap result = and simpl_declaration : Raw.declaration -> declaration Location.wrap result =
@ -614,7 +639,8 @@ and simpl_declaration : Raw.declaration -> declaration Location.wrap result =
bind_map_location simpl_const_decl (Location.lift_region x) bind_map_location simpl_const_decl (Location.lift_region x)
| FunDecl x -> ( | FunDecl x -> (
let (x , loc) = r_split x in let (x , loc) = r_split x in
let%bind ((name , ty_opt) , expr) = simpl_fun_declaration ~loc x in let%bind ((name_opt , ty_opt) , expr) = simpl_fun_expression ~loc x.fun_expr.value in
let%bind name = trace_option (unexpected_anonymous_function loc) name_opt in
ok @@ Location.wrap ~loc (Declaration_constant (name , ty_opt , expr)) ok @@ Location.wrap ~loc (Declaration_constant (name , ty_opt , expr))
) )

View File

@ -2,8 +2,8 @@ type storage_ is big_map(int, int) * unit
type foo is big_map(int, int) type foo is big_map(int, int)
function main(const p : unit; const s : storage_) : list(operation) * storage_ is function main(const p : unit; const s : storage_) : list(operation) * storage_ is
var toto : option (int) := Some(0);
block { block {
var toto : option (int) := Some(0);
toto := s.0[23]; toto := s.0[23];
s.0[2] := 444; s.0[2] := 444;
} }

View File

@ -1,4 +1,5 @@
function foo (const i : int) : int is function foo (const i : int) : int is
block {
function bar (const j : int) : int is function bar (const j : int) : int is
block { skip } with i + j ; i + j ;
block { skip } with bar (i) } with bar (i)

View File

@ -1,5 +1,6 @@
function foobar(const i : int) : int is function foobar(const i : int) : int is
block {
const j : int = 3 ; const j : int = 3 ;
function toto(const k : int) : int is function toto(const k : int) : int is
block { skip } with i + j + k ; i + j + k ;
block { skip } with toto(42) } with toto(42)

View File

@ -3,8 +3,10 @@
// https://gitlab.com/ligolang/ligo/commit/faf3bbc06106de98189f1c1673bd57e78351dc7e // https://gitlab.com/ligolang/ligo/commit/faf3bbc06106de98189f1c1673bd57e78351dc7e
function foobar(const i : int) : int is function foobar(const i : int) : int is
block {
const j : int = 3 ; const j : int = 3 ;
const k : int = 4 ; const k : int = 4 ;
function toto(const l : int) : int is function toto(const l : int) : int is
block { skip } with i + j + k + l; i + j + k + l;
block { skip } with toto(42)
} with toto(42)

View File

@ -1,6 +1,7 @@
function toto (const i : int) : int is function toto (const i : int) : int is
block {
function tata (const j : int) : int is function tata (const j : int) : int is
block { skip } with i + j ; i + j ;
function titi (const j : int) : int is function titi (const j : int) : int is
block { skip } with i + j ; i + j ;
block { skip } with tata(i) + titi(i) } with tata(i) + titi(i)

View File

@ -1,8 +1,8 @@
// Test if conditional in PascaLIGO // Test if conditional in PascaLIGO
function main (const i : int) : int is function main (const i : int) : int is
var result : int := 23 ;
begin begin
var result : int := 23 ;
if i = 2 then if i = 2 then
result := 42 result := 42
else else
@ -10,7 +10,7 @@ function main (const i : int) : int is
end with result end with result
function foo (const b : bool) : int is function foo (const b : bool) : int is
var x : int := 41 ;
begin begin
var x : int := 41 ;
x := 1 + (if b then x else main(x)) ; x := 1 + (if b then x else main(x)) ;
end with x end with x

View File

@ -3,20 +3,17 @@ type pii is (int*int)
type ppi is record x:pii; y:pii end type ppi is record x:pii; y:pii end
type ppp is (ppi*ppi) type ppp is (ppi*ppi)
function main (const toto : unit) : int is function main (const toto : unit) : int is block {
var a : ppp := var a : ppp := (
( record
record x = (0,1);
x = (0,1); y = (10,11);
y = (10,11); end ,
end record
, x = (100,101);
record y = (110,111);
x = (100,101); end
y = (110,111); ) ;
end
)
begin
a.0.x.0 := 2; a.0.x.0 := 2;
const b:int = a.0.x.0; const b:int = a.0.x.0;
end with b } with b

View File

@ -12,8 +12,8 @@ function main (const p : param; const s : unit) : list(operation) * unit is
with ((nil : list(operation)), s) with ((nil : list(operation)), s)
function foobar (const i : int) : int is function foobar (const i : int) : int is
var p : param := Zero (42n) ;
block { block {
var p : param := Zero (42n) ;
if i > 0 then block { if i > 0 then block {
i := i + 1 ; i := i + 1 ;
if i > 10 then block { if i > 10 then block {

View File

@ -0,0 +1 @@
const x : int = (function (const i : int) : int is i + 1)(41)

View File

@ -1,9 +1,9 @@
// Test a PascaLIGO function with more complex logic than function.ligo // Test a PascaLIGO function with more complex logic than function.ligo
function main (const i : int) : int is function main (const i : int) : int is
begin
var j : int := 0 ; var j : int := 0 ;
var k : int := 1 ; var k : int := 1 ;
begin
j := k + i ; j := k + i ;
k := i + j ; k := i + j ;
end with (k + j) end with (k + j)

View File

@ -1,10 +1,11 @@
// Test a PascaLIGO function which takes another PascaLIGO function as an argument // Test a PascaLIGO function which takes another PascaLIGO function as an argument
function foobar (const i : int) : int is function foobar (const i : int) : int is
block {
function foo (const i : int) : int is function foo (const i : int) : int is
block { skip } with i ; i ;
function bar (const f : int -> int) : int is function bar (const f : int -> int) : int is
block { skip } with f ( i ) ; f ( i ) ;
block { skip } with bar (foo) ; } with bar (foo) ;
// higher order function with more than one argument // higher order function with more than one argument
function higher2(const i: int; const f: int -> int): int is function higher2(const i: int; const f: int -> int): int is
@ -13,27 +14,26 @@ function higher2(const i: int; const f: int -> int): int is
} with ii } with ii
function foobar2 (const i : int) : int is function foobar2 (const i : int) : int is
block {
function foo2 (const i : int) : int is function foo2 (const i : int) : int is
block { skip } with i; i;
block { skip } with higher2(i,foo2) } with higher2(i,foo2)
const a : int = 0; const a : int = 0;
function foobar3 (const i : int) : int is function foobar3 (const i : int) : int is
block {
function foo2 (const i : int) : int is function foo2 (const i : int) : int is
block { skip } with (a+i); (a+i);
block { skip } with higher2(i,foo2) } with higher2(i,foo2)
function f (const i : int) : int is function f (const i : int) : int is
block { skip } i
with i
function g (const i : int) : int is function g (const i : int) : int is
block { skip } f(i)
with f(i)
function foobar4 (const i : int) : int is function foobar4 (const i : int) : int is
block { skip } g(g(i))
with g(g(i))
function higher3(const i: int; const f: int -> int; const g: int -> int): int is function higher3(const i: int; const f: int -> int; const g: int -> int): int is
block { block {
@ -41,9 +41,10 @@ function higher3(const i: int; const f: int -> int; const g: int -> int): int is
} with ii } with ii
function foobar5 (const i : int) : int is function foobar5 (const i : int) : int is
block {
const a : int = 0; const a : int = 0;
function foo (const i : int) : int is function foo (const i : int) : int is
block { skip } with (a+i); (a+i);
function goo (const i : int) : int is function goo (const i : int) : int is
block { skip } with foo(i); foo(i);
block { skip } with higher3(i,foo,goo) } with higher3(i,foo,goo)

View File

@ -2,5 +2,6 @@ function f (const x : unit) : unit is
begin skip end with unit begin skip end with unit
function main (const p : unit ; const s : unit) : unit is function main (const p : unit ; const s : unit) : unit is
begin
var y : unit := f(unit) ; var y : unit := f(unit) ;
begin skip end with y end with y

View File

@ -25,15 +25,16 @@ const bl : foobar = list
end end
function iter_op (const s : list(int)) : int is function iter_op (const s : list(int)) : int is
begin
var r : int := 0 ; var r : int := 0 ;
function aggregate (const i : int) : unit is function aggregate (const i : int) : unit is
begin begin
r := r + i ; r := r + i ;
end with unit end with unit ;
begin
list_iter(s , aggregate) ; list_iter(s , aggregate) ;
end with r end with r
function map_op (const s : list(int)) : list(int) is function map_op (const s : list(int)) : list(int) is
block {
function increment (const i : int) : int is block { skip } with i + 1 function increment (const i : int) : int is block { skip } with i + 1
block { skip } with list_map(s , increment) } with list_map(s , increment)

View File

@ -48,23 +48,25 @@ function get_ (const m : foobar) : option(int) is
end with map_get(42 , m) end with map_get(42 , m)
function iter_op (const m : foobar) : unit is function iter_op (const m : foobar) : unit is
block {
function aggregate (const i : int ; const j : int) : unit is block function aggregate (const i : int ; const j : int) : unit is block
{ if (i=j) then skip else failwith("fail") } with unit ; { if (i=j) then skip else failwith("fail") } with unit ;
block {skip}
// map_iter(m , aggregate) ; // map_iter(m , aggregate) ;
with map_iter(m, aggregate) ; } with map_iter(m, aggregate) ;
function map_op (const m : foobar) : foobar is function map_op (const m : foobar) : foobar is
block {
function increment (const i : int ; const j : int) : int is block { skip } with j + 1 ; function increment (const i : int ; const j : int) : int is block { skip } with j + 1 ;
block { skip } with map_map(m , increment) ; } with map_map(m , increment) ;
function fold_op (const m : foobar) : int is function fold_op (const m : foobar) : int is
block {
function aggregate (const i : int ; const j : (int * int)) : int is block { skip } with i + j.0 + j.1 ; function aggregate (const i : int ; const j : (int * int)) : int is block { skip } with i + j.0 + j.1 ;
block { skip } with map_fold(m , 10 , aggregate) } with map_fold(m , 10 , aggregate)
function deep_op (var m : foobar) : foobar is function deep_op (var m : foobar) : foobar is
var coco : (int*foobar) := (0, m); block {
block { var coco : (int*foobar) := (0, m);
remove 42 from map coco.1 ; remove 42 from map coco.1 ;
coco.1[32] := 16 ; coco.1[32] := 16 ;
} with coco.1 } with coco.1

View File

@ -1,8 +1,8 @@
// Test the pattern matching functionality of PascaLIGO // Test the pattern matching functionality of PascaLIGO
function match_bool (const i : int) : int is function match_bool (const i : int) : int is
var result : int := 23 ;
begin begin
var result : int := 23 ;
case i = 2 of case i = 2 of
| True -> result := 42 | True -> result := 42
| False -> result := 0 | False -> result := 0
@ -10,8 +10,8 @@ function match_bool (const i : int) : int is
end with result end with result
function match_option (const o : option(int)) : int is function match_option (const o : option(int)) : int is
var result : int := 23 ;
begin begin
var result : int := 23 ;
case o of case o of
| None -> skip | None -> skip
| Some (s) -> result := s | Some (s) -> result := s
@ -19,21 +19,18 @@ function match_option (const o : option(int)) : int is
end with result end with result
function match_expr_bool (const i : int) : int is function match_expr_bool (const i : int) : int is
begin skip end with
case i = 2 of case i = 2 of
| True -> 42 | True -> 42
| False -> 0 | False -> 0
end end
function match_expr_option (const o : option(int)) : int is function match_expr_option (const o : option(int)) : int is
begin skip end with
case o of case o of
| None -> 42 | None -> 42
| Some (s) -> s | Some (s) -> s
end end
function match_expr_list (const l : list(int)) : int is function match_expr_list (const l : list(int)) : int is
begin skip end with
case l of case l of
| nil -> -1 | nil -> -1
| hd # tl -> hd | hd # tl -> hd

View File

@ -6,10 +6,8 @@ const s : foobar = Some(42)
const n : foobar = None const n : foobar = None
function assign (var m : int) : foobar is function assign (var m : int) : foobar is
block {
var coco : foobar := None; var coco : foobar := None;
block
{
coco := Some(m); coco := Some(m);
coco := None; coco := None;
} } with coco
with coco

View File

@ -1,16 +1,17 @@
// Test set iteration in PascaLIGO // Test set iteration in PascaLIGO
function iter_op (const s : set(int)) : int is function iter_op (const s : set(int)) : int is
begin
var r : int := 0 ; var r : int := 0 ;
function aggregate (const i : int) : unit is function aggregate (const i : int) : unit is
begin begin
r := r + i ; r := r + i ;
end with unit end with unit ;
begin
set_iter(s , aggregate) ; set_iter(s , aggregate) ;
end with r end with r
function fold_op (const s : set(int)) : int is function fold_op (const s : set(int)) : int is
block {
function aggregate (const i : int ; const j : int) : int is function aggregate (const i : int ; const j : int) : int is
block { skip } with i + j i + j
block { skip } with set_fold(s , 15 , aggregate) } with set_fold(s , 15 , aggregate)

View File

@ -1,4 +1,5 @@
function foo (const i : int) : int is function foo (const i : int) : int is
block {
function bar (const i : int) : int is function bar (const i : int) : int is
block { skip } with i ; i ;
block { skip } with bar (0) } with bar (0)

View File

@ -7,10 +7,10 @@ end
type mpi is map(string,int) type mpi is map(string,int)
function main (const toto : tpi) : int is function main (const toto : tpi) : int is
begin
var a : tpi := toto; var a : tpi := toto;
var b : rpi := record x = 0; y=1 ; end; var b : rpi := record x = 0; y=1 ; end;
var m : mpi := map "y" -> 1; end; var m : mpi := map "y" -> 1; end;
begin
a.0 := 2; a.0 := 2;
b.x := a.0; b.x := a.0;
m["x"] := b.x; m["x"] := b.x;

View File

@ -3,15 +3,13 @@ type action is
| Increment of int | Increment of int
| Decrement of int | Decrement of int
function add (const a : int ; const b : int) : int is function add (const a : int ; const b : int) : int is a + b
block { skip } with a + b
function subtract (const a : int ; const b : int) : int is function subtract (const a : int ; const b : int) : int is a - b
block { skip } with 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
function main (const p : action ; const s : int) : (list(operation) * int) is function main (const p : action ; const s : int) : (list(operation) * int) is
block {skip} with ((nil : list(operation)), ((nil : list(operation)),
case p of case p of
| Increment (n) -> add (s, n) | Increment (n) -> add (s, n)
| Decrement (n) -> subtract (s, n) | Decrement (n) -> subtract (s, n)

View File

@ -52,6 +52,13 @@ let complex_function () : unit result =
let make_expect = fun n -> (3 * n + 2) in let make_expect = fun n -> (3 * n + 2) in
expect_eq_n_int program "main" make_expect expect_eq_n_int program "main" make_expect
let anon_function () : unit result =
let%bind program = type_file "./contracts/function-anon.ligo" in
let%bind () =
expect_eq_evaluate program "x" (e_int 42)
in
ok ()
let application () : unit result = let application () : unit result =
let%bind program = type_file "./contracts/application.ligo" in let%bind program = type_file "./contracts/application.ligo" in
let%bind () = let%bind () =
@ -1196,6 +1203,7 @@ let main = test_suite "Integration (End to End)" [
test "assign" assign ; test "assign" assign ;
test "declaration local" declaration_local ; test "declaration local" declaration_local ;
test "complex function" complex_function ; test "complex function" complex_function ;
test "anon function" anon_function ;
test "various applications" application ; test "various applications" application ;
test "closure" closure ; test "closure" closure ;
test "shared function" shared_function ; test "shared function" shared_function ;

View File

@ -108,6 +108,8 @@ let make ~(start: Pos.t) ~(stop: Pos.t) =
let ghost = make ~start:Pos.ghost ~stop:Pos.ghost let ghost = make ~start:Pos.ghost ~stop:Pos.ghost
let wrap_ghost value = {value ; region = ghost}
let min = make ~start:Pos.min ~stop:Pos.min let min = make ~start:Pos.min ~stop:Pos.min
(* Comparisons *) (* Comparisons *)

View File

@ -96,6 +96,11 @@ val make : start:Pos.t -> stop:Pos.t -> t
val ghost : t (* Two [Pos.ghost] positions *) val ghost : t (* Two [Pos.ghost] positions *)
(* This wraps a value with a ghost region. *)
val wrap_ghost : 'a -> 'a reg
(* Occasionnally, we may need a minimum region. It is here made of two (* Occasionnally, we may need a minimum region. It is here made of two
minimal positions. *) minimal positions. *)