Patch 8.2.2996
Problem:    Vim9: when debugging cannot inspect local variables.
Solution:   Make local variables available when debugging.
Files:      src/vim9execute.c, src/proto/vim9execute.pro, src/vim9compile.c,
            src/vim9.h, src/debugger.c, src/testdir/test_debugger.vim


*** ../vim-8.2.2995/src/vim9execute.c   2021-06-13 18:38:44.688673497 +0200
--- src/vim9execute.c   2021-06-14 19:46:43.291876427 +0200
***************
*** 172,177 ****
--- 172,178 ----
      int               argcount = argcount_arg;
      dfunc_T   *dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx;
      ufunc_T   *ufunc = dfunc->df_ufunc;
+     int               did_emsg_before = did_emsg_cumul + did_emsg;
      int               arg_to_add;
      int               vararg_count = 0;
      int               varcount;
***************
*** 211,216 ****
--- 212,230 ----
      }
  #endif
  
+     // When debugging and using "cont" switches to the not-debugged
+     // instructions, may need to still compile them.
+     if ((func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
+              && compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL)
+                                                                     == FAIL)
+           || INSTRUCTIONS(dfunc) == NULL)
+     {
+       if (did_emsg_cumul + did_emsg == did_emsg_before)
+           semsg(_(e_function_is_not_compiled_str),
+                                                  printable_func_name(ufunc));
+       return FAIL;
+     }
+ 
      if (ufunc->uf_va_name != NULL)
      {
        // Need to make a list out of the vararg arguments.
***************
*** 1382,1387 ****
--- 1396,1431 ----
  // Get pointer to a local variable on the stack.  Negative for arguments.
  #define STACK_TV_VAR(idx) (((typval_T *)ectx->ec_stack.ga_data) + 
ectx->ec_frame_idx + STACK_FRAME_SIZE + idx)
  
