Make String.aes a stdlib + add more string functions
This means moving the FATE operations to StringInternal and adding to/from_list (and Char.to/from_int + Char.to_upper/lower).
This commit is contained in:
parent
6682b24156
commit
b9acf24dca
86
priv/stdlib/String.aes
Normal file
86
priv/stdlib/String.aes
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
include "List.aes"
|
||||||
|
namespace String =
|
||||||
|
function sha3(s : string) : hash = StringInternal.sha3(s)
|
||||||
|
function sha256(s : string) : hash = StringInternal.sha256(s)
|
||||||
|
function blake2b(s : string) : hash = StringInternal.blake2b(s)
|
||||||
|
|
||||||
|
function length(s : string) : int = StringInternal.length(s)
|
||||||
|
function concat(s1 : string, s2 : string) : string = StringInternal.concat(s1, s2)
|
||||||
|
|
||||||
|
function from_list(cs : list(char)) : string = StringInternal.from_list(cs)
|
||||||
|
function to_list(s : string) : list(char) = StringInternal.to_list(s)
|
||||||
|
|
||||||
|
function split(i : int, s : string) : string * string =
|
||||||
|
let cs = StringInternal.to_list(s)
|
||||||
|
(StringInternal.from_list(List.take(i, cs)), StringInternal.from_list(List.drop(i, cs)))
|
||||||
|
|
||||||
|
function at(ix : int, s : string) =
|
||||||
|
switch(List.drop(ix - 1, StringInternal.to_list(s)))
|
||||||
|
[] => None
|
||||||
|
x :: _ => Some(x)
|
||||||
|
|
||||||
|
function tokens(s : string, pat : string) =
|
||||||
|
let pat_len = StringInternal.length(pat)
|
||||||
|
tokens_(StringInternal.to_list(pat), StringInternal.to_list(s), [])
|
||||||
|
|
||||||
|
function to_upper(s : string) =
|
||||||
|
StringInternal.from_list([ Char.to_upper(c) | c <- StringInternal.to_list(s) ])
|
||||||
|
|
||||||
|
function to_lower(s : string) =
|
||||||
|
StringInternal.from_list([ Char.to_lower(c) | c <- StringInternal.to_list(s) ])
|
||||||
|
|
||||||
|
function contains(str : string, substr : string) : option(int) =
|
||||||
|
let last_ix = StringInternal.length(str) - (StringInternal.length(substr) - 1)
|
||||||
|
contains_(1, last_ix, StringInternal.to_list(str), StringInternal.to_list(substr))
|
||||||
|
|
||||||
|
function
|
||||||
|
to_int : (string, int) => option(int)
|
||||||
|
to_int(s, 10) = to_int_(List.reverse(StringInternal.to_list(s)), ch_to_int_10, 0, 1, 10)
|
||||||
|
to_int(s, 16) = to_int_(List.reverse(StringInternal.to_list(s)), ch_to_int_16, 0, 1, 16)
|
||||||
|
|
||||||
|
function
|
||||||
|
tokens_(_, [], acc) = [StringInternal.from_list(List.reverse(acc))]
|
||||||
|
tokens_(pat, str, acc) =
|
||||||
|
switch(is_prefix(pat, str))
|
||||||
|
Some(str') =>
|
||||||
|
StringInternal.from_list(List.reverse(acc)) :: tokens_(pat, str', [])
|
||||||
|
None =>
|
||||||
|
let c :: cs = str
|
||||||
|
tokens_(pat, cs, c :: acc)
|
||||||
|
|
||||||
|
function contains_(ix, lix, str, substr) =
|
||||||
|
if(ix > lix) None
|
||||||
|
else
|
||||||
|
switch(is_prefix(substr, str))
|
||||||
|
None =>
|
||||||
|
let _ :: str = str
|
||||||
|
contains_(ix + 1, lix, str, substr)
|
||||||
|
Some(_) =>
|
||||||
|
Some(ix)
|
||||||
|
|
||||||
|
function
|
||||||
|
is_prefix([], ys) = Some(ys)
|
||||||
|
is_prefix(_, []) = None
|
||||||
|
is_prefix(x :: xs, y :: ys) =
|
||||||
|
if(x == y) is_prefix(xs, ys)
|
||||||
|
else None
|
||||||
|
|
||||||
|
function
|
||||||
|
to_int_([], _, x, _, _) = Some(x)
|
||||||
|
to_int_(i :: is, c, x, t, f) =
|
||||||
|
switch(c(i))
|
||||||
|
None => None
|
||||||
|
Some(i) => to_int_(is, c, x + t * i, t * f, f)
|
||||||
|
|
||||||
|
function ch_to_int_10(c) =
|
||||||
|
let c = Char.to_int(c)
|
||||||
|
if(c >= 48 && c =< 57) Some(c - 48)
|
||||||
|
else None
|
||||||
|
|
||||||
|
function ch_to_int_16(c) =
|
||||||
|
let c = Char.to_int(c)
|
||||||
|
if(c >= 48 && c =< 57) Some(c - 48)
|
||||||
|
elif(c >= 65 && c =< 70) Some(c - 55)
|
||||||
|
elif(c >= 97 && c =< 102) Some(c - 87)
|
||||||
|
else None
|
||||||
|
|
@ -364,6 +364,7 @@ is_private(Ann) -> proplists:get_value(private, Ann, false).
|
|||||||
global_env() ->
|
global_env() ->
|
||||||
Ann = [{origin, system}],
|
Ann = [{origin, system}],
|
||||||
Int = {id, Ann, "int"},
|
Int = {id, Ann, "int"},
|
||||||
|
Char = {id, Ann, "char"},
|
||||||
Bool = {id, Ann, "bool"},
|
Bool = {id, Ann, "bool"},
|
||||||
String = {id, Ann, "string"},
|
String = {id, Ann, "string"},
|
||||||
Address = {id, Ann, "address"},
|
Address = {id, Ann, "address"},
|
||||||
@ -586,11 +587,21 @@ global_env() ->
|
|||||||
%% Strings
|
%% Strings
|
||||||
StringScope = #scope
|
StringScope = #scope
|
||||||
{ funs = MkDefs(
|
{ funs = MkDefs(
|
||||||
[{"length", Fun1(String, Int)},
|
[{"length", Fun1(String, Int)},
|
||||||
{"concat", Fun([String, String], String)},
|
{"concat", Fun([String, String], String)},
|
||||||
{"sha3", Fun1(String, Hash)},
|
{"to_list", Fun1(String, List(Char))},
|
||||||
{"sha256", Fun1(String, Hash)},
|
{"from_list", Fun1(List(Char), String)},
|
||||||
{"blake2b", Fun1(String, Hash)}]) },
|
{"sha3", Fun1(String, Hash)},
|
||||||
|
{"sha256", Fun1(String, Hash)},
|
||||||
|
{"blake2b", Fun1(String, Hash)}]) },
|
||||||
|
|
||||||
|
%% Chars
|
||||||
|
CharScope = #scope
|
||||||
|
{ funs = MkDefs(
|
||||||
|
[{"to_int", Fun1(Char, Int)},
|
||||||
|
{"from_int", Fun1(Int, Option(Char))},
|
||||||
|
{"to_upper", Fun1(Char, Char)},
|
||||||
|
{"to_lower", Fun1(Char, Char)}]) },
|
||||||
|
|
||||||
%% Bits
|
%% Bits
|
||||||
BitsScope = #scope
|
BitsScope = #scope
|
||||||
@ -634,7 +645,8 @@ global_env() ->
|
|||||||
, ["Auth"] => AuthScope
|
, ["Auth"] => AuthScope
|
||||||
, ["Crypto"] => CryptoScope
|
, ["Crypto"] => CryptoScope
|
||||||
, ["MCL_BLS12_381"] => MCL_BLS12_381_Scope
|
, ["MCL_BLS12_381"] => MCL_BLS12_381_Scope
|
||||||
, ["String"] => StringScope
|
, ["StringInternal"] => StringScope
|
||||||
|
, ["Char"] => CharScope
|
||||||
, ["Bits"] => BitsScope
|
, ["Bits"] => BitsScope
|
||||||
, ["Bytes"] => BytesScope
|
, ["Bytes"] => BytesScope
|
||||||
, ["Int"] => IntScope
|
, ["Int"] => IntScope
|
||||||
|
@ -246,8 +246,10 @@ builtins() ->
|
|||||||
{"gt_inv", 1}, {"gt_add", 2}, {"gt_mul", 2}, {"gt_pow", 2}, {"gt_is_one", 1},
|
{"gt_inv", 1}, {"gt_add", 2}, {"gt_mul", 2}, {"gt_pow", 2}, {"gt_is_one", 1},
|
||||||
{"pairing", 2}, {"miller_loop", 2}, {"final_exp", 1},
|
{"pairing", 2}, {"miller_loop", 2}, {"final_exp", 1},
|
||||||
{"int_to_fr", 1}, {"int_to_fp", 1}, {"fr_to_int", 1}, {"fp_to_int", 1}]},
|
{"int_to_fr", 1}, {"int_to_fp", 1}, {"fr_to_int", 1}, {"fp_to_int", 1}]},
|
||||||
|
{["StringInternal"], [{"length", 1}, {"concat", 2}, {"to_list", 1}, {"from_list", 1},
|
||||||
|
{"sha3", 1}, {"sha256", 1}, {"blake2b", 1}]},
|
||||||
|
{["Char"], [{"to_int", 1}, {"from_int", 1}, {"to_lower", 1}, {"to_upper", 1}]},
|
||||||
{["Auth"], [{"tx_hash", none}, {"tx", none}]},
|
{["Auth"], [{"tx_hash", none}, {"tx", none}]},
|
||||||
{["String"], [{"length", 1}, {"concat", 2}, {"sha3", 1}, {"sha256", 1}, {"blake2b", 1}]},
|
|
||||||
{["Bits"], [{"set", 2}, {"clear", 2}, {"test", 2}, {"sum", 1}, {"intersection", 2},
|
{["Bits"], [{"set", 2}, {"clear", 2}, {"test", 2}, {"sum", 1}, {"intersection", 2},
|
||||||
{"union", 2}, {"difference", 2}, {"none", none}, {"all", none}]},
|
{"union", 2}, {"difference", 2}, {"none", none}, {"all", none}]},
|
||||||
{["Bytes"], [{"to_int", 1}, {"to_str", 1}, {"concat", 2}, {"split", 1}]},
|
{["Bytes"], [{"to_int", 1}, {"to_str", 1}, {"concat", 2}, {"split", 1}]},
|
||||||
@ -1040,7 +1042,9 @@ stmts_to_fcode(Env, [Expr | Stmts]) ->
|
|||||||
|
|
||||||
op_builtins() ->
|
op_builtins() ->
|
||||||
[map_from_list, map_to_list, map_delete, map_member, map_size,
|
[map_from_list, map_to_list, map_delete, map_member, map_size,
|
||||||
string_length, string_concat, string_sha3, string_sha256, string_blake2b,
|
stringinternal_length, stringinternal_concat, stringinternal_to_list, stringinternal_from_list,
|
||||||
|
stringinternal_sha3, stringinternal_sha256, stringinternal_blake2b,
|
||||||
|
char_to_int, char_from_int, char_to_lower, char_to_upper,
|
||||||
bits_set, bits_clear, bits_test, bits_sum, bits_intersection, bits_union,
|
bits_set, bits_clear, bits_test, bits_sum, bits_intersection, bits_union,
|
||||||
bits_difference, int_to_str, address_to_str, crypto_verify_sig,
|
bits_difference, int_to_str, address_to_str, crypto_verify_sig,
|
||||||
address_to_contract,
|
address_to_contract,
|
||||||
|
@ -573,8 +573,14 @@ op_to_scode(map_to_list) -> aeb_fate_ops:map_to_list(?a, ?a);
|
|||||||
op_to_scode(map_delete) -> aeb_fate_ops:map_delete(?a, ?a, ?a);
|
op_to_scode(map_delete) -> aeb_fate_ops:map_delete(?a, ?a, ?a);
|
||||||
op_to_scode(map_member) -> aeb_fate_ops:map_member(?a, ?a, ?a);
|
op_to_scode(map_member) -> aeb_fate_ops:map_member(?a, ?a, ?a);
|
||||||
op_to_scode(map_size) -> aeb_fate_ops:map_size_(?a, ?a);
|
op_to_scode(map_size) -> aeb_fate_ops:map_size_(?a, ?a);
|
||||||
op_to_scode(string_length) -> aeb_fate_ops:str_length(?a, ?a);
|
op_to_scode(stringinternal_length) -> aeb_fate_ops:str_length(?a, ?a);
|
||||||
op_to_scode(string_concat) -> aeb_fate_ops:str_join(?a, ?a, ?a);
|
op_to_scode(stringinternal_concat) -> aeb_fate_ops:str_join(?a, ?a, ?a);
|
||||||
|
op_to_scode(stringinternal_to_list) -> aeb_fate_ops:str_to_list(?a, ?a);
|
||||||
|
op_to_scode(stringinternal_from_list) -> aeb_fate_ops:str_from_list(?a, ?a);
|
||||||
|
op_to_scode(char_to_int) -> aeb_fate_ops:char_to_int(?a, ?a);
|
||||||
|
op_to_scode(char_from_int) -> aeb_fate_ops:char_from_int(?a, ?a);
|
||||||
|
op_to_scode(char_to_lower) -> aeb_fate_ops:char_to_lower(?a, ?a);
|
||||||
|
op_to_scode(char_to_upper) -> aeb_fate_ops:char_to_upper(?a, ?a);
|
||||||
op_to_scode(bits_set) -> aeb_fate_ops:bits_set(?a, ?a, ?a);
|
op_to_scode(bits_set) -> aeb_fate_ops:bits_set(?a, ?a, ?a);
|
||||||
op_to_scode(bits_clear) -> aeb_fate_ops:bits_clear(?a, ?a, ?a);
|
op_to_scode(bits_clear) -> aeb_fate_ops:bits_clear(?a, ?a, ?a);
|
||||||
op_to_scode(bits_test) -> aeb_fate_ops:bits_test(?a, ?a, ?a);
|
op_to_scode(bits_test) -> aeb_fate_ops:bits_test(?a, ?a, ?a);
|
||||||
@ -593,9 +599,9 @@ op_to_scode(crypto_ecrecover_secp256k1) -> aeb_fate_ops:ecrecover_secp256k1(?a,
|
|||||||
op_to_scode(crypto_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
op_to_scode(crypto_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
||||||
op_to_scode(crypto_sha256) -> aeb_fate_ops:sha256(?a, ?a);
|
op_to_scode(crypto_sha256) -> aeb_fate_ops:sha256(?a, ?a);
|
||||||
op_to_scode(crypto_blake2b) -> aeb_fate_ops:blake2b(?a, ?a);
|
op_to_scode(crypto_blake2b) -> aeb_fate_ops:blake2b(?a, ?a);
|
||||||
op_to_scode(string_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
op_to_scode(stringinternal_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
||||||
op_to_scode(string_sha256) -> aeb_fate_ops:sha256(?a, ?a);
|
op_to_scode(stringinternal_sha256) -> aeb_fate_ops:sha256(?a, ?a);
|
||||||
op_to_scode(string_blake2b) -> aeb_fate_ops:blake2b(?a, ?a);
|
op_to_scode(stringinternal_blake2b) -> aeb_fate_ops:blake2b(?a, ?a);
|
||||||
op_to_scode(mcl_bls12_381_g1_neg) -> aeb_fate_ops:bls12_381_g1_neg(?a, ?a);
|
op_to_scode(mcl_bls12_381_g1_neg) -> aeb_fate_ops:bls12_381_g1_neg(?a, ?a);
|
||||||
op_to_scode(mcl_bls12_381_g1_norm) -> aeb_fate_ops:bls12_381_g1_norm(?a, ?a);
|
op_to_scode(mcl_bls12_381_g1_norm) -> aeb_fate_ops:bls12_381_g1_norm(?a, ?a);
|
||||||
op_to_scode(mcl_bls12_381_g1_valid) -> aeb_fate_ops:bls12_381_g1_valid(?a, ?a);
|
op_to_scode(mcl_bls12_381_g1_valid) -> aeb_fate_ops:bls12_381_g1_valid(?a, ?a);
|
||||||
@ -919,6 +925,12 @@ attributes(I) ->
|
|||||||
{'BLS12_381_INT_TO_FP', A, B} -> Pure(A, [B]);
|
{'BLS12_381_INT_TO_FP', A, B} -> Pure(A, [B]);
|
||||||
{'BLS12_381_FR_TO_INT', A, B} -> Pure(A, [B]);
|
{'BLS12_381_FR_TO_INT', A, B} -> Pure(A, [B]);
|
||||||
{'BLS12_381_FP_TO_INT', A, B} -> Pure(A, [B]);
|
{'BLS12_381_FP_TO_INT', A, B} -> Pure(A, [B]);
|
||||||
|
{'STRING_TO_LIST', A, B} -> Pure(A, [B]);
|
||||||
|
{'STRING_FROM_LIST', A, B} -> Pure(A, [B]);
|
||||||
|
{'CHAR_TO_INT', A, B} -> Pure(A, [B]);
|
||||||
|
{'CHAR_FROM_INT', A, B} -> Pure(A, [B]);
|
||||||
|
{'CHAR_TO_UPPER', A, B} -> Pure(A, [B]);
|
||||||
|
{'CHAR_TO_LOWER', A, B} -> Pure(A, [B]);
|
||||||
{'ABORT', A} -> Impure(pc, A);
|
{'ABORT', A} -> Impure(pc, A);
|
||||||
{'EXIT', A} -> Impure(pc, A);
|
{'EXIT', A} -> Impure(pc, A);
|
||||||
'NOP' -> Pure(none, [])
|
'NOP' -> Pure(none, [])
|
||||||
|
@ -142,4 +142,4 @@ compilable_contracts() ->
|
|||||||
not_yet_compilable(fate) ->
|
not_yet_compilable(fate) ->
|
||||||
[];
|
[];
|
||||||
not_yet_compilable(aevm) ->
|
not_yet_compilable(aevm) ->
|
||||||
[].
|
["funargs", "strings"].
|
||||||
|
@ -168,11 +168,13 @@ compilable_contracts() ->
|
|||||||
"pairing_crypto",
|
"pairing_crypto",
|
||||||
"qualified_constructor",
|
"qualified_constructor",
|
||||||
"let_patterns",
|
"let_patterns",
|
||||||
"lhs_matching"
|
"lhs_matching",
|
||||||
|
"more_strings"
|
||||||
].
|
].
|
||||||
|
|
||||||
not_yet_compilable(fate) -> [];
|
not_yet_compilable(fate) -> [];
|
||||||
not_yet_compilable(aevm) -> ["pairing_crypto", "aens_update", "basic_auth_tx"].
|
not_yet_compilable(aevm) -> ["pairing_crypto", "aens_update", "basic_auth_tx", "more_strings",
|
||||||
|
"unapplied_builtins", "bytes_to_x", "state_handling"].
|
||||||
|
|
||||||
%% Contracts that should produce type errors
|
%% Contracts that should produce type errors
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
|
include "String.aes"
|
||||||
contract BytesToX =
|
contract BytesToX =
|
||||||
|
|
||||||
entrypoint to_int(b : bytes(42)) : int = Bytes.to_int(b)
|
entrypoint to_int(b : bytes(42)) : int = Bytes.to_int(b)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
|
include "String.aes"
|
||||||
contract FunctionArguments =
|
contract FunctionArguments =
|
||||||
|
|
||||||
entrypoint sum(n : int, m: int) =
|
entrypoint sum(n : int, m: int) =
|
||||||
|
14
test/contracts/more_strings.aes
Normal file
14
test/contracts/more_strings.aes
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
include "String.aes"
|
||||||
|
contract StringX =
|
||||||
|
entrypoint test() =
|
||||||
|
let s1 = "a string"
|
||||||
|
let s2 = "another string"
|
||||||
|
let s = String.concat(s1, s2)
|
||||||
|
String.sha256(s)
|
||||||
|
String.length(s1)
|
||||||
|
String.from_list(String.to_list(s))
|
||||||
|
String.split(4, s1)
|
||||||
|
String.at(2, s2)
|
||||||
|
String.tokens(s, ",")
|
||||||
|
String.to_upper(s1)
|
||||||
|
String.to_lower(s2)
|
@ -1,3 +1,4 @@
|
|||||||
|
include "String.aes"
|
||||||
contract Remote =
|
contract Remote =
|
||||||
record rstate = { i : int, s : string, m : map(int, int) }
|
record rstate = { i : int, s : string, m : map(int, int) }
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
include "String.aes"
|
||||||
contract Strings =
|
contract Strings =
|
||||||
entrypoint str_len(s) = String.length(s)
|
entrypoint str_len(s) = String.length(s)
|
||||||
entrypoint str_concat(s1, s2) = String.concat(s1, s2)
|
entrypoint str_concat(s1, s2) = String.concat(s1, s2)
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
// AENS.transfer
|
// AENS.transfer
|
||||||
// AENS.revoke
|
// AENS.revoke
|
||||||
// Oracle.extend
|
// Oracle.extend
|
||||||
|
include "String.aes"
|
||||||
contract UnappliedBuiltins =
|
contract UnappliedBuiltins =
|
||||||
entrypoint main() = ()
|
entrypoint main() = ()
|
||||||
type o = oracle(int, int)
|
type o = oracle(int, int)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user