diff --git a/src/passes/1-parser/cameligo/AST.ml b/src/passes/1-parser/cameligo/AST.ml index 84aebb96e..969284b42 100644 --- a/src/passes/1-parser/cameligo/AST.ml +++ b/src/passes/1-parser/cameligo/AST.ml @@ -30,6 +30,7 @@ type kwd_else = Region.t type kwd_end = Region.t type kwd_false = Region.t type kwd_fun = Region.t +type kwd_rec = Region.t type kwd_if = Region.t type kwd_in = Region.t type kwd_let = Region.t @@ -362,6 +363,7 @@ and 'a case_clause = { and let_in = { kwd_let : kwd_let; + kwd_rec : kwd_rec option; binding : let_binding; kwd_in : kwd_in; body : expr; diff --git a/src/passes/1-parser/cameligo/LexToken.mli b/src/passes/1-parser/cameligo/LexToken.mli index 3e3460bc2..26cd6416a 100644 --- a/src/passes/1-parser/cameligo/LexToken.mli +++ b/src/passes/1-parser/cameligo/LexToken.mli @@ -95,6 +95,7 @@ type t = | End of Region.t | False of Region.t | Fun of Region.t +| Rec of Region.t | If of Region.t | In of Region.t | Let of Region.t diff --git a/src/passes/1-parser/cameligo/LexToken.mll b/src/passes/1-parser/cameligo/LexToken.mll index f17ea903a..360425c10 100644 --- a/src/passes/1-parser/cameligo/LexToken.mll +++ b/src/passes/1-parser/cameligo/LexToken.mll @@ -79,6 +79,7 @@ type t = | End of Region.t | False of Region.t | Fun of Region.t +| Rec of Region.t | If of Region.t | In of Region.t | Let of Region.t @@ -154,6 +155,7 @@ let proj_token = function | End region -> region, "End" | False region -> region, "False" | Fun region -> region, "Fun" +| Rec region -> region, "Rec" | If region -> region, "If" | In region -> region, "In" | Let region -> region, "Let" @@ -213,6 +215,7 @@ let to_lexeme = function | End _ -> "end" | False _ -> "false" | Fun _ -> "fun" +| Rec _ -> "rec" | If _ -> "if" | In _ -> "in" | Let _ -> "let" diff --git a/src/passes/1-parser/cameligo/ParToken.mly b/src/passes/1-parser/cameligo/ParToken.mly index 8319d166e..0d32e61de 100644 --- a/src/passes/1-parser/cameligo/ParToken.mly +++ b/src/passes/1-parser/cameligo/ParToken.mly @@ -59,6 +59,7 @@ %token End "end" %token False "false" %token Fun "fun" +%token Rec "rec" %token If "if" %token In "in" %token Let "let" diff --git a/src/passes/1-parser/cameligo/Parser.mly b/src/passes/1-parser/cameligo/Parser.mly index c8c0470a8..b09ea9d38 100644 --- a/src/passes/1-parser/cameligo/Parser.mly +++ b/src/passes/1-parser/cameligo/Parser.mly @@ -453,15 +453,16 @@ case_clause(right_expr): {pattern=$1; arrow=$2; rhs=$3} } let_expr(right_expr): - "let" let_binding seq(Attr) "in" right_expr { + "let" ioption("rec") let_binding seq(Attr) "in" right_expr { let kwd_let = $1 - and binding = $2 - and attributes = $3 - and kwd_in = $4 - and body = $5 in + and kwd_rec = $2 + and binding = $3 + and attributes = $4 + and kwd_in = $5 + and body = $6 in let stop = expr_to_region body in let region = cover kwd_let stop - and value = {kwd_let; binding; kwd_in; body; attributes} + and value = {kwd_let; kwd_rec; binding; kwd_in; body; attributes} in ELetIn {region; value} } fun_expr(right_expr): diff --git a/src/passes/1-parser/cameligo/ParserLog.ml b/src/passes/1-parser/cameligo/ParserLog.ml index aa847e245..36077cffc 100644 --- a/src/passes/1-parser/cameligo/ParserLog.ml +++ b/src/passes/1-parser/cameligo/ParserLog.ml @@ -544,8 +544,9 @@ and print_case_clause state {value; _} = print_expr state rhs and print_let_in state {value; _} = - let {kwd_let; binding; kwd_in; body; attributes} = value in + let {kwd_let; kwd_rec; binding; kwd_in; body; attributes} = value in print_token state kwd_let "let"; + print_token_opt state kwd_rec "rec"; print_let_binding state binding; print_attributes state attributes; print_token state kwd_in "in"; diff --git a/src/passes/1-parser/pascaligo/AST.ml b/src/passes/1-parser/pascaligo/AST.ml index 3591cb94b..b78eefd02 100644 --- a/src/passes/1-parser/pascaligo/AST.ml +++ b/src/passes/1-parser/pascaligo/AST.ml @@ -37,6 +37,7 @@ type kwd_end = Region.t type kwd_for = Region.t type kwd_from = Region.t type kwd_function = Region.t +type kwd_recursive = Region.t type kwd_if = Region.t type kwd_in = Region.t type kwd_is = Region.t @@ -201,6 +202,7 @@ and type_tuple = (type_expr, comma) nsepseq par reg (* Function and procedure declarations *) and fun_expr = { + kwd_recursive: kwd_recursive option; kwd_function : kwd_function; param : parameters; colon : colon; @@ -210,6 +212,7 @@ and fun_expr = { } and fun_decl = { + kwd_recursive: kwd_recursive option; kwd_function : kwd_function; fun_name : variable; param : parameters; diff --git a/src/passes/1-parser/pascaligo/LexToken.mli b/src/passes/1-parser/pascaligo/LexToken.mli index 620be977c..fe6c7dc3a 100644 --- a/src/passes/1-parser/pascaligo/LexToken.mli +++ b/src/passes/1-parser/pascaligo/LexToken.mli @@ -89,6 +89,7 @@ type t = | For of Region.t (* "for" *) | From of Region.t (* "from" *) | Function of Region.t (* "function" *) +| Recursive of Region.t (* "recursive" *) | If of Region.t (* "if" *) | In of Region.t (* "in" *) | Is of Region.t (* "is" *) diff --git a/src/passes/1-parser/pascaligo/LexToken.mll b/src/passes/1-parser/pascaligo/LexToken.mll index 542a36c1e..4b6ab211c 100644 --- a/src/passes/1-parser/pascaligo/LexToken.mll +++ b/src/passes/1-parser/pascaligo/LexToken.mll @@ -87,6 +87,7 @@ type t = | For of Region.t (* "for" *) | From of Region.t (* "from" *) | Function of Region.t (* "function" *) +| Recursive of Region.t (* "recursive" *) | If of Region.t (* "if" *) | In of Region.t (* "in" *) | Is of Region.t (* "is" *) @@ -199,6 +200,7 @@ let proj_token = function | For region -> region, "For" | From region -> region, "From" | Function region -> region, "Function" +| Recursive region -> region, "Recursive" | If region -> region, "If" | In region -> region, "In" | Is region -> region, "Is" @@ -289,6 +291,7 @@ let to_lexeme = function | For _ -> "for" | From _ -> "from" | Function _ -> "function" +| Recursive _ -> "recursive" | If _ -> "if" | In _ -> "in" | Is _ -> "is" diff --git a/src/passes/1-parser/pascaligo/ParToken.mly b/src/passes/1-parser/pascaligo/ParToken.mly index 11275b76e..d0880433e 100644 --- a/src/passes/1-parser/pascaligo/ParToken.mly +++ b/src/passes/1-parser/pascaligo/ParToken.mly @@ -57,6 +57,7 @@ %token False "False" %token For "for" %token Function "function" +%token Recursive "recursive" %token From "from" %token If "if" %token In "in" diff --git a/src/passes/1-parser/pascaligo/Parser.mly b/src/passes/1-parser/pascaligo/Parser.mly index f31407fca..10600d8c7 100644 --- a/src/passes/1-parser/pascaligo/Parser.mly +++ b/src/passes/1-parser/pascaligo/Parser.mly @@ -237,49 +237,52 @@ field_decl: fun_expr: - "function" parameters ":" type_expr "is" expr { - let stop = expr_to_region $6 in - let region = cover $1 stop - and value = {kwd_function = $1; - param = $2; - colon = $3; - ret_type = $4; - kwd_is = $5; - return = $6} + ioption ("recursive") "function" parameters ":" type_expr "is" expr { + let stop = expr_to_region $7 in + let region = cover $2 stop + and value = {kwd_recursive= $1; + kwd_function = $2; + param = $3; + colon = $4; + ret_type = $5; + kwd_is = $6; + return = $7} in {region; value} } (* Function declarations *) open_fun_decl: - "function" fun_name parameters ":" type_expr "is" + ioption("recursive") "function" fun_name parameters ":" type_expr "is" block "with" expr { - Scoping.check_reserved_name $2; - let stop = expr_to_region $9 in - let region = cover $1 stop - and value = {kwd_function = $1; - fun_name = $2; - param = $3; - colon = $4; - ret_type = $5; - kwd_is = $6; - block_with = Some ($7, $8); - return = $9; + Scoping.check_reserved_name $3; + let stop = expr_to_region $10 in + let region = cover $2 stop + and value = {kwd_recursive= $1; + kwd_function = $2; + fun_name = $3; + param = $4; + colon = $5; + ret_type = $6; + kwd_is = $7; + block_with = Some ($8, $9); + return = $10; terminator = None; attributes = None} in {region; value} } -| "function" fun_name parameters ":" type_expr "is" expr { - Scoping.check_reserved_name $2; - let stop = expr_to_region $7 in - let region = cover $1 stop - and value = {kwd_function = $1; - fun_name = $2; - param = $3; - colon = $4; - ret_type = $5; - kwd_is = $6; +| ioption ("recursive") "function" fun_name parameters ":" type_expr "is" expr { + Scoping.check_reserved_name $3; + let stop = expr_to_region $8 in + let region = cover $2 stop + and value = {kwd_recursive= $1; + kwd_function = $2; + fun_name = $3; + param = $4; + colon = $5; + ret_type = $6; + kwd_is = $7; block_with = None; - return = $7; + return = $8; terminator = None; attributes = None} in {region; value} } diff --git a/src/passes/1-parser/pascaligo/ParserLog.ml b/src/passes/1-parser/pascaligo/ParserLog.ml index d423006f2..93c5f7352 100644 --- a/src/passes/1-parser/pascaligo/ParserLog.ml +++ b/src/passes/1-parser/pascaligo/ParserLog.ml @@ -218,8 +218,9 @@ and print_fun_decl state {value; _} = print_terminator state terminator; and print_fun_expr state {value; _} = - let {kwd_function; param; colon; + let {kwd_recursive; kwd_function; param; colon; ret_type; kwd_is; return} : fun_expr = value in + print_token_opt state kwd_recursive "recursive"; print_token state kwd_function "function"; print_parameters state param; print_token state colon ":"; diff --git a/src/passes/1-parser/reasonligo/LexToken.mli b/src/passes/1-parser/reasonligo/LexToken.mli index 09142e23d..4a70d9d13 100644 --- a/src/passes/1-parser/reasonligo/LexToken.mli +++ b/src/passes/1-parser/reasonligo/LexToken.mli @@ -95,6 +95,7 @@ type t = | False of Region.t | If of Region.t | Let of Region.t +| Rec of Region.t | Switch of Region.t | Mod of Region.t | Or of Region.t diff --git a/src/passes/1-parser/reasonligo/LexToken.mll b/src/passes/1-parser/reasonligo/LexToken.mll index 842c0fee1..af1047860 100644 --- a/src/passes/1-parser/reasonligo/LexToken.mll +++ b/src/passes/1-parser/reasonligo/LexToken.mll @@ -80,6 +80,7 @@ type t = | False of Region.t | If of Region.t | Let of Region.t +| Rec of Region.t | Switch of Region.t | Mod of Region.t | Or of Region.t @@ -146,6 +147,7 @@ let proj_token = function | False region -> region, "False" | If region -> region, "If" | Let region -> region, "Let" +| Rec region -> region, "Rec" | Switch region -> region, "Switch" | Mod region -> region, "Mod" | NOT region -> region, "!" @@ -197,6 +199,7 @@ let to_lexeme = function | False _ -> "false" | If _ -> "if" | Let _ -> "let" +| Rec _ -> "rec" | Mod _ -> "mod" | NOT _ -> "!" | Or _ -> "or" diff --git a/src/passes/1-parser/reasonligo/ParToken.mly b/src/passes/1-parser/reasonligo/ParToken.mly index b19effeca..8191b17ec 100644 --- a/src/passes/1-parser/reasonligo/ParToken.mly +++ b/src/passes/1-parser/reasonligo/ParToken.mly @@ -59,6 +59,7 @@ %token False "false" %token If "if" %token Let "let" +%token Rec "rec" %token Switch "switch" %token Mod "mod" %token Or "or" diff --git a/src/passes/1-parser/reasonligo/Parser.mly b/src/passes/1-parser/reasonligo/Parser.mly index d24e3f832..c563628be 100644 --- a/src/passes/1-parser/reasonligo/Parser.mly +++ b/src/passes/1-parser/reasonligo/Parser.mly @@ -650,15 +650,16 @@ case_clause(right_expr): in {region; value} } let_expr(right_expr): - seq(Attr) "let" let_binding ";" right_expr { + seq(Attr) "let" ioption("rec") let_binding ";" right_expr { let attributes = $1 in let kwd_let = $2 in - let binding = $3 in - let kwd_in = $4 in - let body = $5 in - let stop = expr_to_region $5 in + let kwd_rec = $3 in + let binding = $4 in + let kwd_in = $5 in + let body = $6 in + let stop = expr_to_region $6 in let region = cover $2 stop - and value = {kwd_let; binding; kwd_in; body; attributes} + and value = {kwd_let; kwd_rec; binding; kwd_in; body; attributes} in ELetIn {region; value} } disj_expr_level: diff --git a/src/passes/2-simplify/cameligo.ml b/src/passes/2-simplify/cameligo.ml index 569df20b3..a184ea843 100644 --- a/src/passes/2-simplify/cameligo.ml +++ b/src/passes/2-simplify/cameligo.ml @@ -630,6 +630,7 @@ and simpl_fun lamb' : expr result = in let let_in: Raw.let_in = {kwd_let= Region.ghost; + kwd_rec= None; binding= let_in_binding; kwd_in= Region.ghost; body= lamb.body; diff --git a/src/test/contracts/recursion.ligo b/src/test/contracts/recursion.ligo index 839ba45ef..894993eac 100644 --- a/src/test/contracts/recursion.ligo +++ b/src/test/contracts/recursion.ligo @@ -1,4 +1,4 @@ // Test while loops in PascaLIGO -function fibo (const n : int; const acc: int) : int is +recursive function fibo (const n : int; const acc: int) : int is if n<1 then acc else fibo(n-1,acc+n) diff --git a/src/test/contracts/recursion.mligo b/src/test/contracts/recursion.mligo index f072f00b6..2b8eb4e1b 100644 --- a/src/test/contracts/recursion.mligo +++ b/src/test/contracts/recursion.mligo @@ -1,5 +1,5 @@ // Test while loops in PascaLIGO -let fibo (n : int) (acc: int) : int = +let rec fibo (n : int) (acc: int) : int = if (n < 1) then acc else fibo (n-1) (acc+n)