To: vim_dev@googlegroups.com Subject: Patch 8.2.1795 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 -- Bram@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 ///