add pragma to check compiler version
This commit is contained in:
parent
7f86b7d301
commit
dd94a6bd67
@ -591,7 +591,10 @@ infer1(Env, [{namespace, Ann, Name, Code} | Rest], Acc, Options) ->
|
|||||||
check_scope_name_clash(Env, namespace, Name),
|
check_scope_name_clash(Env, namespace, Name),
|
||||||
{Env1, Code1} = infer_contract_top(push_scope(namespace, Name, Env), namespace, Code, Options),
|
{Env1, Code1} = infer_contract_top(push_scope(namespace, Name, Env), namespace, Code, Options),
|
||||||
Namespace1 = {namespace, Ann, Name, Code1},
|
Namespace1 = {namespace, Ann, Name, Code1},
|
||||||
infer1(pop_scope(Env1), Rest, [Namespace1 | Acc], Options).
|
infer1(pop_scope(Env1), Rest, [Namespace1 | Acc], Options);
|
||||||
|
infer1(Env, [{pragma, _, _} | Rest], Acc, Options) ->
|
||||||
|
%% Pragmas are checked in check_modifiers
|
||||||
|
infer1(Env, Rest, Acc, Options).
|
||||||
|
|
||||||
check_scope_name_clash(Env, Kind, Name) ->
|
check_scope_name_clash(Env, Kind, Name) ->
|
||||||
case get_scope(Env, qname(Name)) of
|
case get_scope(Env, qname(Name)) of
|
||||||
@ -713,10 +716,23 @@ check_modifiers(Env, Contracts) ->
|
|||||||
_ -> ok
|
_ -> ok
|
||||||
end;
|
end;
|
||||||
{namespace, _, _, Decls} -> check_modifiers1(namespace, Decls);
|
{namespace, _, _, Decls} -> check_modifiers1(namespace, Decls);
|
||||||
|
{pragma, Ann, Pragma} -> check_pragma(Env, Ann, Pragma);
|
||||||
Decl -> type_error({bad_top_level_decl, Decl})
|
Decl -> type_error({bad_top_level_decl, Decl})
|
||||||
end || C <- Contracts ],
|
end || C <- Contracts ],
|
||||||
destroy_and_report_type_errors(Env).
|
destroy_and_report_type_errors(Env).
|
||||||
|
|
||||||
|
-spec check_pragma(env(), aeso_syntax:ann(), aeso_syntax:pragma()) -> ok.
|
||||||
|
check_pragma(_Env, Ann, {compiler, Op, Ver}) ->
|
||||||
|
case aeso_compiler:numeric_version() of
|
||||||
|
{error, Err} -> type_error({failed_to_get_compiler_version, Err});
|
||||||
|
{ok, Version} ->
|
||||||
|
Strip = fun(V) -> lists:reverse(lists:dropwhile(fun(X) -> X == 0 end, lists:reverse(V))) end,
|
||||||
|
case apply(erlang, Op, [Strip(Version), Strip(Ver)]) of
|
||||||
|
true -> ok;
|
||||||
|
false -> type_error({compiler_version_mismatch, Ann, Version, Op, Ver})
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
-spec check_modifiers1(contract | namespace, [aeso_syntax:decl()] | aeso_syntax:decl()) -> ok.
|
-spec check_modifiers1(contract | namespace, [aeso_syntax:decl()] | aeso_syntax:decl()) -> ok.
|
||||||
check_modifiers1(What, Decls) when is_list(Decls) ->
|
check_modifiers1(What, Decls) when is_list(Decls) ->
|
||||||
_ = [ check_modifiers1(What, Decl) || Decl <- Decls ],
|
_ = [ check_modifiers1(What, Decl) || Decl <- Decls ],
|
||||||
@ -2382,6 +2398,15 @@ mk_error({unsolved_bytes_constraint, Ann, split, A, B, C}) ->
|
|||||||
[ pp_type(" - ", C), pp_loc(C), pp_type(" - ", A), pp_loc(A),
|
[ pp_type(" - ", C), pp_loc(C), pp_type(" - ", A), pp_loc(A),
|
||||||
pp_type(" - ", B), pp_loc(B)]),
|
pp_type(" - ", B), pp_loc(B)]),
|
||||||
mk_t_err(pos(Ann), Msg);
|
mk_t_err(pos(Ann), Msg);
|
||||||
|
mk_error({failed_to_get_compiler_version, Err}) ->
|
||||||
|
Msg = io_lib:format("Failed to get compiler version. Error:\n ~p\n", [Err]),
|
||||||
|
mk_t_err(pos(0, 0), Msg);
|
||||||
|
mk_error({compiler_version_mismatch, Ann, Version, Op, Bound}) ->
|
||||||
|
PrintV = fun(V) -> string:join([integer_to_list(N) || N <- V], ".") end,
|
||||||
|
Msg = io_lib:format("Cannot compile with this version of the compiler,\n"
|
||||||
|
"because it does not satisfy the constraint"
|
||||||
|
" ~s ~s ~s\n", [PrintV(Version), Op, PrintV(Bound)]),
|
||||||
|
mk_t_err(pos(Ann), Msg);
|
||||||
mk_error(Err) ->
|
mk_error(Err) ->
|
||||||
Msg = io_lib:format("Unknown error: ~p\n", [Err]),
|
Msg = io_lib:format("Unknown error: ~p\n", [Err]),
|
||||||
mk_t_err(pos(0, 0), Msg).
|
mk_t_err(pos(0, 0), Msg).
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
, create_calldata/3 %% deprecated
|
, create_calldata/3 %% deprecated
|
||||||
, create_calldata/4
|
, create_calldata/4
|
||||||
, version/0
|
, version/0
|
||||||
|
, numeric_version/0
|
||||||
, sophia_type_to_typerep/1
|
, sophia_type_to_typerep/1
|
||||||
, to_sophia_value/4 %% deprecated, need a backend
|
, to_sophia_value/4 %% deprecated, need a backend
|
||||||
, to_sophia_value/5
|
, to_sophia_value/5
|
||||||
@ -65,6 +66,17 @@ version() ->
|
|||||||
{ok, list_to_binary(VsnString)}
|
{ok, list_to_binary(VsnString)}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec numeric_version() -> {ok, [non_neg_integer()]} | {error, term()}.
|
||||||
|
numeric_version() ->
|
||||||
|
case version() of
|
||||||
|
{ok, Bin} ->
|
||||||
|
[NoSuf | _] = binary:split(Bin, <<"-">>),
|
||||||
|
Numbers = binary:split(NoSuf, <<".">>, [global]),
|
||||||
|
{ok, [binary_to_integer(Num) || Num <- Numbers]};
|
||||||
|
{error, _} = Err ->
|
||||||
|
Err
|
||||||
|
end.
|
||||||
|
|
||||||
-spec file(string()) -> {ok, map()} | {error, [aeso_errors:error()]}.
|
-spec file(string()) -> {ok, map()} | {error, [aeso_errors:error()]}.
|
||||||
file(Filename) ->
|
file(Filename) ->
|
||||||
file(Filename, []).
|
file(Filename, []).
|
||||||
|
@ -87,6 +87,7 @@ decl() ->
|
|||||||
, ?RULE(token(payable), keyword(contract), con(), tok('='), maybe_block(decl()), add_modifiers([_1], {contract, _2, _3, _5}))
|
, ?RULE(token(payable), keyword(contract), con(), tok('='), maybe_block(decl()), add_modifiers([_1], {contract, _2, _3, _5}))
|
||||||
, ?RULE(keyword(namespace), con(), tok('='), maybe_block(decl()), {namespace, _1, _2, _4})
|
, ?RULE(keyword(namespace), con(), tok('='), maybe_block(decl()), {namespace, _1, _2, _4})
|
||||||
, ?RULE(keyword(include), str(), {include, get_ann(_1), _2})
|
, ?RULE(keyword(include), str(), {include, get_ann(_1), _2})
|
||||||
|
, pragma()
|
||||||
|
|
||||||
%% Type declarations TODO: format annotation for "type bla" vs "type bla()"
|
%% Type declarations TODO: format annotation for "type bla" vs "type bla()"
|
||||||
, ?RULE(keyword(type), id(), {type_decl, _1, _2, []})
|
, ?RULE(keyword(type), id(), {type_decl, _1, _2, []})
|
||||||
@ -104,6 +105,16 @@ decl() ->
|
|||||||
, ?RULE(keyword('let'), valdef(), set_pos(get_pos(_1), _2))
|
, ?RULE(keyword('let'), valdef(), set_pos(get_pos(_1), _2))
|
||||||
])).
|
])).
|
||||||
|
|
||||||
|
pragma() ->
|
||||||
|
Op = choice([token(T) || T <- ['<', '=<', '==', '>=', '>']]),
|
||||||
|
?RULE(tok('@'), id("compiler"), Op, version(), {pragma, get_ann(_1), {compiler, element(1, _3), _4}}).
|
||||||
|
|
||||||
|
version() ->
|
||||||
|
?RULE(token(int), many({tok('.'), token(int)}), mk_version(_1, _2)).
|
||||||
|
|
||||||
|
mk_version({int, _, Maj}, Rest) ->
|
||||||
|
[Maj | [N || {_, {int, _, N}} <- Rest]].
|
||||||
|
|
||||||
fun_or_entry() ->
|
fun_or_entry() ->
|
||||||
choice([?RULE(keyword(function), {function, _1}),
|
choice([?RULE(keyword(function), {function, _1}),
|
||||||
?RULE(keyword(entrypoint), {entrypoint, _1})]).
|
?RULE(keyword(entrypoint), {entrypoint, _1})]).
|
||||||
@ -406,7 +417,7 @@ token(Tag) ->
|
|||||||
id(Id) ->
|
id(Id) ->
|
||||||
?LET_P({id, A, X} = Y, id(),
|
?LET_P({id, A, X} = Y, id(),
|
||||||
if X == Id -> Y;
|
if X == Id -> Y;
|
||||||
true -> fail({A, "expected 'bytes'"})
|
true -> fail({A, "expected '" ++ Id ++ "'"})
|
||||||
end).
|
end).
|
||||||
|
|
||||||
id_or_addr() ->
|
id_or_addr() ->
|
||||||
|
@ -149,6 +149,7 @@ decl({contract, _, C, Ds}) ->
|
|||||||
block(follow(text("contract"), hsep(name(C), text("="))), decls(Ds));
|
block(follow(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({type_decl, _, T, Vars}) -> typedecl(alias_t, T, Vars);
|
decl({type_decl, _, T, Vars}) -> typedecl(alias_t, T, Vars);
|
||||||
decl({type_def, _, T, Vars, Def}) ->
|
decl({type_def, _, T, Vars, Def}) ->
|
||||||
Kind = element(1, Def),
|
Kind = element(1, Def),
|
||||||
@ -170,6 +171,10 @@ decl(D = {letfun, Attrs, _, _, _, _}) ->
|
|||||||
hsep(lists:map(Mod, Attrs) ++ [letdecl(Fun, D)]);
|
hsep(lists:map(Mod, Attrs) ++ [letdecl(Fun, D)]);
|
||||||
decl(D = {letval, _, _, _, _}) -> letdecl("let", D).
|
decl(D = {letval, _, _, _, _}) -> letdecl("let", D).
|
||||||
|
|
||||||
|
-spec pragma(aeso_syntax:pragma()) -> doc().
|
||||||
|
pragma({compiler, Op, Ver}) ->
|
||||||
|
text("@compiler " ++ atom_to_list(Op) ++ " " ++ string:join([integer_to_list(N) || N <- Ver], ".")).
|
||||||
|
|
||||||
-spec expr(aeso_syntax:expr(), options()) -> doc().
|
-spec expr(aeso_syntax:expr(), options()) -> doc().
|
||||||
expr(E, Options) ->
|
expr(E, Options) ->
|
||||||
with_options(Options, fun() -> expr(E) end).
|
with_options(Options, fun() -> expr(E) end).
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
-export_type([ann_line/0, ann_col/0, ann_origin/0, ann_format/0, ann/0]).
|
-export_type([ann_line/0, ann_col/0, ann_origin/0, ann_format/0, ann/0]).
|
||||||
-export_type([name/0, id/0, con/0, qid/0, qcon/0, tvar/0, op/0]).
|
-export_type([name/0, id/0, con/0, qid/0, qcon/0, tvar/0, op/0]).
|
||||||
-export_type([bin_op/0, un_op/0]).
|
-export_type([bin_op/0, un_op/0]).
|
||||||
-export_type([decl/0, letbind/0, typedef/0]).
|
-export_type([decl/0, letbind/0, typedef/0, pragma/0]).
|
||||||
-export_type([arg/0, field_t/0, constructor_t/0, named_arg_t/0]).
|
-export_type([arg/0, field_t/0, constructor_t/0, named_arg_t/0]).
|
||||||
-export_type([type/0, constant/0, expr/0, arg_expr/0, field/1, stmt/0, alt/0, lvalue/0, elim/0, pat/0]).
|
-export_type([type/0, constant/0, expr/0, arg_expr/0, field/1, stmt/0, alt/0, lvalue/0, elim/0, pat/0]).
|
||||||
-export_type([ast/0]).
|
-export_type([ast/0]).
|
||||||
@ -36,11 +36,16 @@
|
|||||||
|
|
||||||
-type decl() :: {contract, ann(), con(), [decl()]}
|
-type decl() :: {contract, ann(), con(), [decl()]}
|
||||||
| {namespace, ann(), con(), [decl()]}
|
| {namespace, ann(), con(), [decl()]}
|
||||||
|
| {pragma, ann(), pragma()}
|
||||||
| {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()}
|
||||||
| letbind().
|
| letbind().
|
||||||
|
|
||||||
|
-type compiler_version() :: [non_neg_integer()].
|
||||||
|
|
||||||
|
-type pragma() :: {compiler, '==' | '<' | '>' | '=<' | '>=', compiler_version()}.
|
||||||
|
|
||||||
-type letbind()
|
-type letbind()
|
||||||
:: {letval, ann(), id(), type(), expr()}
|
:: {letval, ann(), id(), type(), expr()}
|
||||||
| {letfun, ann(), id(), [arg()], type(), expr()}.
|
| {letfun, ann(), id(), [arg()], type(), expr()}.
|
||||||
|
@ -176,6 +176,8 @@ not_yet_compilable(aevm) -> [].
|
|||||||
-define(PARSE_ERROR(Name, Errs), ?ERROR("Parse", Name, Errs)).
|
-define(PARSE_ERROR(Name, Errs), ?ERROR("Parse", Name, Errs)).
|
||||||
|
|
||||||
failing_contracts() ->
|
failing_contracts() ->
|
||||||
|
{ok, V} = aeso_compiler:numeric_version(),
|
||||||
|
Version = list_to_binary(string:join([integer_to_list(N) || N <- V], ".")),
|
||||||
%% Parse errors
|
%% Parse errors
|
||||||
[ ?PARSE_ERROR(field_parse_error,
|
[ ?PARSE_ERROR(field_parse_error,
|
||||||
[<<?Pos(5, 26)
|
[<<?Pos(5, 26)
|
||||||
@ -564,6 +566,13 @@ failing_contracts() ->
|
|||||||
"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 19, column 5)">>])
|
||||||
|
, ?TYPE_ERROR(wrong_compiler_version,
|
||||||
|
[<<?Pos(1, 1)
|
||||||
|
"Cannot compile with this version of the compiler,\n"
|
||||||
|
"because it does not satisfy the constraint ", Version/binary, " < 1.0">>,
|
||||||
|
<<?Pos(2, 1)
|
||||||
|
"Cannot compile with this version of the compiler,\n"
|
||||||
|
"because it does not satisfy the constraint ", Version/binary, " == 9.9.9">>])
|
||||||
].
|
].
|
||||||
|
|
||||||
-define(Path(File), "code_errors/" ??File).
|
-define(Path(File), "code_errors/" ??File).
|
||||||
|
7
test/contracts/wrong_compiler_version.aes
Normal file
7
test/contracts/wrong_compiler_version.aes
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
@compiler < 1.0
|
||||||
|
@compiler == 9.9.9
|
||||||
|
@compiler >= 0.1
|
||||||
|
@compiler =< 100.0.1
|
||||||
|
|
||||||
|
contract Fail =
|
||||||
|
entrypoint foo() = ()
|
Loading…
x
Reference in New Issue
Block a user