To: vim_dev@googlegroups.com Subject: Patch 8.2.5003 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 ! 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 ! 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* ----- ! 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* ----- ! 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 **** } /* ! * 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 ---- } /* ! * 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 = ['a', g:string_empty] var ln: list = [g:anint, g:thefour] --- 2058,2064 ---- let $TESTVAR = 'testvar' " type casts ! def Test_expr8() var lines =<< trim END var ls: list = ['a', g:string_empty] var ln: list = [g:anint, 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 = v:errors v9.CheckDefFailure(['var errs: list = v:errors'], 'E1012:') --- 2185,2191 ---- v9.CheckDefAndScriptSuccess(lines) enddef ! def Test_expr9_vimvar() v:errors = [] var errs: list = v:errors v9.CheckDefFailure(['var errs: list = 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", "d = g:list_empty"], 'E1012: Type mismatch; expected dict but got list', 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", "d = g:list_empty"], 'E1012: Type mismatch; expected dict but got list', 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): list --- 3684,3690 ---- v9.CheckScriptSuccess(lines) enddef ! def Test_expr9_method_call_import() var lines =<< trim END vim9script export def Square(items: list): list *************** *** 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 -- Bram@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 ///