Fix error messages for some illegal constructions, fix absolute path includes (#251)
* Updated tests, banned type decls and toplevel letvals * Properly ban nested contracts * Fix including by path * Fix error message test * Fix prettpr attr display. Make dialyzer happy * More tests * Fixed type printing * Updated docs
This commit is contained in:
parent
48b52cb501
commit
4f554acee6
@ -446,6 +446,13 @@ Example syntax:
|
|||||||
// yields [12,13,14,20,21,22,30,31,32]
|
// yields [12,13,14,20,21,22,30,31,32]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Lists can be constructed using the range syntax using special `..` operator:
|
||||||
|
```
|
||||||
|
[1..4] == [1,2,3,4]
|
||||||
|
```
|
||||||
|
The ranges are always ascending and have step equal to 1.
|
||||||
|
|
||||||
|
|
||||||
Please refer to the [standard library](sophia_stdlib.md#List) for the predefined functionalities.
|
Please refer to the [standard library](sophia_stdlib.md#List) for the predefined functionalities.
|
||||||
|
|
||||||
### Maps and records
|
### Maps and records
|
||||||
@ -825,15 +832,17 @@ In describing the syntax below, we use the following conventions:
|
|||||||
A Sophia file consists of a sequence of *declarations* in a layout block.
|
A Sophia file consists of a sequence of *declarations* in a layout block.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
File ::= Block(Decl)
|
File ::= Block(TopDecl)
|
||||||
Decl ::= ['payable'] 'contract' Con '=' Block(Decl)
|
|
||||||
|
TopDecl ::= ['payable'] 'contract' Con '=' Block(Decl)
|
||||||
| 'namespace' Con '=' Block(Decl)
|
| 'namespace' Con '=' Block(Decl)
|
||||||
| '@compiler' PragmaOp Version
|
| '@compiler' PragmaOp Version
|
||||||
| 'include' String
|
| 'include' String
|
||||||
| 'type' Id ['(' TVar* ')'] ['=' TypeAlias]
|
|
||||||
|
Decl ::= 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||||
| 'record' Id ['(' TVar* ')'] '=' RecordType
|
| 'record' Id ['(' TVar* ')'] '=' RecordType
|
||||||
| 'datatype' Id ['(' TVar* ')'] '=' DataType
|
| 'datatype' Id ['(' TVar* ')'] '=' DataType
|
||||||
| EModifier* ('entrypoint' | 'function') Block(FunDecl)
|
| (EModifier* 'entrypoint' | FModifier* 'function') Block(FunDecl)
|
||||||
|
|
||||||
FunDecl ::= Id ':' Type // Type signature
|
FunDecl ::= Id ':' Type // Type signature
|
||||||
| Id Args [':' Type] '=' Block(Stmt) // Definition
|
| Id Args [':' Type] '=' Block(Stmt) // Definition
|
||||||
@ -945,6 +954,7 @@ Expr ::= '(' LamArgs ')' '=>' Block(Stmt) // Anonymous function (x) => x +
|
|||||||
| '[' Sep(Expr, ',') ']' // List [1, 2, 3]
|
| '[' Sep(Expr, ',') ']' // List [1, 2, 3]
|
||||||
| '[' Expr '|' Sep(Generator, ',') ']'
|
| '[' Expr '|' Sep(Generator, ',') ']'
|
||||||
// List comprehension [k | x <- [1], if (f(x)), let k = x+1]
|
// List comprehension [k | x <- [1], if (f(x)), let k = x+1]
|
||||||
|
| '[' Expr '..' Expr ']' // List range [1..n]
|
||||||
| '{' Sep(FieldUpdate, ',') '}' // Record or map value {x = 0, y = 1}, {[key] = val}
|
| '{' Sep(FieldUpdate, ',') '}' // Record or map value {x = 0, y = 1}, {[key] = val}
|
||||||
| '(' Expr ')' // Parens (1 + 2) * 3
|
| '(' Expr ')' // Parens (1 + 2) * 3
|
||||||
| Id | Con | QId | QCon // Identifiers x, None, Map.member, AELib.Token
|
| Id | Con | QId | QCon // Identifiers x, None, Map.member, AELib.Token
|
||||||
|
@ -2262,6 +2262,24 @@ mk_t_err(Pos, Msg) ->
|
|||||||
mk_t_err(Pos, Msg, Ctxt) ->
|
mk_t_err(Pos, Msg, Ctxt) ->
|
||||||
aeso_errors:new(type_error, Pos, lists:flatten(Msg), lists:flatten(Ctxt)).
|
aeso_errors:new(type_error, Pos, lists:flatten(Msg), lists:flatten(Ctxt)).
|
||||||
|
|
||||||
|
mk_error({higher_kinded_typevar, T}) ->
|
||||||
|
Msg = io_lib:format("Type ~s is a higher kinded type variable\n"
|
||||||
|
"(takes another type as an argument)\n", [pp(instantiate(T))]
|
||||||
|
),
|
||||||
|
mk_t_err(pos(T), Msg);
|
||||||
|
mk_error({wrong_type_arguments, X, ArityGiven, ArityReal}) ->
|
||||||
|
Msg = io_lib:format("Arity for ~s doesn't match. Expected ~p, got ~p\n"
|
||||||
|
, [pp(instantiate(X)), ArityReal, ArityGiven]
|
||||||
|
),
|
||||||
|
mk_t_err(pos(X), Msg);
|
||||||
|
mk_error({unnamed_map_update_with_default, Upd}) ->
|
||||||
|
Msg = "Invalid map update with default\n",
|
||||||
|
mk_t_err(pos(Upd), Msg);
|
||||||
|
mk_error({fundecl_must_have_funtype, _Ann, Id, Type}) ->
|
||||||
|
Msg = io_lib:format("~s at ~s was declared with an invalid type ~s.\n"
|
||||||
|
"Entrypoints and functions must have functional types"
|
||||||
|
, [pp(Id), pp_loc(Id), pp(instantiate(Type))]),
|
||||||
|
mk_t_err(pos(Id), Msg);
|
||||||
mk_error({cannot_unify, A, B, When}) ->
|
mk_error({cannot_unify, A, B, When}) ->
|
||||||
Msg = io_lib:format("Cannot unify ~s\n and ~s\n",
|
Msg = io_lib:format("Cannot unify ~s\n and ~s\n",
|
||||||
[pp(instantiate(A)), pp(instantiate(B))]),
|
[pp(instantiate(A)), pp(instantiate(B))]),
|
||||||
@ -2344,14 +2362,6 @@ mk_error({indexed_type_must_be_word, Type, Type1}) ->
|
|||||||
Msg = io_lib:format("The indexed type ~s (at ~s) equals ~s which is not a word type\n",
|
Msg = io_lib:format("The indexed type ~s (at ~s) equals ~s which is not a word type\n",
|
||||||
[pp_type("", Type), pp_loc(Type), pp_type("", Type1)]),
|
[pp_type("", Type), pp_loc(Type), pp_type("", Type1)]),
|
||||||
mk_t_err(pos(Type), Msg);
|
mk_t_err(pos(Type), Msg);
|
||||||
mk_error({payload_type_must_be_string, Type, Type}) ->
|
|
||||||
Msg = io_lib:format("The payload type ~s (at ~s) should be string\n",
|
|
||||||
[pp_type("", Type), pp_loc(Type)]),
|
|
||||||
mk_t_err(pos(Type), Msg);
|
|
||||||
mk_error({payload_type_must_be_string, Type, Type1}) ->
|
|
||||||
Msg = io_lib:format("The payload type ~s (at ~s) equals ~s but it should be string\n",
|
|
||||||
[pp_type("", Type), pp_loc(Type), pp_type("", Type1)]),
|
|
||||||
mk_t_err(pos(Type), Msg);
|
|
||||||
mk_error({event_0_to_3_indexed_values, Constr}) ->
|
mk_error({event_0_to_3_indexed_values, Constr}) ->
|
||||||
Msg = io_lib:format("The event constructor ~s (at ~s) has too many indexed values (max 3)\n",
|
Msg = io_lib:format("The event constructor ~s (at ~s) has too many indexed values (max 3)\n",
|
||||||
[name(Constr), pp_loc(Constr)]),
|
[name(Constr), pp_loc(Constr)]),
|
||||||
@ -2395,13 +2405,21 @@ mk_error({include, _, {string, Pos, Name}}) ->
|
|||||||
[binary_to_list(Name), pp_loc(Pos)]),
|
[binary_to_list(Name), pp_loc(Pos)]),
|
||||||
mk_t_err(pos(Pos), Msg);
|
mk_t_err(pos(Pos), Msg);
|
||||||
mk_error({namespace, _Pos, {con, Pos, Name}, _Def}) ->
|
mk_error({namespace, _Pos, {con, Pos, Name}, _Def}) ->
|
||||||
Msg = io_lib:format("Nested namespace not allowed\nNamespace '~s' at ~s not defined at top level.\n",
|
Msg = io_lib:format("Nested namespaces are not allowed\nNamespace '~s' at ~s not defined at top level.\n",
|
||||||
|
[Name, pp_loc(Pos)]),
|
||||||
|
mk_t_err(pos(Pos), Msg);
|
||||||
|
mk_error({contract, _Pos, {con, Pos, Name}, _Def}) ->
|
||||||
|
Msg = io_lib:format("Nested contracts are not allowed\nContract '~s' at ~s not defined at top level.\n",
|
||||||
|
[Name, pp_loc(Pos)]),
|
||||||
|
mk_t_err(pos(Pos), Msg);
|
||||||
|
mk_error({type_decl, _, {id, Pos, Name}, _}) ->
|
||||||
|
Msg = io_lib:format("Empty type declarations are not supported\nType ~s at ~s lacks a definition\n",
|
||||||
|
[Name, pp_loc(Pos)]),
|
||||||
|
mk_t_err(pos(Pos), Msg);
|
||||||
|
mk_error({letval, _Pos, {id, Pos, Name}, _Def}) ->
|
||||||
|
Msg = io_lib:format("Toplevel \"let\" definitions are not supported\nValue ~s at ~s could be replaced by 0-argument function\n",
|
||||||
[Name, pp_loc(Pos)]),
|
[Name, pp_loc(Pos)]),
|
||||||
mk_t_err(pos(Pos), Msg);
|
mk_t_err(pos(Pos), Msg);
|
||||||
mk_error({repeated_arg, Fun, Arg}) ->
|
|
||||||
Msg = io_lib:format("Repeated argument ~s to function ~s (at ~s).\n",
|
|
||||||
[Arg, pp(Fun), pp_loc(Fun)]),
|
|
||||||
mk_t_err(pos(Fun), Msg);
|
|
||||||
mk_error({stateful_not_allowed, Id, Fun}) ->
|
mk_error({stateful_not_allowed, Id, Fun}) ->
|
||||||
Msg = io_lib:format("Cannot reference stateful function ~s (at ~s)\nin the definition of non-stateful function ~s.\n",
|
Msg = io_lib:format("Cannot reference stateful function ~s (at ~s)\nin the definition of non-stateful function ~s.\n",
|
||||||
[pp(Id), pp_loc(Id), pp(Fun)]),
|
[pp(Id), pp_loc(Id), pp(Fun)]),
|
||||||
|
@ -291,7 +291,6 @@ decls_to_fcode(Env, Decls) ->
|
|||||||
end, Env1, Decls).
|
end, Env1, Decls).
|
||||||
|
|
||||||
-spec decl_to_fcode(env(), aeso_syntax:decl()) -> env().
|
-spec decl_to_fcode(env(), aeso_syntax:decl()) -> env().
|
||||||
decl_to_fcode(Env, {type_decl, _, _, _}) -> Env;
|
|
||||||
decl_to_fcode(Env = #{context := {main_contract, _}}, {fun_decl, _, Id, _}) ->
|
decl_to_fcode(Env = #{context := {main_contract, _}}, {fun_decl, _, Id, _}) ->
|
||||||
case is_no_code(Env) of
|
case is_no_code(Env) of
|
||||||
false -> fcode_error({missing_definition, Id});
|
false -> fcode_error({missing_definition, Id});
|
||||||
|
@ -336,12 +336,12 @@ to_sophia_value(ContractString, FunName, ok, Data, Options0) ->
|
|||||||
try
|
try
|
||||||
{ok, aeso_vm_decode:from_fate(Type, aeb_fate_encoding:deserialize(Data))}
|
{ok, aeso_vm_decode:from_fate(Type, aeb_fate_encoding:deserialize(Data))}
|
||||||
catch throw:cannot_translate_to_sophia ->
|
catch throw:cannot_translate_to_sophia ->
|
||||||
Type1 = prettypr:format(aeso_pretty:type(Type)),
|
Type1 = prettypr:format(aeso_pretty:type(Type0)),
|
||||||
Msg = io_lib:format("Cannot translate FATE value ~p\n of Sophia type ~s\n",
|
Msg = io_lib:format("Cannot translate FATE value ~p\n of Sophia type ~s\n",
|
||||||
[aeb_fate_encoding:deserialize(Data), Type1]),
|
[aeb_fate_encoding:deserialize(Data), Type1]),
|
||||||
{error, [aeso_errors:new(data_error, Msg)]};
|
{error, [aeso_errors:new(data_error, Msg)]};
|
||||||
_:_ ->
|
_:_ ->
|
||||||
Type1 = prettypr:format(aeso_pretty:type(Type)),
|
Type1 = prettypr:format(aeso_pretty:type(Type0)),
|
||||||
Msg = io_lib:format("Failed to decode binary as type ~s\n", [Type1]),
|
Msg = io_lib:format("Failed to decode binary as type ~s\n", [Type1]),
|
||||||
{error, [aeso_errors:new(data_error, Msg)]}
|
{error, [aeso_errors:new(data_error, Msg)]}
|
||||||
end
|
end
|
||||||
|
@ -656,8 +656,14 @@ stdlib_options() ->
|
|||||||
|
|
||||||
get_include_code(File, Ann, Opts) ->
|
get_include_code(File, Ann, Opts) ->
|
||||||
case {read_file(File, Opts), read_file(File, stdlib_options())} of
|
case {read_file(File, Opts), read_file(File, stdlib_options())} of
|
||||||
{{ok, _}, {ok,_ }} ->
|
{{ok, Bin}, {ok, _}} ->
|
||||||
fail(ann_pos(Ann), "Illegal redefinition of standard library " ++ File);
|
case filename:basename(File) == File of
|
||||||
|
true -> { error
|
||||||
|
, fail( ann_pos(Ann)
|
||||||
|
, "Illegal redefinition of standard library " ++ binary_to_list(File))};
|
||||||
|
%% If a path is provided then the stdlib takes lower priority
|
||||||
|
false -> {ok, binary_to_list(Bin)}
|
||||||
|
end;
|
||||||
{_, {ok, Bin}} ->
|
{_, {ok, Bin}} ->
|
||||||
{ok, binary_to_list(Bin)};
|
{ok, binary_to_list(Bin)};
|
||||||
{{ok, Bin}, _} ->
|
{{ok, Bin}, _} ->
|
||||||
|
@ -145,8 +145,12 @@ decl(D, Options) ->
|
|||||||
with_options(Options, fun() -> decl(D) end).
|
with_options(Options, fun() -> decl(D) end).
|
||||||
|
|
||||||
-spec decl(aeso_syntax:decl()) -> doc().
|
-spec decl(aeso_syntax:decl()) -> doc().
|
||||||
decl({contract, _, C, Ds}) ->
|
decl({contract, Attrs, C, Ds}) ->
|
||||||
block(follow(text("contract"), hsep(name(C), text("="))), decls(Ds));
|
Mod = fun({Mod, true}) when Mod == payable ->
|
||||||
|
text(atom_to_list(Mod));
|
||||||
|
(_) -> empty() end,
|
||||||
|
block(follow( hsep(lists:map(Mod, Attrs) ++ [text("contract")])
|
||||||
|
, hsep(name(C), text("="))), decls(Ds));
|
||||||
decl({namespace, _, C, Ds}) ->
|
decl({namespace, _, C, Ds}) ->
|
||||||
block(follow(text("namespace"), hsep(name(C), text("="))), decls(Ds));
|
block(follow(text("namespace"), hsep(name(C), text("="))), decls(Ds));
|
||||||
decl({pragma, _, Pragma}) -> pragma(Pragma);
|
decl({pragma, _, Pragma}) -> pragma(Pragma);
|
||||||
@ -155,13 +159,16 @@ decl({type_def, _, T, Vars, Def}) ->
|
|||||||
Kind = element(1, Def),
|
Kind = element(1, Def),
|
||||||
equals(typedecl(Kind, T, Vars), typedef(Def));
|
equals(typedecl(Kind, T, Vars), typedef(Def));
|
||||||
decl({fun_decl, Ann, F, T}) ->
|
decl({fun_decl, Ann, F, T}) ->
|
||||||
|
Mod = fun({Mod, true}) when Mod == private; Mod == stateful; Mod == payable ->
|
||||||
|
text(atom_to_list(Mod));
|
||||||
|
(_) -> empty() end,
|
||||||
Fun = case aeso_syntax:get_ann(entrypoint, Ann, false) of
|
Fun = case aeso_syntax:get_ann(entrypoint, Ann, false) of
|
||||||
true -> text("entrypoint");
|
true -> text("entrypoint");
|
||||||
false -> text("function")
|
false -> text("function")
|
||||||
end,
|
end,
|
||||||
hsep(Fun, typed(name(F), T));
|
hsep(lists:map(Mod, Ann) ++ [Fun, typed(name(F), T)]);
|
||||||
decl(D = {letfun, Attrs, _, _, _, _}) ->
|
decl(D = {letfun, Attrs, _, _, _, _}) ->
|
||||||
Mod = fun({Mod, true}) when Mod == private; Mod == stateful ->
|
Mod = fun({Mod, true}) when Mod == private; Mod == stateful; Mod == payable ->
|
||||||
text(atom_to_list(Mod));
|
text(atom_to_list(Mod));
|
||||||
(_) -> empty() end,
|
(_) -> empty() end,
|
||||||
Fun = case aeso_syntax:get_ann(entrypoint, Attrs, false) of
|
Fun = case aeso_syntax:get_ann(entrypoint, Attrs, false) of
|
||||||
@ -364,7 +371,8 @@ expr_p(_, {Type, _, Bin})
|
|||||||
Type == oracle_query_id ->
|
Type == oracle_query_id ->
|
||||||
text(binary_to_list(aeser_api_encoder:encode(Type, Bin)));
|
text(binary_to_list(aeser_api_encoder:encode(Type, Bin)));
|
||||||
expr_p(_, {string, _, <<>>}) -> text("\"\"");
|
expr_p(_, {string, _, <<>>}) -> text("\"\"");
|
||||||
expr_p(_, {string, _, S}) -> term(binary_to_list(S));
|
expr_p(_, {string, _, S}) ->
|
||||||
|
text(io_lib:format("\"~s\"", [binary_to_list(S)]));
|
||||||
expr_p(_, {char, _, C}) ->
|
expr_p(_, {char, _, C}) ->
|
||||||
case C of
|
case C of
|
||||||
$' -> text("'\\''");
|
$' -> text("'\\''");
|
||||||
@ -486,6 +494,3 @@ get_elifs(If = {'if', Ann, Cond, Then, Else}, Elifs) ->
|
|||||||
end;
|
end;
|
||||||
get_elifs(Else, Elifs) -> {lists:reverse(Elifs), {else, Else}}.
|
get_elifs(Else, Elifs) -> {lists:reverse(Elifs), {else, Else}}.
|
||||||
|
|
||||||
fmt(Fmt, Args) -> text(lists:flatten(io_lib:format(Fmt, Args))).
|
|
||||||
term(X) -> fmt("~p", [X]).
|
|
||||||
|
|
||||||
|
@ -37,20 +37,24 @@
|
|||||||
-type decl() :: {contract, ann(), con(), [decl()]}
|
-type decl() :: {contract, ann(), con(), [decl()]}
|
||||||
| {namespace, ann(), con(), [decl()]}
|
| {namespace, ann(), con(), [decl()]}
|
||||||
| {pragma, ann(), pragma()}
|
| {pragma, ann(), pragma()}
|
||||||
| {type_decl, ann(), id(), [tvar()]}
|
| {type_decl, ann(), id(), [tvar()]} % Only for error msgs
|
||||||
| {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()]}
|
| {fun_clauses, ann(), id(), type(), [letbind()]}
|
||||||
| {block, ann(), [decl()]}
|
| {block, ann(), [decl()]}
|
||||||
| letbind().
|
| letfun()
|
||||||
|
| letval(). % Only for error msgs
|
||||||
|
|
||||||
-type compiler_version() :: [non_neg_integer()].
|
-type compiler_version() :: [non_neg_integer()].
|
||||||
|
|
||||||
-type pragma() :: {compiler, '==' | '<' | '>' | '=<' | '>=', compiler_version()}.
|
-type pragma() :: {compiler, '==' | '<' | '>' | '=<' | '>=', compiler_version()}.
|
||||||
|
|
||||||
|
|
||||||
|
-type letval() :: {letval, ann(), pat(), expr()}.
|
||||||
|
-type letfun() :: {letfun, ann(), id(), [pat()], type(), expr()}.
|
||||||
-type letbind()
|
-type letbind()
|
||||||
:: {letval, ann(), pat(), expr()}
|
:: letfun()
|
||||||
| {letfun, ann(), id(), [pat()], type(), expr()}.
|
| letval().
|
||||||
|
|
||||||
-type arg() :: {arg, ann(), id(), type()}.
|
-type arg() :: {arg, ann(), id(), type()}.
|
||||||
|
|
||||||
|
@ -45,7 +45,6 @@ fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) ->
|
|||||||
%% decl()
|
%% decl()
|
||||||
{contract, _, _, Ds} -> Decl(Ds);
|
{contract, _, _, Ds} -> Decl(Ds);
|
||||||
{namespace, _, _, Ds} -> Decl(Ds);
|
{namespace, _, _, Ds} -> Decl(Ds);
|
||||||
{type_decl, _, I, _} -> BindType(I);
|
|
||||||
{type_def, _, I, _, D} -> Plus(BindType(I), Decl(D));
|
{type_def, _, I, _, D} -> Plus(BindType(I), Decl(D));
|
||||||
{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));
|
||||||
|
@ -375,11 +375,15 @@ failing_contracts() ->
|
|||||||
" r.foo : (gas : int, value : int) => Remote.themap\n"
|
" r.foo : (gas : int, value : int) => Remote.themap\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" (gas : int, value : int) => map(string, int)">>])
|
" (gas : int, value : int) => map(string, int)">>])
|
||||||
, ?TYPE_ERROR(bad_include_and_ns,
|
, ?TYPE_ERROR(not_toplevel_include,
|
||||||
[<<?Pos(2, 11)
|
[<<?Pos(2, 11)
|
||||||
"Include of 'included.aes' at line 2, column 11\nnot allowed, include only allowed at top level.">>,
|
"Include of 'included.aes' at line 2, column 11\nnot allowed, include only allowed at top level.">>])
|
||||||
<<?Pos(3, 13)
|
, ?TYPE_ERROR(not_toplevel_namespace,
|
||||||
"Nested namespace not allowed\nNamespace 'Foo' at line 3, column 13 not defined at top level.">>])
|
[<<?Pos(2, 13)
|
||||||
|
"Nested namespaces are not allowed\nNamespace 'Foo' at line 2, column 13 not defined at top level.">>])
|
||||||
|
, ?TYPE_ERROR(not_toplevel_contract,
|
||||||
|
[<<?Pos(2, 12)
|
||||||
|
"Nested contracts are not allowed\nContract 'Con' at line 2, column 12 not defined at top level.">>])
|
||||||
, ?TYPE_ERROR(bad_address_literals,
|
, ?TYPE_ERROR(bad_address_literals,
|
||||||
[<<?Pos(11, 5)
|
[<<?Pos(11, 5)
|
||||||
"Cannot unify address\n"
|
"Cannot unify address\n"
|
||||||
@ -612,6 +616,44 @@ failing_contracts() ->
|
|||||||
[<<?Pos(5, 28)
|
[<<?Pos(5, 28)
|
||||||
"Invalid call to contract entrypoint 'Foo.foo'.\n"
|
"Invalid call to contract entrypoint 'Foo.foo'.\n"
|
||||||
"It must be called as 'c.foo' for some c : Foo.">>])
|
"It must be called as 'c.foo' for some c : Foo.">>])
|
||||||
|
, ?TYPE_ERROR(toplevel_let,
|
||||||
|
[<<?Pos(2, 7)
|
||||||
|
"Toplevel \"let\" definitions are not supported\n"
|
||||||
|
"Value this_is_illegal at line 2, column 7 could be replaced by 0-argument function">>])
|
||||||
|
, ?TYPE_ERROR(empty_typedecl,
|
||||||
|
[<<?Pos(2, 8)
|
||||||
|
"Empty type declarations are not supported\n"
|
||||||
|
"Type t at line 2, column 8 lacks a definition">>])
|
||||||
|
, ?TYPE_ERROR(higher_kinded_type,
|
||||||
|
[<<?Pos(2, 35)
|
||||||
|
"Type 'm is a higher kinded type variable\n"
|
||||||
|
"(takes another type as an argument)">>])
|
||||||
|
, ?TYPE_ERROR(bad_arity,
|
||||||
|
[<<?Pos(3, 20)
|
||||||
|
"Arity for id doesn't match. Expected 1, got 0">>,
|
||||||
|
<<?Pos(3, 25)
|
||||||
|
"Cannot unify int\n"
|
||||||
|
" and id\n"
|
||||||
|
"when checking the type of the expression at line 3, column 25\n"
|
||||||
|
" 123 : int\n"
|
||||||
|
"against the expected type\n"
|
||||||
|
" id">>,
|
||||||
|
<<?Pos(4, 20)
|
||||||
|
"Arity for id doesn't match. Expected 1, got 2">>,
|
||||||
|
<<?Pos(4, 35)
|
||||||
|
"Cannot unify int\n"
|
||||||
|
" and id(int, int)\n"
|
||||||
|
"when checking the type of the expression at line 4, column 35\n"
|
||||||
|
" 123 : int\n"
|
||||||
|
"against the expected type\n"
|
||||||
|
" id(int, int)">>])
|
||||||
|
, ?TYPE_ERROR(bad_unnamed_map_update_default,
|
||||||
|
[<<?Pos(4, 17)
|
||||||
|
"Invalid map update with default">>])
|
||||||
|
, ?TYPE_ERROR(non_functional_entrypoint,
|
||||||
|
[<<?Pos(2, 14)
|
||||||
|
"f at line 2, column 14 was declared with an invalid type int.\n"
|
||||||
|
"Entrypoints and functions must have functional types">>])
|
||||||
, ?TYPE_ERROR(bad_records,
|
, ?TYPE_ERROR(bad_records,
|
||||||
[<<?Pos(3, 16)
|
[<<?Pos(3, 16)
|
||||||
"Mixed record fields and map keys in\n"
|
"Mixed record fields and map keys in\n"
|
||||||
|
@ -58,8 +58,7 @@ contract Greeter =
|
|||||||
|
|
||||||
let state = { greeting = "Hello" }
|
let state = { greeting = "Hello" }
|
||||||
|
|
||||||
let setGreeting =
|
function setGreeting(greeting: string) =
|
||||||
(greeting: string) =>
|
|
||||||
state{ greeting = greeting }
|
state{ greeting = greeting }
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,44 +1,78 @@
|
|||||||
// Try to cover all syntactic constructs.
|
// Try to cover all syntactic constructs.
|
||||||
|
@compiler > 0
|
||||||
|
@compiler =< 10.1.1.1.1.1.2.3.4
|
||||||
|
|
||||||
contract AllSyntaxType =
|
|
||||||
type typeDecl /* bla */
|
|
||||||
type paramTypeDecl('a, 'b)
|
|
||||||
|
|
||||||
|
namespace Ns =
|
||||||
|
datatype d('a) = D | S(int) | M('a, list('a), int)
|
||||||
|
private function fff() = 123
|
||||||
|
|
||||||
|
stateful entrypoint
|
||||||
|
f (1, x) = (_) => x
|
||||||
|
|
||||||
|
payable contract AllSyntaxType =
|
||||||
/** Multi-
|
/** Multi-
|
||||||
* line
|
* line
|
||||||
* comment
|
* comment
|
||||||
*/
|
*/
|
||||||
function foo : _
|
stateful function foo : _
|
||||||
|
entrypoint bar : int => (int * 'a)
|
||||||
|
|
||||||
|
|
||||||
contract AllSyntax =
|
contract AllSyntax =
|
||||||
|
|
||||||
type typeDecl = int
|
datatype mickiewicz = Adam | Mickiewicz
|
||||||
type paramTypeDecl('a, 'b) = (('a, 'b) => 'b) => list('a) => 'b => 'b
|
record goethe('a, 'b) = {
|
||||||
|
johann : int,
|
||||||
|
wolfgang : 'a,
|
||||||
|
von : 'a * 'b * int,
|
||||||
|
goethe : unit
|
||||||
|
}
|
||||||
|
type dante = Ns.d(int)
|
||||||
|
type shakespeare('a) = goethe('a, 'a)
|
||||||
|
|
||||||
record nestedRecord = { x : int }
|
type state = shakespeare(int)
|
||||||
record recordType = { z : nestedRecord, y : int }
|
|
||||||
datatype variantType('a) = None | Some('a)
|
|
||||||
|
|
||||||
let valWithType : map(int, int) => option(int) = (m) => Map.get(m, 42)
|
entrypoint init() = {
|
||||||
let valNoType =
|
johann = 1000,
|
||||||
if(valWithType(Map.empty) == None)
|
wolfgang = -10,
|
||||||
print(42 mod 10 * 5 / 3)
|
von = (2 + 2, 0, List.sum([x | k <- [1,2,3]
|
||||||
|
, let l = k + 1
|
||||||
|
, if(l < 10)
|
||||||
|
, let f(x) = x + 100
|
||||||
|
, Adam <- [Adam, Mickiewicz]
|
||||||
|
, let x = f(l)
|
||||||
|
])),
|
||||||
|
goethe = () }
|
||||||
|
|
||||||
function funWithType(x : int, y) : int * list(int) = (x, 0 :: [y] ++ [])
|
function f() =
|
||||||
function funNoType() =
|
let kp = "nietzsche"
|
||||||
let foo = (x, y : bool) =>
|
let p = "Пушкин"
|
||||||
if (! (y && x =< 0x0b || true)) [x]
|
let k(x : bytes(8)) : bytes(8) = Bytes.to_int(#fedcba9876543210)
|
||||||
else [11..20]
|
|
||||||
let setY(r : recordType) : unit = r{ y = 5 }
|
|
||||||
let setX(r : recordType, x : int) : recordType = r { z.x = x } // nested record update
|
|
||||||
let getY(r) = switch(r) {y = y} => y
|
|
||||||
switch (funWithType(1, -2))
|
|
||||||
(x, [y, z]) => bar({x = z, y = -y + - -z * (-1)})
|
|
||||||
(x, y :: _) => ()
|
|
||||||
|
|
||||||
let hash : address = #01ab0fff11
|
let f : () => address = () => ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt
|
||||||
let b = false
|
if(Bits.test(Bits.all, 10))
|
||||||
let qcon = Mod.Con
|
abort("ohno")
|
||||||
let str = "blabla\nfoo"
|
if(true && false)
|
||||||
let chr = '"'
|
require(true, "ohyes")
|
||||||
|
elif(false || 2 == 2)
|
||||||
|
()
|
||||||
|
else
|
||||||
|
()
|
||||||
|
if(true) f(1,2)((1,2))
|
||||||
|
else switch(1::[1,2,3])
|
||||||
|
[] => 1
|
||||||
|
a::b => 123
|
||||||
|
1::2::3 => 123123
|
||||||
|
[2,3,4] => 1
|
||||||
|
_ => 13
|
||||||
|
1::[2] => 2138
|
||||||
|
put(state{johann = 1})
|
||||||
|
|
||||||
|
let m = {["foo"] = 19, /*hey wanna talk about inlined comments?*/ ["bar"] = 42}
|
||||||
|
let n = {}
|
||||||
|
m{ ["x" = 0] @ z = z + state.johann }
|
||||||
|
|
||||||
|
let sh : shakespeare(shakespeare(int)) =
|
||||||
|
{wolfgang = state}
|
||||||
|
sh{wolfgang.wolfgang = sh.wolfgang} // comment
|
||||||
|
4
test/contracts/bad_arity.aes
Normal file
4
test/contracts/bad_arity.aes
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
contract C =
|
||||||
|
type id('a) = 'a
|
||||||
|
entrypoint f() : id = 123
|
||||||
|
entrypoint g() : id(int, int) = 123
|
5
test/contracts/bad_unnamed_map_update_default.aes
Normal file
5
test/contracts/bad_unnamed_map_update_default.aes
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
contract C =
|
||||||
|
entrypoint f() =
|
||||||
|
let z = 123
|
||||||
|
{}{ [1 = 0] = z + 1 }
|
||||||
|
2
|
3
test/contracts/empty_typedecl.aes
Normal file
3
test/contracts/empty_typedecl.aes
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
contract C =
|
||||||
|
type t
|
||||||
|
entrypoint f() = 123
|
3
test/contracts/higher_kinded_type.aes
Normal file
3
test/contracts/higher_kinded_type.aes
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
contract IWantToBelieve =
|
||||||
|
type stateT('s, 'm, 'a) = 's => 'm('a * 's)
|
||||||
|
entrypoint s() = 123
|
@ -15,7 +15,7 @@ contract MultiSig =
|
|||||||
| OwnerRemoved (address) // of { .removedOwner : Address }
|
| OwnerRemoved (address) // of { .removedOwner : Address }
|
||||||
| ReqChanged (int) // of { .newReq : int }
|
| ReqChanged (int) // of { .newReq : int }
|
||||||
|
|
||||||
let maxOwners : int = 250
|
function maxOwners() : int = 250
|
||||||
|
|
||||||
record state = { nRequired : int
|
record state = { nRequired : int
|
||||||
, nOwners : int
|
, nOwners : int
|
||||||
@ -68,7 +68,7 @@ contract MultiSig =
|
|||||||
switch(check_pending(callhash()))
|
switch(check_pending(callhash()))
|
||||||
CheckFail(state') => { state = state' }
|
CheckFail(state') => { state = state' }
|
||||||
CheckOk(state') =>
|
CheckOk(state') =>
|
||||||
if(state.nOwners >= maxOwners) () /* TODO */
|
if(state.nOwners >= maxOwners()) () /* TODO */
|
||||||
else
|
else
|
||||||
let nOwners' = state'.nOwners + 1
|
let nOwners' = state'.nOwners + 1
|
||||||
{ state = state' { owners = Map.insert(nOwners', newOwner, state'.owners)
|
{ state = state' { owners = Map.insert(nOwners', newOwner, state'.owners)
|
||||||
|
5
test/contracts/non_functional_entrypoint.aes
Normal file
5
test/contracts/non_functional_entrypoint.aes
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
contract C1 =
|
||||||
|
entrypoint f : int
|
||||||
|
|
||||||
|
contract C =
|
||||||
|
entrypoint f() = 123
|
6
test/contracts/not_toplevel_contract.aes
Normal file
6
test/contracts/not_toplevel_contract.aes
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace BadNs =
|
||||||
|
contract Con =
|
||||||
|
entrypoint e : () => int
|
||||||
|
|
||||||
|
contract Con =
|
||||||
|
entrypoint foo() = 43
|
5
test/contracts/not_toplevel_include.aes
Normal file
5
test/contracts/not_toplevel_include.aes
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
namespace BadNs =
|
||||||
|
include "included.aes"
|
||||||
|
|
||||||
|
contract Con =
|
||||||
|
entrypoint foo() = 43
|
@ -1,5 +1,4 @@
|
|||||||
contract Bad =
|
contract BadCon =
|
||||||
include "included.aes"
|
|
||||||
namespace Foo =
|
namespace Foo =
|
||||||
function foo() = 42
|
function foo() = 42
|
||||||
|
|
3
test/contracts/toplevel_let.aes
Normal file
3
test/contracts/toplevel_let.aes
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
contract C =
|
||||||
|
let this_is_illegal = 2/0
|
||||||
|
entrypoint this_is_legal() = 2/0
|
@ -1,16 +1,3 @@
|
|||||||
|
|
||||||
/* Contract type */
|
|
||||||
contract VotingType =
|
|
||||||
type state
|
|
||||||
function init : list(string) => state
|
|
||||||
|
|
||||||
function giveRightToVote : address => unit
|
|
||||||
function delegate : address => unit
|
|
||||||
function vote : int => unit
|
|
||||||
function winnerName : unit => string
|
|
||||||
function currentTally : unit => list(string * int)
|
|
||||||
|
|
||||||
/* Contract implementation */
|
|
||||||
contract Voting =
|
contract Voting =
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
|
Loading…
x
Reference in New Issue
Block a user