mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.2.5003: cannot do bitwise shifts
Problem: Cannot do bitwise shifts. Solution: Add the >> and << operators. (Yegappan Lakshmanan, closes #8457)
This commit is contained in:
parent
9b2edfd3bf
commit
a061f34191
@ -868,33 +868,36 @@ Expression syntax summary, from least to most significant:
|
||||
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
|
||||
|expr5| expr6 << expr6 bitwise left shift
|
||||
expr6 >> expr6 bitwise right shift
|
||||
|
||||
|expr6| expr7
|
||||
expr7 * expr7 ... number multiplication
|
||||
expr7 / expr7 ... number division
|
||||
expr7 % expr7 ... number modulo
|
||||
expr7 + expr7 ... number addition, list or blob concatenation
|
||||
expr7 - expr7 ... number subtraction
|
||||
expr7 . expr7 ... string concatenation
|
||||
expr7 .. expr7 ... string concatenation
|
||||
|
||||
|expr7| expr8
|
||||
<type>expr8 type check and conversion (|Vim9| only)
|
||||
expr8 * expr8 ... number multiplication
|
||||
expr8 / expr8 ... number division
|
||||
expr8 % expr8 ... number modulo
|
||||
|
||||
|expr8| expr9
|
||||
! expr8 logical NOT
|
||||
- expr8 unary minus
|
||||
+ expr8 unary plus
|
||||
<type>expr9 type check and conversion (|Vim9| only)
|
||||
|
||||
|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
|
||||
! expr9 logical NOT
|
||||
- expr9 unary minus
|
||||
+ expr9 unary plus
|
||||
|
||||
|expr10| number number constant
|
||||
|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,14 +1131,26 @@ can be matched like an ordinary character. Examples:
|
||||
"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-..*
|
||||
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.
|
||||
|
||||
For |Lists| only "+" is possible and then both expr6 must be a list. The
|
||||
|
||||
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,9 +1162,9 @@ In |Vim9| script the arguments of ".." are converted to String for simple
|
||||
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-%*
|
||||
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,18 +1206,18 @@ None of these work for |Funcref|s.
|
||||
".", ".." and "%" do not work for Float. *E804* *E1035*
|
||||
|
||||
|
||||
expr7 *expr7*
|
||||
expr8 *expr8*
|
||||
-----
|
||||
<type>expr8
|
||||
<type>expr9
|
||||
|
||||
This is only available in |Vim9| script, see |type-casting|.
|
||||
|
||||
|
||||
expr8 *expr8*
|
||||
expr9 *expr9*
|
||||
-----
|
||||
! expr8 logical NOT *expr-!*
|
||||
- expr8 unary minus *expr-unary--*
|
||||
+ expr8 unary plus *expr-unary-+*
|
||||
! 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,21 +1239,21 @@ These three can be repeated and mixed. Examples:
|
||||
--9 == 9
|
||||
|
||||
|
||||
expr9 *expr9*
|
||||
-----
|
||||
This expression is either |expr10| or a sequence of the alternatives below,
|
||||
expr10 *expr10*
|
||||
------
|
||||
This expression is either |expr11| 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]
|
||||
expr10[expr1].name
|
||||
expr10.name[expr1]
|
||||
expr10(expr1, ...)[expr1].name
|
||||
expr10->(expr1, ...)[expr1]
|
||||
Evaluation is always from left to right.
|
||||
|
||||
expr9[expr1] item of String or |List| *expr-[]* *E111*
|
||||
expr10[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
|
||||
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,8 +1261,8 @@ byte under the cursor: >
|
||||
: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
|
||||
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,7 +1273,7 @@ String. A negative index always results in an empty string (reason: backward
|
||||
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|
|
||||
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,14 +1283,14 @@ Generally, if a |List| index is equal to or higher than the length of the
|
||||
error.
|
||||
|
||||
|
||||
expr9[expr1a : expr1b] substring or sublist *expr-[:]*
|
||||
expr10[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,
|
||||
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 expr9 is
|
||||
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,20 +1317,20 @@ Examples: >
|
||||
: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
|
||||
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 expr9 is a |Blob| this results in a new |Blob| with the bytes in the
|
||||
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 expr9[expr1] or expr9[expr1a : expr1b] on a |Funcref| results in an
|
||||
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,11 +1339,11 @@ for a sublist: >
|
||||
mylist[s:] " uses namespace s:, error!
|
||||
|
||||
|
||||
expr9.name entry in a |Dictionary| *expr-entry*
|
||||
expr10.name entry in a |Dictionary| *expr-entry*
|
||||
*E1203* *E1229*
|
||||
If expr9 is a |Dictionary| and it is followed by a dot, then the following
|
||||
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:
|
||||
expr9[name].
|
||||
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,17 +1360,17 @@ Note that the dot is also used for String concatenation. To avoid confusion
|
||||
always put spaces around the dot for String concatenation.
|
||||
|
||||
|
||||
expr9(expr1, ...) |Funcref| function call *E1085*
|
||||
expr10(expr1, ...) |Funcref| function call *E1085*
|
||||
|
||||
When expr9 is a |Funcref| type variable, invoke the function it refers to.
|
||||
When expr10 is a |Funcref| type variable, invoke the function it refers to.
|
||||
|
||||
|
||||
expr9->name([args]) method call *method* *->*
|
||||
expr9->{lambda}([args])
|
||||
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(expr9 [, args])
|
||||
There can also be methods specifically for the type of "expr9".
|
||||
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,7 +1379,7 @@ next method: >
|
||||
Example of using a lambda: >
|
||||
GetPercentage()->{x -> x * 100}()->printf('%d%%')
|
||||
<
|
||||
When using -> the |expr8| operators will be applied first, thus: >
|
||||
When using -> the |expr9| operators will be applied first, thus: >
|
||||
-1.234->string()
|
||||
Is equivalent to: >
|
||||
(-1.234)->string()
|
||||
@ -1393,7 +1408,7 @@ When using the lambda form there must be no white space between the } and the
|
||||
(.
|
||||
|
||||
|
||||
*expr10*
|
||||
*expr11*
|
||||
number
|
||||
------
|
||||
number number constant *expr-number*
|
||||
|
@ -3279,3 +3279,9 @@ EXTERN char e_illegal_character_in_word[]
|
||||
#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
|
||||
|
163
src/eval.c
163
src/eval.c
@ -49,10 +49,11 @@ static int eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
|
||||
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 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 eval7_leader(typval_T *rettv, int numeric_only, char_u *start_leader, char_u **end_leaderp);
|
||||
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,7 +639,7 @@ deref_function_name(
|
||||
char_u *name = *arg;
|
||||
|
||||
ref.v_type = VAR_UNKNOWN;
|
||||
if (eval7(arg, &ref, evalarg, FALSE) == FAIL)
|
||||
if (eval9(arg, &ref, evalarg, FALSE) == FAIL)
|
||||
{
|
||||
dictitem_T *v;
|
||||
|
||||
@ -2591,7 +2592,7 @@ eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
||||
int getnext;
|
||||
|
||||
/*
|
||||
* Get the first variable.
|
||||
* Get the first expression.
|
||||
*/
|
||||
if (eval3(arg, rettv, evalarg) == FAIL)
|
||||
return FAIL;
|
||||
@ -2717,7 +2718,7 @@ eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
||||
int getnext;
|
||||
|
||||
/*
|
||||
* Get the first variable.
|
||||
* Get the first expression.
|
||||
*/
|
||||
if (eval4(arg, rettv, evalarg) == FAIL)
|
||||
return FAIL;
|
||||
@ -2856,12 +2857,13 @@ eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
||||
int type_is = FALSE;
|
||||
|
||||
/*
|
||||
* Get the first variable.
|
||||
* 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,7 +2993,120 @@ eval_addlist(typval_T *tv1, typval_T *tv2)
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle fourth level expression:
|
||||
* 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,12 +3118,12 @@ eval_addlist(typval_T *tv1, typval_T *tv2)
|
||||
* Return OK or FAIL.
|
||||
*/
|
||||
static int
|
||||
eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
||||
eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
||||
{
|
||||
/*
|
||||
* Get the first variable.
|
||||
* Get the first expression.
|
||||
*/
|
||||
if (eval6(arg, rettv, evalarg, FALSE) == FAIL)
|
||||
if (eval7(arg, rettv, evalarg, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
/*
|
||||
@ -3086,7 +3201,7 @@ eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
||||
return FAIL;
|
||||
}
|
||||
*arg = skipwhite_and_linebreak(*arg + oplen, evalarg);
|
||||
if (eval6(arg, &var2, evalarg, !vim9script && op == '.') == FAIL)
|
||||
if (eval7(arg, &var2, evalarg, !vim9script && op == '.') == FAIL)
|
||||
{
|
||||
clear_tv(rettv);
|
||||
return FAIL;
|
||||
@ -3221,7 +3336,7 @@ eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle fifth level expression:
|
||||
* Handle sixth level expression:
|
||||
* * number multiplication
|
||||
* / number division
|
||||
* % number modulo
|
||||
@ -3232,7 +3347,7 @@ eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
||||
* Return OK or FAIL.
|
||||
*/
|
||||
static int
|
||||
eval6(
|
||||
eval7(
|
||||
char_u **arg,
|
||||
typval_T *rettv,
|
||||
evalarg_T *evalarg,
|
||||
@ -3243,9 +3358,9 @@ eval6(
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get the first variable.
|
||||
* Get the first expression.
|
||||
*/
|
||||
if (eval7t(arg, rettv, evalarg, want_string) == FAIL)
|
||||
if (eval8(arg, rettv, evalarg, want_string) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
/*
|
||||
@ -3318,7 +3433,7 @@ eval6(
|
||||
return FAIL;
|
||||
}
|
||||
*arg = skipwhite_and_linebreak(*arg + 1, evalarg);
|
||||
if (eval7t(arg, &var2, evalarg, FALSE) == FAIL)
|
||||
if (eval8(arg, &var2, evalarg, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
if (evaluate)
|
||||
@ -3415,7 +3530,7 @@ eval6(
|
||||
* Return OK or FAIL.
|
||||
*/
|
||||
static int
|
||||
eval7t(
|
||||
eval8(
|
||||
char_u **arg,
|
||||
typval_T *rettv,
|
||||
evalarg_T *evalarg,
|
||||
@ -3453,7 +3568,7 @@ eval7t(
|
||||
*arg = skipwhite_and_linebreak(*arg, evalarg);
|
||||
}
|
||||
|
||||
res = eval7(arg, rettv, evalarg, want_string);
|
||||
res = eval9(arg, rettv, evalarg, want_string);
|
||||
|
||||
if (want_type != NULL && evaluate)
|
||||
{
|
||||
@ -3642,7 +3757,7 @@ handle_predefined(char_u *s, int len, typval_T *rettv)
|
||||
* Return OK or FAIL.
|
||||
*/
|
||||
static int
|
||||
eval7(
|
||||
eval9(
|
||||
char_u **arg,
|
||||
typval_T *rettv,
|
||||
evalarg_T *evalarg,
|
||||
@ -3720,7 +3835,7 @@ eval7(
|
||||
// "->" follows.
|
||||
if (ret == OK && evaluate && end_leader > start_leader
|
||||
&& rettv->v_type != VAR_BLOB)
|
||||
ret = eval7_leader(rettv, TRUE, start_leader, &end_leader);
|
||||
ret = eval9_leader(rettv, TRUE, start_leader, &end_leader);
|
||||
break;
|
||||
|
||||
/*
|
||||
@ -3920,19 +4035,19 @@ eval7(
|
||||
* 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);
|
||||
ret = eval9_leader(rettv, FALSE, start_leader, &end_leader);
|
||||
|
||||
--recurse;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply the leading "!" and "-" before an eval7 expression to "rettv".
|
||||
* 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
|
||||
eval7_leader(
|
||||
eval9_leader(
|
||||
typval_T *rettv,
|
||||
int numeric_only,
|
||||
char_u *start_leader,
|
||||
|
@ -4152,6 +4152,8 @@ typedef enum
|
||||
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
|
||||
|
@ -946,4 +946,66 @@ func Test_string_interp()
|
||||
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
|
||||
|
@ -2864,4 +2864,31 @@ def Test_disassemble_string_interp()
|
||||
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
|
||||
|
@ -1483,8 +1483,13 @@ func Test_expr4_fails()
|
||||
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_expr5()
|
||||
def Test_expr6()
|
||||
var lines =<< trim END
|
||||
assert_equal(66, 60 + 6)
|
||||
assert_equal(70, 60 +
|
||||
@ -1549,7 +1554,7 @@ def Test_expr5()
|
||||
v9.CheckDefAndScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_expr5_vim9script()
|
||||
def Test_expr6_vim9script()
|
||||
# check line continuation
|
||||
var lines =<< trim END
|
||||
var name = 11
|
||||
@ -1698,7 +1703,7 @@ def Test_expr5_vim9script()
|
||||
endfor
|
||||
enddef
|
||||
|
||||
def Test_expr5_vim9script_channel()
|
||||
def Test_expr6_vim9script_channel()
|
||||
if !has('channel')
|
||||
MissingFeature 'channel'
|
||||
else
|
||||
@ -1713,7 +1718,7 @@ def Test_expr5_vim9script_channel()
|
||||
endif
|
||||
enddef
|
||||
|
||||
def Test_expr5_float()
|
||||
def Test_expr6_float()
|
||||
if !has('float')
|
||||
MissingFeature 'float'
|
||||
else
|
||||
@ -1741,7 +1746,7 @@ def Test_expr5_float()
|
||||
endif
|
||||
enddef
|
||||
|
||||
func Test_expr5_fails()
|
||||
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,14 +1785,14 @@ func Test_expr5_fails()
|
||||
call v9.CheckDefAndScriptFailure(['var x = 1 + false'], ['E1051:', 'E1138:'], 1)
|
||||
endfunc
|
||||
|
||||
func Test_expr5_fails_channel()
|
||||
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_expr5_list_add()
|
||||
def Test_expr6_list_add()
|
||||
var lines =<< trim END
|
||||
# concatenating two lists with same member types is OK
|
||||
var d = {}
|
||||
@ -1818,7 +1823,7 @@ def Test_expr5_list_add()
|
||||
enddef
|
||||
|
||||
" test multiply, divide, modulo
|
||||
def Test_expr6()
|
||||
def Test_expr7()
|
||||
var lines =<< trim END
|
||||
assert_equal(36, 6 * 6)
|
||||
assert_equal(24, 6 *
|
||||
@ -1890,7 +1895,7 @@ def Test_expr6()
|
||||
v9.CheckDefExecAndScriptFailure(lines, 'E1154', 2)
|
||||
enddef
|
||||
|
||||
def Test_expr6_vim9script()
|
||||
def Test_expr7_vim9script()
|
||||
# check line continuation
|
||||
var lines =<< trim END
|
||||
var name = 11
|
||||
@ -1942,7 +1947,7 @@ def Test_expr6_vim9script()
|
||||
v9.CheckDefAndScriptFailure(lines, 'E1004:', 1)
|
||||
enddef
|
||||
|
||||
def Test_expr6_float()
|
||||
def Test_expr7_float()
|
||||
if !has('float')
|
||||
MissingFeature 'float'
|
||||
else
|
||||
@ -1975,7 +1980,7 @@ def Test_expr6_float()
|
||||
endif
|
||||
enddef
|
||||
|
||||
func Test_expr6_fails()
|
||||
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,7 +2024,7 @@ func Test_expr6_fails()
|
||||
endfor
|
||||
endfunc
|
||||
|
||||
func Test_expr6_float_fails()
|
||||
func Test_expr7_float_fails()
|
||||
CheckFeature float
|
||||
call v9.CheckDefAndScriptFailure(["var x = 1.0 % 2"], ['E1035:', 'E804:'], 1)
|
||||
endfunc
|
||||
@ -2053,7 +2058,7 @@ let g:dict_one = #{one: 1}
|
||||
let $TESTVAR = 'testvar'
|
||||
|
||||
" type casts
|
||||
def Test_expr7()
|
||||
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,7 +2084,7 @@ def Test_expr7()
|
||||
enddef
|
||||
|
||||
" test low level expression
|
||||
def Test_expr8_number()
|
||||
def Test_expr9_number()
|
||||
# number constant
|
||||
var lines =<< trim END
|
||||
assert_equal(0, 0)
|
||||
@ -2092,7 +2097,7 @@ def Test_expr8_number()
|
||||
v9.CheckDefAndScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_expr8_float()
|
||||
def Test_expr9_float()
|
||||
# float constant
|
||||
if !has('float')
|
||||
MissingFeature 'float'
|
||||
@ -2107,7 +2112,7 @@ def Test_expr8_float()
|
||||
endif
|
||||
enddef
|
||||
|
||||
def Test_expr8_blob()
|
||||
def Test_expr9_blob()
|
||||
# blob constant
|
||||
var lines =<< trim END
|
||||
assert_equal(g:blob_empty, 0z)
|
||||
@ -2139,7 +2144,7 @@ def Test_expr8_blob()
|
||||
v9.CheckDefAndScriptFailure(["var x = 0z123"], 'E973:', 1)
|
||||
enddef
|
||||
|
||||
def Test_expr8_string()
|
||||
def Test_expr9_string()
|
||||
# string constant
|
||||
var lines =<< trim END
|
||||
assert_equal(g:string_empty, '')
|
||||
@ -2180,7 +2185,7 @@ def Test_expr8_string()
|
||||
v9.CheckDefAndScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_expr8_vimvar()
|
||||
def Test_expr9_vimvar()
|
||||
v:errors = []
|
||||
var errs: list<string> = v:errors
|
||||
v9.CheckDefFailure(['var errs: list<number> = v:errors'], 'E1012:')
|
||||
@ -2205,7 +2210,7 @@ def Test_expr8_vimvar()
|
||||
bwipe!
|
||||
enddef
|
||||
|
||||
def Test_expr8_special()
|
||||
def Test_expr9_special()
|
||||
# special constant
|
||||
var lines =<< trim END
|
||||
assert_equal(g:special_true, true)
|
||||
@ -2242,7 +2247,7 @@ def Test_expr8_special()
|
||||
v9.CheckDefAndScriptFailure(['v:none = 22'], 'E46:', 1)
|
||||
enddef
|
||||
|
||||
def Test_expr8_list()
|
||||
def Test_expr9_list()
|
||||
# list
|
||||
var lines =<< trim END
|
||||
assert_equal(g:list_empty, [])
|
||||
@ -2320,7 +2325,7 @@ def Test_expr8_list()
|
||||
v9.CheckDefAndScriptFailure(lines + ['echo numbers[a :b]'], 'E1004:', 4)
|
||||
enddef
|
||||
|
||||
def Test_expr8_list_vim9script()
|
||||
def Test_expr9_list_vim9script()
|
||||
var lines =<< trim END
|
||||
var l = [
|
||||
11,
|
||||
@ -2408,7 +2413,7 @@ def LambdaUsingArg(x: number): func
|
||||
x == 2
|
||||
enddef
|
||||
|
||||
def Test_expr8_lambda()
|
||||
def Test_expr9_lambda()
|
||||
var lines =<< trim END
|
||||
var La = () => 'result'
|
||||
# comment
|
||||
@ -2494,7 +2499,7 @@ def Test_expr8_lambda()
|
||||
v9.CheckDefAndScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_expr8_lambda_block()
|
||||
def Test_expr9_lambda_block()
|
||||
var lines =<< trim END
|
||||
var Func = (s: string): string => {
|
||||
return 'hello ' .. s
|
||||
@ -2574,7 +2579,7 @@ def NewLambdaUsingArg(x: number): func
|
||||
x == 2
|
||||
enddef
|
||||
|
||||
def Test_expr8_new_lambda()
|
||||
def Test_expr9_new_lambda()
|
||||
var lines =<< trim END
|
||||
var La = () => 'result'
|
||||
assert_equal('result', La())
|
||||
@ -2659,7 +2664,7 @@ def Test_expr8_new_lambda()
|
||||
v9.CheckDefAndScriptFailure(['var Fx = (a) => [0', ' 1]'], 'E696:', 2)
|
||||
enddef
|
||||
|
||||
def Test_expr8_lambda_vim9script()
|
||||
def Test_expr9_lambda_vim9script()
|
||||
var lines =<< trim END
|
||||
var v = 10->((a) =>
|
||||
a
|
||||
@ -2678,7 +2683,7 @@ def Test_expr8_lambda_vim9script()
|
||||
v9.CheckDefAndScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_expr8funcref()
|
||||
def Test_expr9funcref()
|
||||
var lines =<< trim END
|
||||
def RetNumber(): number
|
||||
return 123
|
||||
@ -2730,7 +2735,7 @@ enddef
|
||||
let g:test_space_dict = {'': 'empty', ' ': 'space'}
|
||||
let g:test_hash_dict = #{one: 1, two: 2}
|
||||
|
||||
def Test_expr8_dict()
|
||||
def Test_expr9_dict()
|
||||
# dictionary
|
||||
var lines =<< trim END
|
||||
assert_equal(g:dict_empty, {})
|
||||
@ -2850,7 +2855,7 @@ def Test_expr8_dict()
|
||||
v9.CheckDefExecAndScriptFailure(['{}[getftype("file")]'], 'E716: Key not present in Dictionary: ""', 1)
|
||||
enddef
|
||||
|
||||
def Test_expr8_dict_vim9script()
|
||||
def Test_expr9_dict_vim9script()
|
||||
var lines =<< trim END
|
||||
var d = {
|
||||
['one']:
|
||||
@ -2981,7 +2986,7 @@ def Test_expr8_dict_vim9script()
|
||||
v9.CheckScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_expr8_dict_in_block()
|
||||
def Test_expr9_dict_in_block()
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
command MyCommand {
|
||||
@ -3004,7 +3009,7 @@ def Test_expr8_dict_in_block()
|
||||
delcommand YourCommand
|
||||
enddef
|
||||
|
||||
def Test_expr8_call_2bool()
|
||||
def Test_expr9_call_2bool()
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
|
||||
@ -3052,7 +3057,7 @@ def Test_expr_member()
|
||||
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()
|
||||
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,7 +3228,7 @@ def SetSomeVar()
|
||||
b:someVar = &fdm
|
||||
enddef
|
||||
|
||||
def Test_expr8_option()
|
||||
def Test_expr9_option()
|
||||
var lines =<< trim END
|
||||
# option
|
||||
set ts=11
|
||||
@ -3250,7 +3255,7 @@ def Test_expr8_option()
|
||||
v9.CheckDefAndScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_expr8_environment()
|
||||
def Test_expr9_environment()
|
||||
var lines =<< trim END
|
||||
# environment variable
|
||||
assert_equal('testvar', $TESTVAR)
|
||||
@ -3262,7 +3267,7 @@ def Test_expr8_environment()
|
||||
v9.CheckDefAndScriptFailure(["$"], ['E1002:', 'E15:'], 1)
|
||||
enddef
|
||||
|
||||
def Test_expr8_register()
|
||||
def Test_expr9_register()
|
||||
var lines =<< trim END
|
||||
@a = 'register a'
|
||||
assert_equal('register a', @a)
|
||||
@ -3288,7 +3293,7 @@ def Test_expr8_register()
|
||||
enddef
|
||||
|
||||
" This is slow when run under valgrind.
|
||||
def Test_expr8_namespace()
|
||||
def Test_expr9_namespace()
|
||||
var lines =<< trim END
|
||||
g:some_var = 'some'
|
||||
assert_equal('some', get(g:, 'some_var'))
|
||||
@ -3317,7 +3322,7 @@ def Test_expr8_namespace()
|
||||
v9.CheckDefAndScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_expr8_namespace_loop_def()
|
||||
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,8 +3341,8 @@ def Test_expr8_namespace_loop_def()
|
||||
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()
|
||||
" :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,7 +3361,7 @@ def Test_expr8_namespace_loop_script()
|
||||
v9.CheckScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_expr8_parens()
|
||||
def Test_expr9_parens()
|
||||
# (expr)
|
||||
var lines =<< trim END
|
||||
assert_equal(4, (6 * 4) / 6)
|
||||
@ -3403,7 +3408,7 @@ def Test_expr8_parens()
|
||||
unlet g:result
|
||||
enddef
|
||||
|
||||
def Test_expr8_negate_add()
|
||||
def Test_expr9_negate_add()
|
||||
var lines =<< trim END
|
||||
assert_equal(-99, -99)
|
||||
assert_equal(-99, - 99)
|
||||
@ -3452,7 +3457,7 @@ def LegacyReturn(): string
|
||||
legacy return #{key: 'ok'}.key
|
||||
enddef
|
||||
|
||||
def Test_expr8_legacy_script()
|
||||
def Test_expr9_legacy_script()
|
||||
var lines =<< trim END
|
||||
let s:legacy = 'legacy'
|
||||
def GetLocal(): string
|
||||
@ -3495,7 +3500,7 @@ def s:Echo4Arg(arg: any): string
|
||||
return arg
|
||||
enddef
|
||||
|
||||
def Test_expr8_call()
|
||||
def Test_expr9_call()
|
||||
var lines =<< trim END
|
||||
assert_equal('yes', 'yes'->g:Echo())
|
||||
assert_equal(true, !range(5)->empty())
|
||||
@ -3518,7 +3523,7 @@ def g:ExistingGlobal(): string
|
||||
return 'existing'
|
||||
enddef
|
||||
|
||||
def Test_expr8_call_global()
|
||||
def Test_expr9_call_global()
|
||||
assert_equal('existing', g:ExistingGlobal())
|
||||
|
||||
def g:DefinedLater(): string
|
||||
@ -3532,7 +3537,7 @@ def Test_expr8_call_global()
|
||||
v9.CheckDefAndScriptFailure(lines, 'E117: Unknown function: ExistingGlobal')
|
||||
enddef
|
||||
|
||||
def Test_expr8_autoload_var()
|
||||
def Test_expr9_autoload_var()
|
||||
var auto_lines =<< trim END
|
||||
let autofile#var = 'found'
|
||||
END
|
||||
@ -3555,7 +3560,7 @@ def Test_expr8_autoload_var()
|
||||
delete('Xruntime', 'rf')
|
||||
enddef
|
||||
|
||||
def Test_expr8_call_autoload()
|
||||
def Test_expr9_call_autoload()
|
||||
var auto_lines =<< trim END
|
||||
def g:some#func(): string
|
||||
return 'found'
|
||||
@ -3572,7 +3577,7 @@ def Test_expr8_call_autoload()
|
||||
delete('Xruntime', 'rf')
|
||||
enddef
|
||||
|
||||
def Test_expr8_method_call()
|
||||
def Test_expr9_method_call()
|
||||
var lines =<< trim END
|
||||
new
|
||||
setline(1, ['first', 'last'])
|
||||
@ -3663,7 +3668,7 @@ def Test_expr8_method_call()
|
||||
v9.CheckDefFailure(lines, 'E15: Invalid expression: "->SetList[0]x()"')
|
||||
enddef
|
||||
|
||||
def Test_expr8_method_call_linebreak()
|
||||
def Test_expr9_method_call_linebreak()
|
||||
# this was giving an error when skipping over the expression
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
@ -3679,7 +3684,7 @@ def Test_expr8_method_call_linebreak()
|
||||
v9.CheckScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_expr8_method_call_import()
|
||||
def Test_expr9_method_call_import()
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
export def Square(items: list<number>): list<number>
|
||||
@ -3714,7 +3719,7 @@ def Test_expr8_method_call_import()
|
||||
enddef
|
||||
|
||||
|
||||
def Test_expr8_not()
|
||||
def Test_expr9_not()
|
||||
var lines =<< trim END
|
||||
assert_equal(true, !'')
|
||||
assert_equal(true, ![])
|
||||
@ -3766,7 +3771,7 @@ enddef
|
||||
|
||||
let g:anumber = 42
|
||||
|
||||
def Test_expr8_negate()
|
||||
def Test_expr9_negate()
|
||||
var lines =<< trim END
|
||||
var nr = 1
|
||||
assert_equal(-1, -nr)
|
||||
@ -3775,7 +3780,7 @@ def Test_expr8_negate()
|
||||
v9.CheckDefAndScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
func Test_expr8_fails()
|
||||
func Test_expr9_fails()
|
||||
call v9.CheckDefFailure(["var x = (12"], "E1097:", 3)
|
||||
call v9.CheckScriptFailure(['vim9script', "var x = (12"], 'E110:', 2)
|
||||
|
||||
@ -3837,7 +3842,7 @@ func CallMe2(one, two)
|
||||
return a:one .. a:two
|
||||
endfunc
|
||||
|
||||
def Test_expr8_trailing()
|
||||
def Test_expr9_trailing()
|
||||
var lines =<< trim END
|
||||
# user function call
|
||||
assert_equal(123, g:CallMe(123))
|
||||
@ -3873,7 +3878,7 @@ def Test_expr8_trailing()
|
||||
v9.CheckDefAndScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_expr8_string_subscript()
|
||||
def Test_expr9_string_subscript()
|
||||
var lines =<< trim END
|
||||
var text = 'abcdef'
|
||||
assert_equal('f', text[-1])
|
||||
@ -3972,7 +3977,7 @@ def Test_expr8_string_subscript()
|
||||
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()
|
||||
def Test_expr9_list_subscript()
|
||||
var lines =<< trim END
|
||||
var list = [0, 1, 2, 3, 4]
|
||||
assert_equal(0, list[0])
|
||||
@ -4015,7 +4020,7 @@ def Test_expr8_list_subscript()
|
||||
v9.CheckDefAndScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_expr8_dict_subscript()
|
||||
def Test_expr9_dict_subscript()
|
||||
var lines =<< trim END
|
||||
var l = [{lnum: 2}, {lnum: 1}]
|
||||
var res = l[0].lnum > l[1].lnum
|
||||
@ -4036,7 +4041,7 @@ def Test_expr8_dict_subscript()
|
||||
v9.CheckDefAndScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_expr8_blob_subscript()
|
||||
def Test_expr9_blob_subscript()
|
||||
var lines =<< trim END
|
||||
var b = 0z112233
|
||||
assert_equal(0x11, b[0])
|
||||
@ -4048,7 +4053,7 @@ def Test_expr8_blob_subscript()
|
||||
v9.CheckDefAndScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_expr8_funcref_subscript()
|
||||
def Test_expr9_funcref_subscript()
|
||||
var lines =<< trim END
|
||||
var l = function('len')("abc")
|
||||
assert_equal(3, l)
|
||||
@ -4058,7 +4063,7 @@ def Test_expr8_funcref_subscript()
|
||||
v9.CheckDefAndScriptFailure(["var l = function('len')(xxx)"], ['E1001: Variable not found: xxx', 'E121: Undefined variable: xxx'], 1)
|
||||
enddef
|
||||
|
||||
def Test_expr8_subscript_linebreak()
|
||||
def Test_expr9_subscript_linebreak()
|
||||
var lines =<< trim END
|
||||
var range = range(
|
||||
3)
|
||||
@ -4101,7 +4106,7 @@ def Test_expr8_subscript_linebreak()
|
||||
v9.CheckDefAndScriptFailure(lines, ['E1127:', 'E116:'], 2)
|
||||
enddef
|
||||
|
||||
func Test_expr8_trailing_fails()
|
||||
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
|
||||
|
@ -734,6 +734,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
5003,
|
||||
/**/
|
||||
5002,
|
||||
/**/
|
||||
|
@ -2808,4 +2808,5 @@ long elapsed(DWORD start_tick);
|
||||
#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
|
||||
|
@ -4055,6 +4055,17 @@ exec_instructions(ectx_T *ectx)
|
||||
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,6 +4088,21 @@ exec_instructions(ectx_T *ectx)
|
||||
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,6 +6042,8 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
||||
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)
|
||||
|
155
src/vim9expr.c
155
src/vim9expr.c
@ -1748,7 +1748,7 @@ compile_parenthesis(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int compile_expr8(char_u **arg, cctx_T *cctx, ppconst_T *ppconst);
|
||||
static int compile_expr9(char_u **arg, cctx_T *cctx, ppconst_T *ppconst);
|
||||
|
||||
/*
|
||||
* Compile whatever comes after "name" or "name()".
|
||||
@ -1909,7 +1909,7 @@ compile_subscript(
|
||||
// do not look in the next line
|
||||
cctx->ctx_ufunc->uf_lines.ga_len = 1;
|
||||
|
||||
fail = compile_expr8(arg, cctx, ppconst) == FAIL
|
||||
fail = compile_expr9(arg, cctx, ppconst) == FAIL
|
||||
|| *skipwhite(*arg) != NUL;
|
||||
*paren = '(';
|
||||
--paren_follows_after_expr;
|
||||
@ -2143,7 +2143,7 @@ compile_subscript(
|
||||
* trailing ->name() method call
|
||||
*/
|
||||
static int
|
||||
compile_expr8(
|
||||
compile_expr9(
|
||||
char_u **arg,
|
||||
cctx_T *cctx,
|
||||
ppconst_T *ppconst)
|
||||
@ -2389,10 +2389,10 @@ compile_expr8(
|
||||
}
|
||||
|
||||
/*
|
||||
* <type>expr8: runtime type check / conversion
|
||||
* <type>expr9: runtime type check / conversion
|
||||
*/
|
||||
static int
|
||||
compile_expr7(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
compile_expr8(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
{
|
||||
type_T *want_type = NULL;
|
||||
|
||||
@ -2417,7 +2417,7 @@ compile_expr7(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (compile_expr8(arg, cctx, ppconst) == FAIL)
|
||||
if (compile_expr9(arg, cctx, ppconst) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
if (want_type != NULL)
|
||||
@ -2444,14 +2444,14 @@ compile_expr7(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
* % number modulo
|
||||
*/
|
||||
static int
|
||||
compile_expr6(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
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_expr7(arg, cctx, ppconst) == FAIL)
|
||||
if (compile_expr8(arg, cctx, ppconst) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
/*
|
||||
@ -2477,7 +2477,7 @@ compile_expr6(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
return FAIL;
|
||||
|
||||
// get the second expression
|
||||
if (compile_expr7(arg, cctx, ppconst) == FAIL)
|
||||
if (compile_expr8(arg, cctx, ppconst) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
if (ppconst->pp_used == ppconst_used + 2
|
||||
@ -2522,7 +2522,7 @@ compile_expr6(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
* .. string concatenation
|
||||
*/
|
||||
static int
|
||||
compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
compile_expr6(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
{
|
||||
char_u *op;
|
||||
char_u *next;
|
||||
@ -2530,7 +2530,7 @@ compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
int ppconst_used = ppconst->pp_used;
|
||||
|
||||
// get the first variable
|
||||
if (compile_expr6(arg, cctx, ppconst) == FAIL)
|
||||
if (compile_expr7(arg, cctx, ppconst) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
/*
|
||||
@ -2562,7 +2562,7 @@ compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
return FAIL;
|
||||
|
||||
// get the second expression
|
||||
if (compile_expr6(arg, cctx, ppconst) == FAIL)
|
||||
if (compile_expr7(arg, cctx, ppconst) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
if (ppconst->pp_used == ppconst_used + 2
|
||||
@ -2620,6 +2620,136 @@ compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -2652,6 +2782,7 @@ compile_expr4(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
||||
return FAIL;
|
||||
|
||||
p = may_peek_next_line(cctx, *arg, &next);
|
||||
|
||||
type = get_compare_type(p, &len, &type_is);
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user