Implement some string manipulation functions
This commit is contained in:
parent
1634b9439b
commit
2e7fefc7f7
5 changed files with 143 additions and 0 deletions
|
|
@ -112,6 +112,7 @@ functionaltest("compare")
|
|||
functionaltest("concat")
|
||||
functionaltest("join")
|
||||
functionaltest("quine")
|
||||
functionaltest("string-manip")
|
||||
|
||||
install(TARGETS apfl DESTINATION lib)
|
||||
install(TARGETS apfl-bin DESTINATION bin)
|
||||
|
|
|
|||
|
|
@ -576,6 +576,35 @@ set_func_name(apfl_ctx ctx)
|
|||
apfl_set_func_name(ctx, -2, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
substring(apfl_ctx ctx)
|
||||
{
|
||||
apfl_get_list_member_by_index(ctx, 0, 0);
|
||||
struct apfl_string_view sv = apfl_get_string(ctx, -1);
|
||||
apfl_get_list_member_by_index(ctx, 0, 1);
|
||||
apfl_number start = apfl_get_number(ctx, -1);
|
||||
apfl_get_list_member_by_index(ctx, 0, 2);
|
||||
apfl_number len = apfl_get_number(ctx, -1);
|
||||
|
||||
apfl_push_string_view_copy(ctx, apfl_string_view_substr(sv, (size_t)start, (size_t)len));
|
||||
}
|
||||
|
||||
static void
|
||||
stringsearch(apfl_ctx ctx)
|
||||
{
|
||||
apfl_get_list_member_by_index(ctx, 0, 0);
|
||||
struct apfl_string_view haystack = apfl_get_string(ctx, -1);
|
||||
apfl_get_list_member_by_index(ctx, 0, 1);
|
||||
struct apfl_string_view needle = apfl_get_string(ctx, -1);
|
||||
|
||||
ptrdiff_t off = apfl_string_view_search(haystack, needle);
|
||||
if (off < 0) {
|
||||
apfl_push_nil(ctx);
|
||||
} else {
|
||||
apfl_push_number(ctx, (apfl_number)off);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
iterate_dict_callback(apfl_ctx ctx, void *opaque)
|
||||
{
|
||||
|
|
@ -646,5 +675,7 @@ apfl_builtins(apfl_ctx ctx)
|
|||
add_builtin(ctx, "-serialize-bytecode", serialize_bytecode);
|
||||
add_builtin(ctx, "-unserialize-bytecode", unserialize_bytecode);
|
||||
add_builtin(ctx, "set-func-name", set_func_name);
|
||||
add_builtin(ctx, "substring", substring);
|
||||
add_builtin(ctx, "stringsearch", stringsearch);
|
||||
add_builtin(ctx, "iterate-dict", iterate_dict);
|
||||
}
|
||||
|
|
|
|||
42
src/functional-tests/string-manip.at
Normal file
42
src/functional-tests/string-manip.at
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
===== script =====
|
||||
print (substr 0 3 "foobar")
|
||||
print (substr 3 "foobar")
|
||||
print (substr 1 3 "foobar")
|
||||
print (substr -1 "foobar")
|
||||
print (substr 6 "foobar")
|
||||
print (substr 10 "foobar")
|
||||
|
||||
print (strsearch "a" "aaababcabcde")
|
||||
print (strsearch "ab" "aaababcabcde")
|
||||
print (strsearch "x" "aaababcabcde")
|
||||
print (strsearch "ab" 3 "aaababcabcde")
|
||||
|
||||
print (split "::" "foo:bar:::baz::::xxx::::y::z::")
|
||||
print (split "::" 3 "foo:bar:::baz::::xxx::::y::z::")
|
||||
|
||||
===== output =====
|
||||
foo
|
||||
bar
|
||||
oob
|
||||
r
|
||||
|
||||
|
||||
0
|
||||
2
|
||||
nil
|
||||
4
|
||||
[
|
||||
"foo:bar"
|
||||
":baz"
|
||||
""
|
||||
"xxx"
|
||||
""
|
||||
"y"
|
||||
"z"
|
||||
""
|
||||
]
|
||||
[
|
||||
"foo:bar"
|
||||
":baz"
|
||||
"::xxx::::y::z::"
|
||||
]
|
||||
|
|
@ -99,6 +99,65 @@
|
|||
has pred == y
|
||||
}
|
||||
|
||||
identity := { x -> x }
|
||||
|
||||
is := -named 'is (partial has identity)
|
||||
|
||||
-raw-substring := builtins.substring
|
||||
substr := {
|
||||
start s ->
|
||||
substr start (len s) s
|
||||
start?(is < 0) end s ->
|
||||
substr (+ start (len s)) end s
|
||||
start end?(is < 0) s ->
|
||||
substr start (+ end (- (len s) start)) s
|
||||
start end s ->
|
||||
-raw-substring s start end
|
||||
}
|
||||
|
||||
-raw-stringsearch := builtins.stringsearch
|
||||
strsearch := {
|
||||
needle haystack ->
|
||||
-raw-stringsearch haystack needle
|
||||
needle start?(is < 0) haystack ->
|
||||
strsearch needle (+ start (len s)) haystack
|
||||
needle start haystack ->
|
||||
off := (strsearch needle (substr start haystack))
|
||||
if (== off nil) { nil } { + start off }
|
||||
}
|
||||
|
||||
split := ({
|
||||
split-aux := { maxlen-reached sep s ->
|
||||
sep-len := len sep
|
||||
parts := []
|
||||
loop {
|
||||
if (maxlen-reached (+ 1 (len parts))) {
|
||||
parts = [~parts s]
|
||||
false
|
||||
} {
|
||||
off := strsearch sep s
|
||||
if (== nil off) {
|
||||
parts = [~parts s]
|
||||
false
|
||||
} {
|
||||
parts = [~parts (substr 0 off s)]
|
||||
s = substr (+ off sep-len) s
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parts
|
||||
}
|
||||
|
||||
split := {
|
||||
sep s ->
|
||||
split-aux {false} sep s
|
||||
sep maxlen s ->
|
||||
split-aux (is >= maxlen) sep s
|
||||
}
|
||||
})
|
||||
|
||||
keach := {
|
||||
d?(has type 'dict) body ->
|
||||
out := nil
|
||||
|
|
@ -155,9 +214,14 @@
|
|||
'-serialize-bytecode -> -serialize-bytecode
|
||||
'-unserialize-bytecode -> -unserialize-bytecode
|
||||
'& -> &
|
||||
'substr -> substr
|
||||
'strsearch -> strsearch
|
||||
'split -> split
|
||||
'partial -> partial
|
||||
'compose -> compose
|
||||
'has -> has
|
||||
'identity -> identity
|
||||
'is -> is
|
||||
'!= -> !=
|
||||
'!> -> !>
|
||||
'!< -> !<
|
||||
|
|
|
|||
|
|
@ -80,6 +80,11 @@ bool
|
|||
apfl_string_copy(struct apfl_allocator allocator, struct apfl_string *dst, struct apfl_string_view src)
|
||||
{
|
||||
apfl_string_deinit(allocator, dst);
|
||||
|
||||
if (src.len == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((dst->bytes = ALLOC_BYTES(allocator, src.len)) == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue