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() ->
|
||||
Ann = [{origin, system}],
|
||||
Int = {id, Ann, "int"},
|
||||
Char = {id, Ann, "char"},
|
||||
Bool = {id, Ann, "bool"},
|
||||
String = {id, Ann, "string"},
|
||||
Address = {id, Ann, "address"},
|
||||
@ -588,10 +589,20 @@ global_env() ->
|
||||
{ funs = MkDefs(
|
||||
[{"length", Fun1(String, Int)},
|
||||
{"concat", Fun([String, String], String)},
|
||||
{"to_list", Fun1(String, List(Char))},
|
||||
{"from_list", Fun1(List(Char), String)},
|
||||
{"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
|
||||
BitsScope = #scope
|
||||
{ funs = MkDefs(
|
||||
@ -634,7 +645,8 @@ global_env() ->
|
||||
, ["Auth"] => AuthScope
|
||||
, ["Crypto"] => CryptoScope
|
||||
, ["MCL_BLS12_381"] => MCL_BLS12_381_Scope
|
||||
, ["String"] => StringScope
|
||||
, ["StringInternal"] => StringScope
|
||||
, ["Char"] => CharScope
|
||||
, ["Bits"] => BitsScope
|
||||
, ["Bytes"] => BytesScope
|
||||
, ["Int"] => IntScope
|
||||
|
@ -246,8 +246,10 @@ builtins() ->
|
||||
{"gt_inv", 1}, {"gt_add", 2}, {"gt_mul", 2}, {"gt_pow", 2}, {"gt_is_one", 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}]},
|
||||
{["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}]},
|
||||
{["String"], [{"length", 1}, {"concat", 2}, {"sha3", 1}, {"sha256", 1}, {"blake2b", 1}]},
|
||||
{["Bits"], [{"set", 2}, {"clear", 2}, {"test", 2}, {"sum", 1}, {"intersection", 2},
|
||||
{"union", 2}, {"difference", 2}, {"none", none}, {"all", none}]},
|
||||
{["Bytes"], [{"to_int", 1}, {"to_str", 1}, {"concat", 2}, {"split", 1}]},
|
||||
@ -1040,7 +1042,9 @@ stmts_to_fcode(Env, [Expr | Stmts]) ->
|
||||
|
||||
op_builtins() ->
|
||||
[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_difference, int_to_str, address_to_str, crypto_verify_sig,
|
||||
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_member) -> aeb_fate_ops:map_member(?a, ?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(string_concat) -> aeb_fate_ops:str_join(?a, ?a, ?a);
|
||||
op_to_scode(stringinternal_length) -> aeb_fate_ops:str_length(?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_clear) -> aeb_fate_ops:bits_clear(?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_sha256) -> aeb_fate_ops:sha256(?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(string_sha256) -> aeb_fate_ops:sha256(?a, ?a);
|
||||
op_to_scode(string_blake2b) -> aeb_fate_ops:blake2b(?a, ?a);
|
||||
op_to_scode(stringinternal_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
||||
op_to_scode(stringinternal_sha256) -> aeb_fate_ops:sha256(?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_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);
|
||||
@ -919,6 +925,12 @@ attributes(I) ->
|
||||
{'BLS12_381_INT_TO_FP', 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]);
|
||||
{'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);
|
||||
{'EXIT', A} -> Impure(pc, A);
|
||||
'NOP' -> Pure(none, [])
|
||||
|
@ -142,4 +142,4 @@ compilable_contracts() ->
|
||||
not_yet_compilable(fate) ->
|
||||
[];
|
||||
not_yet_compilable(aevm) ->
|
||||
[].
|
||||
["funargs", "strings"].
|
||||
|
@ -168,11 +168,13 @@ compilable_contracts() ->
|
||||
"pairing_crypto",
|
||||
"qualified_constructor",
|
||||
"let_patterns",
|
||||
"lhs_matching"
|
||||
"lhs_matching",
|
||||
"more_strings"
|
||||
].
|
||||
|
||||
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
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
|
||||
include "String.aes"
|
||||
contract BytesToX =
|
||||
|
||||
entrypoint to_int(b : bytes(42)) : int = Bytes.to_int(b)
|
||||
|
@ -1,4 +1,4 @@
|
||||
|
||||
include "String.aes"
|
||||
contract FunctionArguments =
|
||||
|
||||
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 =
|
||||
record rstate = { i : int, s : string, m : map(int, int) }
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
include "String.aes"
|
||||
contract Strings =
|
||||
entrypoint str_len(s) = String.length(s)
|
||||
entrypoint str_concat(s1, s2) = String.concat(s1, s2)
|
||||
|
@ -7,6 +7,7 @@
|
||||
// AENS.transfer
|
||||
// AENS.revoke
|
||||
// Oracle.extend
|
||||
include "String.aes"
|
||||
contract UnappliedBuiltins =
|
||||
entrypoint main() = ()
|
||||
type o = oracle(int, int)
|
||||
|
Loading…
x
Reference in New Issue
Block a user