Patch 8.2.3442
Problem:    Vim9: || and && are not handled at compile time when possible.
Solution:   When using constants generate fewer instructions.
Files:      src/vim9.h, src/vim9compile.c, src/vim9execute.c,
            src/testdir/test_vim9_disassemble.vim


*** ../vim-8.2.3441/src/vim9.h  2021-09-13 18:25:50.456525311 +0200
--- src/vim9.h  2021-09-15 19:55:46.370902701 +0200
***************
*** 221,226 ****
--- 221,227 ----
  
  typedef enum {
      JUMP_ALWAYS,
+     JUMP_NEVER,
      JUMP_IF_FALSE,            // pop and jump if false
      JUMP_AND_KEEP_IF_TRUE,    // jump if top of stack is truthy, drop if not
      JUMP_AND_KEEP_IF_FALSE,   // jump if top of stack is falsy, drop if not
*** ../vim-8.2.3441/src/vim9compile.c   2021-09-13 18:25:50.456525311 +0200
--- src/vim9compile.c   2021-09-16 11:44:01.352095465 +0200
***************
*** 2847,2853 ****
  }
  
  /*
!  * Check that the last item of "ppconst" is a bool.
   */
      static int
  check_ppconst_bool(ppconst_T *ppconst)
--- 2847,2853 ----
  }
  
  /*
!  * Check that the last item of "ppconst" is a bool, if there is an item.
   */
      static int
  check_ppconst_bool(ppconst_T *ppconst)
***************
*** 4845,4851 ****
        }
        else
        {
!           if (generate_ppconst(cctx, ppconst) == FAIL)
                return FAIL;
            r = compile_load(arg, p, cctx, TRUE, TRUE);
        }
--- 4845,4852 ----
        }
        else
        {
!           if (cctx->ctx_skip != SKIP_YES
!                                   && generate_ppconst(cctx, ppconst) == FAIL)
                return FAIL;
            r = compile_load(arg, p, cctx, TRUE, TRUE);
        }
