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.

Raspunde prin e-mail lui