Disallow the empty string for some string fns.

This will prevent these functions from being run
with empty strings, which usually produces useless
output, as the internal string search algorithm will
never "find" empty strings. This is by design, as it is
not always obvious which empty strings should be found in
the search text.
This commit is contained in:
Calvin Rose 2019-09-24 13:23:18 -05:00
parent 45dfc7cc96
commit b26a7bb22a
3 changed files with 19 additions and 9 deletions

View File

@ -2,6 +2,8 @@
All notable changes to this project will be documented in this file.
## Unreleased
- `string/` functions that take a pattern to search for will throw an error
when receiving the empty string.
- Replace (start:end) style stacktrace source position information with
line, column. This should be more readable for humans. Also, range information
can be recovered by re-parsing source.

View File

@ -108,6 +108,9 @@ static void kmp_init(
if (!lookup) {
JANET_OUT_OF_MEMORY;
}
if (patlen == 0) {
janet_panic("expected non-empty pattern");
}
s->lookup = lookup;
s->i = 0;
s->j = 0;
@ -378,15 +381,13 @@ static Janet cfun_string_split(int32_t argc, Janet *argv) {
}
findsetup(argc, argv, &state, 1);
array = janet_array(0);
while ((result = kmp_next(&state)) >= 0 && limit--) {
while ((result = kmp_next(&state)) >= 0 && --limit) {
const uint8_t *slice = janet_string(state.text + lastindex, result - lastindex);
janet_array_push(array, janet_wrap_string(slice));
lastindex = result + state.patlen;
}
{
const uint8_t *slice = janet_string(state.text + lastindex, state.textlen - lastindex);
janet_array_push(array, janet_wrap_string(slice));
}
const uint8_t *slice = janet_string(state.text + lastindex, state.textlen - lastindex);
janet_array_push(array, janet_wrap_string(slice));
kmp_deinit(&state);
return janet_wrap_array(array);
}
@ -600,10 +601,12 @@ static const JanetReg string_cfuns[] = {
},
{
"string/split", cfun_string_split,
JDOC("(string/split delim str)\n\n"
JDOC("(string/split delim str &opt start limit)\n\n"
"Splits a string str with delimiter delim and returns an array of "
"substrings. The substrings will not contain the delimiter delim. If delim "
"is not found, the returned array will have one element.")
"is not found, the returned array will have one element. Will start searching "
"for delim at the index start (if provided), and return up to a maximum "
"of limit results (if provided).")
},
{
"string/check-set", cfun_string_checkset,

View File

@ -62,8 +62,7 @@
# String functions
(assert (= 3 (string/find "abc" " abcdefghijklmnop")) "string/find 1")
(assert (= nil (string/find "" "")) "string/find 2")
(assert (= 0 (string/find "A" "A")) "string/find 3")
(assert (= 0 (string/find "A" "A")) "string/find 2")
(assert (string/has-prefix? "" "foo") "string/has-prefix? 1")
(assert (string/has-prefix? "fo" "foo") "string/has-prefix? 2")
(assert (not (string/has-prefix? "o" "foo")) "string/has-prefix? 3")
@ -98,6 +97,12 @@
(assert (deep= (string/find-all "e" "onetwothree") @[2 9 10]) "string/find-all 1")
(assert (deep= (string/find-all "," "onetwothree") @[]) "string/find-all 2")
(assert-error "string/find error 1" (string/find "" "abcd"))
(assert-error "string/split error 1" (string/split "" "abcd"))
(assert-error "string/replace error 1" (string/replace "" "." "abcd"))
(assert-error "string/replace-all error 1" (string/replace-all "" "." "abcdabcd"))
(assert-error "string/find-all error 1" (string/find-all "" "abcd"))
# Check if abstract test works
(assert (abstract? stdout) "abstract? stdout")
(assert (abstract? stdin) "abstract? stdin")