+ // Set when calling do_debug().
+ static ectx_T *debug_context = NULL;
+ static int    debug_arg_count;
+ 
+ /*
+  * When debugging lookup "name" and return the typeval.
+  * When not found return NULL.
+  */
+     typval_T *
+ lookup_debug_var(char_u *name)
+ {
+     int                   idx;
+     dfunc_T       *dfunc;
+     ectx_T        *ectx = debug_context;
+ 
+     if (ectx == NULL)
+       return NULL;
+     dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
+ 
+     // Go through the local variable names, from last to first.
+     for (idx = debug_arg_count - 1; idx >= 0; --idx)
+     {
+       char_u *s = ((char_u **)dfunc->df_var_names.ga_data)[idx];
+       if (STRCMP(s, name) == 0)
+           return STACK_TV_VAR(idx);
+     }
+ 
+     return NULL;
+ }
+ 
  /*
   * Execute instructions in execution context "ectx".
   * Return OK or FAIL;
***************
*** 4087,4093 ****
                    funccall_T cookie;
                    ufunc_T         *cur_ufunc =
                                    (((dfunc_T *)def_functions.ga_data)
!                                                + 
ectx->ec_dfunc_idx)->df_ufunc;
  
                    cookie.func = cur_ufunc;
                    if (iptr->isn_type == ISN_PROF_START)
--- 4131,4137 ----
                    funccall_T cookie;
                    ufunc_T         *cur_ufunc =
                                    (((dfunc_T *)def_functions.ga_data)
!                                              + ectx->ec_dfunc_idx)->df_ufunc;
  
                    cookie.func = cur_ufunc;
                    if (iptr->isn_type == ISN_PROF_START)
***************
*** 4110,4120 ****
--- 4154,4167 ----
                                               + ectx->ec_dfunc_idx)->df_ufunc;
  
                    SOURCING_LNUM = iptr->isn_lnum;
+                   debug_context = ectx;
+                   debug_arg_count = iptr->isn_arg.number;
                    line = ((char_u **)ufunc->uf_lines.ga_data)[
                                                           iptr->isn_lnum - 1];
                    if (line == NULL)
                        line = (char_u *)"[empty]";
                    do_debug(line);
+                   debug_context = NULL;
                }
                break;
  
***************
*** 5346,5352 ****
                break;
  
            case ISN_DEBUG:
!               smsg("%s%4d DEBUG line %d", pfx, current, iptr->isn_lnum);
                break;
  
            case ISN_UNPACK: smsg("%s%4d UNPACK %d%s", pfx, current,
--- 5393,5400 ----
                break;
  
            case ISN_DEBUG:
!               smsg("%s%4d DEBUG line %d varcount %lld", pfx, current,
!                                        iptr->isn_lnum, iptr->isn_arg.number);
                break;
  
            case ISN_UNPACK: smsg("%s%4d UNPACK %d%s", pfx, current,
*** ../vim-8.2.2995/src/proto/vim9execute.pro   2021-06-13 18:38:44.688673497 
+0200
--- src/proto/vim9execute.pro   2021-06-14 16:21:13.469944772 +0200
***************
*** 4,9 ****
--- 4,10 ----
  char_u *char_from_string(char_u *str, varnumber_T index);
  char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int 
exclusive);
  int fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx);
+ typval_T *lookup_debug_var(char_u *name);
  int exe_typval_instr(typval_T *tv, typval_T *rettv);
  char_u *exe_substitute_instr(void);
  int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, partial_T 
*partial, typval_T *rettv);
*** ../vim-8.2.2995/src/vim9compile.c   2021-06-13 21:52:42.525260056 +0200
--- src/vim9compile.c   2021-06-14 19:49:58.575466644 +0200
***************
*** 177,183 ****
      compiletype_T ctx_compile_type;
  
      garray_T  ctx_locals;         // currently visible local variables
-     int               ctx_locals_count;   // total number of local variables
  
      int               ctx_has_closure;    // set to one if a closures was 
created in
                                    // the function
--- 177,182 ----
***************
*** 575,580 ****
--- 574,595 ----
  }
  
  /*
+  * Generate an ISN_DEBUG instruction.
+  */
+     static isn_T *
+ generate_instr_debug(cctx_T *cctx)
+ {
+     isn_T     *isn;
+     dfunc_T   *dfunc = ((dfunc_T *)def_functions.ga_data)
+                                              + cctx->ctx_ufunc->uf_dfunc_idx;
+ 
+     if ((isn = generate_instr(cctx, ISN_DEBUG)) == NULL)
+       return NULL;
+     isn->isn_arg.number = dfunc->df_var_names.ga_len;
+     return isn;
+ }
+ 
+ /*
   * If type at "offset" isn't already VAR_STRING then generate ISN_2STRING.
   * But only for simple types.
   * When "tolerant" is TRUE convert most types to string, e.g. a List.
***************
*** 2365,2370 ****
--- 2380,2386 ----
        type_T  *type)
  {
      lvar_T  *lvar;
+     dfunc_T *dfunc;
  
      if (arg_exists(name, len, NULL, NULL, NULL, cctx) == OK)
      {
***************
*** 2381,2392 ****
      // the last ones when leaving a scope, but then variables used in a 
closure
      // might get overwritten.  To keep things simple do not re-use stack
      // entries.  This is less efficient, but memory is cheap these days.
!     lvar->lv_idx = cctx->ctx_locals_count++;
  
      lvar->lv_name = vim_strnsave(name, len == 0 ? STRLEN(name) : len);
      lvar->lv_const = isConst;
      lvar->lv_type = type;
  
      return lvar;
  }
  
--- 2397,2416 ----
      // the last ones when leaving a scope, but then variables used in a 
closure
      // might get overwritten.  To keep things simple do not re-use stack
      // entries.  This is less efficient, but memory is cheap these days.
!     dfunc = ((dfunc_T *)def_functions.ga_data) + 
cctx->ctx_ufunc->uf_dfunc_idx;
!     lvar->lv_idx = dfunc->df_var_names.ga_len;
  
      lvar->lv_name = vim_strnsave(name, len == 0 ? STRLEN(name) : len);
      lvar->lv_const = isConst;
      lvar->lv_type = type;
  
+     // Remember the name for debugging.
+     if (ga_grow(&dfunc->df_var_names, 1) == FAIL)
+       return NULL;
+     ((char_u **)dfunc->df_var_names.ga_data)[lvar->lv_idx] =
+                                                   vim_strsave(lvar->lv_name);
+     ++dfunc->df_var_names.ga_len;
+ 
      return lvar;
  }
  
***************
*** 7486,7492 ****
        if (cctx->ctx_compile_type == CT_DEBUG)
        {
            // the previous block was skipped, may want to debug this line
!           generate_instr(cctx, ISN_DEBUG);
            instr_count = instr->ga_len;
        }
      }
--- 7510,7516 ----
        if (cctx->ctx_compile_type == CT_DEBUG)
        {
            // the previous block was skipped, may want to debug this line
!           generate_instr_debug(cctx);
            instr_count = instr->ga_len;
        }
      }
***************
*** 8239,8245 ****
        }
  #endif
        if (cctx->ctx_compile_type == CT_DEBUG)
!           generate_instr(cctx, ISN_DEBUG);
      }
  
      p = skipwhite(arg);
--- 8263,8269 ----
        }
  #endif
        if (cctx->ctx_compile_type == CT_DEBUG)
!           generate_instr_debug(cctx);
      }
  
      p = skipwhite(arg);
***************
*** 8976,8981 ****
--- 9000,9006 ----
      ufunc->uf_dfunc_idx = dfunc->df_idx;
      dfunc->df_ufunc = ufunc;
      dfunc->df_name = vim_strsave(ufunc->uf_name);
+     ga_init2(&dfunc->df_var_names, sizeof(char_u *), 10);
      ++dfunc->df_refcount;
      ++def_functions.ga_len;
      return OK;
***************
*** 9026,9032 ****
      {
        dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
                                                         + ufunc->uf_dfunc_idx;
!       delete_def_function_contents(dfunc, FALSE);
      }
      else
      {
--- 9051,9071 ----
      {
        dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
                                                         + ufunc->uf_dfunc_idx;
!       isn_T   *instr_dest;
! 
!       switch (compile_type)
!       {
!           case CT_PROFILE:
! #ifdef FEAT_PROFILE
!                           instr_dest = dfunc->df_instr_prof; break;
! #endif
!           case CT_NONE:   instr_dest = dfunc->df_instr; break;
!           case CT_DEBUG:  instr_dest = dfunc->df_instr_debug; break;
!       }
!       if (instr_dest != NULL)
!           // Was compiled in this mode before: Free old instructions.
!           delete_def_function_contents(dfunc, FALSE);
!       ga_clear_strings(&dfunc->df_var_names);
      }
      else
      {
***************
*** 9202,9208 ****
                                                  && cctx.ctx_skip != SKIP_YES)
        {
            debug_lnum = cctx.ctx_lnum;
!           generate_instr(&cctx, ISN_DEBUG);
        }
  
        // Some things can be recognized by the first character.
--- 9241,9247 ----
                                                  && cctx.ctx_skip != SKIP_YES)
        {
            debug_lnum = cctx.ctx_lnum;
!           generate_instr_debug(&cctx);
        }
  
        // Some things can be recognized by the first character.
***************
*** 9670,9676 ****
            dfunc->df_instr = instr->ga_data;
            dfunc->df_instr_count = instr->ga_len;
        }
!       dfunc->df_varcount = cctx.ctx_locals_count;
        dfunc->df_has_closure = cctx.ctx_has_closure;
        if (cctx.ctx_outer_used)
            ufunc->uf_flags |= FC_CLOSURE;
--- 9709,9715 ----
            dfunc->df_instr = instr->ga_data;
            dfunc->df_instr_count = instr->ga_len;
        }
!       dfunc->df_varcount = dfunc->df_var_names.ga_len;
        dfunc->df_has_closure = cctx.ctx_has_closure;
        if (cctx.ctx_outer_used)
            ufunc->uf_flags |= FC_CLOSURE;
***************
*** 10037,10042 ****
--- 10076,10082 ----
      int idx;
  
      ga_clear(&dfunc->df_def_args_isn);
+     ga_clear_strings(&dfunc->df_var_names);
  
      if (dfunc->df_instr != NULL)
      {
*** ../vim-8.2.2995/src/vim9.h  2021-06-13 15:15:58.412822225 +0200
--- src/vim9.h  2021-06-14 19:11:44.587949612 +0200
***************
*** 168,174 ****
      ISN_PROF_START, // start a line for profiling
      ISN_PROF_END,   // end a line for profiling
  
!     ISN_DEBUG,            // check for debug breakpoint
  
      ISN_UNPACK,           // unpack list into items, uses isn_arg.unpack
      ISN_SHUFFLE,    // move item on stack up or down
--- 168,175 ----
      ISN_PROF_START, // start a line for profiling
      ISN_PROF_END,   // end a line for profiling
  
!     ISN_DEBUG,            // check for debug breakpoint, isn_arg.number is 
current
!                   // number of local variables
  
      ISN_UNPACK,           // unpack list into items, uses isn_arg.unpack
      ISN_SHUFFLE,    // move item on stack up or down
***************
*** 447,452 ****
--- 448,454 ----
                                    // was compiled.
  
      garray_T  df_def_args_isn;    // default argument instructions
+     garray_T  df_var_names;       // names of local vars
  
      // After compiling "df_instr" and/or "df_instr_prof" is not NULL.
      isn_T     *df_instr;          // function body to be executed
*** ../vim-8.2.2995/src/debugger.c      2021-06-07 22:04:48.406620074 +0200
--- src/debugger.c      2021-06-12 16:50:32.238322962 +0200
***************
*** 218,224 ****
  
            if (last_cmd != 0)
            {
!               // Execute debug command: decided where to break next and
                // return.
                switch (last_cmd)
                {
--- 218,224 ----
  
            if (last_cmd != 0)
            {
!               // Execute debug command: decide where to break next and
                // return.
                switch (last_cmd)
                {
*** ../vim-8.2.2995/src/testdir/test_debugger.vim       2021-06-13 
14:01:22.760396977 +0200
--- src/testdir/test_debugger.vim       2021-06-14 20:31:47.040141296 +0200
***************
*** 853,858 ****
--- 853,859 ----
      enddef
  
      def g:GlobalFunction()
+       var some = "some var"
        CallAFunction()
      enddef
  
***************
*** 884,902 ****
                  \ ':debug call GlobalFunction()',
                  \ ['cmd: call GlobalFunction()'])
  
!   call RunDbgCmd(buf, 'step', ['line 1:   CallAFunction()'])
  
-   " FIXME: not quite right
    call RunDbgCmd(buf, 'backtrace', [
          \ '\V>backtrace',
          \ '\V->0 function GlobalFunction',
!         \ '\Vline 1:   CallAFunction()',
          \ ],
          \ #{match: 'pattern'})
  
    call RunDbgCmd(buf, 'step', ['line 1:   SourceAnotherFile()'])
    call RunDbgCmd(buf, 'step', ['line 1:   source Xtest2.vim'])
!   " FIXME: repeated line
    call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
    call RunDbgCmd(buf, 'step', ['line 1: vim9script'])
    call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number'])
--- 885,905 ----
                  \ ':debug call GlobalFunction()',
                  \ ['cmd: call GlobalFunction()'])
  
!   call RunDbgCmd(buf, 'step', ['line 1:   var some = "some var"'])
!   call RunDbgCmd(buf, 'step', ['line 2:   CallAFunction()'])
!   call RunDbgCmd(buf, 'echo some', ['some var'])
  
    call RunDbgCmd(buf, 'backtrace', [
          \ '\V>backtrace',
          \ '\V->0 function GlobalFunction',
!         \ '\Vline 2:   CallAFunction()',
          \ ],
          \ #{match: 'pattern'})
  
    call RunDbgCmd(buf, 'step', ['line 1:   SourceAnotherFile()'])
    call RunDbgCmd(buf, 'step', ['line 1:   source Xtest2.vim'])
!   " Repeated line, because we fist are in the compiled function before the
!   " EXEC and then in do_cmdline() before the :source command.
    call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
    call RunDbgCmd(buf, 'step', ['line 1: vim9script'])
    call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number'])
***************
*** 906,912 ****
    call RunDbgCmd(buf, 'step', ['line 14: File2Function()'])
    call RunDbgCmd(buf, 'backtrace', [
          \ '\V>backtrace',
!         \ '\V  3 function GlobalFunction[1]',
          \ '\V  2 <SNR>\.\*_CallAFunction[1]',
          \ '\V  1 <SNR>\.\*_SourceAnotherFile[1]',
          \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
--- 909,915 ----
    call RunDbgCmd(buf, 'step', ['line 14: File2Function()'])
    call RunDbgCmd(buf, 'backtrace', [
          \ '\V>backtrace',
!         \ '\V  3 function GlobalFunction[2]',
          \ '\V  2 <SNR>\.\*_CallAFunction[1]',
          \ '\V  1 <SNR>\.\*_SourceAnotherFile[1]',
          \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
***************
*** 917,923 ****
    call RunDbgCmd(buf, 'next', ['line 15: End of sourced file'])
    call RunDbgCmd(buf, 'backtrace', [
          \ '\V>backtrace',
!         \ '\V  3 function GlobalFunction[1]',
          \ '\V  2 <SNR>\.\*_CallAFunction[1]',
          \ '\V  1 <SNR>\.\*_SourceAnotherFile[1]',
          \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
--- 920,926 ----
    call RunDbgCmd(buf, 'next', ['line 15: End of sourced file'])
    call RunDbgCmd(buf, 'backtrace', [
          \ '\V>backtrace',
!         \ '\V  3 function GlobalFunction[2]',
          \ '\V  2 <SNR>\.\*_CallAFunction[1]',
          \ '\V  1 <SNR>\.\*_SourceAnotherFile[1]',
          \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
*** ../vim-8.2.2995/src/version.c       2021-06-14 15:08:26.331250889 +0200
--- src/version.c       2021-06-14 16:12:49.891434923 +0200
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2996,
  /**/

-- 
I once paid $12 to peer at the box that held King Tutankhamen's little
bandage-covered midget corpse at the De Young Museum in San Francisco.  I
remember thinking how pleased he'd be about the way things turned out in his
afterlife.
                                (Scott Adams - The Dilbert principle)

 /// 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/202106141841.15EIf3Lb911555%40masaka.moolenaar.net.

Raspunde prin e-mail lui