Patch 8.2.5003

29 views
Skip to first unread message

Bram Moolenaar

unread,
May 22, 2022, 2:14:39 PM5/22/22
to vim...@googlegroups.com

Patch 8.2.5003
Problem: Cannot do bitwise shifts.
Solution: Add the >> and << operators. (Yegappan Lakshmanan, closes #8457)
Files: runtime/doc/eval.txt, src/errors.h, src/eval.c, src/structs.h,
src/vim.h, src/vim9execute.c, src/vim9expr.c,
src/testdir/test_expr.vim, src/testdir/test_vim9_disassemble.vim,
src/testdir/test_vim9_expr.vim


*** ../vim-8.2.5002/runtime/doc/eval.txt 2022-05-22 14:48:26.327247291 +0100
--- runtime/doc/eval.txt 2022-05-22 19:06:51.564142481 +0100
***************
*** 868,900 ****
expr5 isnot expr5 different |List|, |Dictionary| or |Blob|
instance

! |expr5| expr6
! expr6 + expr6 ... number addition, list or blob concatenation
! expr6 - expr6 ... number subtraction
! expr6 . expr6 ... string concatenation
! expr6 .. expr6 ... string concatenation

|expr6| expr7
! expr7 * expr7 ... number multiplication
! expr7 / expr7 ... number division
! expr7 % expr7 ... number modulo

|expr7| expr8
! <type>expr8 type check and conversion (|Vim9| only)

|expr8| expr9
! ! expr8 logical NOT
! - expr8 unary minus
! + expr8 unary plus

|expr9| expr10
! expr9[expr1] byte of a String or item of a |List|
! expr9[expr1 : expr1] substring of a String or sublist of a |List|
! expr9.name entry in a |Dictionary|
! expr9(expr1, ...) function call with |Funcref| variable
! expr9->name(expr1, ...) |method| call

! |expr10| number number constant
"string" string constant, backslash is special
'string' string constant, ' is doubled
[expr1, ...] |List|
--- 868,903 ----
expr5 isnot expr5 different |List|, |Dictionary| or |Blob|
instance

! |expr5| expr6 << expr6 bitwise left shift
! expr6 >> expr6 bitwise right shift

|expr6| expr7
! expr7 + expr7 ... number addition, list or blob concatenation
! expr7 - expr7 ... number subtraction
! expr7 . expr7 ... string concatenation
! expr7 .. expr7 ... string concatenation

|expr7| expr8
! expr8 * expr8 ... number multiplication
! expr8 / expr8 ... number division
! expr8 % expr8 ... number modulo

|expr8| expr9
! <type>expr9 type check and conversion (|Vim9| only)

|expr9| expr10
! ! expr9 logical NOT
! - expr9 unary minus
! + expr9 unary plus
!
! |expr10| expr11
! expr10[expr1] byte of a String or item of a |List|
! expr10[expr1 : expr1] substring of a String or sublist of a |List|
! expr10.name entry in a |Dictionary|
! expr10(expr1, ...) function call with |Funcref| variable
! expr10->name(expr1, ...) |method| call

! |expr11| number number constant
"string" string constant, backslash is special
'string' string constant, ' is doubled
[expr1, ...] |List|
***************
*** 1128,1141 ****
"foo\nbar" =~ "\\n" evaluates to 0


! expr5 and expr6 *expr5* *expr6* *E1036* *E1051*
---------------
! expr6 + expr6 Number addition, |List| or |Blob| concatenation *expr-+*
! expr6 - expr6 Number subtraction *expr--*
! expr6 . expr6 String concatenation *expr-.*
! expr6 .. expr6 String concatenation *expr-..*

! For |Lists| only "+" is possible and then both expr6 must be a list. The
result is a new list with the two lists Concatenated.

For String concatenation ".." is preferred, since "." is ambiguous, it is also
--- 1131,1156 ----
"foo\nbar" =~ "\\n" evaluates to 0


! expr5 *expr5* *bitwise-shift*
! -----
! expr6 << expr6 bitwise left shift *expr-<<*
! expr6 >> expr6 bitwise right shift *expr->>*
! *E1282* *E1283*
! The "<<" and ">>" operators can be used to perform bitwise left or right shift
! of the left operand by the number of bits specified by the right operand. The
! operands must be positive numbers. The topmost bit (sign bit) is always
! cleared for ">>". If the right operand (shift amount) is more than the
! maximum number of bits in a number (|v:numbersize|) the result is zero.
!
!
! expr6 and expr7 *expr6* *expr7* *E1036* *E1051*
---------------
! expr7 + expr7 Number addition, |List| or |Blob| concatenation *expr-+*
! expr7 - expr7 Number subtraction *expr--*
! expr7 . expr7 String concatenation *expr-.*
! expr7 .. expr7 String concatenation *expr-..*

! For |Lists| only "+" is possible and then both expr7 must be a list. The
result is a new list with the two lists Concatenated.

For String concatenation ".." is preferred, since "." is ambiguous, it is also
***************
*** 1147,1155 ****
types: Number, Float, Special and Bool. For other types |string()| should be
used.

! expr7 * expr7 Number multiplication *expr-star*
! expr7 / expr7 Number division *expr-/*
! expr7 % expr7 Number modulo *expr-%*

In legacy script, for all operators except "." and "..", Strings are converted
to Numbers.
--- 1162,1170 ----
types: Number, Float, Special and Bool. For other types |string()| should be
used.

! expr8 * expr8 Number multiplication *expr-star*
! expr8 / expr8 Number division *expr-/*
! expr8 % expr8 Number modulo *expr-%*

In legacy script, for all operators except "." and "..", Strings are converted
to Numbers.
***************
*** 1191,1208 ****
".", ".." and "%" do not work for Float. *E804* *E1035*


! expr7 *expr7*
-----
! <type>expr8

This is only available in |Vim9| script, see |type-casting|.


! expr8 *expr8*
-----
! ! expr8 logical NOT *expr-!*
! - expr8 unary minus *expr-unary--*
! + expr8 unary plus *expr-unary-+*

For '!' |TRUE| becomes |FALSE|, |FALSE| becomes |TRUE| (one).
For '-' the sign of the number is changed.
--- 1206,1223 ----
".", ".." and "%" do not work for Float. *E804* *E1035*


! expr8 *expr8*
-----
! <type>expr9

This is only available in |Vim9| script, see |type-casting|.


! expr9 *expr9*
-----
! ! expr9 logical NOT *expr-!*
! - expr9 unary minus *expr-unary--*
! + expr9 unary plus *expr-unary-+*

For '!' |TRUE| becomes |FALSE|, |FALSE| becomes |TRUE| (one).
For '-' the sign of the number is changed.
***************
*** 1224,1244 ****
--9 == 9


! expr9 *expr9*
! -----
! This expression is either |expr10| or a sequence of the alternatives below,
in any order. E.g., these are all possible:
! expr9[expr1].name
! expr9.name[expr1]
! expr9(expr1, ...)[expr1].name
! expr9->(expr1, ...)[expr1]
Evaluation is always from left to right.

! expr9[expr1] item of String or |List| *expr-[]* *E111*
*E909* *subscript* *E1062*
In legacy Vim script:
! If expr9 is a Number or String this results in a String that contains the
! expr1'th single byte from expr9. expr9 is used as a String (a number is
automatically converted to a String), expr1 as a Number. This doesn't
recognize multibyte encodings, see `byteidx()` for an alternative, or use
`split()` to turn the string into a list of characters. Example, to get the
--- 1239,1259 ----
--9 == 9


! expr10 *expr10*
! ------
! This expression is either |expr11| or a sequence of the alternatives below,
in any order. E.g., these are all possible:
! expr10[expr1].name
! expr10.name[expr1]
! expr10(expr1, ...)[expr1].name
! expr10->(expr1, ...)[expr1]
Evaluation is always from left to right.

! expr10[expr1] item of String or |List| *expr-[]* *E111*
*E909* *subscript* *E1062*
In legacy Vim script:
! If expr10 is a Number or String this results in a String that contains the
! expr1'th single byte from expr10. expr10 is used as a String (a number is
automatically converted to a String), expr1 as a Number. This doesn't
recognize multibyte encodings, see `byteidx()` for an alternative, or use
`split()` to turn the string into a list of characters. Example, to get the
***************
*** 1246,1253 ****
:let c = getline(".")[col(".") - 1]

In |Vim9| script: *E1147* *E1148*
! If expr9 is a String this results in a String that contains the expr1'th
! single character (including any composing characters) from expr9. To use byte
indexes use |strpart()|.

Index zero gives the first byte or character. Careful: text column numbers
--- 1261,1268 ----
:let c = getline(".")[col(".") - 1]

In |Vim9| script: *E1147* *E1148*
! If expr10 is a String this results in a String that contains the expr1'th
! single character (including any composing characters) from expr10. To use byte
indexes use |strpart()|.

Index zero gives the first byte or character. Careful: text column numbers
***************
*** 1258,1264 ****
compatibility). Use [-1:] to get the last byte or character.
In Vim9 script a negative index is used like with a list: count from the end.

! If expr9 is a |List| then it results the item at index expr1. See |list-index|
for possible index values. If the index is out of range this results in an
error. Example: >
:let item = mylist[-1] " get last item
--- 1273,1279 ----
compatibility). Use [-1:] to get the last byte or character.
In Vim9 script a negative index is used like with a list: count from the end.

! If expr10 is a |List| then it results the item at index expr1. See |list-index|
for possible index values. If the index is out of range this results in an
error. Example: >
:let item = mylist[-1] " get last item
***************
*** 1268,1281 ****
error.


! expr9[expr1a : expr1b] substring or sublist *expr-[:]*

! If expr9 is a String this results in the substring with the bytes or
! characters from expr1a to and including expr1b. expr9 is used as a String,
expr1a and expr1b are used as a Number.

In legacy Vim script the indexes are byte indexes. This doesn't recognize
! multibyte encodings, see |byteidx()| for computing the indexes. If expr9 is
a Number it is first converted to a String.

In Vim9 script the indexes are character indexes and include composing
--- 1283,1296 ----
error.


! expr10[expr1a : expr1b] substring or sublist *expr-[:]*

! If expr10 is a String this results in the substring with the bytes or
! characters from expr1a to and including expr1b. expr10 is used as a String,
expr1a and expr1b are used as a Number.

In legacy Vim script the indexes are byte indexes. This doesn't recognize
! multibyte encodings, see |byteidx()| for computing the indexes. If expr10 is
a Number it is first converted to a String.

In Vim9 script the indexes are character indexes and include composing
***************
*** 1302,1321 ****
:let s = s[:-3] " remove last two bytes
<
*slice*
! If expr9 is a |List| this results in a new |List| with the items indicated by
the indexes expr1a and expr1b. This works like with a String, as explained
just above. Also see |sublist| below. Examples: >
:let l = mylist[:3] " first four items
:let l = mylist[4:4] " List with one item
:let l = mylist[:] " shallow copy of a List

! If expr9 is a |Blob| this results in a new |Blob| with the bytes in the
indexes expr1a and expr1b, inclusive. Examples: >
:let b = 0zDEADBEEF
:let bs = b[1:2] " 0zADBE
:let bs = b[:] " copy of 0zDEADBEEF

! Using expr9[expr1] or expr9[expr1a : expr1b] on a |Funcref| results in an
error.

Watch out for confusion between a namespace and a variable followed by a colon
--- 1317,1336 ----
:let s = s[:-3] " remove last two bytes
<
*slice*
! If expr10 is a |List| this results in a new |List| with the items indicated by
the indexes expr1a and expr1b. This works like with a String, as explained
just above. Also see |sublist| below. Examples: >
:let l = mylist[:3] " first four items
:let l = mylist[4:4] " List with one item
:let l = mylist[:] " shallow copy of a List

! If expr10 is a |Blob| this results in a new |Blob| with the bytes in the
indexes expr1a and expr1b, inclusive. Examples: >
:let b = 0zDEADBEEF
:let bs = b[1:2] " 0zADBE
:let bs = b[:] " copy of 0zDEADBEEF

! Using expr10[expr1] or expr10[expr1a : expr1b] on a |Funcref| results in an
error.

Watch out for confusion between a namespace and a variable followed by a colon
***************
*** 1324,1334 ****
mylist[s:] " uses namespace s:, error!


! expr9.name entry in a |Dictionary| *expr-entry*
*E1203* *E1229*
! If expr9 is a |Dictionary| and it is followed by a dot, then the following
name will be used as a key in the |Dictionary|. This is just like:
! expr9[name].

The name must consist of alphanumeric characters, just like a variable name,
but it may start with a number. Curly braces cannot be used.
--- 1339,1349 ----
mylist[s:] " uses namespace s:, error!


! expr10.name entry in a |Dictionary| *expr-entry*
*E1203* *E1229*
! If expr10 is a |Dictionary| and it is followed by a dot, then the following
name will be used as a key in the |Dictionary|. This is just like:
! expr10[name].

The name must consist of alphanumeric characters, just like a variable name,
but it may start with a number. Curly braces cannot be used.
***************
*** 1345,1361 ****
always put spaces around the dot for String concatenation.


! expr9(expr1, ...) |Funcref| function call *E1085*

! When expr9 is a |Funcref| type variable, invoke the function it refers to.


! expr9->name([args]) method call *method* *->*
! expr9->{lambda}([args])
*E260* *E276* *E1265*
For methods that are also available as global functions this is the same as: >
! name(expr9 [, args])
! There can also be methods specifically for the type of "expr9".

This allows for chaining, passing the value that one method returns to the
next method: >
--- 1360,1376 ----
always put spaces around the dot for String concatenation.


! expr10(expr1, ...) |Funcref| function call *E1085*

! When expr10 is a |Funcref| type variable, invoke the function it refers to.


! expr10->name([args]) method call *method* *->*
! expr10->{lambda}([args])
*E260* *E276* *E1265*
For methods that are also available as global functions this is the same as: >
! name(expr10 [, args])
! There can also be methods specifically for the type of "expr10".

This allows for chaining, passing the value that one method returns to the
next method: >
***************
*** 1364,1370 ****
Example of using a lambda: >
GetPercentage()->{x -> x * 100}()->printf('%d%%')
<
! When using -> the |expr8| operators will be applied first, thus: >
-1.234->string()
Is equivalent to: >
(-1.234)->string()
--- 1379,1385 ----
Example of using a lambda: >
GetPercentage()->{x -> x * 100}()->printf('%d%%')
<
! When using -> the |expr9| operators will be applied first, thus: >
-1.234->string()
Is equivalent to: >
(-1.234)->string()
***************
*** 1393,1399 ****
(.


! *expr10*
number
------
number number constant *expr-number*
--- 1408,1414 ----
(.


! *expr11*
number
------
number number constant *expr-number*
*** ../vim-8.2.5002/src/errors.h 2022-05-18 15:03:58.171540249 +0100
--- src/errors.h 2022-05-22 18:57:17.987843294 +0100
***************
*** 3279,3281 ****
--- 3279,3287 ----
#endif
EXTERN char e_atom_engine_must_be_at_start_of_pattern[]
INIT(= N_("E1281: Atom '\\%%#=%c' must be at the start of the pattern"));
+ #ifdef FEAT_EVAL
+ EXTERN char e_bitshift_ops_must_be_number[]
+ INIT(= N_("E1282: bitshift operands must be numbers"));
+ EXTERN char e_bitshift_ops_must_be_postive[]
+ INIT(= N_("E1283: bitshift amount must be a positive number"));
+ #endif
*** ../vim-8.2.5002/src/eval.c 2022-05-10 13:24:17.632706901 +0100
--- src/eval.c 2022-05-22 19:13:18.984315611 +0100
***************
*** 49,58 ****
static int eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
static int eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
static int eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
! static int eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string);
! static int eval7t(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string);
static int eval7(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string);
! static int eval7_leader(typval_T *rettv, int numeric_only, char_u *start_leader, char_u **end_leaderp);

static int free_unref_items(int copyID);
static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end);
--- 49,59 ----
static int eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
static int eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
static int eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
! static int eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
static int eval7(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string);
! static int eval8(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string);
! static int eval9(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string);
! static int eval9_leader(typval_T *rettv, int numeric_only, char_u *start_leader, char_u **end_leaderp);

static int free_unref_items(int copyID);
static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end);
***************
*** 638,644 ****
char_u *name = *arg;

ref.v_type = VAR_UNKNOWN;
! if (eval7(arg, &ref, evalarg, FALSE) == FAIL)
{
dictitem_T *v;

--- 639,645 ----
char_u *name = *arg;

ref.v_type = VAR_UNKNOWN;
! if (eval9(arg, &ref, evalarg, FALSE) == FAIL)
{
dictitem_T *v;

***************
*** 2591,2597 ****
int getnext;

/*
! * Get the first variable.
*/
if (eval3(arg, rettv, evalarg) == FAIL)
return FAIL;
--- 2592,2598 ----
int getnext;

/*
! * Get the first expression.
*/
if (eval3(arg, rettv, evalarg) == FAIL)
return FAIL;
***************
*** 2717,2723 ****
int getnext;

/*
! * Get the first variable.
*/
if (eval4(arg, rettv, evalarg) == FAIL)
return FAIL;
--- 2718,2724 ----
int getnext;

/*
! * Get the first expression.
*/
if (eval4(arg, rettv, evalarg) == FAIL)
return FAIL;
***************
*** 2856,2867 ****
int type_is = FALSE;

/*
! * Get the first variable.
*/
if (eval5(arg, rettv, evalarg) == FAIL)
return FAIL;

p = eval_next_non_blank(*arg, evalarg, &getnext);
type = get_compare_type(p, &len, &type_is);

/*
--- 2857,2869 ----
int type_is = FALSE;

/*
! * Get the first expression.
*/
if (eval5(arg, rettv, evalarg) == FAIL)
return FAIL;

p = eval_next_non_blank(*arg, evalarg, &getnext);
+
type = get_compare_type(p, &len, &type_is);

/*
***************
*** 2991,2997 ****
}

/*
! * Handle fourth level expression:
* + number addition, concatenation of list or blob
* - number subtraction
* . string concatenation (if script version is 1)
--- 2993,3112 ----
}

/*
! * Handle the bitwise left/right shift operator expression:
! * var1 << var2
! * var1 >> var2
! *
! * "arg" must point to the first non-white of the expression.
! * "arg" is advanced to just after the recognized expression.
! *
! * Return OK or FAIL.
! */
! static int
! eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
! {
! /*
! * Get the first expression.
! */
! if (eval6(arg, rettv, evalarg) == FAIL)
! return FAIL;
!
! /*
! * Repeat computing, until no '<<' or '>>' is following.
! */
! for (;;)
! {
! char_u *p;
! int getnext;
! exprtype_T type;
! int evaluate;
! typval_T var2;
! int vim9script;
!
! p = eval_next_non_blank(*arg, evalarg, &getnext);
! if (p[0] == '<' && p[1] == '<')
! type = EXPR_LSHIFT;
! else if (p[0] == '>' && p[1] == '>')
! type = EXPR_RSHIFT;
! else
! return OK;
!
! // Handle a bitwise left or right shift operator
! if (rettv->v_type != VAR_NUMBER)
! {
! // left operand should be a number
! emsg(_(e_bitshift_ops_must_be_number));
! clear_tv(rettv);
! return FAIL;
! }
!
! evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
! vim9script = in_vim9script();
! if (getnext)
! {
! *arg = eval_next_line(*arg, evalarg);
! p = *arg;
! }
! else if (evaluate && vim9script && !VIM_ISWHITE(**arg))
! {
! error_white_both(*arg, 2);
! clear_tv(rettv);
! return FAIL;
! }
!
! /*
! * Get the second variable.
! */
! if (evaluate && vim9script && !IS_WHITE_OR_NUL(p[2]))
! {
! error_white_both(p, 2);
! clear_tv(rettv);
! return FAIL;
! }
! *arg = skipwhite_and_linebreak(p + 2, evalarg);
! if (eval6(arg, &var2, evalarg) == FAIL)
! {
! clear_tv(rettv);
! return FAIL;
! }
!
! if (var2.v_type != VAR_NUMBER || var2.vval.v_number < 0)
! {
! // right operand should be a positive number
! if (var2.v_type != VAR_NUMBER)
! emsg(_(e_bitshift_ops_must_be_number));
! else
! emsg(_(e_bitshift_ops_must_be_postive));
! clear_tv(rettv);
! clear_tv(&var2);
! return FAIL;
! }
!
! if (evaluate)
! {
! if (var2.vval.v_number > MAX_LSHIFT_BITS)
! // shifting more bits than we have always results in zero
! rettv->vval.v_number = 0;
! else if (type == EXPR_LSHIFT)
! rettv->vval.v_number =
! rettv->vval.v_number << var2.vval.v_number;
! else
! {
! rettv->vval.v_number =
! rettv->vval.v_number >> var2.vval.v_number;
! // clear the topmost sign bit
! rettv->vval.v_number &= ~((uvarnumber_T)1 << MAX_LSHIFT_BITS);
! }
! }
!
! clear_tv(&var2);
! }
!
! return OK;
! }
!
! /*
! * Handle fifth level expression:
* + number addition, concatenation of list or blob
* - number subtraction
* . string concatenation (if script version is 1)
***************
*** 3003,3014 ****
* Return OK or FAIL.
*/
static int
! eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
{
/*
! * Get the first variable.
*/
! if (eval6(arg, rettv, evalarg, FALSE) == FAIL)
return FAIL;

/*
--- 3118,3129 ----
* Return OK or FAIL.
*/
static int
! eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
{
/*
! * Get the first expression.
*/
! if (eval7(arg, rettv, evalarg, FALSE) == FAIL)
return FAIL;

/*
***************
*** 3086,3092 ****
return FAIL;
}
*arg = skipwhite_and_linebreak(*arg + oplen, evalarg);
! if (eval6(arg, &var2, evalarg, !vim9script && op == '.') == FAIL)
{
clear_tv(rettv);
return FAIL;
--- 3201,3207 ----
return FAIL;
}
*arg = skipwhite_and_linebreak(*arg + oplen, evalarg);
! if (eval7(arg, &var2, evalarg, !vim9script && op == '.') == FAIL)
{
clear_tv(rettv);
return FAIL;
***************
*** 3221,3227 ****
}

/*
! * Handle fifth level expression:
* * number multiplication
* / number division
* % number modulo
--- 3336,3342 ----
}

/*
! * Handle sixth level expression:
* * number multiplication
* / number division
* % number modulo
***************
*** 3232,3238 ****
* Return OK or FAIL.
*/
static int
! eval6(
char_u **arg,
typval_T *rettv,
evalarg_T *evalarg,
--- 3347,3353 ----
* Return OK or FAIL.
*/
static int
! eval7(
char_u **arg,
typval_T *rettv,
evalarg_T *evalarg,
***************
*** 3243,3251 ****
#endif

/*
! * Get the first variable.
*/
! if (eval7t(arg, rettv, evalarg, want_string) == FAIL)
return FAIL;

/*
--- 3358,3366 ----
#endif

/*
! * Get the first expression.
*/
! if (eval8(arg, rettv, evalarg, want_string) == FAIL)
return FAIL;

/*
***************
*** 3318,3324 ****
return FAIL;
}
*arg = skipwhite_and_linebreak(*arg + 1, evalarg);
! if (eval7t(arg, &var2, evalarg, FALSE) == FAIL)
return FAIL;

if (evaluate)
--- 3433,3439 ----
return FAIL;
}
*arg = skipwhite_and_linebreak(*arg + 1, evalarg);
! if (eval8(arg, &var2, evalarg, FALSE) == FAIL)
return FAIL;

if (evaluate)
***************
*** 3415,3421 ****
* Return OK or FAIL.
*/
static int
! eval7t(
char_u **arg,
typval_T *rettv,
evalarg_T *evalarg,
--- 3530,3536 ----
* Return OK or FAIL.
*/
static int
! eval8(
char_u **arg,
typval_T *rettv,
evalarg_T *evalarg,
***************
*** 3453,3459 ****
*arg = skipwhite_and_linebreak(*arg, evalarg);
}

! res = eval7(arg, rettv, evalarg, want_string);

if (want_type != NULL && evaluate)
{
--- 3568,3574 ----
*arg = skipwhite_and_linebreak(*arg, evalarg);
}

! res = eval9(arg, rettv, evalarg, want_string);

if (want_type != NULL && evaluate)
{
***************
*** 3642,3648 ****
* Return OK or FAIL.
*/
static int
! eval7(
char_u **arg,
typval_T *rettv,
evalarg_T *evalarg,
--- 3757,3763 ----
* Return OK or FAIL.
*/
static int
! eval9(
char_u **arg,
typval_T *rettv,
evalarg_T *evalarg,
***************
*** 3720,3726 ****
// "->" follows.
if (ret == OK && evaluate && end_leader > start_leader
&& rettv->v_type != VAR_BLOB)
! ret = eval7_leader(rettv, TRUE, start_leader, &end_leader);
break;

/*
--- 3835,3841 ----
// "->" follows.
if (ret == OK && evaluate && end_leader > start_leader
&& rettv->v_type != VAR_BLOB)
! ret = eval9_leader(rettv, TRUE, start_leader, &end_leader);
break;

/*
***************
*** 3920,3938 ****
* Apply logical NOT and unary '-', from right to left, ignore '+'.
*/
if (ret == OK && evaluate && end_leader > start_leader)
! ret = eval7_leader(rettv, FALSE, start_leader, &end_leader);

--recurse;
return ret;
}

/*
! * Apply the leading "!" and "-" before an eval7 expression to "rettv".
* When "numeric_only" is TRUE only handle "+" and "-".
* Adjusts "end_leaderp" until it is at "start_leader".
*/
static int
! eval7_leader(
typval_T *rettv,
int numeric_only,
char_u *start_leader,
--- 4035,4053 ----
* Apply logical NOT and unary '-', from right to left, ignore '+'.
*/
if (ret == OK && evaluate && end_leader > start_leader)
! ret = eval9_leader(rettv, FALSE, start_leader, &end_leader);

--recurse;
return ret;
}

/*
! * Apply the leading "!" and "-" before an eval9 expression to "rettv".
* When "numeric_only" is TRUE only handle "+" and "-".
* Adjusts "end_leaderp" until it is at "start_leader".
*/
static int
! eval9_leader(
typval_T *rettv,
int numeric_only,
char_u *start_leader,
*** ../vim-8.2.5002/src/structs.h 2022-05-21 20:16:51.011567174 +0100
--- src/structs.h 2022-05-22 18:25:44.089073531 +0100
***************
*** 4152,4157 ****
--- 4152,4159 ----
EXPR_MULT, // *
EXPR_DIV, // /
EXPR_REM, // %
+ EXPR_LSHIFT, // <<
+ EXPR_RSHIFT, // >>
// used with ISN_ADDLIST
EXPR_COPY, // create new list
EXPR_APPEND, // append to first list
*** ../vim-8.2.5002/src/vim.h 2022-05-09 20:09:19.294641425 +0100
--- src/vim.h 2022-05-22 18:25:44.089073531 +0100
***************
*** 2808,2811 ****
--- 2808,2812 ----
#define FFED_IS_GLOBAL 1 // "g:" was used
#define FFED_NO_GLOBAL 2 // only check for script-local functions

+ #define MAX_LSHIFT_BITS (varnumber_T)((sizeof(uvarnumber_T) * 8) - 1)
#endif // VIM__H
*** ../vim-8.2.5002/src/vim9execute.c 2022-05-21 21:55:49.456619728 +0100
--- src/vim9execute.c 2022-05-22 18:56:02.543796783 +0100
***************
*** 4055,4060 ****
--- 4055,4071 ----
varnumber_T res = 0;
int div_zero = FALSE;

+ if (iptr->isn_arg.op.op_type == EXPR_LSHIFT
+ || iptr->isn_arg.op.op_type == EXPR_RSHIFT)
+ {
+ if (arg2 < 0)
+ {
+ SOURCING_LNUM = iptr->isn_lnum;
+ emsg(_(e_bitshift_ops_must_be_postive));
+ goto on_error;
+ }
+ }
+
switch (iptr->isn_arg.op.op_type)
{
case EXPR_MULT: res = arg1 * arg2; break;
***************
*** 4077,4082 ****
--- 4088,4108 ----
case EXPR_GEQUAL: res = arg1 >= arg2; break;
case EXPR_SMALLER: res = arg1 < arg2; break;
case EXPR_SEQUAL: res = arg1 <= arg2; break;
+ case EXPR_LSHIFT: if (arg2 > MAX_LSHIFT_BITS)
+ res = 0;
+ else
+ res = arg1 << arg2;
+ break;
+ case EXPR_RSHIFT: if (arg2 > MAX_LSHIFT_BITS)
+ res = 0;
+ else
+ {
+ res = arg1 >> arg2;
+ // clear the topmost sign bit
+ res &= ~((uvarnumber_T)1
+ << MAX_LSHIFT_BITS);
+ }
+ break;
default: break;
}

***************
*** 6016,6021 ****
--- 6042,6049 ----
case EXPR_REM: what = "%"; break;
case EXPR_SUB: what = "-"; break;
case EXPR_ADD: what = "+"; break;
+ case EXPR_LSHIFT: what = "<<"; break;
+ case EXPR_RSHIFT: what = ">>"; break;
default: what = "???"; break;
}
switch (iptr->isn_type)
*** ../vim-8.2.5002/src/vim9expr.c 2022-05-17 15:03:29.702610338 +0100
--- src/vim9expr.c 2022-05-22 18:57:10.663838875 +0100
***************
*** 1748,1754 ****
return ret;
}

! static int compile_expr8(char_u **arg, cctx_T *cctx, ppconst_T *ppconst);

/*
* Compile whatever comes after "name" or "name()".
--- 1748,1754 ----
return ret;
}

! static int compile_expr9(char_u **arg, cctx_T *cctx, ppconst_T *ppconst);

/*
* Compile whatever comes after "name" or "name()".
***************
*** 1909,1915 ****
// do not look in the next line
cctx->ctx_ufunc->uf_lines.ga_len = 1;

! fail = compile_expr8(arg, cctx, ppconst) == FAIL
|| *skipwhite(*arg) != NUL;
*paren = '(';
--paren_follows_after_expr;
--- 1909,1915 ----
// do not look in the next line
cctx->ctx_ufunc->uf_lines.ga_len = 1;

! fail = compile_expr9(arg, cctx, ppconst) == FAIL
|| *skipwhite(*arg) != NUL;
*paren = '(';
--paren_follows_after_expr;
***************
*** 2143,2149 ****
* trailing ->name() method call
*/
static int
! compile_expr8(
char_u **arg,
cctx_T *cctx,
ppconst_T *ppconst)
--- 2143,2149 ----
* trailing ->name() method call
*/
static int
! compile_expr9(
char_u **arg,
cctx_T *cctx,
ppconst_T *ppconst)
***************
*** 2389,2398 ****
}

/*
! * <type>expr8: runtime type check / conversion
*/
static int
! compile_expr7(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
type_T *want_type = NULL;

--- 2389,2398 ----
}

/*
! * <type>expr9: runtime type check / conversion
*/
static int
! compile_expr8(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
type_T *want_type = NULL;

***************
*** 2417,2423 ****
return FAIL;
}

! if (compile_expr8(arg, cctx, ppconst) == FAIL)
return FAIL;

if (want_type != NULL)
--- 2417,2423 ----
return FAIL;
}

! if (compile_expr9(arg, cctx, ppconst) == FAIL)
return FAIL;

if (want_type != NULL)
***************
*** 2444,2457 ****
* % number modulo
*/
static int
! compile_expr6(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
char_u *op;
char_u *next;
int ppconst_used = ppconst->pp_used;

// get the first expression
! if (compile_expr7(arg, cctx, ppconst) == FAIL)
return FAIL;

/*
--- 2444,2457 ----
* % number modulo
*/
static int
! compile_expr7(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
char_u *op;
char_u *next;
int ppconst_used = ppconst->pp_used;

// get the first expression
! if (compile_expr8(arg, cctx, ppconst) == FAIL)
return FAIL;

/*
***************
*** 2477,2483 ****
return FAIL;

// get the second expression
! if (compile_expr7(arg, cctx, ppconst) == FAIL)
return FAIL;

if (ppconst->pp_used == ppconst_used + 2
--- 2477,2483 ----
return FAIL;

// get the second expression
! if (compile_expr8(arg, cctx, ppconst) == FAIL)
return FAIL;

if (ppconst->pp_used == ppconst_used + 2
***************
*** 2522,2528 ****
* .. string concatenation
*/
static int
! compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
char_u *op;
char_u *next;
--- 2522,2528 ----
* .. string concatenation
*/
static int
! compile_expr6(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
char_u *op;
char_u *next;
***************
*** 2530,2536 ****
int ppconst_used = ppconst->pp_used;

// get the first variable
! if (compile_expr6(arg, cctx, ppconst) == FAIL)
return FAIL;

/*
--- 2530,2536 ----
int ppconst_used = ppconst->pp_used;

// get the first variable
! if (compile_expr7(arg, cctx, ppconst) == FAIL)
return FAIL;

/*
***************
*** 2562,2568 ****
return FAIL;

// get the second expression
! if (compile_expr6(arg, cctx, ppconst) == FAIL)
return FAIL;

if (ppconst->pp_used == ppconst_used + 2
--- 2562,2568 ----
return FAIL;

// get the second expression
! if (compile_expr7(arg, cctx, ppconst) == FAIL)
return FAIL;

if (ppconst->pp_used == ppconst_used + 2
***************
*** 2621,2626 ****
--- 2621,2756 ----
}

/*
+ * expr6a >> expr6b
+ * expr6a << expr6b
+ *
+ * Produces instructions:
+ * OPNR bitwise left or right shift
+ */
+ static int
+ compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
+ {
+ exprtype_T type = EXPR_UNKNOWN;
+ char_u *p;
+ char_u *next;
+ int len = 2;
+ int ppconst_used = ppconst->pp_used;
+ typval_T *tv1;
+ typval_T *tv2;
+ isn_T *isn;
+
+ // get the first variable
+ if (compile_expr6(arg, cctx, ppconst) == FAIL)
+ return FAIL;
+
+ /*
+ * Repeat computing, until no "+", "-" or ".." is following.
+ */
+ for (;;)
+ {
+ type = EXPR_UNKNOWN;
+
+ p = may_peek_next_line(cctx, *arg, &next);
+ if (p[0] == '<' && p[1] == '<')
+ type = EXPR_LSHIFT;
+ else if (p[0] == '>' && p[1] == '>')
+ type = EXPR_RSHIFT;
+
+ if (type == EXPR_UNKNOWN)
+ return OK;
+
+ // Handle a bitwise left or right shift operator
+ if (ppconst->pp_used == ppconst_used + 1)
+ {
+ tv1 = &ppconst->pp_tv[ppconst->pp_used - 1];
+ if (tv1->v_type != VAR_NUMBER)
+ {
+ // left operand should be a number
+ emsg(_(e_bitshift_ops_must_be_number));
+ return FAIL;
+ }
+ }
+ else
+ {
+ type_T *t = get_type_on_stack(cctx, 0);
+
+ if (need_type(t, &t_number, 0, 0, cctx, FALSE, FALSE) == FAIL)
+ {
+ emsg(_(e_bitshift_ops_must_be_number));
+ return FAIL;
+ }
+ }
+
+ if (next != NULL)
+ {
+ *arg = next_line_from_context(cctx, TRUE);
+ p = skipwhite(*arg);
+ }
+
+ if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(p[len]))
+ {
+ error_white_both(p, len);
+ return FAIL;
+ }
+
+ // get the second variable
+ if (may_get_next_line_error(p + len, arg, cctx) == FAIL)
+ return FAIL;
+
+ if (compile_expr6(arg, cctx, ppconst) == FAIL)
+ return FAIL;
+
+ if (ppconst->pp_used == ppconst_used + 2)
+ {
+ // Both sides are a constant, compute the result now.
+ tv2 = &ppconst->pp_tv[ppconst->pp_used - 1];
+ if (tv2->v_type != VAR_NUMBER || tv2->vval.v_number < 0)
+ {
+ // right operand should be a positive number
+ if (tv2->v_type != VAR_NUMBER)
+ emsg(_(e_bitshift_ops_must_be_number));
+ else
+ emsg(_(e_bitshift_ops_must_be_postive));
+ return FAIL;
+ }
+
+ if (tv2->vval.v_number > MAX_LSHIFT_BITS)
+ tv1->vval.v_number = 0;
+ else if (type == EXPR_LSHIFT)
+ tv1->vval.v_number = tv1->vval.v_number << tv2->vval.v_number;
+ else
+ {
+ tv1->vval.v_number = tv1->vval.v_number >> tv2->vval.v_number;
+ // clear the topmost sign bit
+ tv1->vval.v_number &= ~((uvarnumber_T)1 << MAX_LSHIFT_BITS);
+ }
+ clear_tv(tv2);
+ --ppconst->pp_used;
+ }
+ else
+ {
+ if (need_type(get_type_on_stack(cctx, 0), &t_number, 0, 0, cctx,
+ FALSE, FALSE) == FAIL)
+ {
+ emsg(_(e_bitshift_ops_must_be_number));
+ return FAIL;
+ }
+
+ generate_ppconst(cctx, ppconst);
+
+ isn = generate_instr_drop(cctx, ISN_OPNR, 1);
+ if (isn == NULL)
+ return FAIL;
+
+ if (isn != NULL)
+ isn->isn_arg.op.op_type = type;
+ }
+ }
+
+ return OK;
+ }
+
+ /*
* expr5a == expr5b
* expr5a =~ expr5b
* expr5a != expr5b
***************
*** 2652,2657 ****
--- 2782,2788 ----
return FAIL;

p = may_peek_next_line(cctx, *arg, &next);
+
type = get_compare_type(p, &len, &type_is);

/*
*** ../vim-8.2.5002/src/testdir/test_expr.vim 2022-05-10 13:24:17.640706898 +0100
--- src/testdir/test_expr.vim 2022-05-22 18:58:54.647899723 +0100
***************
*** 946,949 ****
--- 946,1011 ----
call v9.CheckDefAndScriptSuccess(lines)
endfunc

+ " Test for bitwise left and right shift (<< and >>)
+ func Test_bitwise_shift()
+ let lines =<< trim END
+ call assert_equal(16, 1 << 4)
+ call assert_equal(2, 16 >> 3)
+ call assert_equal(0, 0 << 2)
+ call assert_equal(0, 0 >> 4)
+ call assert_equal(3, 3 << 0)
+ call assert_equal(3, 3 >> 0)
+ call assert_equal(0, 0 >> 4)
+ call assert_equal(0, 999999 >> 100)
+ call assert_equal(0, 999999 << 100)
+ VAR a = 8
+ VAR b = 2
+ call assert_equal(2, a >> b)
+ call assert_equal(32, a << b)
+ #" operator precedence
+ call assert_equal(48, 1 + 2 << 5 - 1)
+ call assert_equal(3, 8 + 4 >> 4 - 2)
+ call assert_true(1 << 2 < 1 << 3)
+ call assert_true(1 << 4 > 1 << 3)
+ VAR val = 0
+ for i in range(0, v:numbersize - 2)
+ LET val = or(val, 1 << i)
+ endfor
+ call assert_equal(v:numbermax, val)
+ LET val = v:numbermax
+ for i in range(0, v:numbersize - 2)
+ LET val = and(val, invert(1 << i))
+ endfor
+ call assert_equal(0, val)
+ #" multiple operators
+ call assert_equal(16, 1 << 2 << 2)
+ call assert_equal(4, 64 >> 2 >> 2)
+ call assert_true(1 << 2 << 2 == 256 >> 2 >> 2)
+ END
+ call v9.CheckLegacyAndVim9Success(lines)
+
+ call v9.CheckLegacyAndVim9Failure(['VAR v = 2 << -1'], ['E1283:', 'E1283:', 'E1283:'])
+ call v9.CheckLegacyAndVim9Failure(['VAR a = 2', 'VAR b = -1', 'VAR v = a << b'], ['E1283:', 'E1283:', 'E1283:'])
+ call v9.CheckLegacyAndVim9Failure(['VAR v = "8" >> 2'], ['E1282:', 'E1282:', 'E1282:'])
+ call v9.CheckLegacyAndVim9Failure(['VAR v = 1 << "2"'], ['E1282:', 'E1282:', 'E1282:'])
+ call v9.CheckLegacyAndVim9Failure(['VAR a = "8"', 'VAR b = 2', 'VAR v = a << b'], ['E1282:', 'E1012:', 'E1282:'])
+ call v9.CheckLegacyAndVim9Failure(['VAR a = 8', 'VAR b = "2"', 'VAR v = a >> b'], ['E1282:', 'E1012:', 'E1282:'])
+ call v9.CheckLegacyAndVim9Failure(['VAR v = ![] << 1'], ['E745:', 'E1012:', 'E1282:'])
+ call v9.CheckLegacyAndVim9Failure(['VAR v = 1 << ![]'], ['E745:', 'E1012:', 'E1282:'])
+ call v9.CheckLegacyAndVim9Failure(['VAR v = ![] >> 1'], ['E745:', 'E1012:', 'E1282:'])
+ call v9.CheckLegacyAndVim9Failure(['VAR v = 1 >> ![]'], ['E745:', 'E1012:', 'E1282:'])
+ call v9.CheckDefAndScriptFailure(['echo 1<< 2'], ['E1004:', 'E1004:'])
+ call v9.CheckDefAndScriptFailure(['echo 1 <<2'], ['E1004:', 'E1004:'])
+ call v9.CheckDefAndScriptFailure(['echo 1>> 2'], ['E1004:', 'E1004:'])
+ call v9.CheckDefAndScriptFailure(['echo 1 >>2'], ['E1004:', 'E1004:'])
+
+ let lines =<< trim END
+ var a = 1
+ <<
+ 4
+ assert_equal(16, a)
+ END
+ call v9.CheckDefAndScriptSuccess(lines)
+ endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.2.5002/src/testdir/test_vim9_disassemble.vim 2022-05-21 15:38:33.094080625 +0100
--- src/testdir/test_vim9_disassemble.vim 2022-05-22 18:25:44.089073531 +0100
***************
*** 2864,2867 ****
--- 2864,2894 ----
instr)
enddef

+ def BitShift()
+ var a = 1 << 2
+ var b = 8 >> 1
+ var c = a << b
+ var d = b << a
+ enddef
+
+ def Test_disassemble_bitshift()
+ var instr = execute('disassemble BitShift')
+ assert_match('BitShift\_s*' ..
+ 'var a = 1 << 2\_s*' ..
+ '0 STORE 4 in $0\_s*' ..
+ 'var b = 8 >> 1\_s*' ..
+ '1 STORE 4 in $1\_s*' ..
+ 'var c = a << b\_s*' ..
+ '2 LOAD $0\_s*' ..
+ '3 LOAD $1\_s*' ..
+ '4 OPNR <<\_s*' ..
+ '5 STORE $2\_s*' ..
+ 'var d = b << a\_s*' ..
+ '6 LOAD $1\_s*' ..
+ '7 LOAD $0\_s*' ..
+ '8 OPNR <<\_s*' ..
+ '9 STORE $3\_s*' ..
+ '10 RETURN void', instr)
+ enddef
+
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
*** ../vim-8.2.5002/src/testdir/test_vim9_expr.vim 2022-05-17 15:03:29.706610336 +0100
--- src/testdir/test_vim9_expr.vim 2022-05-22 18:25:44.089073531 +0100
***************
*** 1483,1490 ****
endif
endfunc

" test addition, subtraction, concatenation
! def Test_expr5()
var lines =<< trim END
assert_equal(66, 60 + 6)
assert_equal(70, 60 +
--- 1483,1495 ----
endif
endfunc

+ " test bitwise left and right shift operators
+ " The tests for this is in test_expr.vim (Test_bitwise_shift)
+ " def Test_expr5()
+ " enddef
+
" test addition, subtraction, concatenation
! def Test_expr6()
var lines =<< trim END
assert_equal(66, 60 + 6)
assert_equal(70, 60 +
***************
*** 1549,1555 ****
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr5_vim9script()
# check line continuation
var lines =<< trim END
var name = 11
--- 1554,1560 ----
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr6_vim9script()
# check line continuation
var lines =<< trim END
var name = 11
***************
*** 1698,1704 ****
endfor
enddef

! def Test_expr5_vim9script_channel()
if !has('channel')
MissingFeature 'channel'
else
--- 1703,1709 ----
endfor
enddef

! def Test_expr6_vim9script_channel()
if !has('channel')
MissingFeature 'channel'
else
***************
*** 1713,1719 ****
endif
enddef

! def Test_expr5_float()
if !has('float')
MissingFeature 'float'
else
--- 1718,1724 ----
endif
enddef

! def Test_expr6_float()
if !has('float')
MissingFeature 'float'
else
***************
*** 1741,1747 ****
endif
enddef

! func Test_expr5_fails()
let msg = "White space required before and after '+'"
call v9.CheckDefAndScriptFailure(["var x = 1+2"], msg, 1)
call v9.CheckDefAndScriptFailure(["var x = 1 +2"], msg, 1)
--- 1746,1752 ----
endif
enddef

! func Test_expr6_fails()
let msg = "White space required before and after '+'"
call v9.CheckDefAndScriptFailure(["var x = 1+2"], msg, 1)
call v9.CheckDefAndScriptFailure(["var x = 1 +2"], msg, 1)
***************
*** 1780,1793 ****
call v9.CheckDefAndScriptFailure(['var x = 1 + false'], ['E1051:', 'E1138:'], 1)
endfunc

! func Test_expr5_fails_channel()
CheckFeature channel

call v9.CheckDefAndScriptFailure(["var x = 'a' .. test_null_job()"], ['E1105:', 'E908:'], 1)
call v9.CheckDefAndScriptFailure(["var x = 'a' .. test_null_channel()"], ['E1105:', 'E908:'], 1)
endfunc

! def Test_expr5_list_add()
var lines =<< trim END
# concatenating two lists with same member types is OK
var d = {}
--- 1785,1798 ----
call v9.CheckDefAndScriptFailure(['var x = 1 + false'], ['E1051:', 'E1138:'], 1)
endfunc

! func Test_expr6_fails_channel()
CheckFeature channel

call v9.CheckDefAndScriptFailure(["var x = 'a' .. test_null_job()"], ['E1105:', 'E908:'], 1)
call v9.CheckDefAndScriptFailure(["var x = 'a' .. test_null_channel()"], ['E1105:', 'E908:'], 1)
endfunc

! def Test_expr6_list_add()
var lines =<< trim END
# concatenating two lists with same member types is OK
var d = {}
***************
*** 1818,1824 ****
enddef

" test multiply, divide, modulo
! def Test_expr6()
var lines =<< trim END
assert_equal(36, 6 * 6)
assert_equal(24, 6 *
--- 1823,1829 ----
enddef

" test multiply, divide, modulo
! def Test_expr7()
var lines =<< trim END
assert_equal(36, 6 * 6)
assert_equal(24, 6 *
***************
*** 1890,1896 ****
v9.CheckDefExecAndScriptFailure(lines, 'E1154', 2)
enddef

! def Test_expr6_vim9script()
# check line continuation
var lines =<< trim END
var name = 11
--- 1895,1901 ----
v9.CheckDefExecAndScriptFailure(lines, 'E1154', 2)
enddef

! def Test_expr7_vim9script()
# check line continuation
var lines =<< trim END
var name = 11
***************
*** 1942,1948 ****
v9.CheckDefAndScriptFailure(lines, 'E1004:', 1)
enddef

! def Test_expr6_float()
if !has('float')
MissingFeature 'float'
else
--- 1947,1953 ----
v9.CheckDefAndScriptFailure(lines, 'E1004:', 1)
enddef

! def Test_expr7_float()
if !has('float')
MissingFeature 'float'
else
***************
*** 1975,1981 ****
endif
enddef

! func Test_expr6_fails()
let msg = "White space required before and after '*'"
call v9.CheckDefAndScriptFailure(["var x = 1*2"], msg, 1)
call v9.CheckDefAndScriptFailure(["var x = 1 *2"], msg, 1)
--- 1980,1986 ----
endif
enddef

! func Test_expr7_fails()
let msg = "White space required before and after '*'"
call v9.CheckDefAndScriptFailure(["var x = 1*2"], msg, 1)
call v9.CheckDefAndScriptFailure(["var x = 1 *2"], msg, 1)
***************
*** 2019,2025 ****
endfor
endfunc

! func Test_expr6_float_fails()
CheckFeature float
call v9.CheckDefAndScriptFailure(["var x = 1.0 % 2"], ['E1035:', 'E804:'], 1)
endfunc
--- 2024,2030 ----
endfor
endfunc

! func Test_expr7_float_fails()
CheckFeature float
call v9.CheckDefAndScriptFailure(["var x = 1.0 % 2"], ['E1035:', 'E804:'], 1)
endfunc
***************
*** 2053,2059 ****
let $TESTVAR = 'testvar'

" type casts
! def Test_expr7()
var lines =<< trim END
var ls: list<string> = ['a', <string>g:string_empty]
var ln: list<number> = [<number>g:anint, <number>g:thefour]
--- 2058,2064 ----
let $TESTVAR = 'testvar'

" type casts
! def Test_expr8()
var lines =<< trim END
var ls: list<string> = ['a', <string>g:string_empty]
var ln: list<number> = [<number>g:anint, <number>g:thefour]
***************
*** 2079,2085 ****
enddef

" test low level expression
! def Test_expr8_number()
# number constant
var lines =<< trim END
assert_equal(0, 0)
--- 2084,2090 ----
enddef

" test low level expression
! def Test_expr9_number()
# number constant
var lines =<< trim END
assert_equal(0, 0)
***************
*** 2092,2098 ****
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr8_float()
# float constant
if !has('float')
MissingFeature 'float'
--- 2097,2103 ----
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr9_float()
# float constant
if !has('float')
MissingFeature 'float'
***************
*** 2107,2113 ****
endif
enddef

! def Test_expr8_blob()
# blob constant
var lines =<< trim END
assert_equal(g:blob_empty, 0z)
--- 2112,2118 ----
endif
enddef

! def Test_expr9_blob()
# blob constant
var lines =<< trim END
assert_equal(g:blob_empty, 0z)
***************
*** 2139,2145 ****
v9.CheckDefAndScriptFailure(["var x = 0z123"], 'E973:', 1)
enddef

! def Test_expr8_string()
# string constant
var lines =<< trim END
assert_equal(g:string_empty, '')
--- 2144,2150 ----
v9.CheckDefAndScriptFailure(["var x = 0z123"], 'E973:', 1)
enddef

! def Test_expr9_string()
# string constant
var lines =<< trim END
assert_equal(g:string_empty, '')
***************
*** 2180,2186 ****
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr8_vimvar()
v:errors = []
var errs: list<string> = v:errors
v9.CheckDefFailure(['var errs: list<number> = v:errors'], 'E1012:')
--- 2185,2191 ----
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr9_vimvar()
v:errors = []
var errs: list<string> = v:errors
v9.CheckDefFailure(['var errs: list<number> = v:errors'], 'E1012:')
***************
*** 2205,2211 ****
bwipe!
enddef

! def Test_expr8_special()
# special constant
var lines =<< trim END
assert_equal(g:special_true, true)
--- 2210,2216 ----
bwipe!
enddef

! def Test_expr9_special()
# special constant
var lines =<< trim END
assert_equal(g:special_true, true)
***************
*** 2242,2248 ****
v9.CheckDefAndScriptFailure(['v:none = 22'], 'E46:', 1)
enddef

! def Test_expr8_list()
# list
var lines =<< trim END
assert_equal(g:list_empty, [])
--- 2247,2253 ----
v9.CheckDefAndScriptFailure(['v:none = 22'], 'E46:', 1)
enddef

! def Test_expr9_list()
# list
var lines =<< trim END
assert_equal(g:list_empty, [])
***************
*** 2320,2326 ****
v9.CheckDefAndScriptFailure(lines + ['echo numbers[a :b]'], 'E1004:', 4)
enddef

! def Test_expr8_list_vim9script()
var lines =<< trim END
var l = [
11,
--- 2325,2331 ----
v9.CheckDefAndScriptFailure(lines + ['echo numbers[a :b]'], 'E1004:', 4)
enddef

! def Test_expr9_list_vim9script()
var lines =<< trim END
var l = [
11,
***************
*** 2408,2414 ****
x == 2
enddef

! def Test_expr8_lambda()
var lines =<< trim END
var La = () => 'result'
# comment
--- 2413,2419 ----
x == 2
enddef

! def Test_expr9_lambda()
var lines =<< trim END
var La = () => 'result'
# comment
***************
*** 2494,2500 ****
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr8_lambda_block()
var lines =<< trim END
var Func = (s: string): string => {
return 'hello ' .. s
--- 2499,2505 ----
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr9_lambda_block()
var lines =<< trim END
var Func = (s: string): string => {
return 'hello ' .. s
***************
*** 2574,2580 ****
x == 2
enddef

! def Test_expr8_new_lambda()
var lines =<< trim END
var La = () => 'result'
assert_equal('result', La())
--- 2579,2585 ----
x == 2
enddef

! def Test_expr9_new_lambda()
var lines =<< trim END
var La = () => 'result'
assert_equal('result', La())
***************
*** 2659,2665 ****
v9.CheckDefAndScriptFailure(['var Fx = (a) => [0', ' 1]'], 'E696:', 2)
enddef

! def Test_expr8_lambda_vim9script()
var lines =<< trim END
var v = 10->((a) =>
a
--- 2664,2670 ----
v9.CheckDefAndScriptFailure(['var Fx = (a) => [0', ' 1]'], 'E696:', 2)
enddef

! def Test_expr9_lambda_vim9script()
var lines =<< trim END
var v = 10->((a) =>
a
***************
*** 2678,2684 ****
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr8funcref()
var lines =<< trim END
def RetNumber(): number
return 123
--- 2683,2689 ----
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr9funcref()
var lines =<< trim END
def RetNumber(): number
return 123
***************
*** 2730,2736 ****
let g:test_space_dict = {'': 'empty', ' ': 'space'}
let g:test_hash_dict = #{one: 1, two: 2}

! def Test_expr8_dict()
# dictionary
var lines =<< trim END
assert_equal(g:dict_empty, {})
--- 2735,2741 ----
let g:test_space_dict = {'': 'empty', ' ': 'space'}
let g:test_hash_dict = #{one: 1, two: 2}

! def Test_expr9_dict()
# dictionary
var lines =<< trim END
assert_equal(g:dict_empty, {})
***************
*** 2850,2856 ****
v9.CheckDefExecAndScriptFailure(['{}[getftype("file")]'], 'E716: Key not present in Dictionary: ""', 1)
enddef

! def Test_expr8_dict_vim9script()
var lines =<< trim END
var d = {
['one']:
--- 2855,2861 ----
v9.CheckDefExecAndScriptFailure(['{}[getftype("file")]'], 'E716: Key not present in Dictionary: ""', 1)
enddef

! def Test_expr9_dict_vim9script()
var lines =<< trim END
var d = {
['one']:
***************
*** 2981,2987 ****
v9.CheckScriptSuccess(lines)
enddef

! def Test_expr8_dict_in_block()
var lines =<< trim END
vim9script
command MyCommand {
--- 2986,2992 ----
v9.CheckScriptSuccess(lines)
enddef

! def Test_expr9_dict_in_block()
var lines =<< trim END
vim9script
command MyCommand {
***************
*** 3004,3010 ****
delcommand YourCommand
enddef

! def Test_expr8_call_2bool()
var lines =<< trim END
vim9script

--- 3009,3015 ----
delcommand YourCommand
enddef

! def Test_expr9_call_2bool()
var lines =<< trim END
vim9script

***************
*** 3052,3058 ****
v9.CheckDefExecAndScriptFailure(["var d: dict<number>", "d = g:list_empty"], 'E1012: Type mismatch; expected dict<number> but got list<unknown>', 2)
enddef

! def Test_expr8_any_index_slice()
var lines =<< trim END
# getting the one member should clear the list only after getting the item
assert_equal('bbb', ['aaa', 'bbb', 'ccc'][1])
--- 3057,3063 ----
v9.CheckDefExecAndScriptFailure(["var d: dict<number>", "d = g:list_empty"], 'E1012: Type mismatch; expected dict<number> but got list<unknown>', 2)
enddef

! def Test_expr9_any_index_slice()
var lines =<< trim END
# getting the one member should clear the list only after getting the item
assert_equal('bbb', ['aaa', 'bbb', 'ccc'][1])
***************
*** 3223,3229 ****
b:someVar = &fdm
enddef

! def Test_expr8_option()
var lines =<< trim END
# option
set ts=11
--- 3228,3234 ----
b:someVar = &fdm
enddef

! def Test_expr9_option()
var lines =<< trim END
# option
set ts=11
***************
*** 3250,3256 ****
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr8_environment()
var lines =<< trim END
# environment variable
assert_equal('testvar', $TESTVAR)
--- 3255,3261 ----
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr9_environment()
var lines =<< trim END
# environment variable
assert_equal('testvar', $TESTVAR)
***************
*** 3262,3268 ****
v9.CheckDefAndScriptFailure(["$"], ['E1002:', 'E15:'], 1)
enddef

! def Test_expr8_register()
var lines =<< trim END
@a = 'register a'
assert_equal('register a', @a)
--- 3267,3273 ----
v9.CheckDefAndScriptFailure(["$"], ['E1002:', 'E15:'], 1)
enddef

! def Test_expr9_register()
var lines =<< trim END
@a = 'register a'
assert_equal('register a', @a)
***************
*** 3288,3294 ****
enddef

" This is slow when run under valgrind.
! def Test_expr8_namespace()
var lines =<< trim END
g:some_var = 'some'
assert_equal('some', get(g:, 'some_var'))
--- 3293,3299 ----
enddef

" This is slow when run under valgrind.
! def Test_expr9_namespace()
var lines =<< trim END
g:some_var = 'some'
assert_equal('some', get(g:, 'some_var'))
***************
*** 3317,3323 ****
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr8_namespace_loop_def()
var lines =<< trim END
# check using g: in a for loop more than DO_NOT_FREE_CNT times
var exists = 0
--- 3322,3328 ----
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr9_namespace_loop_def()
var lines =<< trim END
# check using g: in a for loop more than DO_NOT_FREE_CNT times
var exists = 0
***************
*** 3336,3343 ****
enddef

" NOTE: this is known to be slow. To skip use:
! " :let $TEST_SKIP_PAT = 'Test_expr8_namespace_loop_script'
! def Test_expr8_namespace_loop_script()
var lines =<< trim END
vim9script
# check using g: in a for loop more than DO_NOT_FREE_CNT times
--- 3341,3348 ----
enddef

" NOTE: this is known to be slow. To skip use:
! " :let $TEST_SKIP_PAT = 'Test_expr9_namespace_loop_script'
! def Test_expr9_namespace_loop_script()
var lines =<< trim END
vim9script
# check using g: in a for loop more than DO_NOT_FREE_CNT times
***************
*** 3356,3362 ****
v9.CheckScriptSuccess(lines)
enddef

! def Test_expr8_parens()
# (expr)
var lines =<< trim END
assert_equal(4, (6 * 4) / 6)
--- 3361,3367 ----
v9.CheckScriptSuccess(lines)
enddef

! def Test_expr9_parens()
# (expr)
var lines =<< trim END
assert_equal(4, (6 * 4) / 6)
***************
*** 3403,3409 ****
unlet g:result
enddef

! def Test_expr8_negate_add()
var lines =<< trim END
assert_equal(-99, -99)
assert_equal(-99, - 99)
--- 3408,3414 ----
unlet g:result
enddef

! def Test_expr9_negate_add()
var lines =<< trim END
assert_equal(-99, -99)
assert_equal(-99, - 99)
***************
*** 3452,3458 ****
legacy return #{key: 'ok'}.key
enddef

! def Test_expr8_legacy_script()
var lines =<< trim END
let s:legacy = 'legacy'
def GetLocal(): string
--- 3457,3463 ----
legacy return #{key: 'ok'}.key
enddef

! def Test_expr9_legacy_script()
var lines =<< trim END
let s:legacy = 'legacy'
def GetLocal(): string
***************
*** 3495,3501 ****
return arg
enddef

! def Test_expr8_call()
var lines =<< trim END
assert_equal('yes', 'yes'->g:Echo())
assert_equal(true, !range(5)->empty())
--- 3500,3506 ----
return arg
enddef

! def Test_expr9_call()
var lines =<< trim END
assert_equal('yes', 'yes'->g:Echo())
assert_equal(true, !range(5)->empty())
***************
*** 3518,3524 ****
return 'existing'
enddef

! def Test_expr8_call_global()
assert_equal('existing', g:ExistingGlobal())

def g:DefinedLater(): string
--- 3523,3529 ----
return 'existing'
enddef

! def Test_expr9_call_global()
assert_equal('existing', g:ExistingGlobal())

def g:DefinedLater(): string
***************
*** 3532,3538 ****
v9.CheckDefAndScriptFailure(lines, 'E117: Unknown function: ExistingGlobal')
enddef

! def Test_expr8_autoload_var()
var auto_lines =<< trim END
let autofile#var = 'found'
END
--- 3537,3543 ----
v9.CheckDefAndScriptFailure(lines, 'E117: Unknown function: ExistingGlobal')
enddef

! def Test_expr9_autoload_var()
var auto_lines =<< trim END
let autofile#var = 'found'
END
***************
*** 3555,3561 ****
delete('Xruntime', 'rf')
enddef

! def Test_expr8_call_autoload()
var auto_lines =<< trim END
def g:some#func(): string
return 'found'
--- 3560,3566 ----
delete('Xruntime', 'rf')
enddef

! def Test_expr9_call_autoload()
var auto_lines =<< trim END
def g:some#func(): string
return 'found'
***************
*** 3572,3578 ****
delete('Xruntime', 'rf')
enddef

! def Test_expr8_method_call()
var lines =<< trim END
new
setline(1, ['first', 'last'])
--- 3577,3583 ----
delete('Xruntime', 'rf')
enddef

! def Test_expr9_method_call()
var lines =<< trim END
new
setline(1, ['first', 'last'])
***************
*** 3663,3669 ****
v9.CheckDefFailure(lines, 'E15: Invalid expression: "->SetList[0]x()"')
enddef

! def Test_expr8_method_call_linebreak()
# this was giving an error when skipping over the expression
var lines =<< trim END
vim9script
--- 3668,3674 ----
v9.CheckDefFailure(lines, 'E15: Invalid expression: "->SetList[0]x()"')
enddef

! def Test_expr9_method_call_linebreak()
# this was giving an error when skipping over the expression
var lines =<< trim END
vim9script
***************
*** 3679,3685 ****
v9.CheckScriptSuccess(lines)
enddef

! def Test_expr8_method_call_import()
var lines =<< trim END
vim9script
export def Square(items: list<number>): list<number>
--- 3684,3690 ----
v9.CheckScriptSuccess(lines)
enddef

! def Test_expr9_method_call_import()
var lines =<< trim END
vim9script
export def Square(items: list<number>): list<number>
***************
*** 3714,3720 ****
enddef


! def Test_expr8_not()
var lines =<< trim END
assert_equal(true, !'')
assert_equal(true, ![])
--- 3719,3725 ----
enddef


! def Test_expr9_not()
var lines =<< trim END
assert_equal(true, !'')
assert_equal(true, ![])
***************
*** 3766,3772 ****

let g:anumber = 42

! def Test_expr8_negate()
var lines =<< trim END
var nr = 1
assert_equal(-1, -nr)
--- 3771,3777 ----

let g:anumber = 42

! def Test_expr9_negate()
var lines =<< trim END
var nr = 1
assert_equal(-1, -nr)
***************
*** 3775,3781 ****
v9.CheckDefAndScriptSuccess(lines)
enddef

! func Test_expr8_fails()
call v9.CheckDefFailure(["var x = (12"], "E1097:", 3)
call v9.CheckScriptFailure(['vim9script', "var x = (12"], 'E110:', 2)

--- 3780,3786 ----
v9.CheckDefAndScriptSuccess(lines)
enddef

! func Test_expr9_fails()
call v9.CheckDefFailure(["var x = (12"], "E1097:", 3)
call v9.CheckScriptFailure(['vim9script', "var x = (12"], 'E110:', 2)

***************
*** 3837,3843 ****
return a:one .. a:two
endfunc

! def Test_expr8_trailing()
var lines =<< trim END
# user function call
assert_equal(123, g:CallMe(123))
--- 3842,3848 ----
return a:one .. a:two
endfunc

! def Test_expr9_trailing()
var lines =<< trim END
# user function call
assert_equal(123, g:CallMe(123))
***************
*** 3873,3879 ****
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr8_string_subscript()
var lines =<< trim END
var text = 'abcdef'
assert_equal('f', text[-1])
--- 3878,3884 ----
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr9_string_subscript()
var lines =<< trim END
var text = 'abcdef'
assert_equal('f', text[-1])
***************
*** 3972,3978 ****
v9.CheckDefAndScriptFailure(lines, ['E1012: Type mismatch; expected number but got string', 'E1030: Using a String as a Number: "2"'], 1)
enddef

! def Test_expr8_list_subscript()
var lines =<< trim END
var list = [0, 1, 2, 3, 4]
assert_equal(0, list[0])
--- 3977,3983 ----
v9.CheckDefAndScriptFailure(lines, ['E1012: Type mismatch; expected number but got string', 'E1030: Using a String as a Number: "2"'], 1)
enddef

! def Test_expr9_list_subscript()
var lines =<< trim END
var list = [0, 1, 2, 3, 4]
assert_equal(0, list[0])
***************
*** 4015,4021 ****
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr8_dict_subscript()
var lines =<< trim END
var l = [{lnum: 2}, {lnum: 1}]
var res = l[0].lnum > l[1].lnum
--- 4020,4026 ----
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr9_dict_subscript()
var lines =<< trim END
var l = [{lnum: 2}, {lnum: 1}]
var res = l[0].lnum > l[1].lnum
***************
*** 4036,4042 ****
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr8_blob_subscript()
var lines =<< trim END
var b = 0z112233
assert_equal(0x11, b[0])
--- 4041,4047 ----
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr9_blob_subscript()
var lines =<< trim END
var b = 0z112233
assert_equal(0x11, b[0])
***************
*** 4048,4054 ****
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr8_funcref_subscript()
var lines =<< trim END
var l = function('len')("abc")
assert_equal(3, l)
--- 4053,4059 ----
v9.CheckDefAndScriptSuccess(lines)
enddef

! def Test_expr9_funcref_subscript()
var lines =<< trim END
var l = function('len')("abc")
assert_equal(3, l)
***************
*** 4058,4064 ****
v9.CheckDefAndScriptFailure(["var l = function('len')(xxx)"], ['E1001: Variable not found: xxx', 'E121: Undefined variable: xxx'], 1)
enddef

! def Test_expr8_subscript_linebreak()
var lines =<< trim END
var range = range(
3)
--- 4063,4069 ----
v9.CheckDefAndScriptFailure(["var l = function('len')(xxx)"], ['E1001: Variable not found: xxx', 'E121: Undefined variable: xxx'], 1)
enddef

! def Test_expr9_subscript_linebreak()
var lines =<< trim END
var range = range(
3)
***************
*** 4101,4107 ****
v9.CheckDefAndScriptFailure(lines, ['E1127:', 'E116:'], 2)
enddef

! func Test_expr8_trailing_fails()
call v9.CheckDefAndScriptFailure(['var l = [2]', 'l->((ll) => add(ll, 8))'], 'E107:', 2)
call v9.CheckDefAndScriptFailure(['var l = [2]', 'l->((ll) => add(ll, 8)) ()'], 'E274:', 2)
endfunc
--- 4106,4112 ----
v9.CheckDefAndScriptFailure(lines, ['E1127:', 'E116:'], 2)
enddef

! func Test_expr9_trailing_fails()
call v9.CheckDefAndScriptFailure(['var l = [2]', 'l->((ll) => add(ll, 8))'], 'E107:', 2)
call v9.CheckDefAndScriptFailure(['var l = [2]', 'l->((ll) => add(ll, 8)) ()'], 'E274:', 2)
endfunc
*** ../vim-8.2.5002/src/version.c 2022-05-22 15:35:39.922194215 +0100
--- src/version.c 2022-05-22 19:09:24.436212420 +0100
***************
*** 736,737 ****
--- 736,739 ----
{ /* Add new patch number below this line */
+ /**/
+ 5003,
/**/

--
hundred-and-one symptoms of being an internet addict:
266. You hear most of your jokes via e-mail instead of in person.

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

John Marriott

unread,
May 22, 2022, 3:09:12 PM5/22/22
to vim...@googlegroups.com


On 23-May-2022 04:14, Bram Moolenaar wrote:
> Patch 8.2.5003
> Problem: Cannot do bitwise shifts.
> Solution: Add the >> and << operators. (Yegappan Lakshmanan, closes #8457)
> Files: runtime/doc/eval.txt, src/errors.h, src/eval.c, src/structs.h,
> src/vim.h, src/vim9execute.c, src/vim9expr.c,
> src/testdir/test_expr.vim, src/testdir/test_vim9_disassemble.vim,
> src/testdir/test_vim9_expr.vim
>
>
After this patch, mingw64 (gcc 11.3.0) throws this compile warning:
<snip>
gcc -c -I. -Iproto -DWIN32 -DWINVER=0x0603 -D_WIN32_WINNT=0x0603
-DHAVE_PATHDEF -DFEAT_NORMAL -DHAVE_STDINT_H -D__USE_MINGW_ANSI_STDIO
-pipe -march=native -Wall -O3 -fomit-frame-pointer -freg-struct-return
-fpie -fPIE -DFEAT_GUI_MSWIN -DFEAT_CLIPBOARD vim9expr.c -o
gobjnative/vim9expr.o
vim9expr.c: In function 'compile_expr5':
vim9expr.c:2718:36: warning: 'tv1' may be used uninitialized in this
function [-Wmaybe-uninitialized]
 2718 |                 tv1->vval.v_number = 0;
      |                 ~~~~~~~~~~~~~~~~~~~^~~
</snip>

Sorry I don't have a patch for this. I'm not sure what the purpose of
tv1 is. It gets set (lines 2718 to 2722) but I don't see where it is used.

Cheers
John

John Marriott

unread,
May 22, 2022, 3:44:38 PM5/22/22
to vim...@googlegroups.com
Ah, I think I get what tv1 is doing now.

I still don't have a patch though. ;)

Tony Mechelynck

unread,
May 22, 2022, 3:52:30 PM5/22/22
to vim_dev, Bram Moolenaar
Me too, but slightly more verbose, and in Huge, Big and Normal but not
in Small and Tiny:

gcc -c -I. -Iproto -DHAVE_CONFIG_H -DFEAT_GUI_GTK
-I/usr/include/gtk-3.0 -I/usr/include/pango-1.0
-I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include
-I/usr/include/harfbuzz -I/usr/include/freetype2
-I/usr/include/libmount -I/usr/include/blkid -I/usr/include/fribidi
-I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/libpng16
-I/usr/include/gdk-pixbuf-2.0 -I/usr/include/gio-unix-2.0
-I/usr/include/wayland -I/usr/include/libxkbcommon
-I/usr/include/atk-1.0 -I/usr/include/at-spi2-atk/2.0
-I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include
-I/usr/include/at-spi-2.0 -pthread -O2 -fno-strength-reduce -Wall
-Wno-deprecated-declarations -D_REENTRANT -U_FORTIFY_SOURCE
-D_FORTIFY_SOURCE=1 -o objects/vim9expr.o vim9expr.c
vim9expr.c: In function ‘compile_expr5’:
vim9expr.c:2718:36: warning: ‘tv1’ may be used uninitialized
[-Wmaybe-uninitialized]
2718 | tv1->vval.v_number = 0;
| ~~~~~~~~~~~~~~~~~~~^~~
vim9expr.c:2638:18: note: ‘tv1’ was declared here
2638 | typval_T *tv1;
| ^~~

Best regards,
Tony.

Bram Moolenaar

unread,
May 22, 2022, 4:50:35 PM5/22/22
to vim...@googlegroups.com, John Marriott

John Marriott wrote:

> On 23-May-2022 04:14, Bram Moolenaar wrote:
> > Patch 8.2.5003
> > Problem: Cannot do bitwise shifts.
> > Solution: Add the >> and << operators. (Yegappan Lakshmanan, closes #84=
> 57)
> > Files: runtime/doc/eval.txt, src/errors.h, src/eval.c, src/structs.h=
> ,
> > src/vim.h, src/vim9execute.c, src/vim9expr.c,
> > src/testdir/test_expr.vim, src/testdir/test_vim9_disassemble=
> .vim,
> > src/testdir/test_vim9_expr.vim
> >
> >
> After this patch, mingw64 (gcc 11.3.0) throws this compile warning:
> <snip>
> gcc -c -I. -Iproto -DWIN32 -DWINVER=0x0603 -D_WIN32_WINNT=0x0603
> -DHAVE_PATHDEF -DFEAT_NORMAL -DHAVE_STDINT_H -D__USE_MINGW_ANSI_STDIO
> -pipe -march=native -Wall -O3 -fomit-frame-pointer -freg-struct-return
> -fpie -fPIE -DFEAT_GUI_MSWIN -DFEAT_CLIPBOARD vim9expr.c -o
> gobjnative/vim9expr.o
> vim9expr.c: In function 'compile_expr5':
> vim9expr.c:2718:36: warning: 'tv1' may be used uninitialized in this
> function [-Wmaybe-uninitialized]
>  2718 |                 tv1->vval.v_number = 0;
>       |                 ~~~~~~~~~~~~~~~~~~~^~~
> </snip>
>
> Sorry I don't have a patch for this. I'm not sure what the purpose of
> tv1 is. It gets set (lines 2718 to 2722) but I don't see where it is used.

I can shut up the compiler by initializing tv1 to NULL. Which is weird,
since using NULL would cause a crash. Oh, we can set tv1 later, that
looks better.

--
hundred-and-one symptoms of being an internet addict:
269. You receive an e-mail from the wife of a deceased president, offering
to send you twenty million dollar, and you are not even surprised.

Yegappan Lakshmanan

unread,
May 22, 2022, 10:11:01 PM5/22/22
to vim_dev
Hi,

On Sun, May 22, 2022 at 11:14 AM Bram Moolenaar <Br...@moolenaar.net> wrote:
>
> Patch 8.2.5003
> Problem: Cannot do bitwise shifts.
> Solution: Add the >> and << operators. (Yegappan Lakshmanan, closes #8457)
>

Now that we have the support for the bitwise shift operators, should we add the
support for the bitwise and (&), or (|) and xor (^) operators (like
other popular languages)?
But we do have the and(), or() and xor() builtin functions for these
operations though.

- Yegappan

Ernie Rael

unread,
May 23, 2022, 12:01:06 AM5/23/22
to vim...@googlegroups.com, Yegappan Lakshmanan
Is there a bit-wise "not()" function or bit "~" operator? I didn't see it.

Having the operator certainly makes the code easier to read than with
function calls. I did a  test and was quite surprised to see that the
function call is only around 20% slower.


0.396802 2.252702 / p            ==> "+" 17% of the loop time
0.536753 2.431641 / p            ==> and() 22% of the loop time

0.536753 0.454308 - 0.454308 / p ==> and() 18% slower than "+"
2.431641 2.252702 - 2.252702 / p ==> and() loop 8% slower than "+" loop

FUNCTION  <SNR>42_DoAnd()
    Defined: ~/experiment/vim/isn_opnr-imp.vim:18
Called 1 time
Total time:   2.431641
 Self time:   2.431641

count  total (s)   self (s)
    1              0.000000     var a = 1
    1              0.000000     var b = 2
    1              0.000001     var lim = limit
    1              0.000000     var i = 0
    1              0.000000     var res: number

10000001              0.469681     while i < lim
10000000              0.536753         res = and(a, b)
10000000              0.378225         i += 1
10000000              0.255815     endwhile

FUNCTION  <SNR>42_DoAdd()
    Defined: ~/experiment/vim/isn_opnr-imp.vim:5
Called 1 time
Total time:   2.252702
 Self time:   2.252702

count  total (s)   self (s)
    1              0.000001     var a = 1
    1              0.000001     var b = 2
    1              0.000002     var lim = limit
    1              0.000001     var i = 0
    1              0.000000     var res: number

10000001              0.460535     while i < lim
10000000              0.454308         res = a + b
10000000              0.396802         i += 1
10000000              0.142694     endwhile

FUNCTIONS SORTED ON TOTAL TIME
count  total (s)   self (s)  function
    1   2.431641             <SNR>42_DoAnd()
    1   2.252702             <SNR>42_DoAdd()

FUNCTIONS SORTED ON SELF TIME
count  total (s)   self (s)  function
    1              2.431641  <SNR>42_DoAnd()
    1              2.252702  <SNR>42_DoAdd()


Bram Moolenaar

unread,
May 23, 2022, 7:02:21 AM5/23/22
to vim...@googlegroups.com, Ernie Rael, Yegappan Lakshmanan

> /usr/bin/env: ‘python’: No such file or directory

Where do you see that?

I noticed that after upgrading to Ubuntu 22.04 the "python" command no
longer exists. One has to use "python2" now.

--
ARTHUR: This new learning amazes me, Sir Bedevere. Explain again how sheep's
bladders may be employed to prevent earthquakes.
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

Bram Moolenaar

unread,
May 23, 2022, 7:02:22 AM5/23/22
to vim...@googlegroups.com, Yegappan Lakshmanan
The reason we made these functions is that at least "|" already has a
meaning and it can't be used in legacy script. There might be ways to
use the operators in Vim9 script, but it quickly becomes inconsistent.
And the functions have existed for a longer time, having two ways also
isn't good.

--
hundred-and-one symptoms of being an internet addict:
10E. You start counting in hex.
Reply all
Reply to author
Forward
0 new messages