forked from aniani/vim
patch 8.2.2765: Vim9: not all blob operations work
Problem: Vim9: not all blob operations work. Solution: Run more tests also with Vim9 script and :def functions. Fix what doesn't work.
This commit is contained in:
30
src/blob.c
30
src/blob.c
@@ -336,6 +336,36 @@ blob_slice_or_index(
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if "n1"- is a valid index for a blobl with length "bloblen".
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
check_blob_index(long bloblen, varnumber_T n1, int is_range, int quiet)
|
||||||
|
{
|
||||||
|
if (n1 < 0 || n1 > bloblen)
|
||||||
|
{
|
||||||
|
if (!quiet)
|
||||||
|
semsg(_(e_blobidx), n1);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if "n1"-"n2" is a valid range for a blob with length "bloblen".
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
check_blob_range(long bloblen, varnumber_T n1, varnumber_T n2, int quiet)
|
||||||
|
{
|
||||||
|
if (n2 < 0 || n2 >= bloblen || n2 < n1)
|
||||||
|
{
|
||||||
|
if (!quiet)
|
||||||
|
semsg(_(e_blobidx), n2);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set bytes "n1" to "n2" (inclusive) in "dest" to the value of "src".
|
* Set bytes "n1" to "n2" (inclusive) in "dest" to the value of "src".
|
||||||
* Caller must make sure "src" is a blob.
|
* Caller must make sure "src" is a blob.
|
||||||
|
@@ -401,3 +401,5 @@ EXTERN char e_cannot_use_underscore_here[]
|
|||||||
INIT(= N_("E1181: Cannot use an underscore here"));
|
INIT(= N_("E1181: Cannot use an underscore here"));
|
||||||
EXTERN char e_blob_required[]
|
EXTERN char e_blob_required[]
|
||||||
INIT(= N_("E1182: Blob required"));
|
INIT(= N_("E1182: Blob required"));
|
||||||
|
EXTERN char e_cannot_use_range_with_assignment_operator_str[]
|
||||||
|
INIT(= N_("E1183: Cannot use a range with an assignment operator: %s"));
|
||||||
|
16
src/eval.c
16
src/eval.c
@@ -1175,12 +1175,9 @@ get_lval(
|
|||||||
lp->ll_n1 = (long)tv_get_number(&var1);
|
lp->ll_n1 = (long)tv_get_number(&var1);
|
||||||
clear_tv(&var1);
|
clear_tv(&var1);
|
||||||
|
|
||||||
if (lp->ll_n1 < 0
|
if (check_blob_index(bloblen, lp->ll_n1, lp->ll_range, quiet)
|
||||||
|| lp->ll_n1 > bloblen
|
== FAIL)
|
||||||
|| (lp->ll_range && lp->ll_n1 == bloblen))
|
|
||||||
{
|
{
|
||||||
if (!quiet)
|
|
||||||
semsg(_(e_blobidx), lp->ll_n1);
|
|
||||||
clear_tv(&var2);
|
clear_tv(&var2);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1188,14 +1185,9 @@ get_lval(
|
|||||||
{
|
{
|
||||||
lp->ll_n2 = (long)tv_get_number(&var2);
|
lp->ll_n2 = (long)tv_get_number(&var2);
|
||||||
clear_tv(&var2);
|
clear_tv(&var2);
|
||||||
if (lp->ll_n2 < 0
|
if (check_blob_range(bloblen, lp->ll_n1, lp->ll_n2, quiet)
|
||||||
|| lp->ll_n2 >= bloblen
|
== FAIL)
|
||||||
|| lp->ll_n2 < lp->ll_n1)
|
|
||||||
{
|
|
||||||
if (!quiet)
|
|
||||||
semsg(_(e_blobidx), lp->ll_n2);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
lp->ll_blob = lp->ll_tv->vval.v_blob;
|
lp->ll_blob = lp->ll_tv->vval.v_blob;
|
||||||
lp->ll_tv = NULL;
|
lp->ll_tv = NULL;
|
||||||
|
@@ -14,6 +14,8 @@ int write_blob(FILE *fd, blob_T *blob);
|
|||||||
char_u *blob2string(blob_T *blob, char_u **tofree, char_u *numbuf);
|
char_u *blob2string(blob_T *blob, char_u **tofree, char_u *numbuf);
|
||||||
blob_T *string2blob(char_u *str);
|
blob_T *string2blob(char_u *str);
|
||||||
int blob_slice_or_index(blob_T *blob, int is_range, varnumber_T n1, varnumber_T n2, int exclusive, typval_T *rettv);
|
int blob_slice_or_index(blob_T *blob, int is_range, varnumber_T n1, varnumber_T n2, int exclusive, typval_T *rettv);
|
||||||
|
int check_blob_index(long bloblen, varnumber_T n1, int is_range, int quiet);
|
||||||
|
int check_blob_range(long bloblen, varnumber_T n1, varnumber_T n2, int quiet);
|
||||||
int blob_set_range(blob_T *dest, long n1, long n2, typval_T *src);
|
int blob_set_range(blob_T *dest, long n1, long n2, typval_T *src);
|
||||||
void blob_remove(typval_T *argvars, typval_T *rettv);
|
void blob_remove(typval_T *argvars, typval_T *rettv);
|
||||||
/* vim: set ft=c : */
|
/* vim: set ft=c : */
|
||||||
|
@@ -76,16 +76,47 @@ func Test_blob_assign()
|
|||||||
END
|
END
|
||||||
call CheckLegacyAndVim9Success(lines)
|
call CheckLegacyAndVim9Success(lines)
|
||||||
|
|
||||||
" TODO: move to above once it works
|
let lines =<< trim END
|
||||||
let b = 0zDEADBEEF
|
VAR b = 0zDEADBEEF
|
||||||
call assert_fails('let b[2 : 3] = 0z112233', 'E972:')
|
LET b[2 : 3] = 0z112233
|
||||||
call assert_fails('let b[2 : 3] = 0z11', 'E972:')
|
END
|
||||||
call assert_fails('let b[3 : 2] = 0z', 'E979:')
|
call CheckLegacyAndVim9Failure(lines, 'E972:')
|
||||||
|
|
||||||
call assert_fails('let b ..= 0z33', 'E734:')
|
let lines =<< trim END
|
||||||
call assert_fails('let b ..= "xx"', 'E734:')
|
VAR b = 0zDEADBEEF
|
||||||
call assert_fails('let b += "xx"', 'E734:')
|
LET b[2 : 3] = 0z11
|
||||||
call assert_fails('let b[1 : 1] ..= 0z55', 'E734:')
|
END
|
||||||
|
call CheckLegacyAndVim9Failure(lines, 'E972:')
|
||||||
|
|
||||||
|
let lines =<< trim END
|
||||||
|
VAR b = 0zDEADBEEF
|
||||||
|
LET b[3 : 2] = 0z
|
||||||
|
END
|
||||||
|
call CheckLegacyAndVim9Failure(lines, 'E979:')
|
||||||
|
|
||||||
|
let lines =<< trim END
|
||||||
|
VAR b = 0zDEADBEEF
|
||||||
|
LET b ..= 0z33
|
||||||
|
END
|
||||||
|
call CheckLegacyAndVim9Failure(lines, ['E734:', 'E1019:', 'E734:'])
|
||||||
|
|
||||||
|
let lines =<< trim END
|
||||||
|
VAR b = 0zDEADBEEF
|
||||||
|
LET b ..= "xx"
|
||||||
|
END
|
||||||
|
call CheckLegacyAndVim9Failure(lines, ['E734:', 'E1019:', 'E734:'])
|
||||||
|
|
||||||
|
let lines =<< trim END
|
||||||
|
VAR b = 0zDEADBEEF
|
||||||
|
LET b += "xx"
|
||||||
|
END
|
||||||
|
call CheckLegacyAndVim9Failure(lines, ['E734:', 'E1012:', 'E734:'])
|
||||||
|
|
||||||
|
let lines =<< trim END
|
||||||
|
VAR b = 0zDEADBEEF
|
||||||
|
LET b[1 : 1] ..= 0z55
|
||||||
|
END
|
||||||
|
call CheckLegacyAndVim9Failure(lines, ['E734:', 'E1183:', 'E734:'])
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_blob_get_range()
|
func Test_blob_get_range()
|
||||||
|
@@ -144,8 +144,23 @@ func CheckLegacySuccess(lines)
|
|||||||
try
|
try
|
||||||
exe 'so ' .. fname
|
exe 'so ' .. fname
|
||||||
call Func()
|
call Func()
|
||||||
delfunc! Func
|
|
||||||
finally
|
finally
|
||||||
|
delfunc! Func
|
||||||
|
call chdir(cwd)
|
||||||
|
call delete(fname)
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Check that "lines" inside a legacy function results in the expected error
|
||||||
|
func CheckLegacyFailure(lines, error)
|
||||||
|
let cwd = getcwd()
|
||||||
|
let fname = 'XlegacyFails' .. s:sequence
|
||||||
|
let s:sequence += 1
|
||||||
|
call writefile(['func Func()'] + a:lines + ['endfunc', 'call Func()'], fname)
|
||||||
|
try
|
||||||
|
call assert_fails('so ' .. fname, a:error)
|
||||||
|
finally
|
||||||
|
delfunc! Func
|
||||||
call chdir(cwd)
|
call chdir(cwd)
|
||||||
call delete(fname)
|
call delete(fname)
|
||||||
endtry
|
endtry
|
||||||
@@ -168,3 +183,35 @@ def CheckLegacyAndVim9Success(lines: list<string>)
|
|||||||
CheckDefSuccess(vim9lines)
|
CheckDefSuccess(vim9lines)
|
||||||
CheckScriptSuccess(['vim9script'] + vim9lines)
|
CheckScriptSuccess(['vim9script'] + vim9lines)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
" Execute "lines" in a legacy function, :def function and Vim9 script.
|
||||||
|
" Use 'VAR' for a declaration.
|
||||||
|
" Use 'LET' for an assignment
|
||||||
|
" Use ' #"' for a comment
|
||||||
|
def CheckLegacyAndVim9Failure(lines: list<string>, error: any)
|
||||||
|
var legacyError: string
|
||||||
|
var defError: string
|
||||||
|
var scriptError: string
|
||||||
|
|
||||||
|
if type(error) == type('string')
|
||||||
|
legacyError = error
|
||||||
|
defError = error
|
||||||
|
scriptError = error
|
||||||
|
else
|
||||||
|
legacyError = error[0]
|
||||||
|
defError = error[1]
|
||||||
|
scriptError = error[2]
|
||||||
|
endif
|
||||||
|
|
||||||
|
var legacylines = lines->mapnew((_, v) =>
|
||||||
|
v->substitute('\<VAR\>', 'let', 'g')
|
||||||
|
->substitute('\<LET\>', 'let', 'g')
|
||||||
|
->substitute('#"', ' "', 'g'))
|
||||||
|
CheckLegacyFailure(legacylines, legacyError)
|
||||||
|
|
||||||
|
var vim9lines = lines->mapnew((_, v) =>
|
||||||
|
v->substitute('\<VAR\>', 'var', 'g')
|
||||||
|
->substitute('\<LET ', '', 'g'))
|
||||||
|
CheckDefExecFailure(vim9lines, defError)
|
||||||
|
CheckScriptFailure(['vim9script'] + vim9lines, scriptError)
|
||||||
|
enddef
|
||||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2765,
|
||||||
/**/
|
/**/
|
||||||
2764,
|
2764,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -2278,8 +2278,18 @@ call_def_function(
|
|||||||
if (error)
|
if (error)
|
||||||
status = FAIL;
|
status = FAIL;
|
||||||
else
|
else
|
||||||
status = blob_set_range(tv_dest->vval.v_blob,
|
{
|
||||||
n1, n2, tv);
|
long bloblen = blob_len(tv_dest->vval.v_blob);
|
||||||
|
|
||||||
|
if (check_blob_index(bloblen,
|
||||||
|
n1, TRUE, FALSE) == FAIL
|
||||||
|
|| check_blob_range(bloblen,
|
||||||
|
n1, n2, FALSE) == FAIL)
|
||||||
|
status = FAIL;
|
||||||
|
else
|
||||||
|
status = blob_set_range(
|
||||||
|
tv_dest->vval.v_blob, n1, n2, tv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user