Refactoring builtins and improve base58 encoding
This commit is contained in:
parent
dbf2aa45c3
commit
9187659a1e
@ -13,6 +13,38 @@
|
|||||||
, check_event_type/1
|
, check_event_type/1
|
||||||
, used_builtins/1 ]).
|
, used_builtins/1 ]).
|
||||||
|
|
||||||
|
-export([ builtin_event/1
|
||||||
|
, builtin_abort/0
|
||||||
|
, builtin_map_lookup/1
|
||||||
|
, builtin_map_put/0
|
||||||
|
, builtin_map_delete/0
|
||||||
|
, builtin_map_size/0
|
||||||
|
, builtin_map_get/1
|
||||||
|
, builtin_map_lookup_default/1
|
||||||
|
, builtin_map_member/0
|
||||||
|
, builtin_map_upd/1
|
||||||
|
, builtin_map_upd_default/1
|
||||||
|
, builtin_map_from_list/0
|
||||||
|
, builtin_list_concat/0
|
||||||
|
, builtin_string_length/0
|
||||||
|
, builtin_string_concat/0
|
||||||
|
, builtin_string_concat_inner1/0
|
||||||
|
, builtin_string_concat_inner2/0
|
||||||
|
, builtin_str_equal_p/0
|
||||||
|
, builtin_str_equal/0
|
||||||
|
, builtin_int_to_str/0
|
||||||
|
, builtin_int_to_str_/0
|
||||||
|
, builtin_int_digits/1
|
||||||
|
, builtin_base58_tab/0
|
||||||
|
, builtin_base58_int/0
|
||||||
|
, builtin_string_reverse/0
|
||||||
|
, builtin_string_reverse_/0
|
||||||
|
, builtin_base58_int_pad/0
|
||||||
|
, builtin_base58_int_encode/0
|
||||||
|
, builtin_base58_int_encode_/0
|
||||||
|
, builtin_addr_to_str/0]).
|
||||||
|
|
||||||
|
|
||||||
-import(aeso_ast_to_icode, [prim_call/5]).
|
-import(aeso_ast_to_icode, [prim_call/5]).
|
||||||
|
|
||||||
-include_lib("aebytecode/include/aeb_opcodes.hrl").
|
-include_lib("aebytecode/include/aeb_opcodes.hrl").
|
||||||
@ -39,10 +71,10 @@ builtin_deps1({map_upd_default, Type}) -> [{map_lookup_default, Type}, map_pu
|
|||||||
builtin_deps1(map_from_list) -> [map_put];
|
builtin_deps1(map_from_list) -> [map_put];
|
||||||
builtin_deps1(str_equal) -> [str_equal_p];
|
builtin_deps1(str_equal) -> [str_equal_p];
|
||||||
builtin_deps1(string_concat) -> [string_concat_inner1, string_concat_inner2];
|
builtin_deps1(string_concat) -> [string_concat_inner1, string_concat_inner2];
|
||||||
builtin_deps1(int_to_str) -> [int_to_str_, int_digits];
|
builtin_deps1(int_to_str) -> [int_to_str_, {int_digits, 10}];
|
||||||
builtin_deps1(addr_to_str) -> [base58_int, string_concat];
|
builtin_deps1(addr_to_str) -> [base58_int, string_concat];
|
||||||
builtin_deps1(base58_int) -> [base58_int_encode, base58_int_pad, string_reverse, string_concat];
|
builtin_deps1(base58_int) -> [base58_int_encode, base58_int_pad, string_reverse, string_concat];
|
||||||
builtin_deps1(base58_int_encode) -> [base58_int_encode_, base58_tab];
|
builtin_deps1(base58_int_encode) -> [base58_int_encode_, base58_tab, {int_digits, 58}];
|
||||||
builtin_deps1(string_reverse) -> [string_reverse_];
|
builtin_deps1(string_reverse) -> [string_reverse_];
|
||||||
builtin_deps1(_) -> [].
|
builtin_deps1(_) -> [].
|
||||||
|
|
||||||
@ -108,8 +140,6 @@ check_event_type(Evts, Icode) ->
|
|||||||
|| {constr_t, _, {con, _, Name}, Types} <- Evts, T <- Types ].
|
|| {constr_t, _, {con, _, Name}, Types} <- Evts, T <- Types ].
|
||||||
|
|
||||||
check_event_type(EvtName, Type, Icode) ->
|
check_event_type(EvtName, Type, Icode) ->
|
||||||
io:format("~p: ~p??\n", [EvtName, Type]),
|
|
||||||
io:format("=> ~p\n", [aeso_ast_to_icode:ast_typerep(Type, Icode)]),
|
|
||||||
VMType =
|
VMType =
|
||||||
try
|
try
|
||||||
aeso_ast_to_icode:ast_typerep(Type, Icode)
|
aeso_ast_to_icode:ast_typerep(Type, Icode)
|
||||||
@ -123,11 +153,49 @@ check_event_type(EvtName, Type, Icode) ->
|
|||||||
false -> error({EvtName, payload_should_be_string, is, VMType})
|
false -> error({EvtName, payload_should_be_string, is, VMType})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
bfun(B, F, Args) ->
|
||||||
|
{IArgs, IExpr, IRet} = erlang:apply(?MODULE, F, Args),
|
||||||
|
{{builtin, B}, [private], IArgs, IExpr, IRet}.
|
||||||
|
|
||||||
|
builtin_function(BF) ->
|
||||||
|
case BF of
|
||||||
|
{event, EventT} -> bfun(BF, builtin_event, [EventT]);
|
||||||
|
abort -> bfun(BF, builtin_abort, []);
|
||||||
|
{map_lookup, Type} -> bfun(BF, builtin_map_lookup, [Type]);
|
||||||
|
map_put -> bfun(BF, builtin_map_put, []);
|
||||||
|
map_delete -> bfun(BF, builtin_map_delete, []);
|
||||||
|
map_size -> bfun(BF, builtin_map_size, []);
|
||||||
|
{map_get, Type} -> bfun(BF, builtin_map_get, [Type]);
|
||||||
|
{map_lookup_default, Type} -> bfun(BF, builtin_map_lookup_default, [Type]);
|
||||||
|
map_member -> bfun(BF, builtin_map_member, []);
|
||||||
|
{map_upd, Type} -> bfun(BF, builtin_map_upd, [Type]);
|
||||||
|
{map_upd_default, Type} -> bfun(BF, builtin_map_upd_default, [Type]);
|
||||||
|
map_from_list -> bfun(BF, builtin_map_from_list, []);
|
||||||
|
list_concat -> bfun(BF, builtin_list_concat, []);
|
||||||
|
string_length -> bfun(BF, builtin_string_length, []);
|
||||||
|
string_concat -> bfun(BF, builtin_string_concat, []);
|
||||||
|
string_concat_inner1 -> bfun(BF, builtin_string_concat_inner1, []);
|
||||||
|
string_concat_inner2 -> bfun(BF, builtin_string_concat_inner2, []);
|
||||||
|
str_equal_p -> bfun(BF, builtin_str_equal_p, []);
|
||||||
|
str_equal -> bfun(BF, builtin_str_equal, []);
|
||||||
|
int_to_str -> bfun(BF, builtin_int_to_str, []);
|
||||||
|
int_to_str_ -> bfun(BF, builtin_int_to_str_, []);
|
||||||
|
{int_digits, X} -> bfun(BF, builtin_int_digits, [X]);
|
||||||
|
base58_tab -> bfun(BF, builtin_base58_tab, []);
|
||||||
|
base58_int -> bfun(BF, builtin_base58_int, []);
|
||||||
|
string_reverse -> bfun(BF, builtin_string_reverse, []);
|
||||||
|
string_reverse_ -> bfun(BF, builtin_string_reverse_, []);
|
||||||
|
base58_int_pad -> bfun(BF, builtin_base58_int_pad, []);
|
||||||
|
base58_int_encode -> bfun(BF, builtin_base58_int_encode, []);
|
||||||
|
base58_int_encode_ -> bfun(BF, builtin_base58_int_encode_, []);
|
||||||
|
addr_to_str -> bfun(BF, builtin_addr_to_str, [])
|
||||||
|
end.
|
||||||
|
|
||||||
%% Event primitive (dependent on Event type)
|
%% Event primitive (dependent on Event type)
|
||||||
%%
|
%%
|
||||||
%% We need to switch on the event and prepare the correct #event for icode_to_asm
|
%% We need to switch on the event and prepare the correct #event for icode_to_asm
|
||||||
%% NOTE: we assume all errors are already checked!
|
%% NOTE: we assume all errors are already checked!
|
||||||
builtin_function(Builtin = {event, EventT}) ->
|
builtin_event(EventT) ->
|
||||||
A = fun(X) -> aeb_opcodes:mnemonic(X) end,
|
A = fun(X) -> aeb_opcodes:mnemonic(X) end,
|
||||||
VIx = fun(Ix) -> v(lists:concat(["v", Ix])) end,
|
VIx = fun(Ix) -> v(lists:concat(["v", Ix])) end,
|
||||||
ArgPats = fun(Ts) -> [ VIx(Ix) || Ix <- lists:seq(0, length(Ts) - 1) ] end,
|
ArgPats = fun(Ts) -> [ VIx(Ix) || Ix <- lists:seq(0, length(Ts) - 1) ] end,
|
||||||
@ -149,149 +217,132 @@ builtin_function(Builtin = {event, EventT}) ->
|
|||||||
{variant_t, Cons} = EventT,
|
{variant_t, Cons} = EventT,
|
||||||
Tags = lists:seq(0, length(Cons) - 1),
|
Tags = lists:seq(0, length(Cons) - 1),
|
||||||
|
|
||||||
{{builtin, Builtin}, [private],
|
{[{"e", event}],
|
||||||
[{"e", event}],
|
{switch, v(e),
|
||||||
{switch, v(e),
|
[{Pat(Tag, Types), Clause(Tag, Con, Types)}
|
||||||
[{Pat(Tag, Types), Clause(Tag, Con, Types)}
|
|| {Tag, {constr_t, _, Con, Types}} <- lists:zip(Tags, Cons) ]},
|
||||||
|| {Tag, {constr_t, _, Con, Types}} <- lists:zip(Tags, Cons) ]},
|
{tuple, []}}.
|
||||||
{tuple, []}};
|
|
||||||
|
|
||||||
%% Abort primitive.
|
%% Abort primitive.
|
||||||
builtin_function(abort) ->
|
builtin_abort() ->
|
||||||
A = fun(X) -> aeb_opcodes:mnemonic(X) end,
|
A = fun(X) -> aeb_opcodes:mnemonic(X) end,
|
||||||
{{builtin, abort}, [private],
|
{[{"s", string}],
|
||||||
[{"s", string}],
|
|
||||||
{inline_asm, [A(?PUSH1),0, %% Push a dummy 0 for the first arg
|
{inline_asm, [A(?PUSH1),0, %% Push a dummy 0 for the first arg
|
||||||
A(?REVERT)]}, %% Stack: 0,Ptr
|
A(?REVERT)]}, %% Stack: 0,Ptr
|
||||||
{tuple,[]}};
|
{tuple,[]}}.
|
||||||
|
|
||||||
%% Map primitives
|
%% Map primitives
|
||||||
builtin_function(Builtin = {map_lookup, Type}) ->
|
builtin_map_lookup(Type) ->
|
||||||
Ret = aeso_icode:option_typerep(Type),
|
Ret = aeso_icode:option_typerep(Type),
|
||||||
{{builtin, Builtin}, [private],
|
{[{"m", word}, {"k", word}],
|
||||||
[{"m", word}, {"k", word}],
|
prim_call(?PRIM_CALL_MAP_GET, #integer{value = 0},
|
||||||
prim_call(?PRIM_CALL_MAP_GET, #integer{value = 0},
|
[#var_ref{name = "m"}, #var_ref{name = "k"}],
|
||||||
[#var_ref{name = "m"}, #var_ref{name = "k"}],
|
[word, word], Ret),
|
||||||
[word, word], Ret),
|
Ret}.
|
||||||
Ret};
|
|
||||||
|
|
||||||
builtin_function(Builtin = map_put) ->
|
builtin_map_put() ->
|
||||||
%% We don't need the types for put.
|
%% We don't need the types for put.
|
||||||
{{builtin, Builtin}, [private],
|
{[{"m", word}, {"k", word}, {"v", word}],
|
||||||
[{"m", word}, {"k", word}, {"v", word}],
|
prim_call(?PRIM_CALL_MAP_PUT, #integer{value = 0},
|
||||||
prim_call(?PRIM_CALL_MAP_PUT, #integer{value = 0},
|
[v(m), v(k), v(v)], [word, word, word], word),
|
||||||
[v(m), v(k), v(v)],
|
word}.
|
||||||
[word, word, word], word),
|
|
||||||
word};
|
|
||||||
|
|
||||||
builtin_function(Builtin = map_delete) ->
|
builtin_map_delete() ->
|
||||||
{{builtin, Builtin}, [private],
|
{[{"m", word}, {"k", word}],
|
||||||
[{"m", word}, {"k", word}],
|
prim_call(?PRIM_CALL_MAP_DELETE, #integer{value = 0},
|
||||||
prim_call(?PRIM_CALL_MAP_DELETE, #integer{value = 0},
|
[v(m), v(k)], [word, word], word),
|
||||||
[v(m), v(k)],
|
word}.
|
||||||
[word, word], word),
|
|
||||||
word};
|
|
||||||
|
|
||||||
builtin_function(Builtin = map_size) ->
|
builtin_map_size() ->
|
||||||
Name = {builtin, Builtin},
|
{[{"m", word}],
|
||||||
{Name, [private], [{"m", word}],
|
prim_call(?PRIM_CALL_MAP_SIZE, #integer{value = 0},
|
||||||
prim_call(?PRIM_CALL_MAP_SIZE, #integer{value = 0},
|
[v(m)], [word], word),
|
||||||
[v(m)], [word], word),
|
word}.
|
||||||
word};
|
|
||||||
|
|
||||||
%% Map builtins
|
%% Map builtins
|
||||||
builtin_function(Builtin = {map_get, Type}) ->
|
builtin_map_get(Type) ->
|
||||||
%% function map_get(m, k) =
|
%% function map_get(m, k) =
|
||||||
%% switch(map_lookup(m, k))
|
%% switch(map_lookup(m, k))
|
||||||
%% Some(v) => v
|
%% Some(v) => v
|
||||||
{{builtin, Builtin}, [private],
|
{[{"m", word}, {"k", word}],
|
||||||
[{"m", word}, {"k", word}],
|
{switch, ?call({map_lookup, Type}, [v(m), v(k)]), [{option_some(v(v)), v(v)}]},
|
||||||
{switch, ?call({map_lookup, Type}, [v(m), v(k)]),
|
Type}.
|
||||||
[{option_some(v(v)), v(v)}]},
|
|
||||||
Type};
|
|
||||||
|
|
||||||
builtin_function(Builtin = {map_lookup_default, Type}) ->
|
builtin_map_lookup_default(Type) ->
|
||||||
%% function map_lookup_default(m, k, default) =
|
%% function map_lookup_default(m, k, default) =
|
||||||
%% switch(map_lookup(m, k))
|
%% switch(map_lookup(m, k))
|
||||||
%% None => default
|
%% None => default
|
||||||
%% Some(v) => v
|
%% Some(v) => v
|
||||||
{{builtin, Builtin}, [private],
|
{[{"m", word}, {"k", word}, {"default", Type}],
|
||||||
[{"m", word}, {"k", word}, {"default", Type}],
|
{switch, ?call({map_lookup, Type}, [v(m), v(k)]),
|
||||||
{switch, ?call({map_lookup, Type}, [v(m), v(k)]),
|
[{option_none(), v(default)},
|
||||||
[{option_none(), v(default)},
|
{option_some(v(v)), v(v)}]},
|
||||||
{option_some(v(v)), v(v)}]},
|
Type}.
|
||||||
Type};
|
|
||||||
|
|
||||||
builtin_function(Builtin = map_member) ->
|
builtin_map_member() ->
|
||||||
%% function map_member(m, k) : bool =
|
%% function map_member(m, k) : bool =
|
||||||
%% switch(Map.lookup(m, k))
|
%% switch(Map.lookup(m, k))
|
||||||
%% None => false
|
%% None => false
|
||||||
%% _ => true
|
%% _ => true
|
||||||
{{builtin, Builtin}, [private],
|
{[{"m", word}, {"k", word}],
|
||||||
[{"m", word}, {"k", word}],
|
{switch, ?call({map_lookup, word}, [v(m), v(k)]),
|
||||||
{switch, ?call({map_lookup, word}, [v(m), v(k)]),
|
[{option_none(), {integer, 0}},
|
||||||
[{option_none(), {integer, 0}},
|
{{var_ref, "_"}, {integer, 1}}]},
|
||||||
{{var_ref, "_"}, {integer, 1}}]},
|
word}.
|
||||||
word};
|
|
||||||
|
|
||||||
builtin_function(Builtin = {map_upd, Type}) ->
|
builtin_map_upd(Type) ->
|
||||||
%% function map_upd(map, key, fun) =
|
%% function map_upd(map, key, fun) =
|
||||||
%% map_put(map, key, fun(map_get(map, key)))
|
%% map_put(map, key, fun(map_get(map, key)))
|
||||||
{{builtin, Builtin}, [private],
|
{[{"map", word}, {"key", word}, {"valfun", word}],
|
||||||
[{"map", word}, {"key", word}, {"valfun", word}],
|
|
||||||
?call(map_put,
|
?call(map_put,
|
||||||
[v(map), v(key),
|
[v(map), v(key),
|
||||||
#funcall{ function = v(valfun),
|
#funcall{ function = v(valfun),
|
||||||
args = [?call({map_get, Type}, [v(map), v(key)])] }]),
|
args = [?call({map_get, Type}, [v(map), v(key)])] }]),
|
||||||
word};
|
word}.
|
||||||
|
|
||||||
builtin_function(Builtin = {map_upd_default, Type}) ->
|
builtin_map_upd_default(Type) ->
|
||||||
%% function map_upd(map, key, val, fun) =
|
%% function map_upd(map, key, val, fun) =
|
||||||
%% map_put(map, key, fun(map_lookup_default(map, key, val)))
|
%% map_put(map, key, fun(map_lookup_default(map, key, val)))
|
||||||
{{builtin, Builtin}, [private],
|
{[{"map", word}, {"key", word}, {"val", word}, {"valfun", word}],
|
||||||
[{"map", word}, {"key", word}, {"val", word}, {"valfun", word}],
|
|
||||||
?call(map_put,
|
?call(map_put,
|
||||||
[v(map), v(key),
|
[v(map), v(key),
|
||||||
#funcall{ function = v(valfun),
|
#funcall{ function = v(valfun),
|
||||||
args = [?call({map_lookup_default, Type}, [v(map), v(key), v(val)])] }]),
|
args = [?call({map_lookup_default, Type}, [v(map), v(key), v(val)])] }]),
|
||||||
word};
|
word}.
|
||||||
|
|
||||||
builtin_function(Builtin = map_from_list) ->
|
builtin_map_from_list() ->
|
||||||
%% function map_from_list(xs, acc) =
|
%% function map_from_list(xs, acc) =
|
||||||
%% switch(xs)
|
%% switch(xs)
|
||||||
%% [] => acc
|
%% [] => acc
|
||||||
%% (k, v) :: xs => map_from_list(xs, acc { [k] = v })
|
%% (k, v) :: xs => map_from_list(xs, acc { [k] = v })
|
||||||
{{builtin, Builtin}, [private],
|
{[{"xs", {list, {tuple, [word, word]}}}, {"acc", word}],
|
||||||
[{"xs", {list, {tuple, [word, word]}}}, {"acc", word}],
|
|
||||||
{switch, v(xs),
|
{switch, v(xs),
|
||||||
[{{list, []}, v(acc)},
|
[{{list, []}, v(acc)},
|
||||||
{{binop, '::', {tuple, [v(k), v(v)]}, v(ys)},
|
{{binop, '::', {tuple, [v(k), v(v)]}, v(ys)},
|
||||||
?call(map_from_list,
|
?call(map_from_list,
|
||||||
[v(ys), ?call(map_put, [v(acc), v(k), v(v)])])}]},
|
[v(ys), ?call(map_put, [v(acc), v(k), v(v)])])}]},
|
||||||
word};
|
word}.
|
||||||
|
|
||||||
%% list_concat
|
%% list_concat
|
||||||
%%
|
%%
|
||||||
%% Concatenates two lists.
|
%% Concatenates two lists.
|
||||||
builtin_function(list_concat) ->
|
builtin_list_concat() ->
|
||||||
{{builtin, list_concat}, [private],
|
{[{"l1", {list, word}}, {"l2", {list, word}}],
|
||||||
[{"l1", {list, word}}, {"l2", {list, word}}],
|
|
||||||
{switch, v(l1),
|
{switch, v(l1),
|
||||||
[{{list, []}, v(l2)},
|
[{{list, []}, v(l2)},
|
||||||
{{binop, '::', v(hd), v(tl)},
|
{{binop, '::', v(hd), v(tl)},
|
||||||
{binop, '::', v(hd), ?call(list_concat, [v(tl), v(l2)])}}
|
{binop, '::', v(hd), ?call(list_concat, [v(tl), v(l2)])}}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
word};
|
word}.
|
||||||
|
|
||||||
builtin_function(string_length) ->
|
builtin_string_length() ->
|
||||||
%% function length(str) =
|
%% function length(str) =
|
||||||
%% switch(str)
|
%% switch(str)
|
||||||
%% {n} -> n // (ab)use the representation
|
%% {n} -> n // (ab)use the representation
|
||||||
{{builtin, string_length}, [private],
|
{[{"s", string}],
|
||||||
[{"s", string}],
|
?DEREF(n, s, ?V(n)),
|
||||||
?DEREF(n, s, ?V(n)),
|
word}.
|
||||||
word};
|
|
||||||
|
|
||||||
%% str_concat - concatenate two strings
|
%% str_concat - concatenate two strings
|
||||||
%%
|
%%
|
||||||
@ -299,9 +350,8 @@ builtin_function(string_length) ->
|
|||||||
%% top of the Heap and the address to it is returned. The tricky bit is when
|
%% top of the Heap and the address to it is returned. The tricky bit is when
|
||||||
%% the words from the second string has to be shifted to fit next to the first
|
%% the words from the second string has to be shifted to fit next to the first
|
||||||
%% string.
|
%% string.
|
||||||
builtin_function(string_concat) ->
|
builtin_string_concat() ->
|
||||||
{{builtin, string_concat}, [private],
|
{[{"s1", string}, {"s2", string}],
|
||||||
[{"s1", string}, {"s2", string}],
|
|
||||||
?DEREF(n1, s1,
|
?DEREF(n1, s1,
|
||||||
?DEREF(n2, s2,
|
?DEREF(n2, s2,
|
||||||
{ifte, ?EQ(n2, 0),
|
{ifte, ?EQ(n2, 0),
|
||||||
@ -313,13 +363,12 @@ builtin_function(string_concat) ->
|
|||||||
?V(ret) %% Put the actual return value
|
?V(ret) %% Put the actual return value
|
||||||
]})}
|
]})}
|
||||||
)),
|
)),
|
||||||
word};
|
word}.
|
||||||
|
|
||||||
builtin_function(string_concat_inner1) ->
|
builtin_string_concat_inner1() ->
|
||||||
%% Copy all whole words from the first string, and set up for word fusion
|
%% Copy all whole words from the first string, and set up for word fusion
|
||||||
%% Special case when the length of the first string is divisible by 32.
|
%% Special case when the length of the first string is divisible by 32.
|
||||||
{{builtin, string_concat_inner1}, [private],
|
{[{"n1", word}, {"p1", pointer}, {"n2", word}, {"p2", pointer}],
|
||||||
[{"n1", word}, {"p1", pointer}, {"n2", word}, {"p2", pointer}],
|
|
||||||
?DEREF(w1, p1,
|
?DEREF(w1, p1,
|
||||||
{ifte, ?GT(n1, 32),
|
{ifte, ?GT(n1, 32),
|
||||||
{seq, [?V(w1), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
|
{seq, [?V(w1), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
|
||||||
@ -328,13 +377,12 @@ builtin_function(string_concat_inner1) ->
|
|||||||
?call(string_concat_inner2, [?I(32), ?I(0), ?V(n2), ?V(p2)]),
|
?call(string_concat_inner2, [?I(32), ?I(0), ?V(n2), ?V(p2)]),
|
||||||
?call(string_concat_inner2, [?SUB(32, n1), ?V(w1), ?V(n2), ?V(p2)])}
|
?call(string_concat_inner2, [?SUB(32, n1), ?V(w1), ?V(n2), ?V(p2)])}
|
||||||
}),
|
}),
|
||||||
word};
|
word}.
|
||||||
|
|
||||||
builtin_function(string_concat_inner2) ->
|
builtin_string_concat_inner2() ->
|
||||||
%% Current "work in progess" word 'x', has 'o' bytes that are "free" - fill them from
|
%% Current "work in progess" word 'x', has 'o' bytes that are "free" - fill them from
|
||||||
%% words of the second string.
|
%% words of the second string.
|
||||||
{{builtin, string_concat_inner2}, [private],
|
{[{"o", word}, {"x", word}, {"n2", word}, {"p2", pointer}],
|
||||||
[{"o", word}, {"x", word}, {"n2", word}, {"p2", pointer}],
|
|
||||||
{ifte, ?LT(n2, 1),
|
{ifte, ?LT(n2, 1),
|
||||||
{seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]}, %% Use MSIZE as dummy return value
|
{seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]}, %% Use MSIZE as dummy return value
|
||||||
?DEREF(w2, p2,
|
?DEREF(w2, p2,
|
||||||
@ -348,163 +396,142 @@ builtin_function(string_concat_inner2) ->
|
|||||||
{inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]} %% Use MSIZE as dummy return value
|
{inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]} %% Use MSIZE as dummy return value
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
word};
|
word}.
|
||||||
|
|
||||||
builtin_function(str_equal_p) ->
|
builtin_str_equal_p() ->
|
||||||
%% function str_equal_p(n, p1, p2) =
|
%% function str_equal_p(n, p1, p2) =
|
||||||
%% if(n =< 0) true
|
%% if(n =< 0) true
|
||||||
%% else
|
%% else
|
||||||
%% let w1 = *p1
|
%% let w1 = *p1
|
||||||
%% let w2 = *p2
|
%% let w2 = *p2
|
||||||
%% w1 == w2 && str_equal_p(n - 32, p1 + 32, p2 + 32)
|
%% w1 == w2 && str_equal_p(n - 32, p1 + 32, p2 + 32)
|
||||||
{{builtin, str_equal_p}, [private],
|
{[{"n", word}, {"p1", pointer}, {"p2", pointer}],
|
||||||
[{"n", word}, {"p1", pointer}, {"p2", pointer}],
|
{ifte, ?LT(n, 1),
|
||||||
{ifte, ?LT(n, 1),
|
?I(1),
|
||||||
?I(1),
|
?DEREF(w1, p1,
|
||||||
?DEREF(w1, p1,
|
?DEREF(w2, p2,
|
||||||
?DEREF(w2, p2,
|
?AND(?EQ(w1, w2),
|
||||||
?AND(?EQ(w1, w2),
|
?call(str_equal_p, [?SUB(n, 32), ?NXT(p1), ?NXT(p2)]))))},
|
||||||
?call(str_equal_p, [?SUB(n, 32), ?NXT(p1), ?NXT(p2)]))))},
|
word}.
|
||||||
word};
|
|
||||||
|
|
||||||
builtin_function(str_equal) ->
|
builtin_str_equal() ->
|
||||||
%% function str_equal(s1, s2) =
|
%% function str_equal(s1, s2) =
|
||||||
%% let n1 = length(s1)
|
%% let n1 = length(s1)
|
||||||
%% let n2 = length(s2)
|
%% let n2 = length(s2)
|
||||||
%% n1 == n2 && str_equal_p(n1, s1 + 32, s2 + 32)
|
%% n1 == n2 && str_equal_p(n1, s1 + 32, s2 + 32)
|
||||||
{{builtin, str_equal}, [private],
|
{[{"s1", string}, {"s2", string}],
|
||||||
[{"s1", string}, {"s2", string}],
|
?DEREF(n1, s1,
|
||||||
?DEREF(n1, s1,
|
?DEREF(n2, s2,
|
||||||
?DEREF(n2, s2,
|
?AND(?EQ(n1, n2), ?call(str_equal_p, [?V(n1), ?NXT(s1), ?NXT(s2)]))
|
||||||
?AND(?EQ(n1, n2), ?call(str_equal_p, [?V(n1), ?NXT(s1), ?NXT(s2)]))
|
)),
|
||||||
)),
|
word}.
|
||||||
word};
|
|
||||||
|
|
||||||
builtin_function(int_to_str) ->
|
builtin_int_to_str() ->
|
||||||
{{builtin, int_to_str}, [private],
|
{[{"i0", word}],
|
||||||
[{"i0", word}],
|
{switch, {ifte, ?LT(i0, 0),
|
||||||
{switch, {ifte, ?LT(i0, 0),
|
{tuple, [?I(2), ?NEG(i0), ?BSL(45, 31)]},
|
||||||
{tuple, [?I(2), ?NEG(i0), ?BSL(45, 31)]},
|
{tuple, [?I(1), ?V(i0), ?I(0)]}},
|
||||||
{tuple, [?I(1), ?V(i0), ?I(0)]}},
|
[{{tuple, [v(off), v(i), v(x)]},
|
||||||
[{{tuple, [v(off), v(i), v(x)]},
|
?LET(ret, {inline_asm, [?A(?MSIZE)]},
|
||||||
?LET(ret, {inline_asm, [?A(?MSIZE)]},
|
?LET(n, ?call({int_digits, 10}, [?V(i), ?I(0)]),
|
||||||
?LET(n, ?call(int_digits, [?DIV(i, 10), ?I(0)]),
|
?LET(fac, ?EXP(10, n),
|
||||||
?LET(fac, ?EXP(10, n),
|
{seq, [?ADD(n, off), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, %% Store str len
|
||||||
{seq, [?ADD(n, off), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, %% Store str len
|
?call(int_to_str_,
|
||||||
?call(int_to_str_,
|
[?MOD(i, fac), ?ADD(x, ?BSL(?ADD(48, ?DIV(i, fac)), ?SUB(32, off))), ?DIV(fac, 10), ?V(off)]),
|
||||||
[?MOD(i, fac), ?ADD(x, ?BSL(?ADD(48, ?DIV(i, fac)), ?SUB(32, off))), ?DIV(fac, 10), ?V(off)]),
|
{inline_asm, [?A(?POP)]}, ?V(ret)]}
|
||||||
{inline_asm, [?A(?POP)]}, ?V(ret)]}
|
)))}]},
|
||||||
)))}]},
|
word}.
|
||||||
word};
|
|
||||||
|
|
||||||
builtin_function(int_to_str_) ->
|
builtin_int_to_str_() ->
|
||||||
{{builtin, int_to_str_}, [private],
|
{[{"x", word}, {"y", word}, {"fac", word}, {"n", word}],
|
||||||
[{"x", word}, {"y", word}, {"fac", word}, {"n", word}],
|
{ifte, ?EQ(fac, 0),
|
||||||
{ifte, ?EQ(fac, 0),
|
{seq, [?V(y), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, ?V(n)]},
|
||||||
{seq, [?V(y), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, ?V(n)]},
|
{ifte, ?EQ(n, 32),
|
||||||
{ifte, ?EQ(?MOD(n, 32), 0),
|
%% We've filled a word, write it and start on new word
|
||||||
%% We've filled a word, write it and start on new word
|
{seq, [?V(y), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
|
||||||
{seq, [?V(y), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
|
?call(int_to_str_,
|
||||||
?call(int_to_str_,
|
[?MOD(x, fac), ?BSL(?ADD(48, ?DIV(x, fac)), 31),
|
||||||
[?MOD(x, fac), ?BSL(?ADD(48, ?DIV(x, fac)), 31),
|
?DIV(fac, 10), ?I(1)])]},
|
||||||
?DIV(fac, 10), ?I(1)])]},
|
?call(int_to_str_,
|
||||||
?call(int_to_str_,
|
[?MOD(x, fac), ?ADD(y, ?BSL(?ADD(48, ?DIV(x, fac)), ?SUB(31, n))),
|
||||||
[?MOD(x, fac), ?ADD(y, ?BSL(?ADD(48, ?DIV(x, fac)), ?SUB(31, n))),
|
?DIV(fac, 10), ?ADD(n, 1)])}
|
||||||
?DIV(fac, 10), ?ADD(n, 1)])}
|
},
|
||||||
},
|
word}.
|
||||||
word};
|
|
||||||
|
|
||||||
builtin_function(int_digits) ->
|
builtin_base58_tab() ->
|
||||||
{{builtin, int_digits}, [private],
|
<<Fst32:256>> = <<"123456789ABCDEFGHJKLMNPQRSTUVWXY">>,
|
||||||
[{"x", word}, {"n", word}],
|
<<Lst26:256>> = <<"Zabcdefghijkmnopqrstuvwxyz", 0:48>>,
|
||||||
{ifte, ?EQ(x, 0), ?V(n), ?call(int_digits, [?DIV(x, 10), ?ADD(n, 1)])},
|
{[{"ix", word}],
|
||||||
word};
|
{ifte, ?LT(ix, 32),
|
||||||
|
?BYTE(ix, Fst32),
|
||||||
|
?BYTE(?SUB(ix, 32), Lst26)
|
||||||
|
},
|
||||||
|
word}.
|
||||||
|
|
||||||
builtin_function(base58_tab) ->
|
builtin_base58_int() ->
|
||||||
Fst32 = 22252025330403739761829862310514590177935513752035045390683118730099851483225,
|
{[{"w", word}],
|
||||||
Lst26 = 40880219588527126470443504235291962205031881694701834176631306799289575931904,
|
?LET(ret, {inline_asm, [?A(?MSIZE)]},
|
||||||
{{builtin, base58_tab}, [private],
|
{seq, [?call(base58_int_pad, [?V(w), ?I(0), ?I(0)]), {inline_asm, [?A(?POP)]}, ?V(ret)]}),
|
||||||
[{"ix", word}],
|
word}.
|
||||||
{ifte, ?LT(ix, 32),
|
|
||||||
?BYTE(ix, Fst32),
|
|
||||||
?BYTE(?SUB(ix, 32), Lst26)
|
|
||||||
}, word};
|
|
||||||
|
|
||||||
builtin_function(base58_int) ->
|
builtin_base58_int_pad() ->
|
||||||
{{builtin, base58_int}, [private],
|
{[{"src", word}, {"ix", word}, {"dst", word}],
|
||||||
[{"w", word}],
|
{ifte, ?GT(?ADD(?DIV(ix, 31), ?BYTE(ix, src)), 0),
|
||||||
?LET(str0, ?call(base58_int_encode, [?V(w)]),
|
?call(base58_int_encode, [?V(src), ?V(ix), ?V(dst)]),
|
||||||
?LET(str1, ?call(base58_int_pad, [?V(w), ?I(0), ?I(0)]),
|
?call(base58_int_pad, [?V(src), ?ADD(ix, 1), ?ADD(dst, ?BSL($1, ?SUB(31, ix)))])},
|
||||||
?LET(str2, ?call(string_concat, [?V(str0), ?V(str1)]),
|
word}.
|
||||||
?call(string_reverse, [?V(str2)])
|
|
||||||
))),
|
|
||||||
word};
|
|
||||||
|
|
||||||
builtin_function(string_reverse) ->
|
builtin_base58_int_encode() ->
|
||||||
{{builtin, string_reverse}, [private],
|
{[{"src", word}, {"ix", word}, {"dst", word}],
|
||||||
[{"s", string}],
|
?LET(n, ?call({int_digits, 58}, [?V(src), ?I(0)]),
|
||||||
?DEREF(n, s,
|
{seq, [?ADD(n, ?ADD(ix, 1)), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
|
||||||
?LET(ret, {inline_asm, [?A(?MSIZE)]},
|
?call(base58_int_encode_, [?V(src), ?V(dst), ?EXP(58, n), ?V(ix)])]}),
|
||||||
{seq, [?V(n), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
|
word}.
|
||||||
?call(string_reverse_, [?NXT(s), ?I(0), ?I(31), ?SUB(?V(n), 1)]),
|
|
||||||
{inline_asm, [?A(?POP)]}, ?V(ret)]})),
|
|
||||||
word};
|
|
||||||
|
|
||||||
builtin_function(string_reverse_) ->
|
builtin_base58_int_encode_() ->
|
||||||
{{builtin, string_reverse_}, [private],
|
{[{"src", word}, {"dst", word}, {"fac", word}, {"ix", word}],
|
||||||
[{"p", pointer}, {"x", word}, {"i1", word}, {"i2", word}],
|
{ifte, ?EQ(fac, 0),
|
||||||
{ifte, ?LT(i2, 0),
|
{seq, [?V(dst), {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]},
|
||||||
{seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]},
|
{ifte, ?EQ(ix, 32),
|
||||||
?LET(p1, ?ADD(p, ?MUL(?DIV(i2, 32), 32)),
|
%% We've filled a word, write it and start on new word
|
||||||
?DEREF(w, p1,
|
{seq, [?V(dst), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
|
||||||
?LET(b, ?BYTE(?MOD(i2, 32), w),
|
?call(base58_int_encode_, [?V(src), ?I(0), ?V(fac), ?I(0)])]},
|
||||||
{ifte, ?LT(i1, 0),
|
?call(base58_int_encode_,
|
||||||
{seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
|
[?MOD(src, fac), ?ADD(dst, ?BSL(?call(base58_tab, [?DIV(src, fac)]), ?SUB(31, ix))),
|
||||||
?call(string_reverse_,
|
?DIV(fac, 58), ?ADD(ix, 1)])}
|
||||||
[?V(p), ?BSL(b, 31), ?I(30), ?SUB(i2, 1)])]},
|
},
|
||||||
?call(string_reverse_,
|
word}.
|
||||||
[?V(p), ?ADD(x, ?BSL(b, i1)), ?SUB(i1, 1), ?SUB(i2, 1)])})))},
|
|
||||||
word};
|
|
||||||
|
|
||||||
builtin_function(base58_int_pad) ->
|
builtin_int_digits(X) ->
|
||||||
{{builtin, base58_int_pad}, [private],
|
{[{"x0", word}, {"dgts", word}],
|
||||||
[{"w", word}, {"i", word}, {"x", word}],
|
?LET(x1, ?DIV(x0, X),
|
||||||
{ifte, ?GT(?BYTE(i, w), 0),
|
{ifte, ?EQ(x1, 0), ?V(dgts), ?call({int_digits, X}, [?V(x1), ?ADD(dgts, 1)])}),
|
||||||
{seq, [?V(i), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
|
word}.
|
||||||
?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
|
|
||||||
{inline_asm, [?A(?PUSH1), 64, ?A(?MSIZE), ?A(?SUB)]}]},
|
|
||||||
?call(base58_int_pad, [?V(w), ?ADD(i, 1),
|
|
||||||
?ADD(x, ?BSL(49, ?SUB(31, i)))])},
|
|
||||||
word};
|
|
||||||
|
|
||||||
builtin_function(base58_int_encode) ->
|
builtin_string_reverse() ->
|
||||||
{{builtin, base58_int_encode}, [private],
|
{[{"s", string}],
|
||||||
[{"w", word}],
|
?DEREF(n, s,
|
||||||
?LET(ret, {inline_asm, [?A(?MSIZE), ?A(?PUSH1), 0, ?A(?MSIZE), ?A(?MSTORE)]}, %% write placeholder
|
?LET(ret, {inline_asm, [?A(?MSIZE)]},
|
||||||
?LET(n, ?call(base58_int_encode_, [?V(w), ?I(0), ?I(0), ?I(31)]),
|
{seq, [?V(n), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
|
||||||
{seq, [?V(ret), {inline_asm, [?A(?DUP2), ?A(?SWAP1), ?A(?MSTORE)]},
|
?call(string_reverse_, [?NXT(s), ?I(0), ?I(31), ?SUB(?V(n), 1)]),
|
||||||
?V(ret)]})),
|
{inline_asm, [?A(?POP)]}, ?V(ret)]})),
|
||||||
word};
|
word}.
|
||||||
|
|
||||||
builtin_function(base58_int_encode_) ->
|
builtin_string_reverse_() ->
|
||||||
{{builtin, base58_int_encode_}, [private],
|
{[{"p", pointer}, {"x", word}, {"i1", word}, {"i2", word}],
|
||||||
[{"w", word}, {"x", word}, {"n", word}, {"i", word}],
|
{ifte, ?LT(i2, 0),
|
||||||
{ifte, ?EQ(w, 0),
|
{seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]},
|
||||||
{seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, ?V(n)]},
|
?LET(p1, ?ADD(p, ?MUL(?DIV(i2, 32), 32)),
|
||||||
{ifte, ?LT(i, 0),
|
?DEREF(w, p1,
|
||||||
{seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
|
?LET(b, ?BYTE(?MOD(i2, 32), w),
|
||||||
?call(base58_int_encode_,
|
{ifte, ?LT(i1, 0),
|
||||||
[?DIV(w, 58), ?BSL(?call(base58_tab, [?MOD(w, 58)]), 31),
|
{seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
|
||||||
?ADD(n, 1), ?I(30)])]},
|
?call(string_reverse_,
|
||||||
?call(base58_int_encode_,
|
[?V(p), ?BSL(b, 31), ?I(30), ?SUB(i2, 1)])]},
|
||||||
[?DIV(w, 58), ?ADD(x, ?BSL(?call(base58_tab, [?MOD(w, 58)]), i)),
|
?call(string_reverse_,
|
||||||
?ADD(n, 1), ?SUB(i, 1)])}},
|
[?V(p), ?ADD(x, ?BSL(b, i1)), ?SUB(i1, 1), ?SUB(i2, 1)])})))},
|
||||||
word};
|
word}.
|
||||||
|
|
||||||
|
builtin_addr_to_str() ->
|
||||||
builtin_function(addr_to_str) ->
|
{[{"a", word}], ?call(base58_int, [?V(a)]), word}.
|
||||||
{{builtin, addr_to_str}, [private],
|
|
||||||
[{"a", word}],
|
|
||||||
?call(base58_int, [?V(a)]),
|
|
||||||
word}.
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user