Letrec and letfun #556
@ -798,7 +798,7 @@ check_sccs(Env = #env{}, Funs, [{acyclic, X} | SCCs], Acc) ->
|
||||
end;
|
||||
check_sccs(Env = #env{}, Funs, [{cyclic, Xs} | SCCs], Acc) ->
|
||||
Defs = [ maps:get(X, Funs) || X <- Xs ],
|
||||
{TypeSigs, {letrec, _, Defs1}} = infer_letrec(Env, {letrec, [], Defs}),
|
||||
{TypeSigs, Defs1} = infer_letrec(Env, Defs),
|
||||
Env1 = bind_funs(TypeSigs, Env),
|
||||
check_sccs(Env1, Funs, SCCs, Defs1 ++ Acc).
|
||||
|
||||
@ -840,7 +840,7 @@ check_special_funs(_, _) -> ok.
|
||||
|
||||
typesig_to_fun_t({type_sig, Ann, Named, Args, Res}) -> {fun_t, Ann, Named, Args, Res}.
|
||||
|
||||
infer_letrec(Env, {letrec, Attrs, Defs}) ->
|
||||
infer_letrec(Env, Defs) ->
|
||||
create_constraints(),
|
||||
Funs = [{Name, fresh_uvar(A)}
|
||||
|| {letfun, _, {id, A, Name}, _, _, _} <- Defs],
|
||||
@ -860,7 +860,7 @@ infer_letrec(Env, {letrec, Attrs, Defs}) ->
|
||||
TypeSigs = instantiate([Sig || {Sig, _} <- Inferred]),
|
||||
NewDefs = instantiate([D || {_, D} <- Inferred]),
|
||||
[print_typesig(S) || S <- TypeSigs],
|
||||
{TypeSigs, {letrec, Attrs, NewDefs}}.
|
||||
{TypeSigs, NewDefs}.
|
||||
|
||||
infer_letfun(Env, {letfun, Attrib, {id, NameAttrib, Name}, Args, What, Body}) ->
|
||||
ArgTypes = [{ArgName, check_type(Env, arg_type(T))} || {arg, _, ArgName, T} <- Args],
|
||||
@ -1133,12 +1133,11 @@ infer_case(Env, Attrs, Pattern, ExprType, Branch, SwitchType) ->
|
||||
%% NewStmts = infer_block(Env, Attrs, Stmts, BlockType)
|
||||
infer_block(_Env, Attrs, [], BlockType) ->
|
||||
error({impossible, empty_block, Attrs, BlockType});
|
||||
infer_block(Env, Attrs, [Def={letfun, _, _, _, _, _}|Rest], BlockType) ->
|
||||
NewDef = infer_letfun(Env, Def),
|
||||
[NewDef|infer_block(Env, Attrs, Rest, BlockType)];
|
||||
infer_block(Env, Attrs, [Def={letrec, _, _}|Rest], BlockType) ->
|
||||
NewDef = infer_letrec(Env, Def),
|
||||
[NewDef|infer_block(Env, Attrs, Rest, BlockType)];
|
||||
infer_block(Env, Attrs, [Def={letfun, Ann, _, _, _, _}|Rest], BlockType) ->
|
||||
{{Name, TypeSig}, LetFun} = infer_letfun(Env, Def),
|
||||
FunT = freshen_type(typesig_to_fun_t(TypeSig)),
|
||||
NewE = bind_var({id, Ann, Name}, FunT, Env),
|
||||
[LetFun|infer_block(NewE, Attrs, Rest, BlockType)];
|
||||
infer_block(Env, _, [{letval, Attrs, Pattern, Type, E}|Rest], BlockType) ->
|
||||
NewE = {typed, _, _, PatType} = infer_expr(Env, {typed, Attrs, E, arg_type(Type)}),
|
||||
{'case', _, NewPattern, {typed, _, {block, _, NewRest}, _}} =
|
||||
|
@ -722,6 +722,9 @@ decision_tree_to_fcode({'if', A, Then, Else}) ->
|
||||
-spec stmts_to_fcode(env(), [aeso_syntax:stmt()]) -> fexpr().
|
||||
stmts_to_fcode(Env, [{letval, _, {typed, _, {id, _, X}, _}, _, Expr} | Stmts]) ->
|
||||
{'let', X, expr_to_fcode(Env, Expr), stmts_to_fcode(bind_var(Env, X), Stmts)};
|
||||
stmts_to_fcode(Env, [{letfun, Ann, {id, _, X}, Args, _Type, Expr} | Stmts]) ->
|
||||
{'let', X, expr_to_fcode(Env, {lam, Ann, Args, Expr}),
|
||||
stmts_to_fcode(bind_var(Env, X), Stmts)};
|
||||
stmts_to_fcode(Env, [Expr]) ->
|
||||
expr_to_fcode(Env, Expr);
|
||||
stmts_to_fcode(Env, [Expr | Stmts]) ->
|
||||
|
@ -102,13 +102,6 @@ contract_to_icode([{letfun, Attrib, Name, Args, _What, Body={typed,_,_,T}}|Rest]
|
||||
QName = aeso_icode:qualify(Name, Icode),
|
||||
NewIcode = ast_fun_to_icode(ast_id(QName), FunAttrs, FunArgs, FunBody, TypeRep, Icode),
|
||||
contract_to_icode(Rest, NewIcode);
|
||||
contract_to_icode([{letrec,_,Defs}|Rest], Icode) ->
|
||||
%% OBS! This code ignores the letrec structure of the source,
|
||||
%% because the back end treats ALL declarations as recursive! We
|
||||
%% need to decide whether to (a) modify the back end to respect
|
||||
%% the letrec structure, or (b) (preferably) modify the front end
|
||||
%% just to parse a list of (mutually recursive) definitions.
|
||||
contract_to_icode(Defs++Rest, Icode);
|
||||
contract_to_icode([], Icode) -> Icode;
|
||||
contract_to_icode([{fun_decl, _, _, _} | Code], Icode) ->
|
||||
contract_to_icode(Code, Icode);
|
||||
@ -530,6 +523,8 @@ ast_body({switch,_,A,Cases}, Icode) ->
|
||||
ast_body({block,As,[{letval,_,Pat,_,E}|Rest]}, Icode) ->
|
||||
#switch{expr=ast_body(E, Icode),
|
||||
cases=[{ast_body(Pat, Icode),ast_body({block,As,Rest}, Icode)}]};
|
||||
ast_body({block, As, [{letfun, Ann, F, Args, _Type, Expr} | Rest]}, Icode) ->
|
||||
ast_body({block, As, [{letval, Ann, F, unused, {lam, Ann, Args, Expr}} | Rest]}, Icode);
|
||||
ast_body({block,_,[]}, _Icode) ->
|
||||
#tuple{cpts=[]};
|
||||
ast_body({block,_,[E]}, Icode) ->
|
||||
|
@ -241,7 +241,7 @@ to_scode(Env, {remote, Ct, Fun, [{builtin, call_gas_left, _}, Value | Args]}) ->
|
||||
Call = if Env#env.tailpos -> aeb_fate_code:call_tr(?a, Lbl, ?a);
|
||||
true -> aeb_fate_code:call_r(?a, Lbl, ?a)
|
||||
end,
|
||||
call_to_scode(Env, [to_scode(Env, Value), to_scode(Env, Ct), Call], Args);
|
||||
call_to_scode(Env, Call, [Ct, Value | Args]);
|
||||
|
||||
to_scode(Env, {remote, Ct, Fun, [Gas, Value | Args]}) ->
|
||||
%% Gas is limited.
|
||||
@ -249,10 +249,7 @@ to_scode(Env, {remote, Ct, Fun, [Gas, Value | Args]}) ->
|
||||
Call = if Env#env.tailpos -> aeb_fate_code:call_gtr(?a, Lbl, ?a, ?a);
|
||||
true -> aeb_fate_code:call_gr(?a, Lbl, ?a, ?a)
|
||||
end,
|
||||
call_to_scode(Env, [to_scode(Env, Gas),
|
||||
to_scode(Env, Value),
|
||||
to_scode(Env, Ct), Call],
|
||||
Args);
|
||||
call_to_scode(Env, Call, [Ct, Value, Gas | Args]);
|
||||
|
||||
to_scode(Env, {closure, Fun, FVs}) ->
|
||||
to_scode(Env, {tuple, [{lit, {string, make_function_name(Fun)}}, FVs]});
|
||||
|
@ -87,7 +87,7 @@ constructors() ->
|
||||
sep1(constructor(), tok('|')).
|
||||
|
||||
constructor() -> %% TODO: format for Con() vs Con
|
||||
choice(?RULE(con(), {constr_t, get_ann(_1), _1, []}),
|
||||
choice(?RULE(con(), {constr_t, get_ann(_1), _1, []}),
|
||||
?RULE(con(), con_args(), {constr_t, get_ann(_1), _1, _2})).
|
||||
|
||||
con_args() -> paren_list(con_arg()).
|
||||
@ -99,9 +99,7 @@ con_arg() -> choice(type(), ?RULE(keyword(indexed), type(), set_ann(indexed,
|
||||
%% -- Let declarations -------------------------------------------------------
|
||||
|
||||
letdecl() ->
|
||||
choice(
|
||||
?RULE(keyword('let'), letdef(), set_pos(get_pos(_1), _2)),
|
||||
?RULE(keyword('let'), tok(rec), sep1(letdef(), tok('and')), {letrec, _1, _3})).
|
||||
?RULE(keyword('let'), letdef(), set_pos(get_pos(_1), _2)).
|
||||
|
||||
letdef() -> choice(valdef(), fundef()).
|
||||
|
||||
|
@ -160,8 +160,7 @@ decl(D = {letfun, Attrs, _, _, _, _}) ->
|
||||
text(atom_to_list(Mod));
|
||||
(_) -> empty() end,
|
||||
hsep(lists:map(Mod, Attrs) ++ [letdecl("function", D)]);
|
||||
decl(D = {letval, _, _, _, _}) -> letdecl("let", D);
|
||||
decl(D = {letrec, _, _}) -> letdecl("let", D).
|
||||
decl(D = {letval, _, _, _, _}) -> letdecl("let", D).
|
||||
|
||||
-spec expr(aeso_syntax:expr(), options()) -> doc().
|
||||
expr(E, Options) ->
|
||||
@ -184,9 +183,7 @@ name({typed, _, Name, _}) -> name(Name).
|
||||
letdecl(Let, {letval, _, F, T, E}) ->
|
||||
block_expr(0, hsep([text(Let), typed(name(F), T), text("=")]), E);
|
||||
letdecl(Let, {letfun, _, F, Args, T, E}) ->
|
||||
block_expr(0, hsep([text(Let), typed(beside(name(F), args(Args)), T), text("=")]), E);
|
||||
letdecl(Let, {letrec, _, [D | Ds]}) ->
|
||||
hsep(text(Let), above([ letdecl("rec", D) | [ letdecl("and", D1) || D1 <- Ds ] ])).
|
||||
block_expr(0, hsep([text(Let), typed(beside(name(F), args(Args)), T), text("=")]), E).
|
||||
|
||||
-spec args([aeso_syntax:arg()]) -> doc().
|
||||
args(Args) ->
|
||||
@ -435,7 +432,6 @@ statements(Stmts) ->
|
||||
|
||||
statement(S = {letval, _, _, _, _}) -> letdecl("let", S);
|
||||
statement(S = {letfun, _, _, _, _, _}) -> letdecl("let", S);
|
||||
statement(S = {letrec, _, _}) -> letdecl("let", S);
|
||||
statement(E) -> expr(E).
|
||||
|
||||
get_elifs(Expr) -> get_elifs(Expr, []).
|
||||
|
@ -36,8 +36,8 @@ lexer() ->
|
||||
, {"\\*/", pop(skip())}
|
||||
, {"[^/*]+|[/*]", skip()} ],
|
||||
|
||||
Keywords = ["contract", "include", "let", "rec", "switch", "type", "record", "datatype", "if", "elif", "else", "function",
|
||||
"stateful", "true", "false", "and", "mod", "public", "private", "indexed", "internal", "namespace"],
|
||||
Keywords = ["contract", "include", "let", "switch", "type", "record", "datatype", "if", "elif", "else", "function",
|
||||
"stateful", "true", "false", "mod", "public", "private", "indexed", "internal", "namespace"],
|
||||
KW = string:join(Keywords, "|"),
|
||||
|
||||
Rules =
|
||||
|
@ -43,8 +43,7 @@
|
||||
|
||||
-type letbind()
|
||||
:: {letval, ann(), id(), type(), expr()}
|
||||
| {letfun, ann(), id(), [arg()], type(), expr()}
|
||||
| {letrec, ann(), [letbind()]}.
|
||||
| {letfun, ann(), id(), [arg()], type(), expr()}.
|
||||
|
||||
-type arg() :: {arg, ann(), id(), type()}.
|
||||
|
||||
|
@ -39,11 +39,6 @@ fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) ->
|
||||
BindExpr = fun(P) -> fold(Alg, Fun, bind_expr, P) end,
|
||||
BindType = fun(T) -> fold(Alg, Fun, bind_type, T) end,
|
||||
Top = Fun(K, X),
|
||||
Bound = fun LB ({letval, _, Y, _, _}) -> BindExpr(Y);
|
||||
LB ({letfun, _, F, _, _, _}) -> BindExpr(F);
|
||||
LB ({letrec, _, Ds}) -> Sum(lists:map(LB, Ds));
|
||||
LB (_) -> Zero
|
||||
end,
|
||||
Rec = case X of
|
||||
%% lists (bound things in head scope over tail)
|
||||
[A | As] -> Scoped(Same(A), Same(As));
|
||||
@ -55,7 +50,6 @@ fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) ->
|
||||
{fun_decl, _, _, T} -> Type(T);
|
||||
{letval, _, F, T, E} -> Sum([BindExpr(F), Type(T), Expr(E)]);
|
||||
{letfun, _, F, Xs, T, E} -> Sum([BindExpr(F), Type(T), Scoped(BindExpr(Xs), Expr(E))]);
|
||||
{letrec, _, Ds} -> Plus(Bound(Ds), Decl(Ds));
|
||||
%% typedef()
|
||||
{alias_t, T} -> Type(T);
|
||||
{record_t, Fs} -> Type(Fs);
|
||||
|
@ -86,6 +86,7 @@ compilable_contracts() ->
|
||||
"dutch_auction",
|
||||
"environment",
|
||||
"factorial",
|
||||
"functions",
|
||||
"fundme",
|
||||
"identity",
|
||||
"maps",
|
||||
|
@ -41,7 +41,7 @@ all_tokens() ->
|
||||
%% Operators
|
||||
lists:map(Lit, ['=', '==', '!=', '>', '<', '>=', '=<', '-', '+', '++', '*', '/', mod, ':', '::', '->', '=>', '||', '&&', '!']) ++
|
||||
%% Keywords
|
||||
lists:map(Lit, [contract, type, 'let', switch, rec, 'and']) ++
|
||||
lists:map(Lit, [contract, type, 'let', switch]) ++
|
||||
%% Comment token (not an actual token), just for tests
|
||||
[{comment, 0, "// *Comment!\"\n"},
|
||||
{comment, 0, "/* bla /* bla bla */*/"}] ++
|
||||
|
@ -36,11 +36,6 @@ contract AllSyntax =
|
||||
(x, [y, z]) => bar({x = z, y = -y + - -z * (-1)})
|
||||
(x, y :: _) => ()
|
||||
|
||||
function mutual() =
|
||||
let rec recFun(x : int) = mutFun(x)
|
||||
and mutFun(x) = if(x =< 0) 1 else x * recFun(x - 1)
|
||||
recFun(0)
|
||||
|
||||
let hash : address = #01ab0fff11
|
||||
let b = false
|
||||
let qcon = Mod.Con
|
||||
|
15
test/contracts/functions.aes
Normal file
15
test/contracts/functions.aes
Normal file
@ -0,0 +1,15 @@
|
||||
contract Functions =
|
||||
private function curry(f : ('a, 'b) => 'c) =
|
||||
(x) => (y) => f(x, y)
|
||||
private function map(f : 'a => 'b, xs : list('a)) =
|
||||
switch(xs)
|
||||
[] => []
|
||||
x :: xs => f(x) :: map(f, xs)
|
||||
private function map'() = map
|
||||
private function plus(x, y) = x + y
|
||||
function test1(xs : list(int)) = map(curry(plus)(5), xs)
|
||||
function test2(xs : list(int)) = map'()(((x) => (y) => ((x, y) => x + y)(x, y))(100), xs)
|
||||
function test3(xs : list(int)) =
|
||||
let m(f, xs) = map(f, xs)
|
||||
m((x) => x + 1, xs)
|
||||
|
Loading…
x
Reference in New Issue
Block a user