Patch 8.2.0714
Problem: Vim9: handling constant expression does not scale.
Solution: Use another solution, passint typval_T.
Files: src/vim9compile.c, src/testdir/test_vim9_expr.vim
*** ../vim-8.2.0713/src/vim9compile.c 2020-05-07 16:58:10.868572663 +0200
--- src/vim9compile.c 2020-05-07 21:18:51.200742094 +0200
***************
*** 1042,1078 ****
/*
* Generate a PUSH instruction for "tv".
*/
static int
generate_tv_PUSH(cctx_T *cctx, typval_T *tv)
{
! switch (tv->v_type)
{
! case VAR_BOOL:
! generate_PUSHBOOL(cctx, tv->vval.v_number);
! break;
! case VAR_SPECIAL:
! generate_PUSHSPEC(cctx, tv->vval.v_number);
! break;
! case VAR_NUMBER:
! generate_PUSHNR(cctx, tv->vval.v_number);
! break;
#ifdef FEAT_FLOAT
! case VAR_FLOAT:
! generate_PUSHF(cctx, tv->vval.v_float);
! break;
#endif
! case VAR_BLOB:
! generate_PUSHBLOB(cctx, tv->vval.v_blob);
! tv->vval.v_blob = NULL;
! break;
! case VAR_STRING:
! generate_PUSHS(cctx, tv->vval.v_string);
! tv->vval.v_string = NULL;
! break;
! default:
! iemsg("constant type not supported");
! return FAIL;
}
return OK;
}
--- 1042,1086 ----
/*
* Generate a PUSH instruction for "tv".
+ * "tv" will be consumed or cleared. "tv" may be NULL;
*/
static int
generate_tv_PUSH(cctx_T *cctx, typval_T *tv)
{
! if (tv != NULL)
{
! switch (tv->v_type)
! {
! case VAR_UNKNOWN:
! break;
! case VAR_BOOL:
! generate_PUSHBOOL(cctx, tv->vval.v_number);
! break;
! case VAR_SPECIAL:
! generate_PUSHSPEC(cctx, tv->vval.v_number);
! break;
! case VAR_NUMBER:
! generate_PUSHNR(cctx, tv->vval.v_number);
! break;
#ifdef FEAT_FLOAT
! case VAR_FLOAT:
! generate_PUSHF(cctx, tv->vval.v_float);
! break;
#endif
! case VAR_BLOB:
! generate_PUSHBLOB(cctx, tv->vval.v_blob);
! tv->vval.v_blob = NULL;
! break;
! case VAR_STRING:
! generate_PUSHS(cctx, tv->vval.v_string);
! tv->vval.v_string = NULL;
! break;
! default:
! iemsg("constant type not supported");
! clear_tv(tv);
! return FAIL;
! }
! tv->v_type = VAR_UNKNOWN;
}
return OK;
}
***************
*** 3719,3725 ****
char_u **arg,
cctx_T *cctx,
char_u **start_leader,
! char_u *end_leader)
{
for (;;)
{
--- 3727,3736 ----
char_u **arg,
cctx_T *cctx,
char_u **start_leader,
! char_u *end_leader,
! typval_T *bef1_tv,
! typval_T *bef2_tv,
! typval_T *new_tv)
{
for (;;)
{
***************
*** 3729,3734 ****
--- 3740,3750 ----
type_T *type;
int argcount = 0;
+ if (generate_tv_PUSH(cctx, bef1_tv) == FAIL
+ || generate_tv_PUSH(cctx, bef2_tv) == FAIL
+ || generate_tv_PUSH(cctx, new_tv) == FAIL)
+ return FAIL;
+
// funcref(arg)
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
***************
*** 3742,3747 ****
--- 3758,3768 ----
{
char_u *p;
+ if (generate_tv_PUSH(cctx, bef1_tv) == FAIL
+ || generate_tv_PUSH(cctx, bef2_tv) == FAIL
+ || generate_tv_PUSH(cctx, new_tv) == FAIL)
+ return FAIL;
+
// something->method()
// Apply the '!', '-' and '+' first:
// -1.0->func() works like (-1.0)->func()
***************
*** 3779,3784 ****
--- 3800,3810 ----
garray_T *stack;
type_T **typep;
+ if (generate_tv_PUSH(cctx, bef1_tv) == FAIL
+ || generate_tv_PUSH(cctx, bef2_tv) == FAIL
+ || generate_tv_PUSH(cctx, new_tv) == FAIL)
+ return FAIL;
+
// list index: list[123]
// TODO: more arguments
// TODO: dict member dict['name']
***************
*** 3809,3814 ****
--- 3835,3845 ----
{
char_u *p;
+ if (generate_tv_PUSH(cctx, bef1_tv) == FAIL
+ || generate_tv_PUSH(cctx, bef2_tv) == FAIL
+ || generate_tv_PUSH(cctx, new_tv) == FAIL)
+ return FAIL;
+
++*arg;
p = *arg;
// dictionary member: dict.name
***************
*** 3837,3846 ****
}
/*
! * Compile an expression at "*p" and add instructions to "instr".
! * "p" is advanced until after the expression, skipping white space.
*
! * This is the equivalent of eval1(), eval2(), etc.
*/
/*
--- 3868,3880 ----
}
/*
! * Compile an expression at "*arg" and add instructions to "cctx->ctx_instr".
! * "arg" is advanced until after the expression, skipping white space.
*
! * If the value is a constant "new_tv" will be set.
! * Before instructions are generated, any "bef_tv" will generated.
! *
! * This is the compiling equivalent of eval1(), eval2(), etc.
*/
/*
***************
*** 3868,3874 ****
* trailing ->name() method call
*/
static int
! compile_expr7(char_u **arg, cctx_T *cctx)
{
typval_T rettv;
char_u *start_leader, *end_leader;
--- 3902,3913 ----
* trailing ->name() method call
*/
static int
! compile_expr7(
! char_u **arg,
! cctx_T *cctx,
! typval_T *bef1_tv,
! typval_T *bef2_tv,
! typval_T *new_tv)
{
typval_T rettv;
char_u *start_leader, *end_leader;
***************
*** 4007,4021 ****
}
start_leader = end_leader; // don't apply again below
! // push constant
! if (generate_tv_PUSH(cctx, &rettv) == FAIL)
! return FAIL;
}
else if (ret == NOTDONE)
{
char_u *p;
int r;
if (!eval_isnamec1(**arg))
{
semsg(_("E1015: Name expected: %s"), *arg);
--- 4046,4063 ----
}
start_leader = end_leader; // don't apply again below
! // A constant expression can possibly be handled compile time.
! *new_tv = rettv;
}
else if (ret == NOTDONE)
{
char_u *p;
int r;
+ if (generate_tv_PUSH(cctx, bef1_tv) == FAIL
+ || generate_tv_PUSH(cctx, bef2_tv) == FAIL)
+ return FAIL;
+
if (!eval_isnamec1(**arg))
{
semsg(_("E1015: Name expected: %s"), *arg);
***************
*** 4032,4038 ****
return FAIL;
}
! if (compile_subscript(arg, cctx, &start_leader, end_leader) == FAIL)
return FAIL;
// Now deal with prefixed '-', '+' and '!', if not done already.
--- 4074,4081 ----
return FAIL;
}
! if (compile_subscript(arg, cctx, &start_leader, end_leader,
! bef1_tv, bef2_tv, new_tv) == FAIL)
return FAIL;
// Now deal with prefixed '-', '+' and '!', if not done already.
***************
*** 4045,4056 ****
* % number modulo
*/
static int
! compile_expr6(char_u **arg, cctx_T *cctx)
{
char_u *op;
! // get the first variable
! if (compile_expr7(arg, cctx) == FAIL)
return FAIL;
/*
--- 4088,4103 ----
* % number modulo
*/
static int
! compile_expr6(
! char_u **arg,
! cctx_T *cctx,
! typval_T *bef_tv,
! typval_T *new_tv)
{
char_u *op;
! // get the first expression
! if (compile_expr7(arg, cctx, NULL, bef_tv, new_tv) == FAIL)
return FAIL;
/*
***************
*** 4058,4066 ****
--- 4105,4116 ----
*/
for (;;)
{
+ typval_T tv2;
+
op = skipwhite(*arg);
if (*op != '*' && *op != '/' && *op != '%')
break;
+
if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(op[1]))
{
char_u buf[3];
***************
*** 4073,4083 ****
if (may_get_next_line(op + 1, arg, cctx) == FAIL)
return FAIL;
! // get the second variable
! if (compile_expr7(arg, cctx) == FAIL)
return FAIL;
! generate_two_op(cctx, op);
}
return OK;
--- 4123,4154 ----
if (may_get_next_line(op + 1, arg, cctx) == FAIL)
return FAIL;
! // get the second expression
! tv2.v_type = VAR_UNKNOWN;
! if (compile_expr7(arg, cctx, bef_tv, new_tv, &tv2) == FAIL)
return FAIL;
+ if (new_tv->v_type == VAR_NUMBER && tv2.v_type == VAR_NUMBER)
+ {
+ varnumber_T res = 0;
! // both are numbers: compute the result
! switch (*op)
! {
! case '*': res = new_tv->vval.v_number * tv2.vval.v_number;
! break;
! case '/': res = new_tv->vval.v_number / tv2.vval.v_number;
! break;
! case '%': res = new_tv->vval.v_number % tv2.vval.v_number;
! break;
! }
! new_tv->vval.v_number = res;
! }
! else
! {
! generate_tv_PUSH(cctx, new_tv);
! generate_tv_PUSH(cctx, &tv2);
! generate_two_op(cctx, op);
! }
}
return OK;
***************
*** 4091,4101 ****
static int
compile_expr5(char_u **arg, cctx_T *cctx)
{
char_u *op;
int oplen;
// get the first variable
! if (compile_expr6(arg, cctx) == FAIL)
return FAIL;
/*
--- 4162,4174 ----
static int
compile_expr5(char_u **arg, cctx_T *cctx)
{
+ typval_T tv1;
char_u *op;
int oplen;
// get the first variable
! tv1.v_type = VAR_UNKNOWN;
! if (compile_expr6(arg, cctx, NULL, &tv1) == FAIL)
return FAIL;
/*
***************
*** 4103,4108 ****
--- 4176,4183 ----
*/
for (;;)
{
+ typval_T tv2;
+
op = skipwhite(*arg);
if (*op != '+' && *op != '-' && !(*op == '.' && (*(*arg + 1) == '.')))
break;
***************
*** 4121,4141 ****
if (may_get_next_line(op + oplen, arg, cctx) == FAIL)
return FAIL;
! // get the second variable
! if (compile_expr6(arg, cctx) == FAIL)
return FAIL;
! if (*op == '.')
{
! if (may_generate_2STRING(-2, cctx) == FAIL
! || may_generate_2STRING(-1, cctx) == FAIL)
return FAIL;
! generate_instr_drop(cctx, ISN_CONCAT, 1);
}
else
! generate_two_op(cctx, op);
}
return OK;
}
--- 4196,4254 ----
if (may_get_next_line(op + oplen, arg, cctx) == FAIL)
return FAIL;
! // get the second expression
! tv2.v_type = VAR_UNKNOWN;
! if (compile_expr6(arg, cctx, &tv1, &tv2) == FAIL)
return FAIL;
! if (*op == '+' && tv1.v_type == VAR_NUMBER && tv2.v_type == VAR_NUMBER)
! {
! // add constant numbers
! tv1.vval.v_number = tv1.vval.v_number + tv2.vval.v_number;
! }
! else if (*op == '-' && tv1.v_type == VAR_NUMBER
! && tv2.v_type == VAR_NUMBER)
{
! // subtract constant numbers
! tv1.vval.v_number = tv1.vval.v_number - tv2.vval.v_number;
! }
! else if (*op == '.' && tv1.v_type == VAR_STRING
! && tv2.v_type == VAR_STRING)
! {
! // concatenate constant strings
! char_u *s1 = tv1.vval.v_string;
! char_u *s2 = tv2.vval.v_string;
! size_t len1 = STRLEN(s1);
!
! tv1.vval.v_string = alloc((int)(len1 + STRLEN(s2) + 1));
! if (tv1.vval.v_string == NULL)
! {
! vim_free(s1);
! vim_free(s2);
return FAIL;
! }
! mch_memmove(tv1.vval.v_string, s1, len1);
! STRCPY(tv1.vval.v_string + len1, s2);
}
else
! {
! generate_tv_PUSH(cctx, &tv1);
! generate_tv_PUSH(cctx, &tv2);
! if (*op == '.')
! {
! if (may_generate_2STRING(-2, cctx) == FAIL
! || may_generate_2STRING(-1, cctx) == FAIL)
! return FAIL;
! generate_instr_drop(cctx, ISN_CONCAT, 1);
! }
! else
! generate_two_op(cctx, op);
! }
}
+ // TODO: move to caller
+ generate_tv_PUSH(cctx, &tv1);
+
return OK;
}
***************
*** 4342,4360 ****
compile_expr1(char_u **arg, cctx_T *cctx)
{
char_u *p;
- typval_T tv;
// Evaluate the first expression.
! // First try parsing as a constant. If that works just one PUSH
! // instruction needs to be generated.
! tv.v_type = VAR_UNKNOWN;
! p = *arg;
! if (evaluate_const_expr2(&p, cctx, &tv) == OK)
! {
! *arg = p;
! generate_tv_PUSH(cctx, &tv);
! }
! else if (compile_expr2(arg, cctx) == FAIL)
return FAIL;
p = skipwhite(*arg);
--- 4455,4463 ----
compile_expr1(char_u **arg, cctx_T *cctx)
{
char_u *p;
// Evaluate the first expression.
! if (compile_expr2(arg, cctx) == FAIL)
return FAIL;
p = skipwhite(*arg);
*** ../vim-8.2.0713/src/testdir/test_vim9_expr.vim 2020-05-07
16:58:10.872572650 +0200
--- src/testdir/test_vim9_expr.vim 2020-05-07 21:03:19.840077657 +0200
***************
*** 485,493 ****
assert_equal(-6, g:alsoint - g:anint)
assert_equal('hello', 'hel' .. 'lo')
! " TODO: a line break here doesn't work
! " assert_equal('hello 123', 'hello ' ..
! " 123)
assert_equal('hello 123', 'hello ' .. 123)
assert_equal('123 hello', 123 .. ' hello')
assert_equal('123456', 123 .. 456)
--- 485,492 ----
assert_equal(-6, g:alsoint - g:anint)
assert_equal('hello', 'hel' .. 'lo')
! assert_equal('hello 123', 'hello ' ..
! 123)
assert_equal('hello 123', 'hello ' .. 123)
assert_equal('123 hello', 123 .. ' hello')
assert_equal('123456', 123 .. 456)
*** ../vim-8.2.0713/src/version.c 2020-05-07 18:51:24.161933050 +0200
--- src/version.c 2020-05-07 21:04:17.547881750 +0200
***************
*** 748,749 ****
--- 748,751 ----
{ /* Add new patch number below this line */
+ /**/
+ 714,
/**/
--
hundred-and-one symptoms of being an internet addict:
65. The last time you looked at the clock it was 11:30pm, and in what
seems like only a few seconds later, your sister runs past you to
catch her 7am school bus.
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/202005072019.047KJQLo012052%40masaka.moolenaar.net.