diff --git a/src/bin/expect_tests/contract_tests.ml b/src/bin/expect_tests/contract_tests.ml index 0141af522..3ae9bc646 100644 --- a/src/bin/expect_tests/contract_tests.ml +++ b/src/bin/expect_tests/contract_tests.ml @@ -1117,7 +1117,7 @@ let%expect_test _ = let%expect_test _ = run_ligo_bad [ "compile-contract" ; bad_contract "create_contract_toplevel.mligo" ; "main" ] ; [%expect {| -ligo: in file "create_contract_toplevel.mligo", line 4, character 35 to line 8, character 8. No free variable allowed in this lambda: variable 'store' {"expression":"CREATE_CONTRACT(lambda (#P:Some(( nat * string ))) : None return\n let rhs#712 = #P in\n let p = rhs#712.0 in\n let s = rhs#712.1 in\n ( LIST_EMPTY() : (type_operator: list(operation)) , store ) ,\n NONE() : (type_operator: option(key_hash)) ,\n 300000000mutez ,\n \"un\")","location":"in file \"create_contract_toplevel.mligo\", line 4, character 35 to line 8, character 8"} +ligo: in file "create_contract_toplevel.mligo", line 4, character 35 to line 8, character 8. No free variable allowed in this lambda: variable 'store' {"expression":"CREATE_CONTRACT(lambda (#P:Some(( nat * string ))) : None return\n let rhs#713 = #P in\n let p = rhs#713.0 in\n let s = rhs#713.1 in\n ( LIST_EMPTY() : (type_operator: list(operation)) , store ) ,\n NONE() : (type_operator: option(key_hash)) ,\n 300000000mutez ,\n \"un\")","location":"in file \"create_contract_toplevel.mligo\", line 4, character 35 to line 8, character 8"} If you're not sure how to fix this error, you can @@ -1130,7 +1130,7 @@ ligo: in file "create_contract_toplevel.mligo", line 4, character 35 to line 8, run_ligo_bad [ "compile-contract" ; bad_contract "create_contract_var.mligo" ; "main" ] ; [%expect {| -ligo: in file "create_contract_var.mligo", line 6, character 35 to line 10, character 5. No free variable allowed in this lambda: variable 'a' {"expression":"CREATE_CONTRACT(lambda (#P:Some(( nat * int ))) : None return\n let rhs#715 = #P in\n let p = rhs#715.0 in\n let s = rhs#715.1 in\n ( LIST_EMPTY() : (type_operator: list(operation)) , a ) ,\n NONE() : (type_operator: option(key_hash)) ,\n 300000000mutez ,\n 1)","location":"in file \"create_contract_var.mligo\", line 6, character 35 to line 10, character 5"} +ligo: in file "create_contract_var.mligo", line 6, character 35 to line 10, character 5. No free variable allowed in this lambda: variable 'a' {"expression":"CREATE_CONTRACT(lambda (#P:Some(( nat * int ))) : None return\n let rhs#716 = #P in\n let p = rhs#716.0 in\n let s = rhs#716.1 in\n ( LIST_EMPTY() : (type_operator: list(operation)) , a ) ,\n NONE() : (type_operator: option(key_hash)) ,\n 300000000mutez ,\n 1)","location":"in file \"create_contract_var.mligo\", line 6, character 35 to line 10, character 5"} If you're not sure how to fix this error, you can diff --git a/src/bin/expect_tests/misc_cli_commands.ml b/src/bin/expect_tests/misc_cli_commands.ml index a5a5873c0..ee67b18e0 100644 --- a/src/bin/expect_tests/misc_cli_commands.ml +++ b/src/bin/expect_tests/misc_cli_commands.ml @@ -13,7 +13,7 @@ let%expect_test _ = (* list-declarations *) let%expect_test _ = run_ligo_good [ "list-declarations" ; "../../test/contracts/loop.ligo" ] ; - [%expect {| {"source_file":"../../test/contracts/loop.ligo","declarations":["inner_capture_in_conditional_block","dummy","nested_for_collection_local_var","nested_for_collection","for_collection_map_k","for_collection_map_kv","for_collection_empty","for_collection_with_patches","for_collection_comp_with_acc","for_collection_proc_call","for_collection_rhs_capture","for_collection_if_and_local_var","for_collection_set","for_collection_list","for_sum","while_sum","counter"]} |} ]; + [%expect {| {"source_file":"../../test/contracts/loop.ligo","declarations":["inner_capture_in_conditional_block","dummy","nested_for_collection_local_var","nested_for_collection","for_collection_map_k","for_collection_map_kv","for_collection_empty","for_collection_with_patches","for_collection_comp_with_acc","for_collection_proc_call","for_collection_rhs_capture","for_collection_if_and_local_var","for_collection_set","for_collection_list","for_sum_step","for_sum","while_sum","counter"]} |} ]; run_ligo_good [ "list-declarations" ; "../../test/contracts/loop.mligo" ] ; [%expect {| {"source_file":"../../test/contracts/loop.mligo","declarations":["counter_nest","aux_nest","counter","counter_simple","aux_simple"]} |} ]; diff --git a/src/passes/1-parser/pascaligo/AST.ml b/src/passes/1-parser/pascaligo/AST.ml index 0d3a2b050..0c26f87cd 100644 --- a/src/passes/1-parser/pascaligo/AST.ml +++ b/src/passes/1-parser/pascaligo/AST.ml @@ -416,11 +416,13 @@ and for_loop = | ForCollect of for_collect reg and for_int = { - kwd_for : kwd_for; - assign : var_assign reg; - kwd_to : kwd_to; - bound : expr; - block : block reg + kwd_for : kwd_for; + assign : var_assign reg; + kwd_to : kwd_to; + bound : expr; + kwd_step : kwd_step option; + step : expr option; + block : block reg } and var_assign = { diff --git a/src/passes/1-parser/pascaligo/LexToken.mli b/src/passes/1-parser/pascaligo/LexToken.mli index fe6c7dc3a..60479955f 100644 --- a/src/passes/1-parser/pascaligo/LexToken.mli +++ b/src/passes/1-parser/pascaligo/LexToken.mli @@ -105,6 +105,7 @@ type t = | Remove of Region.t (* "remove" *) | Set of Region.t (* "set" *) | Skip of Region.t (* "skip" *) +| Step of Region.t (* "step" *) | Then of Region.t (* "then" *) | To of Region.t (* "to" *) | True of Region.t (* "True" *) diff --git a/src/passes/1-parser/pascaligo/LexToken.mll b/src/passes/1-parser/pascaligo/LexToken.mll index 24c44ab71..95035cf37 100644 --- a/src/passes/1-parser/pascaligo/LexToken.mll +++ b/src/passes/1-parser/pascaligo/LexToken.mll @@ -103,6 +103,7 @@ type t = | Remove of Region.t (* "remove" *) | Set of Region.t (* "set" *) | Skip of Region.t (* "skip" *) +| Step of Region.t (* "step" *) | Then of Region.t (* "then" *) | To of Region.t (* "to" *) | True of Region.t (* "True" *) @@ -216,6 +217,7 @@ let proj_token = function | Remove region -> region, "Remove" | Set region -> region, "Set" | Skip region -> region, "Skip" +| Step region -> region, "Step" | Then region -> region, "Then" | To region -> region, "To" | True region -> region, "True" @@ -307,6 +309,7 @@ let to_lexeme = function | Remove _ -> "remove" | Set _ -> "set" | Skip _ -> "skip" +| Step _ -> "step" | Then _ -> "then" | To _ -> "to" | True _ -> "True" @@ -368,6 +371,7 @@ let keywords = [ (fun reg -> Remove reg); (fun reg -> Set reg); (fun reg -> Skip reg); + (fun reg -> Step reg); (fun reg -> Then reg); (fun reg -> To reg); (fun reg -> True reg); @@ -605,6 +609,7 @@ let is_kwd = function | Remove _ | Set _ | Skip _ +| Step _ | Then _ | To _ | True _ diff --git a/src/passes/1-parser/pascaligo/ParToken.mly b/src/passes/1-parser/pascaligo/ParToken.mly index d0880433e..d7d587fc2 100644 --- a/src/passes/1-parser/pascaligo/ParToken.mly +++ b/src/passes/1-parser/pascaligo/ParToken.mly @@ -74,6 +74,7 @@ %token Remove "remove" %token Set "set" %token Skip "skip" +%token Step "step" %token Then "then" %token To "to" %token True "True" diff --git a/src/passes/1-parser/pascaligo/Parser.mly b/src/passes/1-parser/pascaligo/Parser.mly index eeaf1211f..1c31f92cd 100644 --- a/src/passes/1-parser/pascaligo/Parser.mly +++ b/src/passes/1-parser/pascaligo/Parser.mly @@ -623,11 +623,24 @@ while_loop: for_loop: "for" var_assign "to" expr block { let region = cover $1 $5.region in - let value = {kwd_for = $1; - assign = $2; - kwd_to = $3; - bound = $4; - block = $5} + let value = {kwd_for = $1; + assign = $2; + kwd_to = $3; + bound = $4; + kwd_step = None; + step = None; + block = $5} + in For (ForInt {region; value}) + } +| "for" var_assign "to" expr "step" expr block { + let region = cover $1 $7.region in + let value = {kwd_for = $1; + assign = $2; + kwd_to = $3; + bound = $4; + kwd_step = Some $5; + step = Some $6; + block = $7} in For (ForInt {region; value}) } | "for" var arrow_clause? "in" collection expr block { diff --git a/src/passes/1-parser/pascaligo/ParserLog.ml b/src/passes/1-parser/pascaligo/ParserLog.ml index ce543ce8f..0467d7a61 100644 --- a/src/passes/1-parser/pascaligo/ParserLog.ml +++ b/src/passes/1-parser/pascaligo/ParserLog.ml @@ -392,11 +392,19 @@ and print_for_loop state = function | ForCollect for_collect -> print_for_collect state for_collect and print_for_int state ({value; _} : for_int reg) = - let {kwd_for; assign; kwd_to; bound; block} = value in + let {kwd_for; assign; kwd_to; bound; kwd_step; step; block} = value in print_token state kwd_for "for"; print_var_assign state assign; print_token state kwd_to "to"; print_expr state bound; + match kwd_step with + | None -> (); + | Some kwd_step -> + print_token state kwd_step "step"; + match step with + | None -> (); + | Some step -> + print_expr state step; print_block state block and print_var_assign state {value; _} = diff --git a/src/passes/2-concrete_to_imperative/pascaligo.ml b/src/passes/2-concrete_to_imperative/pascaligo.ml index 8a224f69b..e6ffd7d21 100644 --- a/src/passes/2-concrete_to_imperative/pascaligo.ml +++ b/src/passes/2-concrete_to_imperative/pascaligo.ml @@ -766,10 +766,12 @@ and compile_single_instruction : Raw.instruction -> (_ -> expression result) res let binder = Var.of_name fi.assign.value.name.value in let%bind start = compile_expression fi.assign.value.expr in let%bind bound = compile_expression fi.bound in - let increment = e_int 1 in + let%bind step = match fi.step with + | None -> ok @@ e_int 1 + | Some step -> compile_expression step in let%bind body = compile_block fi.block.value in let%bind body = body @@ None in - return_statement @@ e_for ~loc binder start bound increment body + return_statement @@ e_for ~loc binder start bound step body ) | Loop (For (ForCollect fc)) -> let (fc,loc) = r_split fc in diff --git a/src/test/contracts/loop.ligo b/src/test/contracts/loop.ligo index 03c1671ba..2f4e6b554 100644 --- a/src/test/contracts/loop.ligo +++ b/src/test/contracts/loop.ligo @@ -27,6 +27,15 @@ function for_sum (var n : nat) : int is } } with acc +function for_sum_step (var n : nat) : int is + block { + var acc : int := 0; + for i := 1 to int (2n*n) step 2 + block { + acc := acc + i + } + } with acc + function for_collection_list (var nee : unit) : (int * string) is block { var acc : int := 0; diff --git a/src/test/integration_tests.ml b/src/test/integration_tests.ml index ba51a7d3d..8060c473c 100644 --- a/src/test/integration_tests.ml +++ b/src/test/integration_tests.ml @@ -1241,6 +1241,10 @@ let loop () : unit result = let make_input = e_nat in let make_expected = fun n -> e_int (n * (n + 1) / 2) in expect_eq_n_pos_mid program "for_sum" make_input make_expected in + let%bind () = + let make_input = e_nat in + let make_expected = fun n -> e_int (n * n) in + expect_eq_n_pos_mid program "for_sum_step" make_input make_expected in let input = e_unit () in let%bind () = let expected = e_pair (e_int 3) (e_string "totototo") in