Merge pull request #213 from aeternity/merge_lima_to_master
Merge lima to master
This commit is contained in:
commit
43013ec920
35
CHANGELOG.md
35
CHANGELOG.md
@ -7,7 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
### Changed
|
### Changed
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
## [4.2.0] - 2020-01-15
|
||||||
|
### Added
|
||||||
|
- Allow separate entrypoint/function type signature and definition, and pattern
|
||||||
|
matching in left-hand sides:
|
||||||
|
```
|
||||||
|
function
|
||||||
|
length : list('a) => int
|
||||||
|
length([]) = 0
|
||||||
|
length(x :: xs) = 1 + length(xs)
|
||||||
|
```
|
||||||
|
- Allow pattern matching in list comprehension generators (filtering out match
|
||||||
|
failures):
|
||||||
|
```
|
||||||
|
function somes(xs : list(option('a))) : list('a) =
|
||||||
|
[ x | Some(x) <- xs ]
|
||||||
|
```
|
||||||
|
- Allow pattern matching in let-bindings (aborting on match failures):
|
||||||
|
```
|
||||||
|
function test(m : map(int, int)) =
|
||||||
|
let Some(x) = Map.lookup(m, 0)
|
||||||
|
x
|
||||||
|
```
|
||||||
|
### Changed
|
||||||
- FATE code generator improvements.
|
- FATE code generator improvements.
|
||||||
|
- Bug fix: Handle qualified constructors in patterns.
|
||||||
|
- Bug fix: Allow switching also on negative numbers.
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
## [4.1.0] - 2019-11-26
|
## [4.1.0] - 2019-11-26
|
||||||
@ -165,12 +192,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Simplify calldata creation - instead of passing a compiled contract, simply
|
- Simplify calldata creation - instead of passing a compiled contract, simply
|
||||||
pass a (stubbed) contract string.
|
pass a (stubbed) contract string.
|
||||||
|
|
||||||
[Unreleased]: https://github.com/aeternity/aesophia/compare/v4.0.0...HEAD
|
[Unreleased]: https://github.com/aeternity/aesophia/compare/v4.2.0...HEAD
|
||||||
|
[4.2.0]: https://github.com/aeternity/aesophia/compare/v4.2.0...v4.1.0
|
||||||
|
[4.1.0]: https://github.com/aeternity/aesophia/compare/v4.1.0...v4.0.0
|
||||||
[4.0.0]: https://github.com/aeternity/aesophia/compare/v4.0.0...v3.2.0
|
[4.0.0]: https://github.com/aeternity/aesophia/compare/v4.0.0...v3.2.0
|
||||||
[4.0.0-rc5]: https://github.com/aeternity/aesophia/compare/v4.0.0-rc4...v4.0.0-rc5
|
|
||||||
[4.0.0-rc4]: https://github.com/aeternity/aesophia/compare/v4.0.0-rc3...v4.0.0-rc4
|
|
||||||
[4.0.0-rc3]: https://github.com/aeternity/aesophia/compare/v4.0.0-rc1...v4.0.0-rc3
|
|
||||||
[4.0.0-rc1]: https://github.com/aeternity/aesophia/compare/v3.2.0...v4.0.0-rc1
|
|
||||||
[3.2.0]: https://github.com/aeternity/aesophia/compare/v3.1.0...v3.2.0
|
[3.2.0]: https://github.com/aeternity/aesophia/compare/v3.1.0...v3.2.0
|
||||||
[3.1.0]: https://github.com/aeternity/aesophia/compare/v3.0.0...v3.1.0
|
[3.1.0]: https://github.com/aeternity/aesophia/compare/v3.0.0...v3.1.0
|
||||||
[3.0.0]: https://github.com/aeternity/aesophia/compare/v2.1.0...v3.0.0
|
[3.0.0]: https://github.com/aeternity/aesophia/compare/v2.1.0...v3.0.0
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
|
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
{relx, [{release, {aesophia, "4.1.0"},
|
{relx, [{release, {aesophia, "4.2.0"},
|
||||||
[aesophia, aebytecode, getopt]},
|
[aesophia, aebytecode, getopt]},
|
||||||
|
|
||||||
{dev_mode, true},
|
{dev_mode, true},
|
||||||
|
@ -129,7 +129,7 @@ encode_anon_args(Types) ->
|
|||||||
|
|
||||||
encode_args(Args) -> [ encode_arg(A) || A <- Args ].
|
encode_args(Args) -> [ encode_arg(A) || A <- Args ].
|
||||||
|
|
||||||
encode_arg({arg, _, Id, T}) ->
|
encode_arg({typed, _, Id, T}) ->
|
||||||
#{name => encode_type(Id),
|
#{name => encode_type(Id),
|
||||||
type => encode_type(T)}.
|
type => encode_type(T)}.
|
||||||
|
|
||||||
|
@ -672,10 +672,12 @@ infer_contract_top(Env, Kind, Defs0, _Options) ->
|
|||||||
%% infer_contract takes a proplist mapping global names to types, and
|
%% infer_contract takes a proplist mapping global names to types, and
|
||||||
%% a list of definitions.
|
%% a list of definitions.
|
||||||
-spec infer_contract(env(), main_contract | contract | namespace, [aeso_syntax:decl()]) -> {env(), [aeso_syntax:decl()]}.
|
-spec infer_contract(env(), main_contract | contract | namespace, [aeso_syntax:decl()]) -> {env(), [aeso_syntax:decl()]}.
|
||||||
infer_contract(Env0, What, Defs) ->
|
infer_contract(Env0, What, Defs0) ->
|
||||||
|
Defs = process_blocks(Defs0),
|
||||||
Env = Env0#env{ what = What },
|
Env = Env0#env{ what = What },
|
||||||
Kind = fun({type_def, _, _, _, _}) -> type;
|
Kind = fun({type_def, _, _, _, _}) -> type;
|
||||||
({letfun, _, _, _, _, _}) -> function;
|
({letfun, _, _, _, _, _}) -> function;
|
||||||
|
({fun_clauses, _, _, _, _}) -> function;
|
||||||
({fun_decl, _, _, _}) -> prototype;
|
({fun_decl, _, _, _}) -> prototype;
|
||||||
(_) -> unexpected
|
(_) -> unexpected
|
||||||
end,
|
end,
|
||||||
@ -693,9 +695,11 @@ infer_contract(Env0, What, Defs) ->
|
|||||||
Env3 = bind_funs(ProtoSigs, Env2),
|
Env3 = bind_funs(ProtoSigs, Env2),
|
||||||
Functions = Get(function),
|
Functions = Get(function),
|
||||||
%% Check for duplicates in Functions (we turn it into a map below)
|
%% Check for duplicates in Functions (we turn it into a map below)
|
||||||
_ = bind_funs([{Fun, {tuple_t, Ann, []}} || {letfun, Ann, {id, _, Fun}, _, _, _} <- Functions],
|
FunBind = fun({letfun, Ann, {id, _, Fun}, _, _, _}) -> {Fun, {tuple_t, Ann, []}};
|
||||||
#env{}),
|
({fun_clauses, Ann, {id, _, Fun}, _, _}) -> {Fun, {tuple_t, Ann, []}} end,
|
||||||
FunMap = maps:from_list([ {Fun, Def} || Def = {letfun, _, {id, _, Fun}, _, _, _} <- Functions ]),
|
FunName = fun(Def) -> {Name, _} = FunBind(Def), Name end,
|
||||||
|
_ = bind_funs(lists:map(FunBind, Functions), #env{}),
|
||||||
|
FunMap = maps:from_list([ {FunName(Def), Def} || Def <- Functions ]),
|
||||||
check_reserved_entrypoints(FunMap),
|
check_reserved_entrypoints(FunMap),
|
||||||
DepGraph = maps:map(fun(_, Def) -> aeso_syntax_utils:used_ids(Def) end, FunMap),
|
DepGraph = maps:map(fun(_, Def) -> aeso_syntax_utils:used_ids(Def) end, FunMap),
|
||||||
SCCs = aeso_utils:scc(DepGraph),
|
SCCs = aeso_utils:scc(DepGraph),
|
||||||
@ -706,6 +710,30 @@ infer_contract(Env0, What, Defs) ->
|
|||||||
destroy_and_report_type_errors(Env4),
|
destroy_and_report_type_errors(Env4),
|
||||||
{Env4, TypeDefs ++ Decls ++ Defs1}.
|
{Env4, TypeDefs ++ Decls ++ Defs1}.
|
||||||
|
|
||||||
|
%% Restructure blocks into multi-clause fundefs (`fun_clauses`).
|
||||||
|
-spec process_blocks([aeso_syntax:decl()]) -> [aeso_syntax:decl()].
|
||||||
|
process_blocks(Decls) ->
|
||||||
|
lists:flatmap(
|
||||||
|
fun({block, Ann, Ds}) -> process_block(Ann, Ds);
|
||||||
|
(Decl) -> [Decl] end, Decls).
|
||||||
|
|
||||||
|
-spec process_block(aeso_syntax:ann(), [aeso_syntax:decl()]) -> [aeso_syntax:decl()].
|
||||||
|
process_block(_, []) -> [];
|
||||||
|
process_block(_, [Decl]) -> [Decl];
|
||||||
|
process_block(Ann, [Decl | Decls]) ->
|
||||||
|
IsThis = fun(Name) -> fun({letfun, _, {id, _, Name1}, _, _, _}) -> Name == Name1;
|
||||||
|
(_) -> false end end,
|
||||||
|
case Decl of
|
||||||
|
{fun_decl, Ann1, Id = {id, _, Name}, Type} ->
|
||||||
|
{Clauses, Rest} = lists:splitwith(IsThis(Name), Decls),
|
||||||
|
[{fun_clauses, Ann1, Id, Type, Clauses} |
|
||||||
|
process_block(Ann, Rest)];
|
||||||
|
{letfun, Ann1, Id = {id, _, Name}, _, _, _} ->
|
||||||
|
{Clauses, Rest} = lists:splitwith(IsThis(Name), [Decl | Decls]),
|
||||||
|
[{fun_clauses, Ann1, Id, {id, [{origin, system} | Ann1], "_"}, Clauses} |
|
||||||
|
process_block(Ann, Rest)]
|
||||||
|
end.
|
||||||
|
|
||||||
-spec check_typedefs(env(), [aeso_syntax:decl()]) -> {env(), [aeso_syntax:decl()]}.
|
-spec check_typedefs(env(), [aeso_syntax:decl()]) -> {env(), [aeso_syntax:decl()]}.
|
||||||
check_typedefs(Env = #env{ namespace = Ns }, Defs) ->
|
check_typedefs(Env = #env{ namespace = Ns }, Defs) ->
|
||||||
create_type_errors(),
|
create_type_errors(),
|
||||||
@ -838,9 +866,9 @@ check_type(Env, T) ->
|
|||||||
check_type(Env, T = {tvar, _, _}, Arity) ->
|
check_type(Env, T = {tvar, _, _}, Arity) ->
|
||||||
[ type_error({higher_kinded_typevar, T}) || Arity /= 0 ],
|
[ type_error({higher_kinded_typevar, T}) || Arity /= 0 ],
|
||||||
check_tvar(Env, T);
|
check_tvar(Env, T);
|
||||||
check_type(_Env, X = {id, _, "_"}, Arity) ->
|
check_type(_Env, X = {id, Ann, "_"}, Arity) ->
|
||||||
ensure_base_type(X, Arity),
|
ensure_base_type(X, Arity),
|
||||||
X;
|
fresh_uvar(Ann);
|
||||||
check_type(Env, X = {Tag, _, _}, Arity) when Tag == con; Tag == qcon; Tag == id; Tag == qid ->
|
check_type(Env, X = {Tag, _, _}, Arity) when Tag == con; Tag == qcon; Tag == id; Tag == qid ->
|
||||||
case lookup_type(Env, X) of
|
case lookup_type(Env, X) of
|
||||||
{Q, {_, Def}} ->
|
{Q, {_, Def}} ->
|
||||||
@ -1011,8 +1039,9 @@ typesig_to_fun_t({type_sig, Ann, _Constr, Named, Args, Res}) ->
|
|||||||
|
|
||||||
infer_letrec(Env, Defs) ->
|
infer_letrec(Env, Defs) ->
|
||||||
create_constraints(),
|
create_constraints(),
|
||||||
Funs = [{Name, fresh_uvar(A)}
|
Funs = lists:map(fun({letfun, _, {id, Ann, Name}, _, _, _}) -> {Name, fresh_uvar(Ann)};
|
||||||
|| {letfun, _, {id, A, Name}, _, _, _} <- Defs],
|
({fun_clauses, _, {id, Ann, Name}, _, _}) -> {Name, fresh_uvar(Ann)}
|
||||||
|
end, Defs),
|
||||||
ExtendEnv = bind_funs(Funs, Env),
|
ExtendEnv = bind_funs(Funs, Env),
|
||||||
Inferred =
|
Inferred =
|
||||||
[ begin
|
[ begin
|
||||||
@ -1031,26 +1060,51 @@ infer_letrec(Env, Defs) ->
|
|||||||
[print_typesig(S) || S <- TypeSigs],
|
[print_typesig(S) || S <- TypeSigs],
|
||||||
{TypeSigs, NewDefs}.
|
{TypeSigs, NewDefs}.
|
||||||
|
|
||||||
infer_letfun(Env0, {letfun, Attrib, Fun = {id, NameAttrib, Name}, Args, What, Body}) ->
|
infer_letfun(Env, {fun_clauses, Ann, Fun = {id, _, Name}, Type, Clauses}) ->
|
||||||
|
Type1 = check_type(Env, Type),
|
||||||
|
{NameSigs, Clauses1} = lists:unzip([ infer_letfun1(Env, Clause) || Clause <- Clauses ]),
|
||||||
|
{_, Sigs = [Sig | _]} = lists:unzip(NameSigs),
|
||||||
|
_ = [ begin
|
||||||
|
ClauseT = typesig_to_fun_t(ClauseSig),
|
||||||
|
unify(Env, ClauseT, Type1, {check_typesig, Name, ClauseT, Type1})
|
||||||
|
end || ClauseSig <- Sigs ],
|
||||||
|
{{Name, Sig}, desugar_clauses(Ann, Fun, Sig, Clauses1)};
|
||||||
|
infer_letfun(Env, LetFun = {letfun, Ann, Fun, _, _, _}) ->
|
||||||
|
{{Name, Sig}, Clause} = infer_letfun1(Env, LetFun),
|
||||||
|
{{Name, Sig}, desugar_clauses(Ann, Fun, Sig, [Clause])}.
|
||||||
|
|
||||||
|
infer_letfun1(Env0, {letfun, Attrib, Fun = {id, NameAttrib, Name}, Args, What, Body}) ->
|
||||||
Env = Env0#env{ stateful = aeso_syntax:get_ann(stateful, Attrib, false),
|
Env = Env0#env{ stateful = aeso_syntax:get_ann(stateful, Attrib, false),
|
||||||
current_function = Fun },
|
current_function = Fun },
|
||||||
check_unique_arg_names(Fun, Args),
|
{NewEnv, {typed, _, {tuple, _, TypedArgs}, {tuple_t, _, ArgTypes}}} = infer_pattern(Env, {tuple, [{origin, system} | NameAttrib], Args}),
|
||||||
ArgTypes = [{ArgName, check_type(Env, arg_type(ArgAnn, T))} || {arg, ArgAnn, ArgName, T} <- Args],
|
|
||||||
ExpectedType = check_type(Env, arg_type(NameAttrib, What)),
|
ExpectedType = check_type(Env, arg_type(NameAttrib, What)),
|
||||||
NewBody={typed, _, _, ResultType} = check_expr(bind_vars(ArgTypes, Env), Body, ExpectedType),
|
NewBody={typed, _, _, ResultType} = check_expr(NewEnv, Body, ExpectedType),
|
||||||
NewArgs = [{arg, A1, {id, A2, ArgName}, T}
|
|
||||||
|| {{_, T}, {arg, A1, {id, A2, ArgName}, _}} <- lists:zip(ArgTypes, Args)],
|
|
||||||
NamedArgs = [],
|
NamedArgs = [],
|
||||||
TypeSig = {type_sig, Attrib, none, NamedArgs, [T || {arg, _, _, T} <- NewArgs], ResultType},
|
TypeSig = {type_sig, Attrib, none, NamedArgs, ArgTypes, ResultType},
|
||||||
{{Name, TypeSig},
|
{{Name, TypeSig},
|
||||||
{letfun, Attrib, {id, NameAttrib, Name}, NewArgs, ResultType, NewBody}}.
|
{letfun, Attrib, {id, NameAttrib, Name}, TypedArgs, ResultType, NewBody}}.
|
||||||
|
|
||||||
check_unique_arg_names(Fun, Args) ->
|
desugar_clauses(Ann, Fun, {type_sig, _, _, _, ArgTypes, RetType}, Clauses) ->
|
||||||
Name = fun({arg, _, {id, _, X}, _}) -> X end,
|
NeedDesugar =
|
||||||
Names = lists:map(Name, Args),
|
case Clauses of
|
||||||
Dups = lists:usort(Names -- lists:usort(Names)),
|
[{letfun, _, _, As, _, _}] -> lists:any(fun({typed, _, {id, _, _}, _}) -> false; (_) -> true end, As);
|
||||||
[ type_error({repeated_arg, Fun, Arg}) || Arg <- Dups ],
|
_ -> true
|
||||||
ok.
|
end,
|
||||||
|
case NeedDesugar of
|
||||||
|
false -> [Clause] = Clauses, Clause;
|
||||||
|
true ->
|
||||||
|
NoAnn = [{origin, system}],
|
||||||
|
Args = [ {typed, NoAnn, {id, NoAnn, "x#" ++ integer_to_list(I)}, Type}
|
||||||
|
|| {I, Type} <- indexed(1, ArgTypes) ],
|
||||||
|
Tuple = fun([X]) -> X;
|
||||||
|
(As) -> {typed, NoAnn, {tuple, NoAnn, As}, {tuple_t, NoAnn, ArgTypes}}
|
||||||
|
end,
|
||||||
|
{letfun, Ann, Fun, Args, RetType,
|
||||||
|
{typed, NoAnn,
|
||||||
|
{switch, NoAnn, Tuple(Args),
|
||||||
|
[ {'case', AnnC, Tuple(ArgsC), Body}
|
||||||
|
|| {letfun, AnnC, _, ArgsC, _, Body} <- Clauses ]}, RetType}}
|
||||||
|
end.
|
||||||
|
|
||||||
print_typesig({Name, TypeSig}) ->
|
print_typesig({Name, TypeSig}) ->
|
||||||
?PRINT_TYPES("Inferred ~s : ~s\n", [Name, pp(TypeSig)]).
|
?PRINT_TYPES("Inferred ~s : ~s\n", [Name, pp(TypeSig)]).
|
||||||
@ -1143,9 +1197,9 @@ get_call_chains(Graph, Visited, Queue, Stop, Acc) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
check_expr(Env, Expr, Type) ->
|
check_expr(Env, Expr, Type) ->
|
||||||
E = {typed, _, _, Type1} = infer_expr(Env, Expr),
|
{typed, Ann, Expr1, Type1} = infer_expr(Env, Expr),
|
||||||
unify(Env, Type1, Type, {check_expr, Expr, Type1, Type}),
|
unify(Env, Type1, Type, {check_expr, Expr, Type1, Type}),
|
||||||
E.
|
{typed, Ann, Expr1, Type}. %% Keep the user-given type
|
||||||
|
|
||||||
infer_expr(_Env, Body={bool, As, _}) ->
|
infer_expr(_Env, Body={bool, As, _}) ->
|
||||||
{typed, As, Body, {id, As, "bool"}};
|
{typed, As, Body, {id, As, "bool"}};
|
||||||
@ -1430,7 +1484,7 @@ infer_pattern(Env, Pattern) ->
|
|||||||
end,
|
end,
|
||||||
NewEnv = bind_vars([{Var, fresh_uvar(Ann1)} || Var = {id, Ann1, _} <- Vars], Env#env{ in_pattern = true }),
|
NewEnv = bind_vars([{Var, fresh_uvar(Ann1)} || Var = {id, Ann1, _} <- Vars], Env#env{ in_pattern = true }),
|
||||||
NewPattern = infer_expr(NewEnv, Pattern),
|
NewPattern = infer_expr(NewEnv, Pattern),
|
||||||
{NewEnv, NewPattern}.
|
{NewEnv#env{ in_pattern = Env#env.in_pattern }, NewPattern}.
|
||||||
|
|
||||||
infer_case(Env, Attrs, Pattern, ExprType, Branch, SwitchType) ->
|
infer_case(Env, Attrs, Pattern, ExprType, Branch, SwitchType) ->
|
||||||
{NewEnv, NewPattern = {typed, _, _, PatType}} = infer_pattern(Env, Pattern),
|
{NewEnv, NewPattern = {typed, _, _, PatType}} = infer_pattern(Env, Pattern),
|
||||||
@ -2802,3 +2856,7 @@ updates_key(Name, Updates) ->
|
|||||||
Updates1 = [ Upd || {Upd, false, _} <- Xs ],
|
Updates1 = [ Upd || {Upd, false, _} <- Xs ],
|
||||||
More = [ Rest || {_, true, Rest} <- Xs ],
|
More = [ Rest || {_, true, Rest} <- Xs ],
|
||||||
{More, Updates1}.
|
{More, Updates1}.
|
||||||
|
|
||||||
|
indexed(I, Xs) ->
|
||||||
|
lists:zip(lists:seq(I, I + length(Xs) - 1), Xs).
|
||||||
|
|
||||||
|
@ -433,9 +433,12 @@ type_to_fcode(Env, Sub, {fun_t, _, Named, Args, Res}) ->
|
|||||||
type_to_fcode(_Env, _Sub, Type) ->
|
type_to_fcode(_Env, _Sub, Type) ->
|
||||||
error({todo, Type}).
|
error({todo, Type}).
|
||||||
|
|
||||||
-spec args_to_fcode(env(), [aeso_syntax:arg()]) -> [{var_name(), ftype()}].
|
-spec args_to_fcode(env(), [aeso_syntax:pat()]) -> [{var_name(), ftype()}].
|
||||||
args_to_fcode(Env, Args) ->
|
args_to_fcode(Env, Args) ->
|
||||||
[ {Name, type_to_fcode(Env, Type)} || {arg, _, {id, _, Name}, Type} <- Args ].
|
[ case Arg of
|
||||||
|
{id, _, Name} -> {Name, type_to_fcode(Env, Type)};
|
||||||
|
_ -> internal_error({bad_arg, Arg}) %% Pattern matching has been moved to the rhs at this point
|
||||||
|
end || {typed, _, Arg, Type} <- Args ].
|
||||||
|
|
||||||
-define(make_let(X, Expr, Body),
|
-define(make_let(X, Expr, Body),
|
||||||
make_let(Expr, fun(X) -> Body end)).
|
make_let(Expr, fun(X) -> Body end)).
|
||||||
@ -740,7 +743,7 @@ validate_aens_resolve_type(Ann, {app_t, _, _, [Type]}, {variant, [[], [FType]]})
|
|||||||
|
|
||||||
ensure_first_order_entrypoint(Ann, Id = {id, _, Name}, Args, Ret, FArgs, FRet) ->
|
ensure_first_order_entrypoint(Ann, Id = {id, _, Name}, Args, Ret, FArgs, FRet) ->
|
||||||
[ ensure_first_order(FT, {invalid_entrypoint, higher_order, Ann1, Id, {argument, X, T}})
|
[ ensure_first_order(FT, {invalid_entrypoint, higher_order, Ann1, Id, {argument, X, T}})
|
||||||
|| {{arg, Ann1, X, T}, {_, FT}} <- lists:zip(Args, FArgs) ],
|
|| {{typed, Ann1, X, T}, {_, FT}} <- lists:zip(Args, FArgs) ],
|
||||||
[ ensure_first_order(FRet, {invalid_entrypoint, higher_order, Ann, Id, {result, Ret}})
|
[ ensure_first_order(FRet, {invalid_entrypoint, higher_order, Ann, Id, {result, Ret}})
|
||||||
|| Name /= "init" ], %% init can return higher-order values, since they're written to the store
|
|| Name /= "init" ], %% init can return higher-order values, since they're written to the store
|
||||||
%% rather than being returned.
|
%% rather than being returned.
|
||||||
@ -986,7 +989,11 @@ stmts_to_fcode(Env, [{letval, _, {typed, _, {id, _, X}, _}, Expr} | Stmts]) ->
|
|||||||
stmts_to_fcode(Env, [{letval, Ann, Pat, Expr} | Stmts]) ->
|
stmts_to_fcode(Env, [{letval, Ann, Pat, Expr} | Stmts]) ->
|
||||||
expr_to_fcode(Env, {switch, Ann, Expr, [{'case', Ann, Pat, {block, Ann, Stmts}}]});
|
expr_to_fcode(Env, {switch, Ann, Expr, [{'case', Ann, Pat, {block, Ann, Stmts}}]});
|
||||||
stmts_to_fcode(Env, [{letfun, Ann, {id, _, X}, Args, _Type, Expr} | Stmts]) ->
|
stmts_to_fcode(Env, [{letfun, Ann, {id, _, X}, Args, _Type, Expr} | Stmts]) ->
|
||||||
{'let', X, expr_to_fcode(Env, {lam, Ann, Args, Expr}),
|
LamArgs = [ case Arg of
|
||||||
|
{typed, Ann1, Id, T} -> {arg, Ann1, Id, T};
|
||||||
|
_ -> internal_error({bad_arg, Arg}) %% pattern matching has been desugared
|
||||||
|
end || Arg <- Args ],
|
||||||
|
{'let', X, expr_to_fcode(Env, {lam, Ann, LamArgs, Expr}),
|
||||||
stmts_to_fcode(bind_var(Env, X), Stmts)};
|
stmts_to_fcode(bind_var(Env, X), Stmts)};
|
||||||
stmts_to_fcode(Env, [Expr]) ->
|
stmts_to_fcode(Env, [Expr]) ->
|
||||||
expr_to_fcode(Env, Expr);
|
expr_to_fcode(Env, Expr);
|
||||||
@ -1351,7 +1358,7 @@ simplify(Env, {proj, {var, X}, I} = Expr) ->
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
simplify(Env, {switch, Split}) ->
|
simplify(Env, {switch, Split}) ->
|
||||||
case simpl_switch(Env, Split) of
|
case simpl_switch(Env, [], Split) of
|
||||||
nomatch -> {builtin, abort, [{lit, {string, <<"Incomplete patterns">>}}]};
|
nomatch -> {builtin, abort, [{lit, {string, <<"Incomplete patterns">>}}]};
|
||||||
stuck -> {switch, Split};
|
stuck -> {switch, Split};
|
||||||
Expr -> Expr
|
Expr -> Expr
|
||||||
@ -1375,21 +1382,51 @@ simpl_proj(Env, I, Expr) ->
|
|||||||
_ -> false
|
_ -> false
|
||||||
end.
|
end.
|
||||||
|
|
||||||
simpl_switch(_Env, {nosplit, E}) -> E;
|
get_catchalls(Alts) ->
|
||||||
simpl_switch(Env, {split, _, X, Alts}) ->
|
[ C || C = {'case', {var, _}, _} <- Alts ].
|
||||||
case constructor_form(Env, {var, X}) of
|
|
||||||
false -> stuck;
|
%% The scode compiler can't handle multiple catch-alls, so we need to nest them
|
||||||
E -> simpl_switch(Env, E, Alts)
|
%% inside each other. Instead of
|
||||||
|
%% _ => switch(x) ..
|
||||||
|
%% _ => e
|
||||||
|
%% we do
|
||||||
|
%% _ => switch(x)
|
||||||
|
%% ..
|
||||||
|
%% _ => e
|
||||||
|
add_catchalls(Alts, []) -> Alts;
|
||||||
|
add_catchalls(Alts, Catchalls) ->
|
||||||
|
case lists:splitwith(fun({'case', {var, _}, _}) -> false; (_) -> true end,
|
||||||
|
Alts) of
|
||||||
|
{Alts1, [C]} -> Alts1 ++ [nest_catchalls([C | Catchalls])];
|
||||||
|
{_, []} -> Alts ++ [nest_catchalls(Catchalls)]
|
||||||
|
%% NOTE: relies on catchalls always being at the end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
simpl_switch(_, _, []) -> nomatch;
|
nest_catchalls([C = {'case', {var, _}, {nosplit, _}} | _]) -> C;
|
||||||
simpl_switch(Env, E, [{'case', Pat, Body} | Alts]) ->
|
nest_catchalls([{'case', P = {var, _}, {split, Type, X, Alts}} | Catchalls]) ->
|
||||||
|
{'case', P, {split, Type, X, add_catchalls(Alts, Catchalls)}}.
|
||||||
|
|
||||||
|
simpl_switch(_Env, _, {nosplit, E}) -> E;
|
||||||
|
simpl_switch(Env, Catchalls, {split, Type, X, Alts}) ->
|
||||||
|
Alts1 = add_catchalls(Alts, Catchalls),
|
||||||
|
Stuck = {switch, {split, Type, X, Alts1}},
|
||||||
|
case constructor_form(Env, {var, X}) of
|
||||||
|
false -> Stuck;
|
||||||
|
E ->
|
||||||
|
case simpl_case(Env, E, Alts1) of
|
||||||
|
stuck -> Stuck;
|
||||||
|
Res -> Res
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
simpl_case(_, _, []) -> nomatch;
|
||||||
|
simpl_case(Env, E, [{'case', Pat, Body} | Alts]) ->
|
||||||
case match_pat(Pat, E) of
|
case match_pat(Pat, E) of
|
||||||
false -> simpl_switch(Env, E, Alts);
|
false -> simpl_case(Env, E, Alts);
|
||||||
Binds ->
|
Binds ->
|
||||||
Env1 = maps:merge(Env, maps:from_list(Binds)),
|
Env1 = maps:merge(Env, maps:from_list(Binds)),
|
||||||
case simpl_switch(Env1, Body) of
|
case simpl_switch(Env1, get_catchalls(Alts), Body) of
|
||||||
nomatch -> simpl_switch(Env, E, Alts);
|
nomatch -> simpl_case(Env, E, Alts);
|
||||||
stuck -> stuck;
|
stuck -> stuck;
|
||||||
Body1 -> let_bind(Binds, Body1)
|
Body1 -> let_bind(Binds, Body1)
|
||||||
end
|
end
|
||||||
|
@ -131,7 +131,7 @@ contract_to_icode([Decl | Code], Icode) ->
|
|||||||
ast_id({id, _, Id}) -> Id;
|
ast_id({id, _, Id}) -> Id;
|
||||||
ast_id({qid, _, Id}) -> Id.
|
ast_id({qid, _, Id}) -> Id.
|
||||||
|
|
||||||
ast_args([{arg, _, Name, Type}|Rest], Acc, Icode) ->
|
ast_args([{typed, _, Name, Type}|Rest], Acc, Icode) ->
|
||||||
ast_args(Rest, [{ast_id(Name), ast_typerep1(Type, Icode)}| Acc], Icode);
|
ast_args(Rest, [{ast_id(Name), ast_typerep1(Type, Icode)}| Acc], Icode);
|
||||||
ast_args([], Acc, _Icode) -> lists:reverse(Acc).
|
ast_args([], Acc, _Icode) -> lists:reverse(Acc).
|
||||||
|
|
||||||
@ -355,7 +355,9 @@ ast_body({block, As, [{letval, _, Pat, E} | Rest]}, Icode) ->
|
|||||||
#switch{expr = E1,
|
#switch{expr = E1,
|
||||||
cases = [{Pat1, Rest1}]};
|
cases = [{Pat1, Rest1}]};
|
||||||
ast_body({block, As, [{letfun, Ann, F, Args, _Type, Expr} | Rest]}, Icode) ->
|
ast_body({block, As, [{letfun, Ann, F, Args, _Type, Expr} | Rest]}, Icode) ->
|
||||||
ast_body({block, As, [{letval, Ann, F, {lam, Ann, Args, Expr}} | Rest]}, Icode);
|
ToArg = fun({typed, Ann1, Id, T}) -> {arg, Ann1, Id, T} end, %% Pattern matching has been desugared
|
||||||
|
LamArgs = lists:map(ToArg, Args),
|
||||||
|
ast_body({block, As, [{letval, Ann, F, {lam, Ann, LamArgs, Expr}} | Rest]}, Icode);
|
||||||
ast_body({block,_,[]}, _Icode) ->
|
ast_body({block,_,[]}, _Icode) ->
|
||||||
#tuple{cpts=[]};
|
#tuple{cpts=[]};
|
||||||
ast_body({block,_,[E]}, Icode) ->
|
ast_body({block,_,[E]}, Icode) ->
|
||||||
@ -811,10 +813,10 @@ check_entrypoint_type(Ann, Name, Args, Ret) ->
|
|||||||
true -> ok
|
true -> ok
|
||||||
end end,
|
end end,
|
||||||
[ CheckFirstOrder(T, {invalid_entrypoint, higher_order, Ann1, Name, {argument, X, T}})
|
[ CheckFirstOrder(T, {invalid_entrypoint, higher_order, Ann1, Name, {argument, X, T}})
|
||||||
|| {arg, Ann1, X, T} <- Args ],
|
|| {typed, Ann1, X, T} <- Args ],
|
||||||
CheckFirstOrder(Ret, {invalid_entrypoint, higher_order, Ann, Name, {result, Ret}}),
|
CheckFirstOrder(Ret, {invalid_entrypoint, higher_order, Ann, Name, {result, Ret}}),
|
||||||
[ CheckMonomorphic(T, {invalid_entrypoint, polymorphic, Ann1, Name, {argument, X, T}})
|
[ CheckMonomorphic(T, {invalid_entrypoint, polymorphic, Ann1, Name, {argument, X, T}})
|
||||||
|| {arg, Ann1, X, T} <- Args ],
|
|| {typed, Ann1, X, T} <- Args ],
|
||||||
CheckMonomorphic(Ret, {invalid_entrypoint, polymorphic, Ann, Name, {result, Ret}}).
|
CheckMonomorphic(Ret, {invalid_entrypoint, polymorphic, Ann, Name, {result, Ret}}).
|
||||||
|
|
||||||
check_oracle_type(Ann, Type = ?oracle_t(QType, RType)) ->
|
check_oracle_type(Ann, Type = ?oracle_t(QType, RType)) ->
|
||||||
|
@ -389,8 +389,8 @@ decode_calldata(ContractString, FunName, Calldata, Options0) ->
|
|||||||
#{ typed_ast := TypedAst, type_env := TypeEnv} = Code,
|
#{ typed_ast := TypedAst, type_env := TypeEnv} = Code,
|
||||||
|
|
||||||
{ok, Args, _} = get_decode_type(FunName, TypedAst),
|
{ok, Args, _} = get_decode_type(FunName, TypedAst),
|
||||||
DropArg = fun({arg, _, _, T}) -> T; (T) -> T end,
|
GetType = fun({typed, _, _, T}) -> T; (T) -> T end,
|
||||||
ArgTypes = lists:map(DropArg, Args),
|
ArgTypes = lists:map(GetType, Args),
|
||||||
Type0 = {tuple_t, [], ArgTypes},
|
Type0 = {tuple_t, [], ArgTypes},
|
||||||
%% user defined data types such as variants needed to match against
|
%% user defined data types such as variants needed to match against
|
||||||
Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, [unfold_record_types, unfold_variant_types]),
|
Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, [unfold_record_types, unfold_variant_types]),
|
||||||
|
@ -101,11 +101,19 @@ decl() ->
|
|||||||
, ?RULE(keyword(datatype), id(), type_vars(), tok('='), typedef(variant), {type_def, _1, _2, _3, _5})
|
, ?RULE(keyword(datatype), id(), type_vars(), tok('='), typedef(variant), {type_def, _1, _2, _3, _5})
|
||||||
|
|
||||||
%% Function declarations
|
%% Function declarations
|
||||||
, ?RULE(modifiers(), fun_or_entry(), id(), tok(':'), type(), add_modifiers(_1, _2, {fun_decl, get_ann(_2), _3, _5}))
|
, ?RULE(modifiers(), fun_or_entry(), maybe_block(fundef_or_decl()), fun_block(_1, _2, _3))
|
||||||
, ?RULE(modifiers(), fun_or_entry(), fundef(), add_modifiers(_1, _2, set_pos(get_pos(get_ann(_2)), _3)))
|
, ?RULE(keyword('let'), valdef(),set_pos(get_pos(_1), _2))
|
||||||
, ?RULE(keyword('let'), valdef(), set_pos(get_pos(_1), _2))
|
|
||||||
])).
|
])).
|
||||||
|
|
||||||
|
fun_block(Mods, Kind, [Decl]) ->
|
||||||
|
add_modifiers(Mods, Kind, set_pos(get_pos(Kind), Decl));
|
||||||
|
fun_block(Mods, Kind, Decls) ->
|
||||||
|
{block, get_ann(Kind), [ add_modifiers(Mods, Kind, Decl) || Decl <- Decls ]}.
|
||||||
|
|
||||||
|
fundef_or_decl() ->
|
||||||
|
choice([?RULE(id(), tok(':'), type(), {fun_decl, get_ann(_1), _1, _3}),
|
||||||
|
fundef()]).
|
||||||
|
|
||||||
pragma() ->
|
pragma() ->
|
||||||
Op = choice([token(T) || T <- ['<', '=<', '==', '>=', '>']]),
|
Op = choice([token(T) || T <- ['<', '=<', '==', '>=', '>']]),
|
||||||
?RULE(tok('@'), id("compiler"), Op, version(), {pragma, get_ann(_1), {compiler, element(1, _3), _4}}).
|
?RULE(tok('@'), id("compiler"), Op, version(), {pragma, get_ann(_1), {compiler, element(1, _3), _4}}).
|
||||||
@ -168,14 +176,15 @@ valdef() ->
|
|||||||
|
|
||||||
fundef() ->
|
fundef() ->
|
||||||
choice(
|
choice(
|
||||||
[ ?RULE(id(), args(), tok('='), body(), {letfun, [], _1, _2, type_wildcard(), _4})
|
[ ?RULE(id(), args(), tok('='), body(), {letfun, get_ann(_1), _1, _2, type_wildcard(get_ann(_1)), _4})
|
||||||
, ?RULE(id(), args(), tok(':'), type(), tok('='), body(), {letfun, [], _1, _2, _4, _6})
|
, ?RULE(id(), args(), tok(':'), type(), tok('='), body(), {letfun, get_ann(_1), _1, _2, _4, _6})
|
||||||
]).
|
]).
|
||||||
|
|
||||||
args() -> paren_list(arg()).
|
args() -> paren_list(pattern()).
|
||||||
|
lam_args() -> paren_list(arg()).
|
||||||
|
|
||||||
arg() -> choice(
|
arg() -> choice(
|
||||||
?RULE(id(), {arg, get_ann(_1), _1, type_wildcard()}),
|
?RULE(id(), {arg, get_ann(_1), _1, type_wildcard(get_ann(_1))}),
|
||||||
?RULE(id(), tok(':'), type(), {arg, get_ann(_1), _1, _3})).
|
?RULE(id(), tok(':'), type(), {arg, get_ann(_1), _1, _3})).
|
||||||
|
|
||||||
%% -- Types ------------------------------------------------------------------
|
%% -- Types ------------------------------------------------------------------
|
||||||
@ -246,7 +255,7 @@ expr100() ->
|
|||||||
Expr100 = ?LAZY_P(expr100()),
|
Expr100 = ?LAZY_P(expr100()),
|
||||||
Expr200 = ?LAZY_P(expr200()),
|
Expr200 = ?LAZY_P(expr200()),
|
||||||
choice(
|
choice(
|
||||||
[ ?RULE(args(), keyword('=>'), body(), {lam, _2, _1, _3}) %% TODO: better location
|
[ ?RULE(lam_args(), keyword('=>'), body(), {lam, _2, _1, _3}) %% TODO: better location
|
||||||
, {'if', keyword('if'), parens(Expr100), Expr200, right(tok(else), Expr100)}
|
, {'if', keyword('if'), parens(Expr100), Expr200, right(tok(else), Expr100)}
|
||||||
, ?RULE(Expr200, optional(right(tok(':'), type())),
|
, ?RULE(Expr200, optional(right(tok(':'), type())),
|
||||||
case _2 of
|
case _2 of
|
||||||
@ -492,8 +501,8 @@ infix(L, Op, R) -> set_ann(format, infix, {app, get_ann(L), Op, [L, R]}).
|
|||||||
prefixes(Ops, E) -> lists:foldr(fun prefix/2, E, Ops).
|
prefixes(Ops, E) -> lists:foldr(fun prefix/2, E, Ops).
|
||||||
prefix(Op, E) -> set_ann(format, prefix, {app, get_ann(Op), Op, [E]}).
|
prefix(Op, E) -> set_ann(format, prefix, {app, get_ann(Op), Op, [E]}).
|
||||||
|
|
||||||
type_wildcard() ->
|
type_wildcard(Ann) ->
|
||||||
{id, [{origin, system}], "_"}.
|
{id, [{origin, system} | Ann], "_"}.
|
||||||
|
|
||||||
block_e(Stmts) ->
|
block_e(Stmts) ->
|
||||||
group_ifs(Stmts, []).
|
group_ifs(Stmts, []).
|
||||||
|
@ -169,7 +169,11 @@ decl(D = {letfun, Attrs, _, _, _, _}) ->
|
|||||||
false -> "function"
|
false -> "function"
|
||||||
end,
|
end,
|
||||||
hsep(lists:map(Mod, Attrs) ++ [letdecl(Fun, D)]);
|
hsep(lists:map(Mod, Attrs) ++ [letdecl(Fun, D)]);
|
||||||
decl(D = {letval, _, _, _}) -> letdecl("let", D).
|
decl({fun_clauses, Ann, Name, Type, Clauses}) ->
|
||||||
|
above([ decl(D) || D <- [{fun_decl, Ann, Name, Type} | Clauses] ]);
|
||||||
|
decl(D = {letval, _, _, _}) -> letdecl("let", D);
|
||||||
|
decl({block, _, Ds}) ->
|
||||||
|
above([ decl(D) || D <- Ds ]).
|
||||||
|
|
||||||
-spec pragma(aeso_syntax:pragma()) -> doc().
|
-spec pragma(aeso_syntax:pragma()) -> doc().
|
||||||
pragma({compiler, Op, Ver}) ->
|
pragma({compiler, Op, Ver}) ->
|
||||||
@ -196,7 +200,7 @@ name({typed, _, Name, _}) -> name(Name).
|
|||||||
letdecl(Let, {letval, _, P, E}) ->
|
letdecl(Let, {letval, _, P, E}) ->
|
||||||
block_expr(0, hsep([text(Let), expr(P), text("=")]), E);
|
block_expr(0, hsep([text(Let), expr(P), text("=")]), E);
|
||||||
letdecl(Let, {letfun, _, F, Args, T, E}) ->
|
letdecl(Let, {letfun, _, F, Args, T, E}) ->
|
||||||
block_expr(0, hsep([text(Let), typed(beside(name(F), args(Args)), T), text("=")]), E).
|
block_expr(0, hsep([text(Let), typed(beside(name(F), expr({tuple, [], Args})), T), text("=")]), E).
|
||||||
|
|
||||||
-spec args([aeso_syntax:arg()]) -> doc().
|
-spec args([aeso_syntax:arg()]) -> doc().
|
||||||
args(Args) ->
|
args(Args) ->
|
||||||
|
@ -40,6 +40,8 @@
|
|||||||
| {type_decl, ann(), id(), [tvar()]}
|
| {type_decl, ann(), id(), [tvar()]}
|
||||||
| {type_def, ann(), id(), [tvar()], typedef()}
|
| {type_def, ann(), id(), [tvar()], typedef()}
|
||||||
| {fun_decl, ann(), id(), type()}
|
| {fun_decl, ann(), id(), type()}
|
||||||
|
| {fun_clauses, ann(), id(), type(), [letbind()]}
|
||||||
|
| {block, ann(), [decl()]}
|
||||||
| letbind().
|
| letbind().
|
||||||
|
|
||||||
-type compiler_version() :: [non_neg_integer()].
|
-type compiler_version() :: [non_neg_integer()].
|
||||||
@ -48,7 +50,7 @@
|
|||||||
|
|
||||||
-type letbind()
|
-type letbind()
|
||||||
:: {letval, ann(), pat(), expr()}
|
:: {letval, ann(), pat(), expr()}
|
||||||
| {letfun, ann(), id(), [arg()], type(), expr()}.
|
| {letfun, ann(), id(), [pat()], type(), expr()}.
|
||||||
|
|
||||||
-type arg() :: {arg, ann(), id(), type()}.
|
-type arg() :: {arg, ann(), id(), type()}.
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) ->
|
|||||||
{fun_decl, _, _, T} -> Type(T);
|
{fun_decl, _, _, T} -> Type(T);
|
||||||
{letval, _, P, E} -> Scoped(BindExpr(P), Expr(E));
|
{letval, _, P, E} -> Scoped(BindExpr(P), Expr(E));
|
||||||
{letfun, _, F, Xs, T, E} -> Sum([BindExpr(F), Type(T), Expr(Xs ++ [E])]);
|
{letfun, _, F, Xs, T, E} -> Sum([BindExpr(F), Type(T), Expr(Xs ++ [E])]);
|
||||||
|
{fun_clauses, _, _, T, Cs} -> Sum([Type(T) | [Decl(C) || C <- Cs]]);
|
||||||
%% typedef()
|
%% typedef()
|
||||||
{alias_t, T} -> Type(T);
|
{alias_t, T} -> Type(T);
|
||||||
{record_t, Fs} -> Type(Fs);
|
{record_t, Fs} -> Type(Fs);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{application, aesophia,
|
{application, aesophia,
|
||||||
[{description, "Contract Language for aeternity"},
|
[{description, "Contract Language for aeternity"},
|
||||||
{vsn, "4.1.0"},
|
{vsn, "4.2.0"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications,
|
{applications,
|
||||||
[kernel,
|
[kernel,
|
||||||
|
@ -165,7 +165,8 @@ compilable_contracts() ->
|
|||||||
"underscore_number_literals",
|
"underscore_number_literals",
|
||||||
"pairing_crypto",
|
"pairing_crypto",
|
||||||
"qualified_constructor",
|
"qualified_constructor",
|
||||||
"let_patterns"
|
"let_patterns",
|
||||||
|
"lhs_matching"
|
||||||
].
|
].
|
||||||
|
|
||||||
not_yet_compilable(fate) -> [];
|
not_yet_compilable(fate) -> [];
|
||||||
@ -300,9 +301,22 @@ failing_contracts() ->
|
|||||||
"Repeated name x in pattern\n"
|
"Repeated name x in pattern\n"
|
||||||
" x :: x (at line 26, column 7)">>,
|
" x :: x (at line 26, column 7)">>,
|
||||||
<<?Pos(44, 14)
|
<<?Pos(44, 14)
|
||||||
"Repeated argument x to function repeated_arg (at line 44, column 14).">>,
|
"Repeated names x, y in pattern\n"
|
||||||
<<?Pos(44, 14)
|
" (x : int, y, x : string, y : bool) (at line 44, column 14)">>,
|
||||||
"Repeated argument y to function repeated_arg (at line 44, column 14).">>,
|
<<?Pos(44, 39)
|
||||||
|
"Cannot unify int\n"
|
||||||
|
" and string\n"
|
||||||
|
"when checking the type of the expression at line 44, column 39\n"
|
||||||
|
" x : int\n"
|
||||||
|
"against the expected type\n"
|
||||||
|
" string">>,
|
||||||
|
<<?Pos(44, 72)
|
||||||
|
"Cannot unify int\n"
|
||||||
|
" and string\n"
|
||||||
|
"when checking the type of the expression at line 44, column 72\n"
|
||||||
|
" x : int\n"
|
||||||
|
"against the expected type\n"
|
||||||
|
" string">>,
|
||||||
<<?Pos(14, 24)
|
<<?Pos(14, 24)
|
||||||
"No record type with fields y, z (at line 14, column 24)">>,
|
"No record type with fields y, z (at line 14, column 24)">>,
|
||||||
<<?Pos(15, 26)
|
<<?Pos(15, 26)
|
||||||
@ -368,73 +382,7 @@ failing_contracts() ->
|
|||||||
<<?Pos(3, 13)
|
<<?Pos(3, 13)
|
||||||
"Nested namespace not allowed\nNamespace 'Foo' at line 3, column 13 not defined at top level.">>])
|
"Nested namespace not allowed\nNamespace 'Foo' at line 3, column 13 not defined at top level.">>])
|
||||||
, ?TYPE_ERROR(bad_address_literals,
|
, ?TYPE_ERROR(bad_address_literals,
|
||||||
[<<?Pos(32, 5)
|
[<<?Pos(11, 5)
|
||||||
"The type bytes(32) is not a contract type\n"
|
|
||||||
"when checking that the contract literal\n"
|
|
||||||
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
|
||||||
"has the type\n"
|
|
||||||
" bytes(32)">>,
|
|
||||||
<<?Pos(30, 5)
|
|
||||||
"The type oracle(int, bool) is not a contract type\n"
|
|
||||||
"when checking that the contract literal\n"
|
|
||||||
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
|
||||||
"has the type\n"
|
|
||||||
" oracle(int, bool)">>,
|
|
||||||
<<?Pos(28, 5)
|
|
||||||
"The type address is not a contract type\n"
|
|
||||||
"when checking that the contract literal\n"
|
|
||||||
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
|
||||||
"has the type\n"
|
|
||||||
" address">>,
|
|
||||||
<<?Pos(25, 5)
|
|
||||||
"Cannot unify oracle_query('a, 'b)\n"
|
|
||||||
" and Remote\n"
|
|
||||||
"when checking the type of the expression at line 25, column 5\n"
|
|
||||||
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
|
|
||||||
" oracle_query('a, 'b)\n"
|
|
||||||
"against the expected type\n"
|
|
||||||
" Remote">>,
|
|
||||||
<<?Pos(23, 5)
|
|
||||||
"Cannot unify oracle_query('c, 'd)\n"
|
|
||||||
" and bytes(32)\n"
|
|
||||||
"when checking the type of the expression at line 23, column 5\n"
|
|
||||||
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
|
|
||||||
" oracle_query('c, 'd)\n"
|
|
||||||
"against the expected type\n"
|
|
||||||
" bytes(32)">>,
|
|
||||||
<<?Pos(21, 5)
|
|
||||||
"Cannot unify oracle_query('e, 'f)\n"
|
|
||||||
" and oracle(int, bool)\n"
|
|
||||||
"when checking the type of the expression at line 21, column 5\n"
|
|
||||||
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
|
|
||||||
" oracle_query('e, 'f)\n"
|
|
||||||
"against the expected type\n"
|
|
||||||
" oracle(int, bool)">>,
|
|
||||||
<<?Pos(18, 5)
|
|
||||||
"Cannot unify oracle('g, 'h)\n"
|
|
||||||
" and Remote\n"
|
|
||||||
"when checking the type of the expression at line 18, column 5\n"
|
|
||||||
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
|
|
||||||
" oracle('g, 'h)\n"
|
|
||||||
"against the expected type\n"
|
|
||||||
" Remote">>,
|
|
||||||
<<?Pos(16, 5)
|
|
||||||
"Cannot unify oracle('i, 'j)\n"
|
|
||||||
" and bytes(32)\n"
|
|
||||||
"when checking the type of the expression at line 16, column 5\n"
|
|
||||||
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
|
|
||||||
" oracle('i, 'j)\n"
|
|
||||||
"against the expected type\n"
|
|
||||||
" bytes(32)">>,
|
|
||||||
<<?Pos(14, 5)
|
|
||||||
"Cannot unify oracle('k, 'l)\n"
|
|
||||||
" and oracle_query(int, bool)\n"
|
|
||||||
"when checking the type of the expression at line 14, column 5\n"
|
|
||||||
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
|
|
||||||
" oracle('k, 'l)\n"
|
|
||||||
"against the expected type\n"
|
|
||||||
" oracle_query(int, bool)">>,
|
|
||||||
<<?Pos(11, 5)
|
|
||||||
"Cannot unify address\n"
|
"Cannot unify address\n"
|
||||||
" and oracle(int, bool)\n"
|
" and oracle(int, bool)\n"
|
||||||
"when checking the type of the expression at line 11, column 5\n"
|
"when checking the type of the expression at line 11, column 5\n"
|
||||||
@ -455,6 +403,72 @@ failing_contracts() ->
|
|||||||
" ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address\n"
|
" ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" bytes(32)">>,
|
" bytes(32)">>,
|
||||||
|
<<?Pos(14, 5)
|
||||||
|
"Cannot unify oracle('a, 'b)\n"
|
||||||
|
" and oracle_query(int, bool)\n"
|
||||||
|
"when checking the type of the expression at line 14, column 5\n"
|
||||||
|
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
|
||||||
|
" oracle('a, 'b)\n"
|
||||||
|
"against the expected type\n"
|
||||||
|
" oracle_query(int, bool)">>,
|
||||||
|
<<?Pos(16, 5)
|
||||||
|
"Cannot unify oracle('c, 'd)\n"
|
||||||
|
" and bytes(32)\n"
|
||||||
|
"when checking the type of the expression at line 16, column 5\n"
|
||||||
|
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
|
||||||
|
" oracle('c, 'd)\n"
|
||||||
|
"against the expected type\n"
|
||||||
|
" bytes(32)">>,
|
||||||
|
<<?Pos(18, 5)
|
||||||
|
"Cannot unify oracle('e, 'f)\n"
|
||||||
|
" and Remote\n"
|
||||||
|
"when checking the type of the expression at line 18, column 5\n"
|
||||||
|
" ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 :\n"
|
||||||
|
" oracle('e, 'f)\n"
|
||||||
|
"against the expected type\n"
|
||||||
|
" Remote">>,
|
||||||
|
<<?Pos(21, 5)
|
||||||
|
"Cannot unify oracle_query('g, 'h)\n"
|
||||||
|
" and oracle(int, bool)\n"
|
||||||
|
"when checking the type of the expression at line 21, column 5\n"
|
||||||
|
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
|
||||||
|
" oracle_query('g, 'h)\n"
|
||||||
|
"against the expected type\n"
|
||||||
|
" oracle(int, bool)">>,
|
||||||
|
<<?Pos(23, 5)
|
||||||
|
"Cannot unify oracle_query('i, 'j)\n"
|
||||||
|
" and bytes(32)\n"
|
||||||
|
"when checking the type of the expression at line 23, column 5\n"
|
||||||
|
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
|
||||||
|
" oracle_query('i, 'j)\n"
|
||||||
|
"against the expected type\n"
|
||||||
|
" bytes(32)">>,
|
||||||
|
<<?Pos(25, 5)
|
||||||
|
"Cannot unify oracle_query('k, 'l)\n"
|
||||||
|
" and Remote\n"
|
||||||
|
"when checking the type of the expression at line 25, column 5\n"
|
||||||
|
" oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY :\n"
|
||||||
|
" oracle_query('k, 'l)\n"
|
||||||
|
"against the expected type\n"
|
||||||
|
" Remote">>,
|
||||||
|
<<?Pos(28, 5)
|
||||||
|
"The type address is not a contract type\n"
|
||||||
|
"when checking that the contract literal\n"
|
||||||
|
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
||||||
|
"has the type\n"
|
||||||
|
" address">>,
|
||||||
|
<<?Pos(30, 5)
|
||||||
|
"The type oracle(int, bool) is not a contract type\n"
|
||||||
|
"when checking that the contract literal\n"
|
||||||
|
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
||||||
|
"has the type\n"
|
||||||
|
" oracle(int, bool)">>,
|
||||||
|
<<?Pos(32, 5)
|
||||||
|
"The type bytes(32) is not a contract type\n"
|
||||||
|
"when checking that the contract literal\n"
|
||||||
|
" ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ\n"
|
||||||
|
"has the type\n"
|
||||||
|
" bytes(32)">>,
|
||||||
<<?Pos(34, 5),
|
<<?Pos(34, 5),
|
||||||
"The type address is not a contract type\n"
|
"The type address is not a contract type\n"
|
||||||
"when checking that the call to\n"
|
"when checking that the call to\n"
|
||||||
@ -570,7 +584,7 @@ failing_contracts() ->
|
|||||||
"Failed to resolve byte array lengths in call to Bytes.split with argument of type\n"
|
"Failed to resolve byte array lengths in call to Bytes.split with argument of type\n"
|
||||||
" - 'f (at line 12, column 20)\n"
|
" - 'f (at line 12, column 20)\n"
|
||||||
"and result types\n"
|
"and result types\n"
|
||||||
" - 'e (at line 13, column 5)\n"
|
" - 'e (at line 12, column 25)\n"
|
||||||
" - bytes(20) (at line 12, column 29)">>,
|
" - bytes(20) (at line 12, column 29)">>,
|
||||||
<<?Pos(16, 5)
|
<<?Pos(16, 5)
|
||||||
"Failed to resolve byte array lengths in call to Bytes.split with argument of type\n"
|
"Failed to resolve byte array lengths in call to Bytes.split with argument of type\n"
|
||||||
@ -583,7 +597,7 @@ failing_contracts() ->
|
|||||||
" - 'b (at line 18, column 20)\n"
|
" - 'b (at line 18, column 20)\n"
|
||||||
"and result types\n"
|
"and result types\n"
|
||||||
" - bytes(20) (at line 18, column 25)\n"
|
" - bytes(20) (at line 18, column 25)\n"
|
||||||
" - 'a (at line 19, column 5)">>])
|
" - 'a (at line 18, column 37)">>])
|
||||||
, ?TYPE_ERROR(wrong_compiler_version,
|
, ?TYPE_ERROR(wrong_compiler_version,
|
||||||
[<<?Pos(1, 1)
|
[<<?Pos(1, 1)
|
||||||
"Cannot compile with this version of the compiler,\n"
|
"Cannot compile with this version of the compiler,\n"
|
||||||
|
@ -16,7 +16,7 @@ simple_contracts_test_() ->
|
|||||||
" function id(x) = x\n",
|
" function id(x) = x\n",
|
||||||
?assertMatch(
|
?assertMatch(
|
||||||
[{contract, _, {con, _, "Identity"},
|
[{contract, _, {con, _, "Identity"},
|
||||||
[{letfun, _, {id, _, "id"}, [{arg, _, {id, _, "x"}, {id, _, "_"}}], {id, _, "_"},
|
[{letfun, _, {id, _, "id"}, [{id, _, "x"}], {id, _, "_"},
|
||||||
{id, _, "x"}}]}], parse_string(Text)),
|
{id, _, "x"}}]}], parse_string(Text)),
|
||||||
ok
|
ok
|
||||||
end},
|
end},
|
||||||
|
@ -11,7 +11,7 @@ contract Factorial =
|
|||||||
|
|
||||||
stateful entrypoint set_worker(worker) = put(state{worker = worker})
|
stateful entrypoint set_worker(worker) = put(state{worker = worker})
|
||||||
|
|
||||||
entrypoint fac(x : int) : int =
|
entrypoint
|
||||||
if(x == 0) 1
|
fac : int => int
|
||||||
else x * state.worker.fac(x - 1)
|
fac(0) = 1
|
||||||
|
fac(x) = x * state.worker.fac(x - 1)
|
||||||
|
22
test/contracts/lhs_matching.aes
Normal file
22
test/contracts/lhs_matching.aes
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
contract LHSMatching =
|
||||||
|
|
||||||
|
function from_some(Some(x)) = x
|
||||||
|
|
||||||
|
function
|
||||||
|
length : list('a) => int
|
||||||
|
length([]) = 0
|
||||||
|
length(_ :: xs) = 1 + length(xs)
|
||||||
|
|
||||||
|
function
|
||||||
|
append([], ys) = ys
|
||||||
|
append(x :: xs, ys) = x :: append(xs, ys)
|
||||||
|
|
||||||
|
function local_match(xs : list('a)) =
|
||||||
|
let null([]) = true
|
||||||
|
let null(_ :: _) = false
|
||||||
|
!null(xs)
|
||||||
|
|
||||||
|
entrypoint main() =
|
||||||
|
from_some(Some([0]))
|
||||||
|
++ append([length([true]), 2, 3], [4, 5, 6])
|
||||||
|
++ [7 | if (local_match([false]))]
|
@ -8,10 +8,9 @@ contract Stack =
|
|||||||
|
|
||||||
entrypoint init(ss : list(string)) = { stack = ss, size = length(ss) }
|
entrypoint init(ss : list(string)) = { stack = ss, size = length(ss) }
|
||||||
|
|
||||||
function length(xs) =
|
function
|
||||||
switch(xs)
|
length([]) = 0
|
||||||
[] => 0
|
length(_ :: xs) = length(xs) + 1
|
||||||
_ :: xs => length(xs) + 1
|
|
||||||
|
|
||||||
stateful entrypoint pop() : string =
|
stateful entrypoint pop() : string =
|
||||||
switch(state.stack)
|
switch(state.stack)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user