Compare commits
21 Commits
v4.0.0-rc3
...
v4.0.0-rc5
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f86b7d301 | |||
| e018c31ce1 | |||
| 9234690d31 | |||
| 214a5f0a91 | |||
| d4d3a9650a | |||
| b752965443 | |||
| 0019d92e45 | |||
| 29f2168827 | |||
| f81dc88526 | |||
| a21715a657 | |||
| 048c2ca98d | |||
| 662e5e70ef | |||
| 8e3483ced4 | |||
| 6efc390bb6 | |||
| 981027b2e7 | |||
| 11d998b739 | |||
| b481b3254b | |||
| 01a2efb7b8 | |||
| a730fcc366 | |||
| 457f9cf4ea | |||
| f34b6ed982 |
+16
-1
@@ -9,6 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Changed
|
### Changed
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
## [4.0.0-rc5] - 2019-09-27
|
||||||
|
### Added
|
||||||
|
### Changed
|
||||||
|
- Bug fixes in error reporting.
|
||||||
|
- Bug fix in variable liveness analysis for FATE.
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
## [4.0.0-rc4] - 2019-09-13
|
||||||
|
### Added
|
||||||
|
- Handle numeric escapes, i.e. `"\x19Ethereum Signed Message:\n"`, and similar strings.
|
||||||
|
### Changed
|
||||||
|
### Removed
|
||||||
|
|
||||||
## [4.0.0-rc3] - 2019-09-12
|
## [4.0.0-rc3] - 2019-09-12
|
||||||
### Added
|
### Added
|
||||||
- `Bytes.concat` and `Bytes.split` are added to be able to
|
- `Bytes.concat` and `Bytes.split` are added to be able to
|
||||||
@@ -154,7 +167,9 @@ 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-rc3...HEAD
|
[Unreleased]: https://github.com/aeternity/aesophia/compare/v4.0.0-rc5...HEAD
|
||||||
|
[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-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
|
[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
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
|
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
{relx, [{release, {aesophia, "4.0.0-rc3"},
|
{relx, [{release, {aesophia, "4.0.0-rc5"},
|
||||||
[aesophia, aebytecode, getopt]},
|
[aesophia, aebytecode, getopt]},
|
||||||
|
|
||||||
{dev_mode, true},
|
{dev_mode, true},
|
||||||
|
|||||||
@@ -783,7 +783,8 @@ check_type(_Env, Type = {uvar, _, _}, Arity) ->
|
|||||||
ensure_base_type(Type, Arity),
|
ensure_base_type(Type, Arity),
|
||||||
Type;
|
Type;
|
||||||
check_type(_Env, {args_t, Ann, Ts}, _) ->
|
check_type(_Env, {args_t, Ann, Ts}, _) ->
|
||||||
type_error({new_tuple_syntax, Ann, Ts}).
|
type_error({new_tuple_syntax, Ann, Ts}),
|
||||||
|
{tuple_t, Ann, Ts}.
|
||||||
|
|
||||||
ensure_base_type(Type, Arity) ->
|
ensure_base_type(Type, Arity) ->
|
||||||
[ type_error({wrong_type_arguments, Type, Arity, 0}) || Arity /= 0 ],
|
[ type_error({wrong_type_arguments, Type, Arity, 0}) || Arity /= 0 ],
|
||||||
@@ -1155,8 +1156,6 @@ infer_expr(Env, {typed, As, Body, Type}) ->
|
|||||||
{typed, _, NewBody, NewType} = check_expr(Env, Body, Type1),
|
{typed, _, NewBody, NewType} = check_expr(Env, Body, Type1),
|
||||||
{typed, As, NewBody, NewType};
|
{typed, As, NewBody, NewType};
|
||||||
infer_expr(Env, {app, Ann, Fun, Args0}) ->
|
infer_expr(Env, {app, Ann, Fun, Args0}) ->
|
||||||
%% TODO: fix parser to give proper annotation for normal applications!
|
|
||||||
FunAnn = aeso_syntax:get_ann(Fun),
|
|
||||||
NamedArgs = [ Arg || Arg = {named_arg, _, _, _} <- Args0 ],
|
NamedArgs = [ Arg || Arg = {named_arg, _, _, _} <- Args0 ],
|
||||||
Args = Args0 -- NamedArgs,
|
Args = Args0 -- NamedArgs,
|
||||||
case aeso_syntax:get_ann(format, Ann) of
|
case aeso_syntax:get_ann(format, Ann) of
|
||||||
@@ -1165,15 +1164,15 @@ infer_expr(Env, {app, Ann, Fun, Args0}) ->
|
|||||||
prefix ->
|
prefix ->
|
||||||
infer_op(Env, Ann, Fun, Args, fun infer_prefix/1);
|
infer_op(Env, Ann, Fun, Args, fun infer_prefix/1);
|
||||||
_ ->
|
_ ->
|
||||||
NamedArgsVar = fresh_uvar(FunAnn),
|
NamedArgsVar = fresh_uvar(Ann),
|
||||||
NamedArgs1 = [ infer_named_arg(Env, NamedArgsVar, Arg) || Arg <- NamedArgs ],
|
NamedArgs1 = [ infer_named_arg(Env, NamedArgsVar, Arg) || Arg <- NamedArgs ],
|
||||||
%% TODO: named args constraints
|
%% TODO: named args constraints
|
||||||
NewFun={typed, _, _, FunType} = infer_expr(Env, Fun),
|
NewFun={typed, _, _, FunType} = infer_expr(Env, Fun),
|
||||||
NewArgs = [infer_expr(Env, A) || A <- Args],
|
NewArgs = [infer_expr(Env, A) || A <- Args],
|
||||||
ArgTypes = [T || {typed, _, _, T} <- NewArgs],
|
ArgTypes = [T || {typed, _, _, T} <- NewArgs],
|
||||||
ResultType = fresh_uvar(FunAnn),
|
ResultType = fresh_uvar(Ann),
|
||||||
unify(Env, FunType, {fun_t, [], NamedArgsVar, ArgTypes, ResultType}, {infer_app, Fun, Args, FunType, ArgTypes}),
|
unify(Env, FunType, {fun_t, [], NamedArgsVar, ArgTypes, ResultType}, {infer_app, Fun, Args, FunType, ArgTypes}),
|
||||||
{typed, FunAnn, {app, Ann, NewFun, NamedArgs1 ++ NewArgs}, dereference(ResultType)}
|
{typed, Ann, {app, Ann, NewFun, NamedArgs1 ++ NewArgs}, dereference(ResultType)}
|
||||||
end;
|
end;
|
||||||
infer_expr(Env, {'if', Attrs, Cond, Then, Else}) ->
|
infer_expr(Env, {'if', Attrs, Cond, Then, Else}) ->
|
||||||
NewCond = check_expr(Env, Cond, {id, Attrs, "bool"}),
|
NewCond = check_expr(Env, Cond, {id, Attrs, "bool"}),
|
||||||
@@ -1333,7 +1332,7 @@ infer_case(Env, Attrs, Pattern, ExprType, Branch, SwitchType) ->
|
|||||||
end,
|
end,
|
||||||
NewEnv = bind_vars([{Var, fresh_uvar(Ann)} || Var = {id, Ann, _} <- Vars], Env#env{ in_pattern = true }),
|
NewEnv = bind_vars([{Var, fresh_uvar(Ann)} || Var = {id, Ann, _} <- Vars], Env#env{ in_pattern = true }),
|
||||||
NewPattern = {typed, _, _, PatType} = infer_expr(NewEnv, Pattern),
|
NewPattern = {typed, _, _, PatType} = infer_expr(NewEnv, Pattern),
|
||||||
NewBranch = check_expr(NewEnv, Branch, SwitchType),
|
NewBranch = check_expr(NewEnv#env{ in_pattern = false }, Branch, SwitchType),
|
||||||
unify(Env, PatType, ExprType, {case_pat, Pattern, PatType, ExprType}),
|
unify(Env, PatType, ExprType, {case_pat, Pattern, PatType, ExprType}),
|
||||||
{'case', Attrs, NewPattern, NewBranch}.
|
{'case', Attrs, NewPattern, NewBranch}.
|
||||||
|
|
||||||
|
|||||||
+27
-16
@@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
-define(i(X), {immediate, X}).
|
-define(i(X), {immediate, X}).
|
||||||
-define(a, {stack, 0}).
|
-define(a, {stack, 0}).
|
||||||
-define(s, {var, -1}). %% TODO: until we have state support in FATE
|
-define(s, {store, 1}).
|
||||||
-define(void, {var, 9999}).
|
-define(void, {var, 9999}).
|
||||||
|
|
||||||
-define(IsState(X), (is_tuple(X) andalso tuple_size(X) =:= 2 andalso element(1, X) =:= var andalso element(2, X) < 0)).
|
-define(IsState(X), (is_tuple(X) andalso tuple_size(X) =:= 2 andalso element(1, X) =:= var andalso element(2, X) < 0)).
|
||||||
@@ -477,7 +477,7 @@ call_to_scode(Env, CallCode, Args) ->
|
|||||||
builtin_to_scode(_Env, get_state, []) ->
|
builtin_to_scode(_Env, get_state, []) ->
|
||||||
[push(?s)];
|
[push(?s)];
|
||||||
builtin_to_scode(Env, set_state, [_] = Args) ->
|
builtin_to_scode(Env, set_state, [_] = Args) ->
|
||||||
call_to_scode(Env, [aeb_fate_ops:store(?s, ?a),
|
call_to_scode(Env, [{'STORE', ?s, ?a},
|
||||||
tuple(0)], Args);
|
tuple(0)], Args);
|
||||||
builtin_to_scode(Env, chain_event, Args) ->
|
builtin_to_scode(Env, chain_event, Args) ->
|
||||||
call_to_scode(Env, [erlang:apply(aeb_fate_ops, log, lists:duplicate(length(Args), ?a)),
|
call_to_scode(Env, [erlang:apply(aeb_fate_ops, log, lists:duplicate(length(Args), ?a)),
|
||||||
@@ -624,7 +624,7 @@ op_to_scode(string_blake2b) -> aeb_fate_ops:blake2b(?a, ?a).
|
|||||||
|
|
||||||
%% PUSH and STORE ?a are the same, so we use STORE to make optimizations
|
%% PUSH and STORE ?a are the same, so we use STORE to make optimizations
|
||||||
%% easier, and specialize to PUSH (which is cheaper) at the end.
|
%% easier, and specialize to PUSH (which is cheaper) at the end.
|
||||||
push(A) -> aeb_fate_ops:store(?a, A).
|
push(A) -> {'STORE', ?a, A}.
|
||||||
|
|
||||||
tuple(0) -> push(?i({tuple, {}}));
|
tuple(0) -> push(?i({tuple, {}}));
|
||||||
tuple(N) -> aeb_fate_ops:tuple(?a, N).
|
tuple(N) -> aeb_fate_ops:tuple(?a, N).
|
||||||
@@ -689,7 +689,7 @@ pp_ann(Ind, [{i, #{ live_in := In, live_out := Out }, I} | Code]) ->
|
|||||||
Fmt = fun([]) -> "()";
|
Fmt = fun([]) -> "()";
|
||||||
(Xs) -> string:join([lists:concat(["var", N]) || {var, N} <- Xs], " ")
|
(Xs) -> string:join([lists:concat(["var", N]) || {var, N} <- Xs], " ")
|
||||||
end,
|
end,
|
||||||
Op = [Ind, pp_op(I)],
|
Op = [Ind, pp_op(desugar_args(I))],
|
||||||
Ann = [[" % ", Fmt(In), " -> ", Fmt(Out)] || In ++ Out /= []],
|
Ann = [[" % ", Fmt(In), " -> ", Fmt(Out)] || In ++ Out /= []],
|
||||||
[io_lib:format("~-40s~s\n", [Op, Ann]),
|
[io_lib:format("~-40s~s\n", [Op, Ann]),
|
||||||
pp_ann(Ind, Code)];
|
pp_ann(Ind, Code)];
|
||||||
@@ -701,7 +701,7 @@ pp_op(I) ->
|
|||||||
|
|
||||||
pp_arg(?i(I)) -> io_lib:format("~w", [I]);
|
pp_arg(?i(I)) -> io_lib:format("~w", [I]);
|
||||||
pp_arg({arg, N}) -> io_lib:format("arg~p", [N]);
|
pp_arg({arg, N}) -> io_lib:format("arg~p", [N]);
|
||||||
pp_arg({var, N}) when N < 0 -> io_lib:format("store~p", [-N]);
|
pp_arg(?s) -> "store1";
|
||||||
pp_arg({var, N}) -> io_lib:format("var~p", [N]);
|
pp_arg({var, N}) -> io_lib:format("var~p", [N]);
|
||||||
pp_arg(?a) -> "a".
|
pp_arg(?a) -> "a".
|
||||||
|
|
||||||
@@ -741,18 +741,20 @@ ann_reads([{switch, Arg, Type, Alts, Def} | Code], Reads, Acc) ->
|
|||||||
ann_reads([{i, Ann, I} | Code], Reads, Acc) ->
|
ann_reads([{i, Ann, I} | Code], Reads, Acc) ->
|
||||||
#{ writes_in := WritesIn, writes_out := WritesOut } = Ann,
|
#{ writes_in := WritesIn, writes_out := WritesOut } = Ann,
|
||||||
#{ read := Rs, write := W, pure := Pure } = attributes(I),
|
#{ read := Rs, write := W, pure := Pure } = attributes(I),
|
||||||
Reads1 =
|
%% If we write it here it's not live in (unless we also read it)
|
||||||
|
Reads1 = Reads -- [W],
|
||||||
|
Reads2 =
|
||||||
case {W, Pure andalso not ordsets:is_element(W, Reads)} of
|
case {W, Pure andalso not ordsets:is_element(W, Reads)} of
|
||||||
%% This is a little bit dangerous: if writing to a dead variable, we ignore
|
%% This is a little bit dangerous: if writing to a dead variable, we ignore
|
||||||
%% the reads. Relies on dead writes to be removed by the
|
%% the reads. Relies on dead writes to be removed by the
|
||||||
%% optimisations below (r_write_to_dead_var).
|
%% optimisations below (r_write_to_dead_var).
|
||||||
{{var, _}, true} -> Reads;
|
{{var, _}, true} -> Reads1;
|
||||||
_ -> ordsets:union(Reads, Rs)
|
_ -> ordsets:union(Reads1, Rs)
|
||||||
end,
|
end,
|
||||||
LiveIn = ordsets:intersection(Reads1, WritesIn),
|
LiveIn = ordsets:intersection(Reads2, WritesIn),
|
||||||
LiveOut = ordsets:intersection(Reads, WritesOut),
|
LiveOut = ordsets:intersection(Reads, WritesOut),
|
||||||
Ann1 = #{ live_in => LiveIn, live_out => LiveOut },
|
Ann1 = #{ live_in => LiveIn, live_out => LiveOut },
|
||||||
ann_reads(Code, Reads1, [{i, Ann1, I} | Acc]);
|
ann_reads(Code, Reads2, [{i, Ann1, I} | Acc]);
|
||||||
ann_reads([], Reads, Acc) -> {Acc, Reads}.
|
ann_reads([], Reads, Acc) -> {Acc, Reads}.
|
||||||
|
|
||||||
%% Instruction attributes: reads, writes and purity (pure means no side-effects
|
%% Instruction attributes: reads, writes and purity (pure means no side-effects
|
||||||
@@ -922,6 +924,7 @@ independent({i, _, I}, {i, _, J}) ->
|
|||||||
if WI == pc; WJ == pc -> false; %% no jumps
|
if WI == pc; WJ == pc -> false; %% no jumps
|
||||||
not (PureI or PureJ) -> false; %% at least one is pure
|
not (PureI or PureJ) -> false; %% at least one is pure
|
||||||
StackI and StackJ -> false; %% cannot both use the stack
|
StackI and StackJ -> false; %% cannot both use the stack
|
||||||
|
WI == WJ -> false; %% cannot write to the same register
|
||||||
true ->
|
true ->
|
||||||
%% and cannot write to each other's inputs
|
%% and cannot write to each other's inputs
|
||||||
not lists:member(WI, RJ) andalso
|
not lists:member(WI, RJ) andalso
|
||||||
@@ -1336,18 +1339,26 @@ unannotate({i, _Ann, I}) -> [I].
|
|||||||
|
|
||||||
%% Desugar and specialize
|
%% Desugar and specialize
|
||||||
desugar({'ADD', ?a, ?i(1), ?a}) -> [aeb_fate_ops:inc()];
|
desugar({'ADD', ?a, ?i(1), ?a}) -> [aeb_fate_ops:inc()];
|
||||||
desugar({'ADD', A, ?i(1), A}) -> [aeb_fate_ops:inc(A)];
|
desugar({'ADD', A, ?i(1), A}) -> [aeb_fate_ops:inc(desugar_arg(A))];
|
||||||
desugar({'ADD', ?a, ?a, ?i(1)}) -> [aeb_fate_ops:inc()];
|
desugar({'ADD', ?a, ?a, ?i(1)}) -> [aeb_fate_ops:inc()];
|
||||||
desugar({'ADD', A, A, ?i(1)}) -> [aeb_fate_ops:inc(A)];
|
desugar({'ADD', A, A, ?i(1)}) -> [aeb_fate_ops:inc(desugar_arg(A))];
|
||||||
desugar({'SUB', ?a, ?a, ?i(1)}) -> [aeb_fate_ops:dec()];
|
desugar({'SUB', ?a, ?a, ?i(1)}) -> [aeb_fate_ops:dec()];
|
||||||
desugar({'SUB', A, A, ?i(1)}) -> [aeb_fate_ops:dec(A)];
|
desugar({'SUB', A, A, ?i(1)}) -> [aeb_fate_ops:dec(desugar_arg(A))];
|
||||||
desugar({'STORE', ?a, A}) -> [aeb_fate_ops:push(A)];
|
desugar({'STORE', ?a, A}) -> [aeb_fate_ops:push(desugar_arg(A))];
|
||||||
desugar({switch, Arg, Type, Alts, Def}) ->
|
desugar({switch, Arg, Type, Alts, Def}) ->
|
||||||
[{switch, Arg, Type, [desugar(A) || A <- Alts], desugar(Def)}];
|
[{switch, desugar_arg(Arg), Type, [desugar(A) || A <- Alts], desugar(Def)}];
|
||||||
desugar(missing) -> missing;
|
desugar(missing) -> missing;
|
||||||
desugar(Code) when is_list(Code) ->
|
desugar(Code) when is_list(Code) ->
|
||||||
lists:flatmap(fun desugar/1, Code);
|
lists:flatmap(fun desugar/1, Code);
|
||||||
desugar(I) -> [I].
|
desugar(I) -> [desugar_args(I)].
|
||||||
|
|
||||||
|
desugar_args(I) when is_tuple(I) ->
|
||||||
|
[Op | Args] = tuple_to_list(I),
|
||||||
|
list_to_tuple([Op | lists:map(fun desugar_arg/1, Args)]);
|
||||||
|
desugar_args(I) -> I.
|
||||||
|
|
||||||
|
desugar_arg(?s) -> {var, -1};
|
||||||
|
desugar_arg(A) -> A.
|
||||||
|
|
||||||
%% -- Phase III --------------------------------------------------------------
|
%% -- Phase III --------------------------------------------------------------
|
||||||
%% Constructing basic blocks
|
%% Constructing basic blocks
|
||||||
|
|||||||
+1
-1
@@ -312,7 +312,7 @@ map_key(Key, {ok, {_, Val}}) -> {map_key, Key, Val}.
|
|||||||
|
|
||||||
elim(E, []) -> E;
|
elim(E, []) -> E;
|
||||||
elim(E, [{proj, Ann, P} | Es]) -> elim({proj, Ann, E, P}, Es);
|
elim(E, [{proj, Ann, P} | Es]) -> elim({proj, Ann, E, P}, Es);
|
||||||
elim(E, [{app, Ann, Args} | Es]) -> elim({app, Ann, E, Args}, Es);
|
elim(E, [{app, _Ann, Args} | Es]) -> elim({app, aeso_syntax:get_ann(E), E, Args}, Es);
|
||||||
elim(E, [{rec_upd, Ann, Flds} | Es]) -> elim(record_update(Ann, E, Flds), Es);
|
elim(E, [{rec_upd, Ann, Flds} | Es]) -> elim(record_update(Ann, E, Flds), Es);
|
||||||
elim(E, [{map_get, Ann, Key} | Es]) -> elim({map_get, Ann, E, Key}, Es);
|
elim(E, [{map_get, Ann, Key} | Es]) -> elim({map_get, Ann, E, Key}, Es);
|
||||||
elim(E, [{map_get, Ann, Key, Val} | Es]) -> elim({map_get, Ann, E, Key, Val}, Es).
|
elim(E, [{map_get, Ann, Key, Val} | Es]) -> elim({map_get, Ann, E, Key, Val}, Es).
|
||||||
|
|||||||
+20
-9
@@ -13,14 +13,15 @@
|
|||||||
override/2, push/2, pop/1]).
|
override/2, push/2, pop/1]).
|
||||||
|
|
||||||
lexer() ->
|
lexer() ->
|
||||||
|
Number = fun(Digit) -> [Digit, "+(_", Digit, "+)*"] end,
|
||||||
DIGIT = "[0-9]",
|
DIGIT = "[0-9]",
|
||||||
HEXDIGIT = "[0-9a-fA-F]",
|
HEXDIGIT = "[0-9a-fA-F]",
|
||||||
LOWER = "[a-z_]",
|
LOWER = "[a-z_]",
|
||||||
UPPER = "[A-Z]",
|
UPPER = "[A-Z]",
|
||||||
CON = [UPPER, "[a-zA-Z0-9_]*"],
|
CON = [UPPER, "[a-zA-Z0-9_]*"],
|
||||||
INT = [DIGIT, "+"],
|
INT = Number(DIGIT),
|
||||||
HEX = ["0x", HEXDIGIT, "+"],
|
HEX = ["0x", Number(HEXDIGIT)],
|
||||||
BYTES = ["#", HEXDIGIT, "+"],
|
BYTES = ["#", Number(HEXDIGIT)],
|
||||||
WS = "[\\000-\\ ]+",
|
WS = "[\\000-\\ ]+",
|
||||||
ID = [LOWER, "[a-zA-Z0-9_']*"],
|
ID = [LOWER, "[a-zA-Z0-9_']*"],
|
||||||
TVAR = ["'", ID],
|
TVAR = ["'", ID],
|
||||||
@@ -53,7 +54,7 @@ lexer() ->
|
|||||||
, {CHAR, token(char, fun parse_char/1)}
|
, {CHAR, token(char, fun parse_char/1)}
|
||||||
, {STRING, token(string, fun parse_string/1)}
|
, {STRING, token(string, fun parse_string/1)}
|
||||||
, {HEX, token(hex, fun parse_hex/1)}
|
, {HEX, token(hex, fun parse_hex/1)}
|
||||||
, {INT, token(int, fun list_to_integer/1)}
|
, {INT, token(int, fun parse_int/1)}
|
||||||
, {BYTES, token(bytes, fun parse_bytes/1)}
|
, {BYTES, token(bytes, fun parse_bytes/1)}
|
||||||
|
|
||||||
%% Identifiers (qualified first!)
|
%% Identifiers (qualified first!)
|
||||||
@@ -95,9 +96,11 @@ parse_char([$', C, $']) -> C.
|
|||||||
|
|
||||||
unescape(Str) -> unescape(Str, []).
|
unescape(Str) -> unescape(Str, []).
|
||||||
|
|
||||||
%% TODO: numeric escapes
|
|
||||||
unescape([$"], Acc) ->
|
unescape([$"], Acc) ->
|
||||||
list_to_binary(lists:reverse(Acc));
|
list_to_binary(lists:reverse(Acc));
|
||||||
|
unescape([$\\, $x, D1, D2 | Chars ], Acc) ->
|
||||||
|
C = list_to_integer([D1, D2], 16),
|
||||||
|
unescape(Chars, [C | Acc]);
|
||||||
unescape([$\\, Code | Chars], Acc) ->
|
unescape([$\\, Code | Chars], Acc) ->
|
||||||
Ok = fun(C) -> unescape(Chars, [C | Acc]) end,
|
Ok = fun(C) -> unescape(Chars, [C | Acc]) end,
|
||||||
case Code of
|
case Code of
|
||||||
@@ -115,10 +118,18 @@ unescape([$\\, Code | Chars], Acc) ->
|
|||||||
unescape([C | Chars], Acc) ->
|
unescape([C | Chars], Acc) ->
|
||||||
unescape(Chars, [C | Acc]).
|
unescape(Chars, [C | Acc]).
|
||||||
|
|
||||||
parse_hex("0x" ++ Chars) -> list_to_integer(Chars, 16).
|
strip_underscores(S) ->
|
||||||
|
lists:filter(fun(C) -> C /= $_ end, S).
|
||||||
|
|
||||||
parse_bytes("#" ++ Chars) ->
|
parse_hex("0x" ++ S) ->
|
||||||
N = list_to_integer(Chars, 16),
|
list_to_integer(strip_underscores(S), 16).
|
||||||
Digits = (length(Chars) + 1) div 2,
|
|
||||||
|
parse_int(S) ->
|
||||||
|
list_to_integer(strip_underscores(S)).
|
||||||
|
|
||||||
|
parse_bytes("#" ++ S0) ->
|
||||||
|
S = strip_underscores(S0),
|
||||||
|
N = list_to_integer(S, 16),
|
||||||
|
Digits = (length(S) + 1) div 2,
|
||||||
<<N:Digits/unit:8>>.
|
<<N:Digits/unit:8>>.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{application, aesophia,
|
{application, aesophia,
|
||||||
[{description, "Contract Language for aeternity"},
|
[{description, "Contract Language for aeternity"},
|
||||||
{vsn, "4.0.0-rc3"},
|
{vsn, "4.0.0-rc5"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications,
|
{applications,
|
||||||
[kernel,
|
[kernel,
|
||||||
|
|||||||
@@ -152,7 +152,8 @@ compilable_contracts() ->
|
|||||||
"manual_stdlib_include",
|
"manual_stdlib_include",
|
||||||
"list_comp",
|
"list_comp",
|
||||||
"payable",
|
"payable",
|
||||||
"unapplied_builtins"
|
"unapplied_builtins",
|
||||||
|
"underscore_number_literals"
|
||||||
].
|
].
|
||||||
|
|
||||||
not_yet_compilable(fate) -> [];
|
not_yet_compilable(fate) -> [];
|
||||||
@@ -301,7 +302,14 @@ failing_contracts() ->
|
|||||||
<<?Pos(54, 5)
|
<<?Pos(54, 5)
|
||||||
"Let binding at line 54, column 5 must be followed by an expression">>,
|
"Let binding at line 54, column 5 must be followed by an expression">>,
|
||||||
<<?Pos(58, 5)
|
<<?Pos(58, 5)
|
||||||
"Let binding at line 58, column 5 must be followed by an expression">>])
|
"Let binding at line 58, column 5 must be followed by an expression">>,
|
||||||
|
<<?Pos(63, 5)
|
||||||
|
"Cannot unify int\n"
|
||||||
|
" and bool\n"
|
||||||
|
"when checking the type of the expression at line 63, column 5\n"
|
||||||
|
" id(n) : int\n"
|
||||||
|
"against the expected type\n"
|
||||||
|
" bool">>])
|
||||||
, ?TYPE_ERROR(init_type_error,
|
, ?TYPE_ERROR(init_type_error,
|
||||||
[<<?Pos(7, 3)
|
[<<?Pos(7, 3)
|
||||||
"Cannot unify string\n"
|
"Cannot unify string\n"
|
||||||
|
|||||||
@@ -15,3 +15,5 @@ contract BasicAuth =
|
|||||||
entrypoint to_sign(h : hash, n : int) =
|
entrypoint to_sign(h : hash, n : int) =
|
||||||
Crypto.blake2b((h, n))
|
Crypto.blake2b((h, n))
|
||||||
|
|
||||||
|
entrypoint weird_string() : string =
|
||||||
|
"\x19Weird String\x42\nMore\n"
|
||||||
|
|||||||
@@ -57,3 +57,8 @@ contract Test =
|
|||||||
let f() = 0
|
let f() = 0
|
||||||
let g() = f()
|
let g() = f()
|
||||||
|
|
||||||
|
function id(x : 'a) : 'a = x
|
||||||
|
|
||||||
|
entrypoint wrong_return(n : int) : bool =
|
||||||
|
id(n)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
contract UnderscoreNumberLiterals =
|
||||||
|
|
||||||
|
entrypoint ints() : list(int) =
|
||||||
|
[ 1_999_000_000,
|
||||||
|
19_99_00_00_00,
|
||||||
|
0xfff_FFF_010 ]
|
||||||
|
|
||||||
|
entrypoint bytes() : list(bytes(4)) =
|
||||||
|
[ #abcd_ef_00,
|
||||||
|
#01_02_03_04,
|
||||||
|
#aaaa_FFFF ]
|
||||||
|
|
||||||
Reference in New Issue
Block a user