mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
patch 8.2.1795: Vim9: operators && and || have a confusing result
Problem: Vim9: operators && and || have a confusing result. Solution: Make the result a boolean.
This commit is contained in:
@@ -154,25 +154,25 @@ Functions and variables are script-local by default ~
|
|||||||
*vim9-scopes*
|
*vim9-scopes*
|
||||||
When using `:function` or `:def` to specify a new function at the script level
|
When using `:function` or `:def` to specify a new function at the script level
|
||||||
in a Vim9 script, the function is local to the script, as if "s:" was
|
in a Vim9 script, the function is local to the script, as if "s:" was
|
||||||
prefixed. Using the "s:" prefix is optional. To define or use a global
|
prefixed. Using the "s:" prefix is optional. To define a global function or
|
||||||
function or variable the "g:" prefix should be used. For functions in an
|
variable the "g:" prefix must be used. For functions in an autoload script
|
||||||
autoload script the "name#" prefix is sufficient. >
|
the "name#" prefix is sufficient. >
|
||||||
def ThisFunction() # script-local
|
def ThisFunction() # script-local
|
||||||
def s:ThisFunction() # script-local
|
def s:ThisFunction() # script-local
|
||||||
def g:ThatFunction() # global
|
def g:ThatFunction() # global
|
||||||
def ThatFunction() # global if no local ThatFunction()
|
|
||||||
def scriptname#function() # autoload
|
def scriptname#function() # autoload
|
||||||
|
|
||||||
When using `:function` or `:def` to specify a new function inside a function,
|
When using `:function` or `:def` to specify a nested function inside a `:def`
|
||||||
the function is local to the function. It is not possible to define a
|
function, this nested function is local to the code block it is defined in.
|
||||||
script-local function inside a function. It is possible to define a global
|
In a `:def` function IT is not possible to define a script-local function. it
|
||||||
function, using the "g:" prefix.
|
is possible to define a global function by using the "g:" prefix.
|
||||||
|
|
||||||
When referring to a function and no "s:" or "g:" prefix is used, Vim will
|
When referring to a function and no "s:" or "g:" prefix is used, Vim will
|
||||||
prefer using a local function (in the function scope, script scope or
|
prefer using a local function (in the function scope, script scope or
|
||||||
imported) before looking for a global function.
|
imported) before looking for a global function. However, it is recommended to
|
||||||
In all cases the function must be defined before used. That is when it is
|
always use "g:" to refer to a local function for clarity. In all cases the
|
||||||
first called or when `:defcompile` causes the call to be compiled.
|
function must be defined before used. That is when it is first called or when
|
||||||
|
`:defcompile` causes the call to be compiled.
|
||||||
|
|
||||||
The result is that functions and variables without a namespace can usually be
|
The result is that functions and variables without a namespace can usually be
|
||||||
found in the script, either defined there or imported. Global functions and
|
found in the script, either defined there or imported. Global functions and
|
||||||
@@ -184,7 +184,7 @@ and cannot be deleted or replaced.
|
|||||||
|
|
||||||
|
|
||||||
Variable declarations with :var, :final and :const ~
|
Variable declarations with :var, :final and :const ~
|
||||||
*vim9-declaration*
|
*vim9-declaration* *:var*
|
||||||
Local variables need to be declared with `:var`. Local constants need to be
|
Local variables need to be declared with `:var`. Local constants need to be
|
||||||
declared with `:final` or `:const`. We refer to both as "variables" in this
|
declared with `:final` or `:const`. We refer to both as "variables" in this
|
||||||
section.
|
section.
|
||||||
@@ -261,7 +261,7 @@ Example: >
|
|||||||
myList = [3, 4] # Error!
|
myList = [3, 4] # Error!
|
||||||
myList[0] = 9 # Error!
|
myList[0] = 9 # Error!
|
||||||
muList->add(3) # Error!
|
muList->add(3) # Error!
|
||||||
|
< *:final*
|
||||||
`:final` is used for making only the variable a constant, the value can be
|
`:final` is used for making only the variable a constant, the value can be
|
||||||
changed. This is well known from Java. Example: >
|
changed. This is well known from Java. Example: >
|
||||||
final myList = [1, 2]
|
final myList = [1, 2]
|
||||||
@@ -471,10 +471,6 @@ Conditions and expressions are mostly working like they do in JavaScript. A
|
|||||||
difference is made where JavaScript does not work like most people expect.
|
difference is made where JavaScript does not work like most people expect.
|
||||||
Specifically, an empty list is falsy.
|
Specifically, an empty list is falsy.
|
||||||
|
|
||||||
Any type of variable can be used as a condition, there is no error, not even
|
|
||||||
for using a list or job. This is very much like JavaScript, but there are a
|
|
||||||
few exceptions.
|
|
||||||
|
|
||||||
type TRUE when ~
|
type TRUE when ~
|
||||||
bool v:true or 1
|
bool v:true or 1
|
||||||
number non-zero
|
number non-zero
|
||||||
@@ -490,17 +486,25 @@ few exceptions.
|
|||||||
class when not NULL
|
class when not NULL
|
||||||
object when not NULL (TODO: when isTrue() returns v:true)
|
object when not NULL (TODO: when isTrue() returns v:true)
|
||||||
|
|
||||||
The boolean operators "||" and "&&" do not change the value: >
|
The boolean operators "||" and "&&" expect the values to be boolean, zero or
|
||||||
8 || 2 == 8
|
one: >
|
||||||
0 || 2 == 2
|
1 || false == true
|
||||||
0 || '' == ''
|
0 || 1 == true
|
||||||
8 && 2 == 2
|
0 || false == false
|
||||||
0 && 2 == 0
|
1 && true == true
|
||||||
2 && 0 == 0
|
0 && 1 == false
|
||||||
[] && 2 == []
|
8 || 0 Error!
|
||||||
|
'yes' && 0 Error!
|
||||||
|
[] || 99 Error!
|
||||||
|
|
||||||
When using `..` for string concatenation arguments of simple types are always
|
When using "!" for inverting, there is no error for using any type and the
|
||||||
converted to string. >
|
result is a boolean: >
|
||||||
|
!'yes' == false
|
||||||
|
var myList = [1, 2, 3]
|
||||||
|
!!myList == true
|
||||||
|
|
||||||
|
When using "`.."` for string concatenation arguments of simple types are
|
||||||
|
always converted to string. >
|
||||||
'hello ' .. 123 == 'hello 123'
|
'hello ' .. 123 == 'hello 123'
|
||||||
'hello ' .. v:true == 'hello v:true'
|
'hello ' .. v:true == 'hello v:true'
|
||||||
|
|
||||||
|
102
src/eval.c
102
src/eval.c
@@ -2296,7 +2296,7 @@ eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
int orig_flags;
|
int orig_flags;
|
||||||
long result = FALSE;
|
long result = FALSE;
|
||||||
typval_T var2;
|
typval_T var2;
|
||||||
int error;
|
int error = FALSE;
|
||||||
int vim9script = in_vim9script();
|
int vim9script = in_vim9script();
|
||||||
|
|
||||||
if (evalarg == NULL)
|
if (evalarg == NULL)
|
||||||
@@ -2309,18 +2309,12 @@ eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
if (evaluate)
|
if (evaluate)
|
||||||
{
|
{
|
||||||
if (vim9script)
|
if (vim9script)
|
||||||
{
|
result = tv_get_bool_chk(rettv, &error);
|
||||||
result = tv2bool(rettv);
|
else if (tv_get_number_chk(rettv, &error) != 0)
|
||||||
}
|
result = TRUE;
|
||||||
else
|
clear_tv(rettv);
|
||||||
{
|
if (error)
|
||||||
error = FALSE;
|
return FAIL;
|
||||||
if (tv_get_number_chk(rettv, &error) != 0)
|
|
||||||
result = TRUE;
|
|
||||||
clear_tv(rettv);
|
|
||||||
if (error)
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2360,27 +2354,28 @@ eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
* Compute the result.
|
* Compute the result.
|
||||||
*/
|
*/
|
||||||
if (evaluate && !result)
|
if (evaluate && !result)
|
||||||
|
{
|
||||||
|
if (vim9script)
|
||||||
|
result = tv_get_bool_chk(&var2, &error);
|
||||||
|
else if (tv_get_number_chk(&var2, &error) != 0)
|
||||||
|
result = TRUE;
|
||||||
|
clear_tv(&var2);
|
||||||
|
if (error)
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
if (evaluate)
|
||||||
{
|
{
|
||||||
if (vim9script)
|
if (vim9script)
|
||||||
{
|
{
|
||||||
clear_tv(rettv);
|
rettv->v_type = VAR_BOOL;
|
||||||
*rettv = var2;
|
rettv->vval.v_number = result ? VVAL_TRUE : VVAL_FALSE;
|
||||||
result = tv2bool(rettv);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (tv_get_number_chk(&var2, &error) != 0)
|
rettv->v_type = VAR_NUMBER;
|
||||||
result = TRUE;
|
rettv->vval.v_number = result;
|
||||||
clear_tv(&var2);
|
|
||||||
if (error)
|
|
||||||
return FAIL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (evaluate && !vim9script)
|
|
||||||
{
|
|
||||||
rettv->v_type = VAR_NUMBER;
|
|
||||||
rettv->vval.v_number = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = eval_next_non_blank(*arg, evalarg_used, &getnext);
|
p = eval_next_non_blank(*arg, evalarg_used, &getnext);
|
||||||
}
|
}
|
||||||
@@ -2389,9 +2384,6 @@ eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
clear_evalarg(&local_evalarg, NULL);
|
clear_evalarg(&local_evalarg, NULL);
|
||||||
else
|
else
|
||||||
evalarg->eval_flags = orig_flags;
|
evalarg->eval_flags = orig_flags;
|
||||||
|
|
||||||
// Resulting value can be assigned to a bool.
|
|
||||||
rettv->v_lock |= VAR_BOOL_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
@@ -2430,7 +2422,7 @@ eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
int evaluate;
|
int evaluate;
|
||||||
long result = TRUE;
|
long result = TRUE;
|
||||||
typval_T var2;
|
typval_T var2;
|
||||||
int error;
|
int error = FALSE;
|
||||||
int vim9script = in_vim9script();
|
int vim9script = in_vim9script();
|
||||||
|
|
||||||
if (evalarg == NULL)
|
if (evalarg == NULL)
|
||||||
@@ -2443,18 +2435,12 @@ eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
if (evaluate)
|
if (evaluate)
|
||||||
{
|
{
|
||||||
if (vim9script)
|
if (vim9script)
|
||||||
{
|
result = tv_get_bool_chk(rettv, &error);
|
||||||
result = tv2bool(rettv);
|
else if (tv_get_number_chk(rettv, &error) == 0)
|
||||||
}
|
result = FALSE;
|
||||||
else
|
clear_tv(rettv);
|
||||||
{
|
if (error)
|
||||||
error = FALSE;
|
return FAIL;
|
||||||
if (tv_get_number_chk(rettv, &error) == 0)
|
|
||||||
result = FALSE;
|
|
||||||
clear_tv(rettv);
|
|
||||||
if (error)
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2466,7 +2452,7 @@ eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
*arg = eval_next_line(evalarg_used);
|
*arg = eval_next_line(evalarg_used);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (evaluate && in_vim9script() && !VIM_ISWHITE(p[-1]))
|
if (evaluate && vim9script && !VIM_ISWHITE(p[-1]))
|
||||||
{
|
{
|
||||||
error_white_both(p, 2);
|
error_white_both(p, 2);
|
||||||
clear_tv(rettv);
|
clear_tv(rettv);
|
||||||
@@ -2495,27 +2481,28 @@ eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
* Compute the result.
|
* Compute the result.
|
||||||
*/
|
*/
|
||||||
if (evaluate && result)
|
if (evaluate && result)
|
||||||
|
{
|
||||||
|
if (vim9script)
|
||||||
|
result = tv_get_bool_chk(&var2, &error);
|
||||||
|
else if (tv_get_number_chk(&var2, &error) == 0)
|
||||||
|
result = FALSE;
|
||||||
|
clear_tv(&var2);
|
||||||
|
if (error)
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
if (evaluate)
|
||||||
{
|
{
|
||||||
if (vim9script)
|
if (vim9script)
|
||||||
{
|
{
|
||||||
clear_tv(rettv);
|
rettv->v_type = VAR_BOOL;
|
||||||
*rettv = var2;
|
rettv->vval.v_number = result ? VVAL_TRUE : VVAL_FALSE;
|
||||||
result = tv2bool(rettv);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (tv_get_number_chk(&var2, &error) == 0)
|
rettv->v_type = VAR_NUMBER;
|
||||||
result = FALSE;
|
rettv->vval.v_number = result;
|
||||||
clear_tv(&var2);
|
|
||||||
if (error)
|
|
||||||
return FAIL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (evaluate && !vim9script)
|
|
||||||
{
|
|
||||||
rettv->v_type = VAR_NUMBER;
|
|
||||||
rettv->vval.v_number = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = eval_next_non_blank(*arg, evalarg_used, &getnext);
|
p = eval_next_non_blank(*arg, evalarg_used, &getnext);
|
||||||
}
|
}
|
||||||
@@ -2524,9 +2511,6 @@ eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
clear_evalarg(&local_evalarg, NULL);
|
clear_evalarg(&local_evalarg, NULL);
|
||||||
else
|
else
|
||||||
evalarg->eval_flags = orig_flags;
|
evalarg->eval_flags = orig_flags;
|
||||||
|
|
||||||
// Resulting value can be assigned to a bool.
|
|
||||||
rettv->v_lock |= VAR_BOOL_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
@@ -1382,7 +1382,7 @@ struct type_S {
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
vartype_T v_type;
|
vartype_T v_type;
|
||||||
char v_lock; // see below: VAR_LOCKED, VAR_FIXED, VAR_BOOL_OK
|
char v_lock; // see below: VAR_LOCKED, VAR_FIXED
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
varnumber_T v_number; // number value
|
varnumber_T v_number; // number value
|
||||||
@@ -1409,7 +1409,6 @@ typedef struct
|
|||||||
// Values for "v_lock".
|
// Values for "v_lock".
|
||||||
#define VAR_LOCKED 1 // locked with lock(), can use unlock()
|
#define VAR_LOCKED 1 // locked with lock(), can use unlock()
|
||||||
#define VAR_FIXED 2 // locked forever
|
#define VAR_FIXED 2 // locked forever
|
||||||
#define VAR_BOOL_OK 4 // can be convered to bool
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Structure to hold an item of a list: an internal variable without a name.
|
* Structure to hold an item of a list: an internal variable without a name.
|
||||||
|
@@ -22,11 +22,11 @@ def Test_assignment_bool()
|
|||||||
var bool4: bool = 1
|
var bool4: bool = 1
|
||||||
assert_equal(true, bool4)
|
assert_equal(true, bool4)
|
||||||
|
|
||||||
var bool5: bool = 'yes' && 'no'
|
var bool5: bool = 1 && true
|
||||||
assert_equal(true, bool5)
|
assert_equal(true, bool5)
|
||||||
var bool6: bool = [] && 99
|
var bool6: bool = 0 && 1
|
||||||
assert_equal(false, bool6)
|
assert_equal(false, bool6)
|
||||||
var bool7: bool = [] || #{a: 1} && 99
|
var bool7: bool = 0 || 1 && true
|
||||||
assert_equal(true, bool7)
|
assert_equal(true, bool7)
|
||||||
|
|
||||||
var lines =<< trim END
|
var lines =<< trim END
|
||||||
@@ -41,9 +41,9 @@ def Test_assignment_bool()
|
|||||||
assert_equal(false, flag)
|
assert_equal(false, flag)
|
||||||
flag = 1
|
flag = 1
|
||||||
assert_equal(true, flag)
|
assert_equal(true, flag)
|
||||||
flag = 99 || 123
|
flag = 1 || true
|
||||||
assert_equal(true, flag)
|
assert_equal(true, flag)
|
||||||
flag = 'yes' && []
|
flag = 1 && false
|
||||||
assert_equal(false, flag)
|
assert_equal(false, flag)
|
||||||
END
|
END
|
||||||
CheckScriptSuccess(lines)
|
CheckScriptSuccess(lines)
|
||||||
|
@@ -72,8 +72,8 @@ def Test_if_linebreak()
|
|||||||
var lines =<< trim END
|
var lines =<< trim END
|
||||||
vim9script
|
vim9script
|
||||||
if 1 &&
|
if 1 &&
|
||||||
2
|
true
|
||||||
|| 3
|
|| 1
|
||||||
g:res = 42
|
g:res = 42
|
||||||
endif
|
endif
|
||||||
assert_equal(42, g:res)
|
assert_equal(42, g:res)
|
||||||
|
@@ -766,11 +766,11 @@ def Test_disassemble_and_or()
|
|||||||
'\d LOAD arg\[-1]\_s*' ..
|
'\d LOAD arg\[-1]\_s*' ..
|
||||||
'\d PUSHNR 1\_s*' ..
|
'\d PUSHNR 1\_s*' ..
|
||||||
'\d COMPAREANY ==\_s*' ..
|
'\d COMPAREANY ==\_s*' ..
|
||||||
'\d JUMP_AND_KEEP_IF_FALSE -> \d\+\_s*' ..
|
'\d JUMP_IF_COND_FALSE -> \d\+\_s*' ..
|
||||||
'\d LOAD arg\[-1]\_s*' ..
|
'\d LOAD arg\[-1]\_s*' ..
|
||||||
'\d PUSHNR 2\_s*' ..
|
'\d PUSHNR 2\_s*' ..
|
||||||
'\d COMPAREANY !=\_s*' ..
|
'\d COMPAREANY !=\_s*' ..
|
||||||
'\d JUMP_AND_KEEP_IF_TRUE -> \d\+\_s*' ..
|
'\d JUMP_IF_COND_TRUE -> \d\+\_s*' ..
|
||||||
'\d LOAD arg\[-1]\_s*' ..
|
'\d LOAD arg\[-1]\_s*' ..
|
||||||
'\d\+ PUSHNR 4\_s*' ..
|
'\d\+ PUSHNR 4\_s*' ..
|
||||||
'\d\+ COMPAREANY ==\_s*' ..
|
'\d\+ COMPAREANY ==\_s*' ..
|
||||||
@@ -1200,22 +1200,23 @@ def Test_disassemble_invert_bool()
|
|||||||
enddef
|
enddef
|
||||||
|
|
||||||
def ReturnBool(): bool
|
def ReturnBool(): bool
|
||||||
var var: bool = "no" && [] || 123
|
var name: bool = 1 && 0 || 1
|
||||||
return var
|
return name
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_disassemble_return_bool()
|
def Test_disassemble_return_bool()
|
||||||
var instr = execute('disassemble ReturnBool')
|
var instr = execute('disassemble ReturnBool')
|
||||||
assert_match('ReturnBool\_s*' ..
|
assert_match('ReturnBool\_s*' ..
|
||||||
'var var: bool = "no" && \[\] || 123\_s*' ..
|
'var name: bool = 1 && 0 || 1\_s*' ..
|
||||||
'0 PUSHS "no"\_s*' ..
|
'0 PUSHNR 1\_s*' ..
|
||||||
'1 JUMP_AND_KEEP_IF_FALSE -> 3\_s*' ..
|
'1 JUMP_IF_COND_FALSE -> 3\_s*' ..
|
||||||
'2 NEWLIST size 0\_s*' ..
|
'2 PUSHNR 0\_s*' ..
|
||||||
'3 JUMP_AND_KEEP_IF_TRUE -> 5\_s*' ..
|
'3 COND2BOOL\_s*' ..
|
||||||
'4 PUSHNR 123\_s*' ..
|
'4 JUMP_IF_COND_TRUE -> 6\_s*' ..
|
||||||
'5 2BOOL (!!val)\_s*' ..
|
'5 PUSHNR 1\_s*' ..
|
||||||
|
'6 2BOOL (!!val)\_s*' ..
|
||||||
'\d STORE $0\_s*' ..
|
'\d STORE $0\_s*' ..
|
||||||
'return var\_s*' ..
|
'return name\_s*' ..
|
||||||
'\d LOAD $0\_s*' ..
|
'\d LOAD $0\_s*' ..
|
||||||
'\d RETURN',
|
'\d RETURN',
|
||||||
instr)
|
instr)
|
||||||
|
@@ -196,32 +196,32 @@ enddef
|
|||||||
|
|
||||||
" test ||
|
" test ||
|
||||||
def Test_expr2()
|
def Test_expr2()
|
||||||
assert_equal(2, 2 || 0)
|
assert_equal(true, 1 || 0)
|
||||||
assert_equal(7, 0 ||
|
assert_equal(true, 0 ||
|
||||||
0 ||
|
0 ||
|
||||||
7)
|
1)
|
||||||
assert_equal(0, 0 || 0)
|
assert_equal(false, 0 || 0)
|
||||||
assert_equal(0, 0
|
assert_equal(false, 0
|
||||||
|| 0)
|
|| 0)
|
||||||
assert_equal('', 0 || '')
|
assert_equal(false, 0 || false)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(3, Record(3) || Record(1))
|
assert_equal(true, Record(1) || Record(3))
|
||||||
assert_equal([3], g:vals)
|
assert_equal([1], g:vals)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(5, Record(0) || Record(5))
|
assert_equal(true, Record(0) || Record(1))
|
||||||
assert_equal([0, 5], g:vals)
|
assert_equal([0, 1], g:vals)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(4, Record(0)
|
assert_equal(true, Record(0)
|
||||||
|| Record(4)
|
|| Record(1)
|
||||||
|| Record(0))
|
|| Record(0))
|
||||||
assert_equal([0, 4], g:vals)
|
assert_equal([0, 1], g:vals)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(0, Record([]) || Record('') || Record(0))
|
assert_equal(false, Record(0) || Record(false) || Record(0))
|
||||||
assert_equal([[], '', 0], g:vals)
|
assert_equal([0, false, 0], g:vals)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_expr2_vimscript()
|
def Test_expr2_vimscript()
|
||||||
@@ -230,7 +230,7 @@ def Test_expr2_vimscript()
|
|||||||
vim9script
|
vim9script
|
||||||
var name = 0
|
var name = 0
|
||||||
|| 1
|
|| 1
|
||||||
assert_equal(1, name)
|
assert_equal(true, name)
|
||||||
END
|
END
|
||||||
CheckScriptSuccess(lines)
|
CheckScriptSuccess(lines)
|
||||||
|
|
||||||
@@ -269,80 +269,85 @@ def Test_expr2_vimscript()
|
|||||||
END
|
END
|
||||||
CheckScriptFailure(lines, 'E1004:', 2)
|
CheckScriptFailure(lines, 'E1004:', 2)
|
||||||
|
|
||||||
# check keeping the value
|
# check evaluating to bool
|
||||||
lines =<< trim END
|
lines =<< trim END
|
||||||
vim9script
|
assert_equal(true, 1 || 0)
|
||||||
assert_equal(2, 2 || 0)
|
assert_equal(true, 0 ||
|
||||||
assert_equal(7, 0 ||
|
|
||||||
0 ||
|
0 ||
|
||||||
7)
|
!!7)
|
||||||
assert_equal(0, 0 || 0)
|
assert_equal(false, 0 || 0)
|
||||||
assert_equal(0, 0
|
assert_equal(false, 0
|
||||||
|| 0)
|
|| 0)
|
||||||
assert_equal('', 0 || '')
|
assert_equal(false, 0 || false)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(3, Record(3) || Record(1))
|
assert_equal(true, Record(true) || Record(false))
|
||||||
assert_equal([3], g:vals)
|
assert_equal([true], g:vals)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(5, Record(0) || Record(5))
|
assert_equal(true, Record(0) || Record(true))
|
||||||
assert_equal([0, 5], g:vals)
|
assert_equal([0, true], g:vals)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(4, Record(0)
|
assert_equal(true, Record(0)
|
||||||
|| Record(4)
|
|| Record(true)
|
||||||
|| Record(0))
|
|| Record(0))
|
||||||
assert_equal([0, 4], g:vals)
|
assert_equal([0, true], g:vals)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(0, Record([]) || Record('') || Record(0))
|
assert_equal(false, Record(0) || Record(false) || Record(0))
|
||||||
assert_equal([[], '', 0], g:vals)
|
assert_equal([0, false, 0], g:vals)
|
||||||
END
|
END
|
||||||
CheckScriptSuccess(lines)
|
CheckDefAndScriptSuccess(lines)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
func Test_expr2_fails()
|
def Test_expr2_fails()
|
||||||
let msg = "White space required before and after '||'"
|
var msg = "White space required before and after '||'"
|
||||||
call CheckDefFailure(["var x = 1||2"], msg, 1)
|
call CheckDefFailure(["var x = 1||2"], msg, 1)
|
||||||
call CheckDefFailure(["var x = 1 ||2"], msg, 1)
|
call CheckDefFailure(["var x = 1 ||2"], msg, 1)
|
||||||
call CheckDefFailure(["var x = 1|| 2"], msg, 1)
|
call CheckDefFailure(["var x = 1|| 2"], msg, 1)
|
||||||
|
|
||||||
call CheckDefFailure(["var x = 1 || xxx"], 'E1001:', 1)
|
call CheckDefFailure(["var x = 1 || xxx"], 'E1001:', 1)
|
||||||
endfunc
|
|
||||||
|
# TODO: should fail at compile time
|
||||||
|
call CheckDefExecFailure(["var x = 3 || 7"], 'E1023:', 1)
|
||||||
|
call CheckScriptFailure(["vim9script", "var x = 3 || 7"], 'E1023:', 2)
|
||||||
|
call CheckDefExecFailure(["var x = [] || false"], 'E745:', 1)
|
||||||
|
call CheckScriptFailure(["vim9script", "var x = [] || false"], 'E745:', 2)
|
||||||
|
enddef
|
||||||
|
|
||||||
" test &&
|
" test &&
|
||||||
def Test_expr3()
|
def Test_expr3()
|
||||||
assert_equal(0, 2 && 0)
|
assert_equal(false, 1 && 0)
|
||||||
assert_equal(0, 0 &&
|
assert_equal(false, 0 &&
|
||||||
0 &&
|
0 &&
|
||||||
7)
|
1)
|
||||||
assert_equal(7, 2
|
assert_equal(true, 1
|
||||||
&& 3
|
&& true
|
||||||
&& 7)
|
&& 1)
|
||||||
assert_equal(0, 0 && 0)
|
assert_equal(false, 0 && 0)
|
||||||
assert_equal(0, 0 && '')
|
assert_equal(false, 0 && false)
|
||||||
assert_equal('', 8 && '')
|
assert_equal(true, 1 && true)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(1, Record(3) && Record(1))
|
assert_equal(true, Record(true) && Record(1))
|
||||||
assert_equal([3, 1], g:vals)
|
assert_equal([true, 1], g:vals)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(0, Record(0) && Record(5))
|
assert_equal(false, Record(0) && Record(1))
|
||||||
assert_equal([0], g:vals)
|
assert_equal([0], g:vals)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(0, Record(0) && Record(4) && Record(0))
|
assert_equal(false, Record(0) && Record(4) && Record(0))
|
||||||
assert_equal([0], g:vals)
|
assert_equal([0], g:vals)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(0, Record(8) && Record(4) && Record(0))
|
assert_equal(false, Record(1) && Record(true) && Record(0))
|
||||||
assert_equal([8, 4, 0], g:vals)
|
assert_equal([1, true, 0], g:vals)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(0, Record([1]) && Record('z') && Record(0))
|
assert_equal(false, Record(1) && Record(true) && Record(0))
|
||||||
assert_equal([[1], 'z', 0], g:vals)
|
assert_equal([1, true, 0], g:vals)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_expr3_vimscript()
|
def Test_expr3_vimscript()
|
||||||
@@ -351,7 +356,7 @@ def Test_expr3_vimscript()
|
|||||||
vim9script
|
vim9script
|
||||||
var name = 0
|
var name = 0
|
||||||
&& 1
|
&& 1
|
||||||
assert_equal(0, name)
|
assert_equal(false, name)
|
||||||
END
|
END
|
||||||
CheckScriptSuccess(lines)
|
CheckScriptSuccess(lines)
|
||||||
|
|
||||||
@@ -393,36 +398,32 @@ def Test_expr3_vimscript()
|
|||||||
# check keeping the value
|
# check keeping the value
|
||||||
lines =<< trim END
|
lines =<< trim END
|
||||||
vim9script
|
vim9script
|
||||||
assert_equal(0, 2 && 0)
|
assert_equal(false, 1 && 0)
|
||||||
assert_equal(0, 0 &&
|
assert_equal(false, 0 &&
|
||||||
0 &&
|
0 &&
|
||||||
7)
|
1)
|
||||||
assert_equal(7, 2
|
assert_equal(true, 1
|
||||||
&& 3
|
&& true
|
||||||
&& 7)
|
&& 1)
|
||||||
assert_equal(0, 0 && 0)
|
assert_equal(false, 0 && 0)
|
||||||
assert_equal(0, 0 && '')
|
assert_equal(false, 0 && false)
|
||||||
assert_equal('', 8 && '')
|
assert_equal(false, 1 && 0)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(1, Record(3) && Record(1))
|
assert_equal(true, Record(1) && Record(true))
|
||||||
assert_equal([3, 1], g:vals)
|
assert_equal([1, true], g:vals)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(0, Record(0) && Record(5))
|
assert_equal(false, Record(0) && Record(1))
|
||||||
assert_equal([0], g:vals)
|
assert_equal([0], g:vals)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(0, Record(0) && Record(4) && Record(0))
|
assert_equal(false, Record(0) && Record(1) && Record(0))
|
||||||
assert_equal([0], g:vals)
|
assert_equal([0], g:vals)
|
||||||
|
|
||||||
g:vals = []
|
g:vals = []
|
||||||
assert_equal(0, Record(8) && Record(4) && Record(0))
|
assert_equal(false, Record(1) && Record(true) && Record(0))
|
||||||
assert_equal([8, 4, 0], g:vals)
|
assert_equal([1, true, 0], g:vals)
|
||||||
|
|
||||||
g:vals = []
|
|
||||||
assert_equal(0, Record([1]) && Record('z') && Record(0))
|
|
||||||
assert_equal([[1], 'z', 0], g:vals)
|
|
||||||
END
|
END
|
||||||
CheckScriptSuccess(lines)
|
CheckScriptSuccess(lines)
|
||||||
enddef
|
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 */
|
||||||
|
/**/
|
||||||
|
1795,
|
||||||
/**/
|
/**/
|
||||||
1794,
|
1794,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -128,7 +128,8 @@ typedef enum {
|
|||||||
ISN_GETITEM, // push list item, isn_arg.number is the index
|
ISN_GETITEM, // push list item, isn_arg.number is the index
|
||||||
ISN_MEMBER, // dict[member]
|
ISN_MEMBER, // dict[member]
|
||||||
ISN_STRINGMEMBER, // dict.member using isn_arg.string
|
ISN_STRINGMEMBER, // dict.member using isn_arg.string
|
||||||
ISN_2BOOL, // convert value to bool, invert if isn_arg.number != 0
|
ISN_2BOOL, // falsy/truthy to bool, invert if isn_arg.number != 0
|
||||||
|
ISN_COND2BOOL, // convert value to bool
|
||||||
ISN_2STRING, // convert value to string at isn_arg.number on stack
|
ISN_2STRING, // convert value to string at isn_arg.number on stack
|
||||||
ISN_2STRING_ANY, // like ISN_2STRING but check type
|
ISN_2STRING_ANY, // like ISN_2STRING but check type
|
||||||
ISN_NEGATENR, // apply "-" to number
|
ISN_NEGATENR, // apply "-" to number
|
||||||
@@ -171,8 +172,10 @@ typedef struct {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
JUMP_ALWAYS,
|
JUMP_ALWAYS,
|
||||||
JUMP_IF_FALSE, // pop and jump if false
|
JUMP_IF_FALSE, // pop and jump if false
|
||||||
JUMP_AND_KEEP_IF_TRUE, // jump if top of stack is true, drop if not
|
JUMP_AND_KEEP_IF_TRUE, // jump if top of stack is truthy, drop if not
|
||||||
JUMP_AND_KEEP_IF_FALSE, // jump if top of stack is false, drop if not
|
JUMP_AND_KEEP_IF_FALSE, // jump if top of stack is falsy, drop if not
|
||||||
|
JUMP_IF_COND_TRUE, // jump if top of stack is true, drop if not
|
||||||
|
JUMP_IF_COND_FALSE, // jump if top of stack is false, drop if not
|
||||||
} jumpwhen_T;
|
} jumpwhen_T;
|
||||||
|
|
||||||
// arguments to ISN_JUMP
|
// arguments to ISN_JUMP
|
||||||
|
@@ -706,6 +706,25 @@ generate_2BOOL(cctx_T *cctx, int invert)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate an ISN_COND2BOOL instruction.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
generate_COND2BOOL(cctx_T *cctx)
|
||||||
|
{
|
||||||
|
isn_T *isn;
|
||||||
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
|
|
||||||
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
|
if ((isn = generate_instr(cctx, ISN_COND2BOOL)) == NULL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
// type becomes bool
|
||||||
|
((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_bool;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
generate_TYPECHECK(
|
generate_TYPECHECK(
|
||||||
cctx_T *cctx,
|
cctx_T *cctx,
|
||||||
@@ -4003,7 +4022,7 @@ compile_and_or(
|
|||||||
garray_T *instr = &cctx->ctx_instr;
|
garray_T *instr = &cctx->ctx_instr;
|
||||||
garray_T end_ga;
|
garray_T end_ga;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
type_T **typep;
|
int all_bool_values = TRUE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Repeat until there is no following "||" or "&&"
|
* Repeat until there is no following "||" or "&&"
|
||||||
@@ -4023,9 +4042,13 @@ compile_and_or(
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use ppconst if the value is a constant
|
// TODO: use ppconst if the value is a constant and check
|
||||||
|
// evaluating to bool
|
||||||
generate_ppconst(cctx, ppconst);
|
generate_ppconst(cctx, ppconst);
|
||||||
|
|
||||||
|
if (((type_T **)stack->ga_data)[stack->ga_len - 1] != &t_bool)
|
||||||
|
all_bool_values = FALSE;
|
||||||
|
|
||||||
if (ga_grow(&end_ga, 1) == FAIL)
|
if (ga_grow(&end_ga, 1) == FAIL)
|
||||||
{
|
{
|
||||||
ga_clear(&end_ga);
|
ga_clear(&end_ga);
|
||||||
@@ -4034,7 +4057,7 @@ compile_and_or(
|
|||||||
*(((int *)end_ga.ga_data) + end_ga.ga_len) = instr->ga_len;
|
*(((int *)end_ga.ga_data) + end_ga.ga_len) = instr->ga_len;
|
||||||
++end_ga.ga_len;
|
++end_ga.ga_len;
|
||||||
generate_JUMP(cctx, opchar == '|'
|
generate_JUMP(cctx, opchar == '|'
|
||||||
? JUMP_AND_KEEP_IF_TRUE : JUMP_AND_KEEP_IF_FALSE, 0);
|
? JUMP_IF_COND_TRUE : JUMP_IF_COND_FALSE, 0);
|
||||||
|
|
||||||
// eval the next expression
|
// eval the next expression
|
||||||
*arg = skipwhite(p + 2);
|
*arg = skipwhite(p + 2);
|
||||||
@@ -4064,19 +4087,9 @@ compile_and_or(
|
|||||||
}
|
}
|
||||||
ga_clear(&end_ga);
|
ga_clear(&end_ga);
|
||||||
|
|
||||||
// The resulting type can be used as a bool.
|
// The resulting type is converted to bool if needed.
|
||||||
typep = ((type_T **)stack->ga_data) + stack->ga_len - 1;
|
if (!all_bool_values)
|
||||||
if (*typep != &t_bool)
|
generate_COND2BOOL(cctx);
|
||||||
{
|
|
||||||
type_T *type = get_type_ptr(cctx->ctx_type_list);
|
|
||||||
|
|
||||||
if (type != NULL)
|
|
||||||
{
|
|
||||||
*type = **typep;
|
|
||||||
type->tt_flags |= TTFLAG_BOOL_OK;
|
|
||||||
*typep = type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
@@ -4087,10 +4100,11 @@ compile_and_or(
|
|||||||
*
|
*
|
||||||
* Produces instructions:
|
* Produces instructions:
|
||||||
* EVAL expr4a Push result of "expr4a"
|
* EVAL expr4a Push result of "expr4a"
|
||||||
* JUMP_AND_KEEP_IF_FALSE end
|
* JUMP_IF_COND_FALSE end
|
||||||
* EVAL expr4b Push result of "expr4b"
|
* EVAL expr4b Push result of "expr4b"
|
||||||
* JUMP_AND_KEEP_IF_FALSE end
|
* JUMP_IF_COND_FALSE end
|
||||||
* EVAL expr4c Push result of "expr4c"
|
* EVAL expr4c Push result of "expr4c"
|
||||||
|
* COND2BOOL
|
||||||
* end:
|
* end:
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
@@ -4111,10 +4125,11 @@ compile_expr3(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
|||||||
*
|
*
|
||||||
* Produces instructions:
|
* Produces instructions:
|
||||||
* EVAL expr3a Push result of "expr3a"
|
* EVAL expr3a Push result of "expr3a"
|
||||||
* JUMP_AND_KEEP_IF_TRUE end
|
* JUMP_IF_COND_TRUE end
|
||||||
* EVAL expr3b Push result of "expr3b"
|
* EVAL expr3b Push result of "expr3b"
|
||||||
* JUMP_AND_KEEP_IF_TRUE end
|
* JUMP_IF_COND_TRUE end
|
||||||
* EVAL expr3c Push result of "expr3c"
|
* EVAL expr3c Push result of "expr3c"
|
||||||
|
* COND2BOOL
|
||||||
* end:
|
* end:
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
@@ -7415,6 +7430,7 @@ delete_instr(isn_T *isn)
|
|||||||
case ISN_COMPARESPECIAL:
|
case ISN_COMPARESPECIAL:
|
||||||
case ISN_COMPARESTRING:
|
case ISN_COMPARESTRING:
|
||||||
case ISN_CONCAT:
|
case ISN_CONCAT:
|
||||||
|
case ISN_COND2BOOL:
|
||||||
case ISN_DROP:
|
case ISN_DROP:
|
||||||
case ISN_ECHO:
|
case ISN_ECHO:
|
||||||
case ISN_ECHOERR:
|
case ISN_ECHOERR:
|
||||||
|
@@ -1901,14 +1901,25 @@ call_def_function(
|
|||||||
case ISN_JUMP:
|
case ISN_JUMP:
|
||||||
{
|
{
|
||||||
jumpwhen_T when = iptr->isn_arg.jump.jump_when;
|
jumpwhen_T when = iptr->isn_arg.jump.jump_when;
|
||||||
|
int error = FALSE;
|
||||||
int jump = TRUE;
|
int jump = TRUE;
|
||||||
|
|
||||||
if (when != JUMP_ALWAYS)
|
if (when != JUMP_ALWAYS)
|
||||||
{
|
{
|
||||||
tv = STACK_TV_BOT(-1);
|
tv = STACK_TV_BOT(-1);
|
||||||
jump = tv2bool(tv);
|
if (when == JUMP_IF_COND_FALSE
|
||||||
|
|| when == JUMP_IF_COND_TRUE)
|
||||||
|
{
|
||||||
|
SOURCING_LNUM = iptr->isn_lnum;
|
||||||
|
jump = tv_get_bool_chk(tv, &error);
|
||||||
|
if (error)
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
jump = tv2bool(tv);
|
||||||
if (when == JUMP_IF_FALSE
|
if (when == JUMP_IF_FALSE
|
||||||
|| when == JUMP_AND_KEEP_IF_FALSE)
|
|| when == JUMP_AND_KEEP_IF_FALSE
|
||||||
|
|| when == JUMP_IF_COND_FALSE)
|
||||||
jump = !jump;
|
jump = !jump;
|
||||||
if (when == JUMP_IF_FALSE || !jump)
|
if (when == JUMP_IF_FALSE || !jump)
|
||||||
{
|
{
|
||||||
@@ -2624,13 +2635,25 @@ call_def_function(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ISN_2BOOL:
|
case ISN_2BOOL:
|
||||||
|
case ISN_COND2BOOL:
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
int error = FALSE;
|
||||||
|
|
||||||
tv = STACK_TV_BOT(-1);
|
tv = STACK_TV_BOT(-1);
|
||||||
n = tv2bool(tv);
|
if (iptr->isn_type == ISN_2BOOL)
|
||||||
if (iptr->isn_arg.number) // invert
|
{
|
||||||
n = !n;
|
n = tv2bool(tv);
|
||||||
|
if (iptr->isn_arg.number) // invert
|
||||||
|
n = !n;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SOURCING_LNUM = iptr->isn_lnum;
|
||||||
|
n = tv_get_bool_chk(tv, &error);
|
||||||
|
if (error)
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
clear_tv(tv);
|
clear_tv(tv);
|
||||||
tv->v_type = VAR_BOOL;
|
tv->v_type = VAR_BOOL;
|
||||||
tv->vval.v_number = n ? VVAL_TRUE : VVAL_FALSE;
|
tv->vval.v_number = n ? VVAL_TRUE : VVAL_FALSE;
|
||||||
@@ -3192,6 +3215,12 @@ ex_disassemble(exarg_T *eap)
|
|||||||
case JUMP_AND_KEEP_IF_FALSE:
|
case JUMP_AND_KEEP_IF_FALSE:
|
||||||
when = "JUMP_AND_KEEP_IF_FALSE";
|
when = "JUMP_AND_KEEP_IF_FALSE";
|
||||||
break;
|
break;
|
||||||
|
case JUMP_IF_COND_FALSE:
|
||||||
|
when = "JUMP_IF_COND_FALSE";
|
||||||
|
break;
|
||||||
|
case JUMP_IF_COND_TRUE:
|
||||||
|
when = "JUMP_IF_COND_TRUE";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
smsg("%4d %s -> %d", current, when,
|
smsg("%4d %s -> %d", current, when,
|
||||||
iptr->isn_arg.jump.jump_where);
|
iptr->isn_arg.jump.jump_where);
|
||||||
@@ -3342,6 +3371,7 @@ ex_disassemble(exarg_T *eap)
|
|||||||
iptr->isn_arg.checklen.cl_more_OK ? ">= " : "",
|
iptr->isn_arg.checklen.cl_more_OK ? ">= " : "",
|
||||||
iptr->isn_arg.checklen.cl_min_len);
|
iptr->isn_arg.checklen.cl_min_len);
|
||||||
break;
|
break;
|
||||||
|
case ISN_COND2BOOL: smsg("%4d COND2BOOL", current); break;
|
||||||
case ISN_2BOOL: if (iptr->isn_arg.number)
|
case ISN_2BOOL: if (iptr->isn_arg.number)
|
||||||
smsg("%4d INVERT (!val)", current);
|
smsg("%4d INVERT (!val)", current);
|
||||||
else
|
else
|
||||||
|
@@ -360,13 +360,12 @@ typval2type_int(typval_T *tv, garray_T *type_gap)
|
|||||||
need_convert_to_bool(type_T *type, typval_T *tv)
|
need_convert_to_bool(type_T *type, typval_T *tv)
|
||||||
{
|
{
|
||||||
return type != NULL && type == &t_bool && tv->v_type != VAR_BOOL
|
return type != NULL && type == &t_bool && tv->v_type != VAR_BOOL
|
||||||
&& ((tv->v_lock & VAR_BOOL_OK)
|
&& (tv->v_type == VAR_NUMBER
|
||||||
|| (tv->v_type == VAR_NUMBER
|
&& (tv->vval.v_number == 0 || tv->vval.v_number == 1));
|
||||||
&& (tv->vval.v_number == 0 || tv->vval.v_number == 1)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a type_T for a typval_T and handle VAR_BOOL_OK.
|
* Get a type_T for a typval_T.
|
||||||
* "type_list" is used to temporarily create types in.
|
* "type_list" is used to temporarily create types in.
|
||||||
*/
|
*/
|
||||||
type_T *
|
type_T *
|
||||||
@@ -375,9 +374,8 @@ typval2type(typval_T *tv, garray_T *type_gap)
|
|||||||
type_T *type = typval2type_int(tv, type_gap);
|
type_T *type = typval2type_int(tv, type_gap);
|
||||||
|
|
||||||
if (type != NULL && type != &t_bool
|
if (type != NULL && type != &t_bool
|
||||||
&& ((tv->v_type == VAR_NUMBER
|
&& (tv->v_type == VAR_NUMBER
|
||||||
&& (tv->vval.v_number == 0 || tv->vval.v_number == 1))
|
&& (tv->vval.v_number == 0 || tv->vval.v_number == 1)))
|
||||||
|| (tv->v_lock & VAR_BOOL_OK)))
|
|
||||||
{
|
{
|
||||||
type_T *newtype = get_type_ptr(type_gap);
|
type_T *newtype = get_type_ptr(type_gap);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user