Added standard List library and list comprehensions
Added List library. Flatmaps WIP Fixed dependency in flat_map fcode generation Updated tests to use custom list lib Added comprehension test Added stdlib sanity Test
This commit is contained in:
parent
df12f6af91
commit
18235e5b56
@ -363,6 +363,8 @@ global_env() ->
|
|||||||
Pair = fun(A, B) -> {tuple_t, Ann, [A, B]} end,
|
Pair = fun(A, B) -> {tuple_t, Ann, [A, B]} end,
|
||||||
Fun = fun(Ts, T) -> {type_sig, Ann, [], Ts, T} end,
|
Fun = fun(Ts, T) -> {type_sig, Ann, [], Ts, T} end,
|
||||||
Fun1 = fun(S, T) -> Fun([S], T) end,
|
Fun1 = fun(S, T) -> Fun([S], T) end,
|
||||||
|
%% Lambda = fun(Ts, T) -> {fun_t, Ann, [], Ts, T} end,
|
||||||
|
%% Lambda1 = fun(S, T) -> ArgFun([S], T) end,
|
||||||
StateFun = fun(Ts, T) -> {type_sig, [stateful|Ann], [], Ts, T} end,
|
StateFun = fun(Ts, T) -> {type_sig, [stateful|Ann], [], Ts, T} end,
|
||||||
TVar = fun(X) -> {tvar, Ann, "'" ++ X} end,
|
TVar = fun(X) -> {tvar, Ann, "'" ++ X} end,
|
||||||
SignId = {id, Ann, "signature"},
|
SignId = {id, Ann, "signature"},
|
||||||
@ -1074,6 +1076,23 @@ infer_expr(Env, {list, As, Elems}) ->
|
|||||||
ElemType = fresh_uvar(As),
|
ElemType = fresh_uvar(As),
|
||||||
NewElems = [check_expr(Env, X, ElemType) || X <- Elems],
|
NewElems = [check_expr(Env, X, ElemType) || X <- Elems],
|
||||||
{typed, As, {list, As, NewElems}, {app_t, As, {id, As, "list"}, [ElemType]}};
|
{typed, As, {list, As, NewElems}, {app_t, As, {id, As, "list"}, [ElemType]}};
|
||||||
|
infer_expr(Env, {list_comp, As, Yield, []}) ->
|
||||||
|
{typed, _, TypedYield, Type} = infer_expr(Env, Yield),
|
||||||
|
{typed, As, {list_comp, As, TypedYield, []}, {app_t, As, {id, As, "list"}, [Type]}};
|
||||||
|
infer_expr(Env, {list_comp, As, Yield, [{comprehension_bind, Arg, BExpr}|Rest]}) ->
|
||||||
|
BindVarType = fresh_uvar(As),
|
||||||
|
TypedBind = {typed, As2, _, TypeBExpr} = infer_expr(Env, BExpr),
|
||||||
|
unify( Env
|
||||||
|
, TypeBExpr
|
||||||
|
, {app_t, As, {id, As, "list"}, [BindVarType]}
|
||||||
|
, {list_comp, TypedBind, TypeBExpr, {app_t, As2, {id, As, "list"}, [BindVarType]}}),
|
||||||
|
NewE = bind_var(Arg, BindVarType, Env),
|
||||||
|
{typed, _, {list_comp, _, TypedYield, TypedRest}, ResType} =
|
||||||
|
infer_expr(NewE, {list_comp, As, Yield, Rest}),
|
||||||
|
{ typed
|
||||||
|
, As
|
||||||
|
, {list_comp, As, TypedYield, [{comprehension_bind, {typed, Arg, BindVarType}, TypedBind}|TypedRest]}
|
||||||
|
, ResType};
|
||||||
infer_expr(Env, {typed, As, Body, Type}) ->
|
infer_expr(Env, {typed, As, Body, Type}) ->
|
||||||
Type1 = check_type(Env, Type),
|
Type1 = check_type(Env, Type),
|
||||||
{typed, _, NewBody, NewType} = check_expr(Env, Body, Type1),
|
{typed, _, NewBody, NewType} = check_expr(Env, Body, Type1),
|
||||||
@ -2253,6 +2272,13 @@ pp_when({check_expr, Expr, Inferred0, Expected0}) ->
|
|||||||
pp_when({checking_init_type, Ann}) ->
|
pp_when({checking_init_type, Ann}) ->
|
||||||
io_lib:format("when checking that 'init' returns a value of type 'state' at ~s\n",
|
io_lib:format("when checking that 'init' returns a value of type 'state' at ~s\n",
|
||||||
[pp_loc(Ann)]);
|
[pp_loc(Ann)]);
|
||||||
|
pp_when({list_comp, BindExpr, Inferred0, Expected0}) ->
|
||||||
|
{Inferred, Expected} = instantiate({Inferred0, Expected0}),
|
||||||
|
io_lib:format("when checking rvalue of list comprehension binding at ~s\n~s\n"
|
||||||
|
"against type \n~s\n",
|
||||||
|
[pp_loc(BindExpr), pp_typed(" ", BindExpr, Inferred), pp_type(" ", Expected)]
|
||||||
|
);
|
||||||
|
|
||||||
pp_when(unknown) -> "".
|
pp_when(unknown) -> "".
|
||||||
|
|
||||||
-spec pp_why_record(why_record()) -> iolist().
|
-spec pp_why_record(why_record()) -> iolist().
|
||||||
|
@ -360,7 +360,6 @@ make_let(Expr, Body) ->
|
|||||||
{'let', X, Expr, Body({var, X})}
|
{'let', X, Expr, Body({var, X})}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec expr_to_fcode(env(), aeso_syntax:expr()) -> fexpr().
|
|
||||||
expr_to_fcode(Env, {typed, _, Expr, Type}) ->
|
expr_to_fcode(Env, {typed, _, Expr, Type}) ->
|
||||||
expr_to_fcode(Env, Type, Expr);
|
expr_to_fcode(Env, Type, Expr);
|
||||||
expr_to_fcode(Env, Expr) ->
|
expr_to_fcode(Env, Expr) ->
|
||||||
@ -444,6 +443,14 @@ expr_to_fcode(Env, _Type, {list, _, Es}) ->
|
|||||||
lists:foldr(fun(E, L) -> {op, '::', [expr_to_fcode(Env, E), L]} end,
|
lists:foldr(fun(E, L) -> {op, '::', [expr_to_fcode(Env, E), L]} end,
|
||||||
nil, Es);
|
nil, Es);
|
||||||
|
|
||||||
|
expr_to_fcode(Env, _Type, {list_comp, _, Yield, []}) ->
|
||||||
|
{op, '::', [expr_to_fcode(Env, Yield), nil]};
|
||||||
|
expr_to_fcode(Env, _Type, {list_comp, As, Yield, [{comprehension_bind, {typed, {id, _, Arg}, _}, BindExpr}|Rest]}) ->
|
||||||
|
Env1 = bind_var(Env, Arg),
|
||||||
|
Bind = {lam, [Arg], expr_to_fcode(Env1, {list_comp, As, Yield, Rest})},
|
||||||
|
{funcall, resolve_fun(Env, ["List", "flat_map"]), [expr_to_fcode(Env, BindExpr), Bind]};
|
||||||
|
|
||||||
|
|
||||||
%% Conditionals
|
%% Conditionals
|
||||||
expr_to_fcode(Env, _Type, {'if', _, Cond, Then, Else}) ->
|
expr_to_fcode(Env, _Type, {'if', _, Cond, Then, Else}) ->
|
||||||
make_if(expr_to_fcode(Env, Cond),
|
make_if(expr_to_fcode(Env, Cond),
|
||||||
|
@ -519,6 +519,18 @@ ast_body({app,As,Fun,Args}, Icode) ->
|
|||||||
#funcall{function=ast_body(Fun, Icode),
|
#funcall{function=ast_body(Fun, Icode),
|
||||||
args=[ast_body(A, Icode) || A <- Args]}
|
args=[ast_body(A, Icode) || A <- Args]}
|
||||||
end;
|
end;
|
||||||
|
ast_body({list_comp, _, Yield, []}, Icode) ->
|
||||||
|
#list{elems = [ast_body(Yield, Icode)]};
|
||||||
|
ast_body({list_comp, As, Yield, [{comprehension_bind, {typed, Arg, ArgType}, BindExpr}|Rest]}, Icode) ->
|
||||||
|
#funcall
|
||||||
|
{ function = #var_ref{ name = ["List", "flat_map"] }
|
||||||
|
, args =
|
||||||
|
[ #lambda{ args=[#arg{name = ast_id(Arg), type = ast_type(ArgType, Icode)}]
|
||||||
|
, body = ast_body({list_comp, As, Yield, Rest}, Icode)
|
||||||
|
}
|
||||||
|
, ast_body(BindExpr, Icode)
|
||||||
|
]
|
||||||
|
};
|
||||||
ast_body({'if',_,Dec,Then,Else}, Icode) ->
|
ast_body({'if',_,Dec,Then,Else}, Icode) ->
|
||||||
#ifte{decision = ast_body(Dec, Icode)
|
#ifte{decision = ast_body(Dec, Icode)
|
||||||
,then = ast_body(Then, Icode)
|
,then = ast_body(Then, Icode)
|
||||||
|
@ -230,11 +230,15 @@ exprAtom() ->
|
|||||||
, {bool, keyword(false), false}
|
, {bool, keyword(false), false}
|
||||||
, ?LET_P(Fs, brace_list(?LAZY_P(field_assignment())), record(Fs))
|
, ?LET_P(Fs, brace_list(?LAZY_P(field_assignment())), record(Fs))
|
||||||
, {list, [], bracket_list(Expr)}
|
, {list, [], bracket_list(Expr)}
|
||||||
|
, ?RULE(keyword('['), Expr, tok('|'), comma_sep(?LAZY_P(comprehension_bind())), tok(']'), list_comp_e(_1, _2, _4))
|
||||||
, ?RULE(tok('['), Expr, binop('..'), Expr, tok(']'), _3(_2, _4))
|
, ?RULE(tok('['), Expr, binop('..'), Expr, tok(']'), _3(_2, _4))
|
||||||
, ?RULE(keyword('('), comma_sep(Expr), tok(')'), tuple_e(_1, _2))
|
, ?RULE(keyword('('), comma_sep(Expr), tok(')'), tuple_e(_1, _2))
|
||||||
])
|
])
|
||||||
end).
|
end).
|
||||||
|
|
||||||
|
comprehension_bind() ->
|
||||||
|
?RULE(id(), tok('<-'), expr(), {comprehension_bind, _1, _3}).
|
||||||
|
|
||||||
arg_expr() ->
|
arg_expr() ->
|
||||||
?LAZY_P(
|
?LAZY_P(
|
||||||
choice([ ?RULE(id(), tok('='), expr(), {named_arg, [], _1, _3})
|
choice([ ?RULE(id(), tok('='), expr(), {named_arg, [], _1, _3})
|
||||||
@ -481,6 +485,8 @@ fun_t(Domains, Type) ->
|
|||||||
tuple_e(_Ann, [Expr]) -> Expr; %% Not a tuple
|
tuple_e(_Ann, [Expr]) -> Expr; %% Not a tuple
|
||||||
tuple_e(Ann, Exprs) -> {tuple, Ann, Exprs}.
|
tuple_e(Ann, Exprs) -> {tuple, Ann, Exprs}.
|
||||||
|
|
||||||
|
list_comp_e(Ann, Expr, Binds) -> {list_comp, Ann, Expr, Binds}.
|
||||||
|
|
||||||
-spec parse_pattern(aeso_syntax:expr()) -> aeso_parse_lib:parser(aeso_syntax:pat()).
|
-spec parse_pattern(aeso_syntax:expr()) -> aeso_parse_lib:parser(aeso_syntax:pat()).
|
||||||
parse_pattern({app, Ann, Con = {'::', _}, Es}) ->
|
parse_pattern({app, Ann, Con = {'::', _}, Es}) ->
|
||||||
{app, Ann, Con, lists:map(fun parse_pattern/1, Es)};
|
{app, Ann, Con, lists:map(fun parse_pattern/1, Es)};
|
||||||
@ -527,8 +533,15 @@ expand_includes(AST, Opts) ->
|
|||||||
expand_includes([], Acc, _Opts) ->
|
expand_includes([], Acc, _Opts) ->
|
||||||
{ok, lists:reverse(Acc)};
|
{ok, lists:reverse(Acc)};
|
||||||
expand_includes([{include, _, S = {string, _, File}} | AST], Acc, Opts) ->
|
expand_includes([{include, _, S = {string, _, File}} | AST], Acc, Opts) ->
|
||||||
case read_file(File, Opts) of
|
case {read_file(File, Opts), maps:find(File, aeso_stdlib:stdlib())} of
|
||||||
{ok, Bin} ->
|
{_, {ok, Lib}} ->
|
||||||
|
case string(Lib) of
|
||||||
|
{ok, AST1} ->
|
||||||
|
expand_includes(AST1 ++ AST, Acc, Opts);
|
||||||
|
Err = {error, _} ->
|
||||||
|
Err
|
||||||
|
end;
|
||||||
|
{{ok, Bin}, _} ->
|
||||||
Opts1 = lists:keystore(src_file, 1, Opts, {src_file, File}),
|
Opts1 = lists:keystore(src_file, 1, Opts, {src_file, File}),
|
||||||
case string(binary_to_list(Bin), Opts1) of
|
case string(binary_to_list(Bin), Opts1) of
|
||||||
{ok, AST1} ->
|
{ok, AST1} ->
|
||||||
@ -536,7 +549,7 @@ expand_includes([{include, _, S = {string, _, File}} | AST], Acc, Opts) ->
|
|||||||
Err = {error, _} ->
|
Err = {error, _} ->
|
||||||
Err
|
Err
|
||||||
end;
|
end;
|
||||||
{error, _} ->
|
{{error, _}, _} ->
|
||||||
{error, {get_pos(S), include_error, File}}
|
{error, {get_pos(S), include_error, File}}
|
||||||
end;
|
end;
|
||||||
expand_includes([E | AST], Acc, Opts) ->
|
expand_includes([E | AST], Acc, Opts) ->
|
||||||
|
@ -235,6 +235,8 @@ type(Type, Options) ->
|
|||||||
-spec type(aeso_syntax:type()) -> doc().
|
-spec type(aeso_syntax:type()) -> doc().
|
||||||
type({fun_t, _, Named, Args, Ret}) ->
|
type({fun_t, _, Named, Args, Ret}) ->
|
||||||
follow(hsep(args_type(Named ++ Args), text("=>")), type(Ret));
|
follow(hsep(args_type(Named ++ Args), text("=>")), type(Ret));
|
||||||
|
type({type_sig, _, Named, Args, Ret}) ->
|
||||||
|
follow(hsep(tuple_type(Named ++ Args), text("=>")), type(Ret));
|
||||||
type({app_t, _, Type, []}) ->
|
type({app_t, _, Type, []}) ->
|
||||||
type(Type);
|
type(Type);
|
||||||
type({app_t, _, Type, Args}) ->
|
type({app_t, _, Type, Args}) ->
|
||||||
|
48
src/aeso_stdlib.erl
Normal file
48
src/aeso_stdlib.erl
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @author Radosław Rowicki
|
||||||
|
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||||
|
%%% @doc
|
||||||
|
%%% Standard library for Sophia
|
||||||
|
%%% @end
|
||||||
|
%%% Created : 6 July 2019
|
||||||
|
%%%
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(aeso_stdlib).
|
||||||
|
|
||||||
|
-export([stdlib/0]).
|
||||||
|
|
||||||
|
stdlib() ->
|
||||||
|
maps:from_list(
|
||||||
|
[ {<<"List.aes">>, std_list()}
|
||||||
|
]
|
||||||
|
).
|
||||||
|
|
||||||
|
std_list() ->
|
||||||
|
"
|
||||||
|
namespace List =
|
||||||
|
function length(l) = length_(l, 0)
|
||||||
|
private function length_(l, n) = switch(l)
|
||||||
|
[] => n
|
||||||
|
_::t => length_(t, n + 1)
|
||||||
|
|
||||||
|
function foldr(cons, nil, l) = switch(l)
|
||||||
|
[] => nil
|
||||||
|
h::t => cons(h, foldr(cons, nil, t))
|
||||||
|
|
||||||
|
function foldl(rcons, acc, l) = switch(l)
|
||||||
|
[] => acc
|
||||||
|
h::t => foldl(rcons, rcons(acc, h), t)
|
||||||
|
|
||||||
|
function reverse(l) =
|
||||||
|
foldr((el, cont) => (lst) => cont(el::lst), (x) => x, l)([])
|
||||||
|
|
||||||
|
function map(f, l) = map_(f, l, [])
|
||||||
|
private function map_(f, l, acc) = switch(l)
|
||||||
|
[] => reverse(acc)
|
||||||
|
h::t => map_(f, t, f(h)::acc)
|
||||||
|
|
||||||
|
function flat_map(f, l) = switch(l)
|
||||||
|
[] => []
|
||||||
|
h::t => f(h) ++ flat_map(f, t)
|
||||||
|
".
|
@ -92,6 +92,7 @@
|
|||||||
| {proj, ann(), expr(), id()}
|
| {proj, ann(), expr(), id()}
|
||||||
| {tuple, ann(), [expr()]}
|
| {tuple, ann(), [expr()]}
|
||||||
| {list, ann(), [expr()]}
|
| {list, ann(), [expr()]}
|
||||||
|
| {list_comp, ann(), expr(), [comprehension_bind()]}
|
||||||
| {typed, ann(), expr(), type()}
|
| {typed, ann(), expr(), type()}
|
||||||
| {record, ann(), [field(expr())]}
|
| {record, ann(), [field(expr())]}
|
||||||
| {record, ann(), expr(), [field(expr())]} %% record update
|
| {record, ann(), expr(), [field(expr())]} %% record update
|
||||||
@ -104,6 +105,8 @@
|
|||||||
| id() | qid() | con() | qcon()
|
| id() | qid() | con() | qcon()
|
||||||
| constant().
|
| constant().
|
||||||
|
|
||||||
|
-type comprehension_bind() :: [{comprehension_bind, ann(), id(), type()}].
|
||||||
|
|
||||||
-type arg_expr() :: expr() | {named_arg, ann(), id(), expr()}.
|
-type arg_expr() :: expr() | {named_arg, ann(), id(), expr()}.
|
||||||
|
|
||||||
%% When lvalue is a projection this is sugar for accessing fields in nested
|
%% When lvalue is a projection this is sugar for accessing fields in nested
|
||||||
|
@ -118,7 +118,8 @@ compilable_contracts() ->
|
|||||||
"namespace_bug",
|
"namespace_bug",
|
||||||
"bytes_to_x",
|
"bytes_to_x",
|
||||||
"aens",
|
"aens",
|
||||||
"tuple_match"
|
"tuple_match",
|
||||||
|
"list_comp"
|
||||||
].
|
].
|
||||||
|
|
||||||
not_yet_compilable(fate) -> [];
|
not_yet_compilable(fate) -> [];
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
namespace List =
|
namespace MyList =
|
||||||
|
|
||||||
function map1(f : 'a => 'b, xs : list('a)) =
|
function map1(f : 'a => 'b, xs : list('a)) =
|
||||||
switch(xs)
|
switch(xs)
|
||||||
@ -14,8 +14,8 @@ namespace List =
|
|||||||
contract Deadcode =
|
contract Deadcode =
|
||||||
|
|
||||||
entrypoint inc1(xs : list(int)) : list(int) =
|
entrypoint inc1(xs : list(int)) : list(int) =
|
||||||
List.map1((x) => x + 1, xs)
|
MyList.map1((x) => x + 1, xs)
|
||||||
|
|
||||||
entrypoint inc2(xs : list(int)) : list(int) =
|
entrypoint inc2(xs : list(int)) : list(int) =
|
||||||
List.map1((x) => x + 1, xs)
|
MyList.map1((x) => x + 1, xs)
|
||||||
|
|
||||||
|
16
test/contracts/list_comp.aes
Normal file
16
test/contracts/list_comp.aes
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
include "List.aes"
|
||||||
|
|
||||||
|
contract ListComp =
|
||||||
|
|
||||||
|
entrypoint sample1() = [1,2,3]
|
||||||
|
entrypoint sample2() = [4,5]
|
||||||
|
|
||||||
|
entrypoint l1() = [x | x <- sample1()]
|
||||||
|
entrypoint l1_true() = [1,2,3]
|
||||||
|
|
||||||
|
entrypoint l2() = [x + y | x <- sample1(), y <- sample2()]
|
||||||
|
entrypoint l2_true() = [5,6,6,7,7,8]
|
||||||
|
|
||||||
|
entrypoint l3() = [x ++ y | x <- [[":)"] | x <- [1,2]]
|
||||||
|
, y <- [[":("]]]
|
||||||
|
entrypoint l3_true() = [[":)", ":("], [":)", ":("]]
|
@ -28,8 +28,8 @@ contract MultiSig =
|
|||||||
let n = length(owners) + 1
|
let n = length(owners) + 1
|
||||||
{ nRequired = nRequired,
|
{ nRequired = nRequired,
|
||||||
nOwners = n,
|
nOwners = n,
|
||||||
owners = Map.from_list(List.zip([1..n], caller() :: owners)),
|
owners = Map.from_list(MyList.zip([1..n], caller() :: owners)),
|
||||||
ownerIndex = Map.from_list(List.zip(caller() :: owners, [1..n])) }
|
ownerIndex = Map.from_list(MyList.zip(caller() :: owners, [1..n])) }
|
||||||
|
|
||||||
function lookup(map, key) =
|
function lookup(map, key) =
|
||||||
switch(Map.get(key, map))
|
switch(Map.get(key, map))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
namespace List =
|
namespace MyList =
|
||||||
|
|
||||||
function map1(f : 'a => 'b, xs : list('a)) =
|
function map1(f : 'a => 'b, xs : list('a)) =
|
||||||
switch(xs)
|
switch(xs)
|
||||||
@ -14,8 +14,8 @@ namespace List =
|
|||||||
contract Deadcode =
|
contract Deadcode =
|
||||||
|
|
||||||
entrypoint inc1(xs : list(int)) : list(int) =
|
entrypoint inc1(xs : list(int)) : list(int) =
|
||||||
List.map1((x) => x + 1, xs)
|
MyList.map1((x) => x + 1, xs)
|
||||||
|
|
||||||
entrypoint inc2(xs : list(int)) : list(int) =
|
entrypoint inc2(xs : list(int)) : list(int) =
|
||||||
List.map2((x) => x + 1, xs)
|
MyList.map2((x) => x + 1, xs)
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ module Voting : Voting = {
|
|||||||
let init(proposalNames: args): state =
|
let init(proposalNames: args): state =
|
||||||
{ chairPerson: caller(),
|
{ chairPerson: caller(),
|
||||||
voters: AddrMap.empty,
|
voters: AddrMap.empty,
|
||||||
proposals: List.map((name) => {name: name, voteCount: 0}, proposalNames)
|
proposals: MyList.map((name) => {name: name, voteCount: 0}, proposalNames)
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Boilerplate */
|
/* Boilerplate */
|
||||||
@ -73,7 +73,7 @@ module Voting : Voting = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let addVote(candidate, weight) = {
|
let addVote(candidate, weight) = {
|
||||||
let proposal = List.nth(state().proposals, candidate);
|
let proposal = MyList.nth(state().proposals, candidate);
|
||||||
proposal.voteCount = proposal.voteCount + weight;
|
proposal.voteCount = proposal.voteCount + weight;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -121,6 +121,6 @@ module Voting : Voting = {
|
|||||||
|
|
||||||
/* const */
|
/* const */
|
||||||
let currentTally() =
|
let currentTally() =
|
||||||
List.map((p) => (p.name, p.voteCount), state().proposals);
|
MyList.map((p) => (p.name, p.voteCount), state().proposals);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ open Voting;
|
|||||||
|
|
||||||
let print_tally() = {
|
let print_tally() = {
|
||||||
let tally = call(other, () => currentTally());
|
let tally = call(other, () => currentTally());
|
||||||
List.map(((name, count)) => Printf.printf("%s: %d\n", name, count), tally);
|
MyList.map(((name, count)) => Printf.printf("%s: %d\n", name, count), tally);
|
||||||
let winner = call(other, () => winnerName());
|
let winner = call(other, () => winnerName());
|
||||||
Printf.printf("Winner: %s\n", winner);
|
Printf.printf("Winner: %s\n", winner);
|
||||||
};
|
};
|
||||||
|
@ -36,7 +36,7 @@ contract Voting =
|
|||||||
function init(proposalNames: list(string)): state =
|
function init(proposalNames: list(string)): state =
|
||||||
{ chairPerson = caller(),
|
{ chairPerson = caller(),
|
||||||
voters = Map.empty,
|
voters = Map.empty,
|
||||||
proposals = List.map((name) => {name = name, voteCount = 0}, proposalNames) }
|
proposals = MyList.map((name) => {name = name, voteCount = 0}, proposalNames) }
|
||||||
|
|
||||||
function initVoter() = { weight = 1, vote = NotVoted}
|
function initVoter() = { weight = 1, vote = NotVoted}
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ contract Voting =
|
|||||||
_ => delegate
|
_ => delegate
|
||||||
|
|
||||||
function addVote(candidate, weight) =
|
function addVote(candidate, weight) =
|
||||||
let proposal = List.nth(state.proposals, candidate)
|
let proposal = MyList.nth(state.proposals, candidate)
|
||||||
proposal{ voteCount = proposal.voteCount + weight }
|
proposal{ voteCount = proposal.voteCount + weight }
|
||||||
|
|
||||||
function delegateVote(delegateTo: address, weight: uint) =
|
function delegateVote(delegateTo: address, weight: uint) =
|
||||||
@ -93,5 +93,5 @@ contract Voting =
|
|||||||
|
|
||||||
// const
|
// const
|
||||||
function currentTally() =
|
function currentTally() =
|
||||||
List.map((p) => (p.name, p.voteCount), state.proposals)
|
MyList.map((p) => (p.name, p.voteCount), state.proposals)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user