Patch 8.2.1795
Problem: Vim9: operators && and || have a confusing result.
Solution: Make the result a boolean.
Files: runtime/doc/vim9.txt, src/eval.c, src/vim9compile.c,
src/vim9execute.c, src/vim9type.c, src/structs.h, src/vim9.h,
src/testdir/test_vim9_expr.vim, src/testdir/test_vim9_assign.vim,
src/testdir/test_vim9_cmd.vim,
src/testdir/test_vim9_disassemble.vim
*** ../vim-8.2.1794/runtime/doc/vim9.txt 2020-09-26 15:08:52.877779920 +0200
--- runtime/doc/vim9.txt 2020-10-03 22:48:15.127287808 +0200
***************
*** 65,70 ****
--- 65,99 ----
THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
+ Overview ~
+
+ Brief summary of the differences you will most often encounter when using Vim9
+ script and `:def` functions; details are below:
+ - Comments start with #, not ": >
+ echo "hello" # comment
+ - Using a backslash for line continuation is hardly ever needed: >
+ echo "hello "
+ .. yourName
+ .. ", how are you?"
+ - White space is required in many places.
+ - Assign values without `:let`, declare variables with `:var`: >
+ var count = 0
+ count += 3
+ - Constants can be declared with `:final` and `:const`: >
+ final matches = [] # add matches
+ const names = ['Betty', 'Peter'] # cannot be changed
+ - `:final` cannot be used as an abbreviation of `:finally`.
+ - Variables and functions are script-local by default.
+ - Functions are declared with argument types and return type: >
+ def CallMe(count: number, message: string): bool
+ - Call functions without `:call`: >
+ writefile(['done'], 'file.txt')
+ - You cannot use `:xit`, `:t`, `:append`, `:change`, `:insert` or curly-braces
+ names.
+ - A range before a command must be prefixed with a colon: >
+ :%s/this/that
+
+
Comments starting with # ~
In legacy Vim script comments start with double quote. In Vim9 script
***************
*** 125,149 ****
*vim9-scopes*
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
! prefixed. Using the "s:" prefix is optional. To define or use a global
! function or variable the "g:" prefix should be used. For functions in an
! autoload script the "name#" prefix is sufficient. >
def ThisFunction() # script-local
def s:ThisFunction() # script-local
def g:ThatFunction() # global
- def ThatFunction() # global if no local ThatFunction()
def scriptname#function() # autoload
! When using `:function` or `:def` to specify a new function inside a function,
! the function is local to the function. It is not possible to define a
! script-local function inside a function. It is possible to define a global
! function, using the "g:" prefix.
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
! imported) before looking for a global function.
! In all cases the 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
found in the script, either defined there or imported. Global functions and
--- 154,178 ----
*vim9-scopes*
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
! prefixed. Using the "s:" prefix is optional. To define a global function or
! variable the "g:" prefix must be used. For functions in an autoload script
! the "name#" prefix is sufficient. >
def ThisFunction() # script-local
def s:ThisFunction() # script-local
def g:ThatFunction() # global
def scriptname#function() # autoload
! When using `:function` or `:def` to specify a nested function inside a `:def`
! function, this nested function is local to the code block it is defined in.
! In a `:def` function IT is not possible to define a script-local function. it
! 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
prefer using a local function (in the function scope, script scope or
! imported) before looking for a global function. However, it is recommended to
! always use "g:" to refer to a local function for clarity. In all cases the
! 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
found in the script, either defined there or imported. Global functions and
***************
*** 155,161 ****
Variable declarations with :var, :final and :const ~
! *vim9-declaration*
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
section.
--- 184,190 ----
Variable declarations with :var, :final and :const ~
! *vim9-declaration* *:var*
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
section.
***************
*** 232,238 ****
myList = [3, 4] # Error!
myList[0] = 9 # Error!
muList->add(3) # Error!
!
`:final` is used for making only the variable a constant, the value can be
changed. This is well known from Java. Example: >
final myList = [1, 2]
--- 261,267 ----
myList = [3, 4] # Error!
myList[0] = 9 # Error!
muList->add(3) # Error!
! < *:final*
`:final` is used for making only the variable a constant, the value can be
changed. This is well known from Java. Example: >
final myList = [1, 2]
***************
*** 442,451 ****
difference is made where JavaScript does not work like most people expect.
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 ~
bool v:true or 1
number non-zero
--- 471,476 ----
***************
*** 461,477 ****
class when not NULL
object when not NULL (TODO: when isTrue() returns v:true)
! The boolean operators "||" and "&&" do not change the value: >
! 8 || 2 == 8
! 0 || 2 == 2
! 0 || '' == ''
! 8 && 2 == 2
! 0 && 2 == 0
! 2 && 0 == 0
! [] && 2 == []
! When using `..` for string concatenation arguments of simple types are always
! converted to string. >
'hello ' .. 123 == 'hello 123'
'hello ' .. v:true == 'hello v:true'
--- 486,510 ----
class when not NULL
object when not NULL (TODO: when isTrue() returns v:true)
! The boolean operators "||" and "&&" expect the values to be boolean, zero or
! one: >
! 1 || false == true
! 0 || 1 == true
! 0 || false == false
! 1 && true == true
! 0 && 1 == false
! 8 || 0 Error!
! 'yes' && 0 Error!
! [] || 99 Error!
!
! When using "!" for inverting, there is no error for using any type and the
! 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 ' .. v:true == 'hello v:true'
*** ../vim-8.2.1794/src/eval.c 2020-10-03 20:16:48.771216676 +0200
--- src/eval.c 2020-10-03 21:11:38.013436158 +0200
***************
*** 2296,2302 ****
int orig_flags;
long result = FALSE;
typval_T var2;
! int error;
int vim9script = in_vim9script();
if (evalarg == NULL)
--- 2296,2302 ----
int orig_flags;
long result = FALSE;
typval_T var2;
! int error = FALSE;
int vim9script = in_vim9script();
if (evalarg == NULL)
***************
*** 2309,2326 ****
if (evaluate)
{
if (vim9script)
! {
! result = tv2bool(rettv);
! }
! else
! {
! error = FALSE;
! if (tv_get_number_chk(rettv, &error) != 0)
! result = TRUE;
! clear_tv(rettv);
! if (error)
! return FAIL;
! }
}
/*
--- 2309,2320 ----
if (evaluate)
{
if (vim9script)
! result = tv_get_bool_chk(rettv, &error);
! else if (tv_get_number_chk(rettv, &error) != 0)
! result = TRUE;
! clear_tv(rettv);
! if (error)
! return FAIL;
}
/*
***************
*** 2362,2386 ****
if (evaluate && !result)
{
if (vim9script)
{
! clear_tv(rettv);
! *rettv = var2;
! result = tv2bool(rettv);
}
else
{
! if (tv_get_number_chk(&var2, &error) != 0)
! result = TRUE;
! 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);
}
--- 2356,2381 ----
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)
{
! rettv->v_type = VAR_BOOL;
! rettv->vval.v_number = result ? VVAL_TRUE : VVAL_FALSE;
}
else
{
! rettv->v_type = VAR_NUMBER;
! rettv->vval.v_number = result;
}
}
p = eval_next_non_blank(*arg, evalarg_used, &getnext);
}
***************
*** 2389,2397 ****
clear_evalarg(&local_evalarg, NULL);
else
evalarg->eval_flags = orig_flags;
-
- // Resulting value can be assigned to a bool.
- rettv->v_lock |= VAR_BOOL_OK;
}
return OK;
--- 2384,2389 ----
***************
*** 2430,2436 ****
int evaluate;
long result = TRUE;
typval_T var2;
! int error;
int vim9script = in_vim9script();
if (evalarg == NULL)
--- 2422,2428 ----
int evaluate;
long result = TRUE;
typval_T var2;
! int error = FALSE;
int vim9script = in_vim9script();
if (evalarg == NULL)
***************
*** 2443,2460 ****
if (evaluate)
{
if (vim9script)
! {
! result = tv2bool(rettv);
! }
! else
! {
! error = FALSE;
! if (tv_get_number_chk(rettv, &error) == 0)
! result = FALSE;
! clear_tv(rettv);
! if (error)
! return FAIL;
! }
}
/*
--- 2435,2446 ----
if (evaluate)
{
if (vim9script)
! result = tv_get_bool_chk(rettv, &error);
! else if (tv_get_number_chk(rettv, &error) == 0)
! result = FALSE;
! clear_tv(rettv);
! if (error)
! return FAIL;
}
/*
***************
*** 2466,2472 ****
*arg = eval_next_line(evalarg_used);
else
{
! if (evaluate && in_vim9script() && !VIM_ISWHITE(p[-1]))
{
error_white_both(p, 2);
clear_tv(rettv);
--- 2452,2458 ----
*arg = eval_next_line(evalarg_used);
else
{
! if (evaluate && vim9script && !VIM_ISWHITE(p[-1]))
{
error_white_both(p, 2);
clear_tv(rettv);
***************
*** 2497,2521 ****
if (evaluate && result)
{
if (vim9script)
{
! clear_tv(rettv);
! *rettv = var2;
! result = tv2bool(rettv);
}
else
{
! if (tv_get_number_chk(&var2, &error) == 0)
! result = FALSE;
! 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);
}
--- 2483,2508 ----
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)
{
! rettv->v_type = VAR_BOOL;
! rettv->vval.v_number = result ? VVAL_TRUE : VVAL_FALSE;
}
else
{
! rettv->v_type = VAR_NUMBER;
! rettv->vval.v_number = result;
}
}
p = eval_next_non_blank(*arg, evalarg_used, &getnext);
}
***************
*** 2524,2532 ****
clear_evalarg(&local_evalarg, NULL);
else
evalarg->eval_flags = orig_flags;
-
- // Resulting value can be assigned to a bool.
- rettv->v_lock |= VAR_BOOL_OK;
}
return OK;
--- 2511,2516 ----
*** ../vim-8.2.1794/src/vim9compile.c 2020-10-03 20:16:48.775216665 +0200
--- src/vim9compile.c 2020-10-03 22:24:36.363524418 +0200
***************
*** 706,711 ****
--- 706,730 ----
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
generate_TYPECHECK(
cctx_T *cctx,
***************
*** 4003,4009 ****
garray_T *instr = &cctx->ctx_instr;
garray_T end_ga;
garray_T *stack = &cctx->ctx_type_stack;
! type_T **typep;
/*
* Repeat until there is no following "||" or "&&"
--- 4022,4028 ----
garray_T *instr = &cctx->ctx_instr;
garray_T end_ga;
garray_T *stack = &cctx->ctx_type_stack;
! int all_bool_values = TRUE;
/*
* Repeat until there is no following "||" or "&&"
***************
*** 4023,4031 ****
return FAIL;
}
! // TODO: use ppconst if the value is a constant
generate_ppconst(cctx, ppconst);
if (ga_grow(&end_ga, 1) == FAIL)
{
ga_clear(&end_ga);
--- 4042,4054 ----
return FAIL;
}
! // TODO: use ppconst if the value is a constant and check
! // evaluating to bool
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)
{
ga_clear(&end_ga);
***************
*** 4034,4040 ****
*(((int *)end_ga.ga_data) + end_ga.ga_len) = instr->ga_len;
++end_ga.ga_len;
generate_JUMP(cctx, opchar == '|'
! ? JUMP_AND_KEEP_IF_TRUE : JUMP_AND_KEEP_IF_FALSE, 0);
// eval the next expression
*arg = skipwhite(p + 2);
--- 4057,4063 ----
*(((int *)end_ga.ga_data) + end_ga.ga_len) = instr->ga_len;
++end_ga.ga_len;
generate_JUMP(cctx, opchar == '|'
! ? JUMP_IF_COND_TRUE : JUMP_IF_COND_FALSE, 0);
// eval the next expression
*arg = skipwhite(p + 2);
***************
*** 4064,4082 ****
}
ga_clear(&end_ga);
! // The resulting type can be used as a bool.
! typep = ((type_T **)stack->ga_data) + stack->ga_len - 1;
! if (*typep != &t_bool)
! {
! 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;
--- 4087,4095 ----
}
ga_clear(&end_ga);
! // The resulting type is converted to bool if needed.
! if (!all_bool_values)
! generate_COND2BOOL(cctx);
}
return OK;
***************
*** 4087,4096 ****
*
* Produces instructions:
* EVAL expr4a Push result of "expr4a"
! * JUMP_AND_KEEP_IF_FALSE end
* EVAL expr4b Push result of "expr4b"
! * JUMP_AND_KEEP_IF_FALSE end
* EVAL expr4c Push result of "expr4c"
* end:
*/
static int
--- 4100,4110 ----
*
* Produces instructions:
* EVAL expr4a Push result of "expr4a"
! * JUMP_IF_COND_FALSE end
* EVAL expr4b Push result of "expr4b"
! * JUMP_IF_COND_FALSE end
* EVAL expr4c Push result of "expr4c"
+ * COND2BOOL
* end:
*/
static int
***************
*** 4111,4120 ****
*
* Produces instructions:
* EVAL expr3a Push result of "expr3a"
! * JUMP_AND_KEEP_IF_TRUE end
* EVAL expr3b Push result of "expr3b"
! * JUMP_AND_KEEP_IF_TRUE end
* EVAL expr3c Push result of "expr3c"
* end:
*/
static int
--- 4125,4135 ----
*
* Produces instructions:
* EVAL expr3a Push result of "expr3a"
! * JUMP_IF_COND_TRUE end
* EVAL expr3b Push result of "expr3b"
! * JUMP_IF_COND_TRUE end
* EVAL expr3c Push result of "expr3c"
+ * COND2BOOL
* end:
*/
static int
***************
*** 7415,7420 ****
--- 7430,7436 ----
case ISN_COMPARESPECIAL:
case ISN_COMPARESTRING:
case ISN_CONCAT:
+ case ISN_COND2BOOL:
case ISN_DROP:
case ISN_ECHO:
case ISN_ECHOERR:
*** ../vim-8.2.1794/src/vim9execute.c 2020-10-01 13:01:30.876933240 +0200
--- src/vim9execute.c 2020-10-03 22:15:03.401057661 +0200
***************
*** 1901,1914 ****
case ISN_JUMP:
{
jumpwhen_T when = iptr->isn_arg.jump.jump_when;
int jump = TRUE;
if (when != JUMP_ALWAYS)
{
tv = STACK_TV_BOT(-1);
! jump = tv2bool(tv);
if (when == JUMP_IF_FALSE
! || when == JUMP_AND_KEEP_IF_FALSE)
jump = !jump;
if (when == JUMP_IF_FALSE || !jump)
{
--- 1901,1925 ----
case ISN_JUMP:
{
jumpwhen_T when = iptr->isn_arg.jump.jump_when;
+ int error = FALSE;
int jump = TRUE;
if (when != JUMP_ALWAYS)
{
tv = STACK_TV_BOT(-1);
! 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
! || when == JUMP_AND_KEEP_IF_FALSE
! || when == JUMP_IF_COND_FALSE)
jump = !jump;
if (when == JUMP_IF_FALSE || !jump)
{
***************
*** 2624,2636 ****
break;
case ISN_2BOOL:
{
int n;
tv = STACK_TV_BOT(-1);
! n = tv2bool(tv);
! if (iptr->isn_arg.number) // invert
! n = !n;
clear_tv(tv);
tv->v_type = VAR_BOOL;
tv->vval.v_number = n ? VVAL_TRUE : VVAL_FALSE;
--- 2635,2659 ----
break;
case ISN_2BOOL:
+ case ISN_COND2BOOL:
{
int n;
+ int error = FALSE;
tv = STACK_TV_BOT(-1);
! if (iptr->isn_type == ISN_2BOOL)
! {
! 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);
tv->v_type = VAR_BOOL;
tv->vval.v_number = n ? VVAL_TRUE : VVAL_FALSE;
***************
*** 3192,3197 ****
--- 3215,3226 ----
case JUMP_AND_KEEP_IF_FALSE:
when = "JUMP_AND_KEEP_IF_FALSE";
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,
iptr->isn_arg.jump.jump_where);
***************
*** 3342,3347 ****
--- 3371,3377 ----
iptr->isn_arg.checklen.cl_more_OK ? ">= " : "",
iptr->isn_arg.checklen.cl_min_len);
break;
+ case ISN_COND2BOOL: smsg("%4d COND2BOOL", current); break;
case ISN_2BOOL: if (iptr->isn_arg.number)
smsg("%4d INVERT (!val)", current);
else
*** ../vim-8.2.1794/src/vim9type.c 2020-10-03 20:16:48.775216665 +0200
--- src/vim9type.c 2020-10-03 20:50:29.073621598 +0200
***************
*** 360,372 ****
need_convert_to_bool(type_T *type, typval_T *tv)
{
return type != NULL && type == &t_bool && tv->v_type != VAR_BOOL
! && ((tv->v_lock & VAR_BOOL_OK)
! || (tv->v_type == VAR_NUMBER
! && (tv->vval.v_number == 0 || tv->vval.v_number == 1)));
}
/*
! * Get a type_T for a typval_T and handle VAR_BOOL_OK.
* "type_list" is used to temporarily create types in.
*/
type_T *
--- 360,371 ----
need_convert_to_bool(type_T *type, typval_T *tv)
{
return type != NULL && type == &t_bool && tv->v_type != VAR_BOOL
! && (tv->v_type == VAR_NUMBER
! && (tv->vval.v_number == 0 || tv->vval.v_number == 1));
}
/*
! * Get a type_T for a typval_T.
* "type_list" is used to temporarily create types in.
*/
type_T *
***************
*** 375,383 ****
type_T *type = typval2type_int(tv, type_gap);
if (type != NULL && type != &t_bool
! && ((tv->v_type == VAR_NUMBER
! && (tv->vval.v_number == 0 || tv->vval.v_number == 1))
! || (tv->v_lock & VAR_BOOL_OK)))
{
type_T *newtype = get_type_ptr(type_gap);
--- 374,381 ----
type_T *type = typval2type_int(tv, type_gap);
if (type != NULL && type != &t_bool
! && (tv->v_type == VAR_NUMBER
! && (tv->vval.v_number == 0 || tv->vval.v_number == 1)))
{
type_T *newtype = get_type_ptr(type_gap);
*** ../vim-8.2.1794/src/structs.h 2020-09-16 15:41:06.470287510 +0200
--- src/structs.h 2020-10-03 20:49:29.513787627 +0200
***************
*** 1382,1388 ****
typedef struct
{
vartype_T v_type;
! char v_lock; // see below: VAR_LOCKED, VAR_FIXED, VAR_BOOL_OK
union
{
varnumber_T v_number; // number value
--- 1382,1388 ----
typedef struct
{
vartype_T v_type;
! char v_lock; // see below: VAR_LOCKED, VAR_FIXED
union
{
varnumber_T v_number; // number value
***************
*** 1409,1415 ****
// Values for "v_lock".
#define VAR_LOCKED 1 // locked with lock(), can use unlock()
#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.
--- 1409,1414 ----
*** ../vim-8.2.1794/src/vim9.h 2020-10-01 13:01:30.876933240 +0200
--- src/vim9.h 2020-10-03 21:43:27.946855130 +0200
***************
*** 128,134 ****
ISN_GETITEM, // push list item, isn_arg.number is the index
ISN_MEMBER, // dict[member]
ISN_STRINGMEMBER, // dict.member using isn_arg.string
! ISN_2BOOL, // convert value to bool, invert if isn_arg.number != 0
ISN_2STRING, // convert value to string at isn_arg.number on stack
ISN_2STRING_ANY, // like ISN_2STRING but check type
ISN_NEGATENR, // apply "-" to number
--- 128,135 ----
ISN_GETITEM, // push list item, isn_arg.number is the index
ISN_MEMBER, // dict[member]
ISN_STRINGMEMBER, // dict.member using isn_arg.string
! 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_ANY, // like ISN_2STRING but check type
ISN_NEGATENR, // apply "-" to number
***************
*** 171,178 ****
typedef enum {
JUMP_ALWAYS,
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_FALSE, // jump if top of stack is false, drop if not
} jumpwhen_T;
// arguments to ISN_JUMP
--- 172,181 ----
typedef enum {
JUMP_ALWAYS,
JUMP_IF_FALSE, // pop and jump if false
! 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 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;
// arguments to ISN_JUMP
*** ../vim-8.2.1794/src/testdir/test_vim9_expr.vim 2020-10-03 20:16:48.775216665 +0200
--- src/testdir/test_vim9_expr.vim 2020-10-03 22:27:15.835065220 +0200
***************
*** 196,227 ****
" test ||
def Test_expr2()
! assert_equal(2, 2 || 0)
! assert_equal(7, 0 ||
0 ||
! 7)
! assert_equal(0, 0 || 0)
! assert_equal(0, 0
|| 0)
! assert_equal('', 0 || '')
g:vals = []
! assert_equal(3, Record(3) || Record(1))
! assert_equal([3], g:vals)
g:vals = []
! assert_equal(5, Record(0) || Record(5))
! assert_equal([0, 5], g:vals)
g:vals = []
! assert_equal(4, Record(0)
! || Record(4)
|| Record(0))
! assert_equal([0, 4], g:vals)
g:vals = []
! assert_equal(0, Record([]) || Record('') || Record(0))
! assert_equal([[], '', 0], g:vals)
enddef
def Test_expr2_vimscript()
--- 196,227 ----
" test ||
def Test_expr2()
! assert_equal(true, 1 || 0)
! assert_equal(true, 0 ||
0 ||
! 1)
! assert_equal(false, 0 || 0)
! assert_equal(false, 0
|| 0)
! assert_equal(false, 0 || false)
g:vals = []
! assert_equal(true, Record(1) || Record(3))
! assert_equal([1], g:vals)
g:vals = []
! assert_equal(true, Record(0) || Record(1))
! assert_equal([0, 1], g:vals)
g:vals = []
! assert_equal(true, Record(0)
! || Record(1)
|| Record(0))
! assert_equal([0, 1], g:vals)
g:vals = []
! assert_equal(false, Record(0) || Record(false) || Record(0))
! assert_equal([0, false, 0], g:vals)
enddef
def Test_expr2_vimscript()
***************
*** 230,236 ****
vim9script
var name = 0
|| 1
! assert_equal(1, name)
END
CheckScriptSuccess(lines)
--- 230,236 ----
vim9script
var name = 0
|| 1
! assert_equal(true, name)
END
CheckScriptSuccess(lines)
***************
*** 269,348 ****
END
CheckScriptFailure(lines, 'E1004:', 2)
! # check keeping the value
lines =<< trim END
! vim9script
! assert_equal(2, 2 || 0)
! assert_equal(7, 0 ||
0 ||
! 7)
! assert_equal(0, 0 || 0)
! assert_equal(0, 0
|| 0)
! assert_equal('', 0 || '')
g:vals = []
! assert_equal(3, Record(3) || Record(1))
! assert_equal([3], g:vals)
g:vals = []
! assert_equal(5, Record(0) || Record(5))
! assert_equal([0, 5], g:vals)
g:vals = []
! assert_equal(4, Record(0)
! || Record(4)
|| Record(0))
! assert_equal([0, 4], g:vals)
g:vals = []
! assert_equal(0, Record([]) || Record('') || Record(0))
! assert_equal([[], '', 0], g:vals)
END
! CheckScriptSuccess(lines)
enddef
! func Test_expr2_fails()
! let 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 || xxx"], 'E1001:', 1)
! endfunc
" test &&
def Test_expr3()
! assert_equal(0, 2 && 0)
! assert_equal(0, 0 &&
0 &&
! 7)
! assert_equal(7, 2
! && 3
! && 7)
! assert_equal(0, 0 && 0)
! assert_equal(0, 0 && '')
! assert_equal('', 8 && '')
g:vals = []
! assert_equal(1, Record(3) && Record(1))
! assert_equal([3, 1], g:vals)
g:vals = []
! assert_equal(0, Record(0) && Record(5))
assert_equal([0], g:vals)
g:vals = []
! assert_equal(0, Record(0) && Record(4) && Record(0))
assert_equal([0], g:vals)
g:vals = []
! assert_equal(0, Record(8) && Record(4) && Record(0))
! assert_equal([8, 4, 0], g:vals)
g:vals = []
! assert_equal(0, Record([1]) && Record('z') && Record(0))
! assert_equal([[1], 'z', 0], g:vals)
enddef
def Test_expr3_vimscript()
--- 269,353 ----
END
CheckScriptFailure(lines, 'E1004:', 2)
! # check evaluating to bool
lines =<< trim END
! assert_equal(true, 1 || 0)
! assert_equal(true, 0 ||
0 ||
! !!7)
! assert_equal(false, 0 || 0)
! assert_equal(false, 0
|| 0)
! assert_equal(false, 0 || false)
g:vals = []
! assert_equal(true, Record(true) || Record(false))
! assert_equal([true], g:vals)
g:vals = []
! assert_equal(true, Record(0) || Record(true))
! assert_equal([0, true], g:vals)
g:vals = []
! assert_equal(true, Record(0)
! || Record(true)
|| Record(0))
! assert_equal([0, true], g:vals)
g:vals = []
! assert_equal(false, Record(0) || Record(false) || Record(0))
! assert_equal([0, false, 0], g:vals)
END
! CheckDefAndScriptSuccess(lines)
enddef
! def Test_expr2_fails()
! 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 || xxx"], 'E1001:', 1)
!
! # 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 &&
def Test_expr3()
! assert_equal(false, 1 && 0)
! assert_equal(false, 0 &&
0 &&
! 1)
! assert_equal(true, 1
! && true
! && 1)
! assert_equal(false, 0 && 0)
! assert_equal(false, 0 && false)
! assert_equal(true, 1 && true)
g:vals = []
! assert_equal(true, Record(true) && Record(1))
! assert_equal([true, 1], g:vals)
g:vals = []
! assert_equal(false, Record(0) && Record(1))
assert_equal([0], g:vals)
g:vals = []
! assert_equal(false, Record(0) && Record(4) && Record(0))
assert_equal([0], g:vals)
g:vals = []
! assert_equal(false, Record(1) && Record(true) && Record(0))
! assert_equal([1, true, 0], g:vals)
g:vals = []
! assert_equal(false, Record(1) && Record(true) && Record(0))
! assert_equal([1, true, 0], g:vals)
enddef
def Test_expr3_vimscript()
***************
*** 351,357 ****
vim9script
var name = 0
&& 1
! assert_equal(0, name)
END
CheckScriptSuccess(lines)
--- 356,362 ----
vim9script
var name = 0
&& 1
! assert_equal(false, name)
END
CheckScriptSuccess(lines)
***************
*** 393,428 ****
# check keeping the value
lines =<< trim END
vim9script
! assert_equal(0, 2 && 0)
! assert_equal(0, 0 &&
0 &&
! 7)
! assert_equal(7, 2
! && 3
! && 7)
! assert_equal(0, 0 && 0)
! assert_equal(0, 0 && '')
! assert_equal('', 8 && '')
g:vals = []
! assert_equal(1, Record(3) && Record(1))
! assert_equal([3, 1], g:vals)
g:vals = []
! assert_equal(0, Record(0) && Record(5))
assert_equal([0], g:vals)
g:vals = []
! assert_equal(0, Record(0) && Record(4) && Record(0))
assert_equal([0], g:vals)
g:vals = []
! assert_equal(0, Record(8) && Record(4) && Record(0))
! assert_equal([8, 4, 0], g:vals)
!
! g:vals = []
! assert_equal(0, Record([1]) && Record('z') && Record(0))
! assert_equal([[1], 'z', 0], g:vals)
END
CheckScriptSuccess(lines)
enddef
--- 398,429 ----
# check keeping the value
lines =<< trim END
vim9script
! assert_equal(false, 1 && 0)
! assert_equal(false, 0 &&
0 &&
! 1)
! assert_equal(true, 1
! && true
! && 1)
! assert_equal(false, 0 && 0)
! assert_equal(false, 0 && false)
! assert_equal(false, 1 && 0)
g:vals = []
! assert_equal(true, Record(1) && Record(true))
! assert_equal([1, true], g:vals)
g:vals = []
! assert_equal(false, Record(0) && Record(1))
assert_equal([0], g:vals)
g:vals = []
! assert_equal(false, Record(0) && Record(1) && Record(0))
assert_equal([0], g:vals)
g:vals = []
! assert_equal(false, Record(1) && Record(true) && Record(0))
! assert_equal([1, true, 0], g:vals)
END
CheckScriptSuccess(lines)
enddef
*** ../vim-8.2.1794/src/testdir/test_vim9_assign.vim 2020-09-30 22:59:37.904243979 +0200
--- src/testdir/test_vim9_assign.vim 2020-10-03 22:33:52.265895466 +0200
***************
*** 22,32 ****
var bool4: bool = 1
assert_equal(true, bool4)
! var bool5: bool = 'yes' && 'no'
assert_equal(true, bool5)
! var bool6: bool = [] && 99
assert_equal(false, bool6)
! var bool7: bool = [] || #{a: 1} && 99
assert_equal(true, bool7)
var lines =<< trim END
--- 22,32 ----
var bool4: bool = 1
assert_equal(true, bool4)
! var bool5: bool = 1 && true
assert_equal(true, bool5)
! var bool6: bool = 0 && 1
assert_equal(false, bool6)
! var bool7: bool = 0 || 1 && true
assert_equal(true, bool7)
var lines =<< trim END
***************
*** 41,49 ****
assert_equal(false, flag)
flag = 1
assert_equal(true, flag)
! flag = 99 || 123
assert_equal(true, flag)
! flag = 'yes' && []
assert_equal(false, flag)
END
CheckScriptSuccess(lines)
--- 41,49 ----
assert_equal(false, flag)
flag = 1
assert_equal(true, flag)
! flag = 1 || true
assert_equal(true, flag)
! flag = 1 && false
assert_equal(false, flag)
END
CheckScriptSuccess(lines)
*** ../vim-8.2.1794/src/testdir/test_vim9_cmd.vim 2020-09-27 22:47:01.880163387 +0200
--- src/testdir/test_vim9_cmd.vim 2020-10-03 22:34:44.521739226 +0200
***************
*** 72,79 ****
var lines =<< trim END
vim9script
if 1 &&
! 2
! || 3
g:res = 42
endif
assert_equal(42, g:res)
--- 72,79 ----
var lines =<< trim END
vim9script
if 1 &&
! true
! || 1
g:res = 42
endif
assert_equal(42, g:res)
*** ../vim-8.2.1794/src/testdir/test_vim9_disassemble.vim 2020-10-03 20:16:48.775216665 +0200
--- src/testdir/test_vim9_disassemble.vim 2020-10-03 22:41:11.484573913 +0200
***************
*** 766,776 ****
'\d LOAD arg\[-1]\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d COMPAREANY ==\_s*' ..
! '\d JUMP_AND_KEEP_IF_FALSE -> \d\+\_s*' ..
'\d LOAD arg\[-1]\_s*' ..
'\d PUSHNR 2\_s*' ..
'\d COMPAREANY !=\_s*' ..
! '\d JUMP_AND_KEEP_IF_TRUE -> \d\+\_s*' ..
'\d LOAD arg\[-1]\_s*' ..
'\d\+ PUSHNR 4\_s*' ..
'\d\+ COMPAREANY ==\_s*' ..
--- 766,776 ----
'\d LOAD arg\[-1]\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d COMPAREANY ==\_s*' ..
! '\d JUMP_IF_COND_FALSE -> \d\+\_s*' ..
'\d LOAD arg\[-1]\_s*' ..
'\d PUSHNR 2\_s*' ..
'\d COMPAREANY !=\_s*' ..
! '\d JUMP_IF_COND_TRUE -> \d\+\_s*' ..
'\d LOAD arg\[-1]\_s*' ..
'\d\+ PUSHNR 4\_s*' ..
'\d\+ COMPAREANY ==\_s*' ..
***************
*** 1200,1221 ****
enddef
def ReturnBool(): bool
! var var: bool = "no" && [] || 123
! return var
enddef
def Test_disassemble_return_bool()
var instr = execute('disassemble ReturnBool')
assert_match('ReturnBool\_s*' ..
! 'var var: bool = "no" && \[\] || 123\_s*' ..
! '0 PUSHS "no"\_s*' ..
! '1 JUMP_AND_KEEP_IF_FALSE -> 3\_s*' ..
! '2 NEWLIST size 0\_s*' ..
! '3 JUMP_AND_KEEP_IF_TRUE -> 5\_s*' ..
! '4 PUSHNR 123\_s*' ..
! '5 2BOOL (!!val)\_s*' ..
'\d STORE $0\_s*' ..
! 'return var\_s*' ..
'\d LOAD $0\_s*' ..
'\d RETURN',
instr)
--- 1200,1222 ----
enddef
def ReturnBool(): bool
! var name: bool = 1 && 0 || 1
! return name
enddef
def Test_disassemble_return_bool()
var instr = execute('disassemble ReturnBool')
assert_match('ReturnBool\_s*' ..
! 'var name: bool = 1 && 0 || 1\_s*' ..
! '0 PUSHNR 1\_s*' ..
! '1 JUMP_IF_COND_FALSE -> 3\_s*' ..
! '2 PUSHNR 0\_s*' ..
! '3 COND2BOOL\_s*' ..
! '4 JUMP_IF_COND_TRUE -> 6\_s*' ..
! '5 PUSHNR 1\_s*' ..
! '6 2BOOL (!!val)\_s*' ..
'\d STORE $0\_s*' ..
! 'return name\_s*' ..
'\d LOAD $0\_s*' ..
'\d RETURN',
instr)
*** ../vim-8.2.1794/src/version.c 2020-10-03 20:16:48.775216665 +0200
--- src/version.c 2020-10-03 22:45:42.051753334 +0200
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 1795,
/**/
--
"Space is big. Really big. You just won't believe how vastly hugely mind-
bogglingly big it is. I mean, you may think it's a long way down the
road to the chemist, but that's just peanuts to space."
-- Douglas Adams, "The Hitchhiker's Guide to the Galaxy"
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language --
http://www.Zimbu.org ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///