refactor(eval.c): factor out get_number_tv() (#21893)

It was refactored into a separate function in Vim in patch 8.2.0149.
This commit is contained in:
zeertzjq
2023-01-19 13:27:36 +08:00
committed by GitHub
parent 42e9a09a44
commit 93adf74a03

View File

@@ -2887,12 +2887,7 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string)
/// @return OK or FAIL. /// @return OK or FAIL.
static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
{ {
varnumber_T n;
int len;
char *s;
const char *start_leader, *end_leader;
int ret = OK; int ret = OK;
char *alias;
static int recurse = 0; static int recurse = 0;
// Initialise variable so that tv_clear() can't mistake this for a // Initialise variable so that tv_clear() can't mistake this for a
@@ -2900,11 +2895,11 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
rettv->v_type = VAR_UNKNOWN; rettv->v_type = VAR_UNKNOWN;
// Skip '!', '-' and '+' characters. They are handled later. // Skip '!', '-' and '+' characters. They are handled later.
start_leader = *arg; const char *start_leader = *arg;
while (**arg == '!' || **arg == '-' || **arg == '+') { while (**arg == '!' || **arg == '-' || **arg == '+') {
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
} }
end_leader = *arg; const char *end_leader = *arg;
// Limit recursion to 1000 levels. At least at 10000 we run out of stack // Limit recursion to 1000 levels. At least at 10000 we run out of stack
// and crash. With MSVC the stack is smaller. // and crash. With MSVC the stack is smaller.
@@ -2931,88 +2926,9 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
case '6': case '6':
case '7': case '7':
case '8': case '8':
case '9': { case '9':
char *p = skipdigits(*arg + 1); ret = get_number_tv(arg, rettv, evaluate, want_string);
int get_float = false;
// We accept a float when the format matches
// "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very
// strict to avoid backwards compatibility problems.
// Don't look for a float after the "." operator, so that
// ":let vers = 1.2.3" doesn't fail.
if (!want_string && p[0] == '.' && ascii_isdigit(p[1])) {
get_float = true;
p = skipdigits(p + 2);
if (*p == 'e' || *p == 'E') {
p++;
if (*p == '-' || *p == '+') {
p++;
}
if (!ascii_isdigit(*p)) {
get_float = false;
} else {
p = skipdigits(p + 1);
}
}
if (ASCII_ISALPHA(*p) || *p == '.') {
get_float = false;
}
}
if (get_float) {
float_T f;
*arg += string2float(*arg, &f);
if (evaluate) {
rettv->v_type = VAR_FLOAT;
rettv->vval.v_float = f;
}
} else if (**arg == '0' && ((*arg)[1] == 'z' || (*arg)[1] == 'Z')) {
blob_T *blob = NULL;
// Blob constant: 0z0123456789abcdef
if (evaluate) {
blob = tv_blob_alloc();
}
char *bp;
for (bp = *arg + 2; ascii_isxdigit(bp[0]); bp += 2) {
if (!ascii_isxdigit(bp[1])) {
if (blob != NULL) {
emsg(_("E973: Blob literal should have an even number of hex "
"characters"));
ga_clear(&blob->bv_ga);
XFREE_CLEAR(blob);
}
ret = FAIL;
break;
}
if (blob != NULL) {
ga_append(&blob->bv_ga, (char)((hex2nr(*bp) << 4) + hex2nr(*(bp + 1))));
}
if (bp[2] == '.' && ascii_isxdigit(bp[3])) {
bp++;
}
}
if (blob != NULL) {
tv_blob_set_ret(rettv, blob);
}
*arg = bp;
} else {
// decimal, hex or octal number
vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0, true);
if (len == 0) {
if (evaluate) {
semsg(_(e_invexpr2), *arg);
}
ret = FAIL;
break;
}
*arg += len;
if (evaluate) {
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = n;
}
}
break; break;
}
// String constant: "string". // String constant: "string".
case '"': case '"':
@@ -3090,8 +3006,9 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
if (ret == NOTDONE) { if (ret == NOTDONE) {
// Must be a variable or function name. // Must be a variable or function name.
// Can also be a curly-braces kind of name: {expr}. // Can also be a curly-braces kind of name: {expr}.
s = *arg; char *s = *arg;
len = get_name_len((const char **)arg, &alias, evaluate, true); char *alias;
int len = get_name_len((const char **)arg, &alias, evaluate, true);
if (alias != NULL) { if (alias != NULL) {
s = alias; s = alias;
} }
@@ -3716,6 +3633,91 @@ int get_option_tv(const char **const arg, typval_T *const rettv, const bool eval
return ret; return ret;
} }
/// Allocate a variable for a number constant. Also deals with "0z" for blob.
///
/// @return OK or FAIL.
static int get_number_tv(char **arg, typval_T *rettv, bool evaluate, bool want_string)
{
char *p = skipdigits(*arg + 1);
bool get_float = false;
// We accept a float when the format matches
// "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very
// strict to avoid backwards compatibility problems.
// Don't look for a float after the "." operator, so that
// ":let vers = 1.2.3" doesn't fail.
if (!want_string && p[0] == '.' && ascii_isdigit(p[1])) {
get_float = true;
p = skipdigits(p + 2);
if (*p == 'e' || *p == 'E') {
p++;
if (*p == '-' || *p == '+') {
p++;
}
if (!ascii_isdigit(*p)) {
get_float = false;
} else {
p = skipdigits(p + 1);
}
}
if (ASCII_ISALPHA(*p) || *p == '.') {
get_float = false;
}
}
if (get_float) {
float_T f;
*arg += string2float(*arg, &f);
if (evaluate) {
rettv->v_type = VAR_FLOAT;
rettv->vval.v_float = f;
}
} else if (**arg == '0' && ((*arg)[1] == 'z' || (*arg)[1] == 'Z')) {
// Blob constant: 0z0123456789abcdef
blob_T *blob = NULL;
if (evaluate) {
blob = tv_blob_alloc();
}
char *bp;
for (bp = *arg + 2; ascii_isxdigit(bp[0]); bp += 2) {
if (!ascii_isxdigit(bp[1])) {
if (blob != NULL) {
emsg(_("E973: Blob literal should have an even number of hex characters"));
ga_clear(&blob->bv_ga);
XFREE_CLEAR(blob);
}
return FAIL;
}
if (blob != NULL) {
ga_append(&blob->bv_ga, (char)((hex2nr(*bp) << 4) + hex2nr(*(bp + 1))));
}
if (bp[2] == '.' && ascii_isxdigit(bp[3])) {
bp++;
}
}
if (blob != NULL) {
tv_blob_set_ret(rettv, blob);
}
*arg = bp;
} else {
// decimal, hex or octal number
int len;
varnumber_T n;
vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0, true);
if (len == 0) {
if (evaluate) {
semsg(_(e_invexpr2), *arg);
}
return FAIL;
}
*arg += len;
if (evaluate) {
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = n;
}
}
return OK;
}
/// Allocate a variable for a string constant. /// Allocate a variable for a string constant.
/// ///
/// @return OK or FAIL. /// @return OK or FAIL.