***************
*** 5240,5245 ****
--- 5241,5247 ----
      {
        garray_T        *instr = &cctx->ctx_instr;
        garray_T        end_ga;
+       int             save_skip = cctx->ctx_skip;
  
        /*
         * Repeat until there is no following "||" or "&&"
***************
*** 5251,5257 ****
--- 5253,5262 ----
            long        save_sourcing_lnum;
            int         start_ctx_lnum = cctx->ctx_lnum;
            int         save_lnum;
+           int         const_used;
            int         status;
+           jumpwhen_T  jump_when = opchar == '|'
+                                     ? JUMP_IF_COND_TRUE : JUMP_IF_COND_FALSE;
  
            if (next != NULL)
            {
***************
*** 5274,5287 ****
            status = check_ppconst_bool(ppconst);
            if (status != FAIL)
            {
!               // TODO: use ppconst if the value is a constant
!               generate_ppconst(cctx, ppconst);
  
!               // Every part must evaluate to a bool.
!               status = bool_on_stack(cctx);
!               if (status != FAIL)
!                   status = ga_grow(&end_ga, 1);
            }
            cctx->ctx_lnum = save_lnum;
            if (status == FAIL)
            {
--- 5279,5316 ----
            status = check_ppconst_bool(ppconst);
            if (status != FAIL)
            {
!               // Use the last ppconst if possible.
!               if (ppconst->pp_used > 0)
!               {
!                   typval_T    *tv = &ppconst->pp_tv[ppconst->pp_used - 1];
!                   int         is_true = tv2bool(tv);
  
!                   if ((is_true && opchar == '|')
!                                               || (!is_true && opchar == '&'))
!                   {
!                       // For "false && expr" and "true || expr" the "expr"
!                       // does not need to be evaluated.
!                       cctx->ctx_skip = SKIP_YES;
!                       clear_tv(tv);
!                       tv->v_type = VAR_BOOL;
!                       tv->vval.v_number = is_true ? VVAL_TRUE : VVAL_FALSE;
!                   }
!                   else
!                   {
!                       // For "true && expr" and "false || expr" only "expr"
!                       // needs to be evaluated.
!                       --ppconst->pp_used;
!                       jump_when = JUMP_NEVER;
!                   }
!               }
!               else
!               {
!                   // Every part must evaluate to a bool.
!                   status = bool_on_stack(cctx);
!               }
            }
+           if (status != FAIL)
+               status = ga_grow(&end_ga, 1);
            cctx->ctx_lnum = save_lnum;
            if (status == FAIL)
            {
***************
*** 5289,5298 ****
                return FAIL;
            }
  
!           *(((int *)end_ga.ga_data) + end_ga.ga_len) = instr->ga_len;
!           ++end_ga.ga_len;
!           generate_JUMP(cctx, opchar == '|'
!                                ?  JUMP_IF_COND_TRUE : JUMP_IF_COND_FALSE, 0);
  
            // eval the next expression
            SOURCING_LNUM = save_sourcing_lnum;
--- 5318,5332 ----
                return FAIL;
            }
  
!           if (jump_when != JUMP_NEVER)
!           {
!               if (cctx->ctx_skip != SKIP_YES)
!               {
!                   *(((int *)end_ga.ga_data) + end_ga.ga_len) = instr->ga_len;
!                   ++end_ga.ga_len;
!               }
!               generate_JUMP(cctx, jump_when, 0);
!           }
  
            // eval the next expression
            SOURCING_LNUM = save_sourcing_lnum;
***************
*** 5302,5307 ****
--- 5336,5342 ----
                return FAIL;
            }
  
+           const_used = ppconst->pp_used;
            if ((opchar == '|' ? compile_expr3(arg, cctx, ppconst)
                                  : compile_expr4(arg, cctx, ppconst)) == FAIL)
            {
***************
*** 5309,5314 ****
--- 5344,5363 ----
                return FAIL;
            }
  
+           // "0 || 1" results in true, "1 && 0" results in false.
+           if (ppconst->pp_used == const_used + 1)
+           {
+               typval_T        *tv = &ppconst->pp_tv[ppconst->pp_used - 1];
+ 
+               if (tv->v_type == VAR_NUMBER
+                        && (tv->vval.v_number == 1 || tv->vval.v_number == 0))
+               {
+                   tv->vval.v_number = tv->vval.v_number == 1
+                                                     ? VVAL_TRUE : VVAL_FALSE;
+                   tv->v_type = VAR_BOOL;
+               }
+           }
+ 
            p = may_peek_next_line(cctx, *arg, &next);
        }
  
***************
*** 5317,5342 ****
            ga_clear(&end_ga);
            return FAIL;
        }
-       generate_ppconst(cctx, ppconst);
  
!       // Every part must evaluate to a bool.
!       if (bool_on_stack(cctx) == FAIL)
!       {
!           ga_clear(&end_ga);
!           return FAIL;
!       }
  
!       // Fill in the end label in all jumps.
!       while (end_ga.ga_len > 0)
        {
!           isn_T       *isn;
  
!           --end_ga.ga_len;
!           isn = ((isn_T *)instr->ga_data)
                                  + *(((int *)end_ga.ga_data) + end_ga.ga_len);
!           isn->isn_arg.jump.jump_where = instr->ga_len;
        }
!       ga_clear(&end_ga);
      }
  
      return OK;
--- 5366,5397 ----
            ga_clear(&end_ga);
            return FAIL;
        }
  
!       if (cctx->ctx_skip != SKIP_YES && ppconst->pp_used == 0)
!           // Every part must evaluate to a bool.
!           if (bool_on_stack(cctx) == FAIL)
!           {
!               ga_clear(&end_ga);
!               return FAIL;
!           }
  
!       if (end_ga.ga_len > 0)
        {
!           // Fill in the end label in all jumps.
!           generate_ppconst(cctx, ppconst);
!           while (end_ga.ga_len > 0)
!           {
!               isn_T   *isn;
  
!               --end_ga.ga_len;
!               isn = ((isn_T *)instr->ga_data)
                                  + *(((int *)end_ga.ga_data) + end_ga.ga_len);
!               isn->isn_arg.jump.jump_where = instr->ga_len;
!           }
!           ga_clear(&end_ga);
        }
! 
!       cctx->ctx_skip = save_skip;
      }
  
      return OK;
*** ../vim-8.2.3441/src/vim9execute.c   2021-09-13 18:25:50.456525311 +0200
--- src/vim9execute.c   2021-09-15 20:02:39.930491080 +0200
***************
*** 5487,5492 ****
--- 5487,5495 ----
                        case JUMP_ALWAYS:
                            when = "JUMP";
                            break;
+                       case JUMP_NEVER:
+                           iemsg("JUMP_NEVER should not be used");
+                           break;
                        case JUMP_AND_KEEP_IF_TRUE:
                            when = "JUMP_AND_KEEP_IF_TRUE";
                            break;
*** ../vim-8.2.3441/src/testdir/test_vim9_disassemble.vim       2021-09-13 
18:25:50.456525311 +0200
--- src/testdir/test_vim9_disassemble.vim       2021-09-15 22:32:30.847957856 
+0200
***************
*** 1218,1223 ****
--- 1218,1255 ----
          instr)
  enddef
  
+ def AndConstant(arg: any): string
+   if true && arg
+     return "yes"
+   endif
+   if false && arg
+     return "never"
+   endif
+   return "no"
+ enddef
+ 
+ def Test_disassemble_and_constant()
+   assert_equal("yes", AndConstant(1))
+   assert_equal("no", AndConstant(false))
+   var instr = execute('disassemble AndConstant')
+   assert_match('AndConstant\_s*' ..
+       'if true && arg\_s*' ..
+       '0 LOAD arg\[-1\]\_s*' ..
+       '1 COND2BOOL\_s*' ..
+       '2 JUMP_IF_FALSE -> 5\_s*' ..
+       'return "yes"\_s*' ..
+       '3 PUSHS "yes"\_s*' ..
+       '4 RETURN\_s*' ..
+       'endif\_s*' ..
+       'if false && arg\_s*' ..
+       'return "never"\_s*' ..
+       'endif\_s*' ..
+       'return "no"\_s*' ..
+       '5 PUSHS "no"\_s*' ..
+       '6 RETURN',
+       instr)
+ enddef
+ 
  def ForLoop(): list<number>
    var res: list<number>
    for i in range(3)
***************
*** 1734,1758 ****
  enddef
  
  def ReturnBool(): bool
!   var name: bool = 1 && 0 || 1
    return name
  enddef
  
  def Test_disassemble_return_bool()
    var instr = execute('disassemble ReturnBool')
    assert_match('ReturnBool\_s*' ..
!         'var name: bool = 1 && 0 || 1\_s*' ..
!         '0 PUSHNR 1\_s*' ..
!         '1 COND2BOOL\_s*' ..
!         '2 JUMP_IF_COND_FALSE -> 5\_s*' ..
!         '3 PUSHNR 0\_s*' ..
!         '4 COND2BOOL\_s*' ..
!         '5 JUMP_IF_COND_TRUE -> 8\_s*' ..
!         '6 PUSHNR 1\_s*' ..
!         '7 COND2BOOL\_s*' ..
!         '\d STORE $0\_s*' ..
          'return name\_s*' ..
!         '\d\+ LOAD $0\_s*' ..   
          '\d\+ RETURN',
          instr)
    assert_equal(true, InvertBool())
--- 1766,1796 ----
  enddef
  
  def ReturnBool(): bool
!   var one = 1
!   var zero = 0
!   var name: bool = one && zero || one
    return name
  enddef
  
  def Test_disassemble_return_bool()
    var instr = execute('disassemble ReturnBool')
    assert_match('ReturnBool\_s*' ..
!         'var one = 1\_s*' ..
!         '0 STORE 1 in $0\_s*' ..
!         'var zero = 0\_s*' ..
!         '1 STORE 0 in $1\_s*' ..
!         'var name: bool = one && zero || one\_s*' ..
!         '2 LOAD $0\_s*' ..
!         '3 COND2BOOL\_s*' ..
!         '4 JUMP_IF_COND_FALSE -> 7\_s*' ..
!         '5 LOAD $1\_s*' ..
!         '6 COND2BOOL\_s*' ..
!         '7 JUMP_IF_COND_TRUE -> 10\_s*' ..
!         '8 LOAD $0\_s*' ..
!         '9 COND2BOOL\_s*' ..
!         '10 STORE $2\_s*' ..
          'return name\_s*' ..
!         '\d\+ LOAD $2\_s*' ..   
          '\d\+ RETURN',
          instr)
    assert_equal(true, InvertBool())
*** ../vim-8.2.3441/src/version.c       2021-09-15 12:53:14.029281661 +0200
--- src/version.c       2021-09-16 16:14:06.588318608 +0200
***************
*** 757,758 ****
--- 757,760 ----
  {   /* Add new patch number below this line */
+ /**/
+     3442,
  /**/

-- 
The History of every major Galactic Civilization tends to pass through
three distinct and recognizable phases, those of Survival, Inquiry and
Sophistication, otherwise known as the How, Why and Where phases.
For instance, the first phase is characterized by the question 'How can
we eat?' the second by the question 'Why do we eat?' and the third by
the question 'Where shall we have lunch?'
                -- Douglas Adams, "The Hitchhiker's Guide to the Galaxy"

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            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/202109161415.18GEFlex1942160%40masaka.moolenaar.net.

Raspunde prin e-mail lui