]> granicus.if.org Git - vim/commitdiff
patch 8.2.3011: Vim9: cannot get argument values during debugging v8.2.3011
authorBram Moolenaar <Bram@vim.org>
Wed, 16 Jun 2021 17:19:55 +0000 (19:19 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 16 Jun 2021 17:19:55 +0000 (19:19 +0200)
Problem:    Vim9: cannot get argument values during debugging.
Solution:   Lookup names in the list of arguments.  Put debug instruction
            halfway for command.

src/testdir/test_debugger.vim
src/version.c
src/vim9compile.c
src/vim9execute.c

index bbf74258b289d5e2eea93763324330c79b2e5d43..5326576d02144add5b33bac2539091cf21549af0 100644 (file)
@@ -937,12 +937,20 @@ func Test_debug_def_function()
   let file =<< trim END
     vim9script
     def g:Func()
-        var n: number
-        def Closure(): number
-            return n + 3
-        enddef
-        n += Closure()
-        echo 'result: ' .. n
+      var n: number
+      def Closure(): number
+          return n + 3
+      enddef
+      n += Closure()
+      echo 'result: ' .. n
+    enddef
+
+    def g:FuncWithArgs(text: string, nr: number, ...items: list<number>)
+      echo text .. nr
+      for it in items
+        echo it
+      endfor
+      echo "done"
     enddef
   END
   call writefile(file, 'Xtest.vim')
@@ -954,7 +962,30 @@ func Test_debug_def_function()
                 \ ['cmd: call Func()'])
   call RunDbgCmd(buf, 'next', ['result: 3'])
   call term_sendkeys(buf, "\r")
+  call RunDbgCmd(buf, 'cont')
 
+  call RunDbgCmd(buf,
+                \ ':debug call FuncWithArgs("asdf", 42, 1, 2, 3)',
+                \ ['cmd: call FuncWithArgs("asdf", 42, 1, 2, 3)'])
+  call RunDbgCmd(buf, 'step', ['line 1:   echo text .. nr'])
+  call RunDbgCmd(buf, 'echo text', ['asdf'])
+  call RunDbgCmd(buf, 'echo nr', ['42'])
+  call RunDbgCmd(buf, 'echo items', ['[1, 2, 3]'])
+  call RunDbgCmd(buf, 'step', ['asdf42', 'function FuncWithArgs', 'line 2:   for it in items'])
+  call RunDbgCmd(buf, 'echo it', ['1'])
+  call RunDbgCmd(buf, 'step', ['line 3:     echo it'])
+  call RunDbgCmd(buf, 'step', ['1', 'function FuncWithArgs', 'line 4:   endfor'])
+  call RunDbgCmd(buf, 'step', ['line 2:   for it in items'])
+  call RunDbgCmd(buf, 'echo it', ['2'])
+  call RunDbgCmd(buf, 'step', ['line 3:     echo it'])
+  call RunDbgCmd(buf, 'step', ['2', 'function FuncWithArgs', 'line 4:   endfor'])
+  call RunDbgCmd(buf, 'step', ['line 2:   for it in items'])
+  call RunDbgCmd(buf, 'echo it', ['3'])
+  call RunDbgCmd(buf, 'step', ['line 3:     echo it'])
+  call RunDbgCmd(buf, 'step', ['3', 'function FuncWithArgs', 'line 4:   endfor'])
+  call RunDbgCmd(buf, 'step', ['line 5:   echo "done"'])
+
+  call RunDbgCmd(buf, 'cont')
   call StopVimInTerminal(buf)
   call delete('Xtest.vim')
 endfunc
index 9198e2cb3a09ccca41d282ed0b81607f1fed6752..dbb6d7ecda06a504bbbeace54cb2925ef80f4fe5 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3011,
 /**/
     3010,
 /**/
index 663a52dc7b5bd5c8f6fcd8e190fab371df6d881f..404c819e7800c71ffcfdfdc9d348164b7f3f638c 100644 (file)
@@ -7711,6 +7711,7 @@ compile_for(char_u *arg_start, cctx_T *cctx)
     int                semicolon = FALSE;
     size_t     varlen;
     garray_T   *stack = &cctx->ctx_type_stack;
+    garray_T   *instr = &cctx->ctx_instr;
     scope_T    *scope;
     lvar_T     *loop_lvar;     // loop iteration variable
     lvar_T     *var_lvar;      // variable for "var"
@@ -7737,6 +7738,13 @@ compile_for(char_u *arg_start, cctx_T *cctx)
     if (may_get_next_line_error(wp, &p, cctx) == FAIL)
        return NULL;
 
+    // Remove the already generated ISN_DEBUG, it is written below the ISN_FOR
+    // instruction.
+    if (cctx->ctx_compile_type == CT_DEBUG && instr->ga_len > 0
+           && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
+                                                       .isn_type == ISN_DEBUG)
+       --instr->ga_len;
+
     scope = new_scope(cctx, FOR_SCOPE);
     if (scope == NULL)
        return NULL;
@@ -7788,11 +7796,12 @@ compile_for(char_u *arg_start, cctx_T *cctx)
            item_type = vartype->tt_member->tt_member;
     }
 
-    // CMDMOD_REV must come before the FOR instruction
+    // CMDMOD_REV must come before the FOR instruction.
     generate_undo_cmdmods(cctx);
 
     // "for_end" is set when ":endfor" is found
     scope->se_u.se_for.fs_top_label = current_instr_idx(cctx);
+
     generate_FOR(cctx, loop_lvar->lv_idx);
 
     arg = arg_start;
@@ -7893,6 +7902,10 @@ compile_for(char_u *arg_start, cctx_T *cctx)
        vim_free(name);
     }
 
+    if (cctx->ctx_compile_type == CT_DEBUG)
+       // Add ISN_DEBUG here, so that the loop variables can be inspected.
+       generate_instr_debug(cctx);
+
     return arg_end;
 
 failed:
@@ -7927,7 +7940,7 @@ compile_endfor(char_u *arg, cctx_T *cctx)
     // At end of ":for" scope jump back to the FOR instruction.
     generate_JUMP(cctx, JUMP_ALWAYS, forscope->fs_top_label);
 
-    // Fill in the "end" label in the FOR statement so it can jump here
+    // Fill in the "end" label in the FOR statement so it can jump here.
     isn = ((isn_T *)instr->ga_data) + forscope->fs_top_label;
     isn->isn_arg.forloop.for_end = instr->ga_len;
 
@@ -8234,6 +8247,7 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED)
 #ifdef FEAT_PROFILE
        // the profile-start should be after the jump
        if (cctx->ctx_compile_type == CT_PROFILE
+               && instr->ga_len > 0
                && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
                                                   .isn_type == ISN_PROF_START)
            --instr->ga_len;
index e464732dda8da2b359e4fbd303a0fa60aab93063..bbcf7ffc3c0cd0bd205ea01e3a18156ed4520751 100644 (file)
@@ -1394,7 +1394,7 @@ typedef struct subs_expr_S {
 
 // Set when calling do_debug().
 static ectx_T  *debug_context = NULL;
-static int     debug_arg_count;
+static int     debug_var_count;
 
 /*
  * When debugging lookup "name" and return the typeval.
@@ -1405,20 +1405,31 @@ lookup_debug_var(char_u *name)
 {
     int                    idx;
     dfunc_T        *dfunc;
+    ufunc_T        *ufunc;
     ectx_T         *ectx = debug_context;
+    int                    varargs_off;
 
     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)
+    for (idx = debug_var_count - 1; idx >= 0; --idx)
     {
-       char_u *s = ((char_u **)dfunc->df_var_names.ga_data)[idx];
-       if (STRCMP(s, name) == 0)
+       if (STRCMP(((char_u **)dfunc->df_var_names.ga_data)[idx], name) == 0)
            return STACK_TV_VAR(idx);
     }
 
+    // Go through argument names.
+    ufunc = dfunc->df_ufunc;
+    varargs_off = ufunc->uf_va_name == NULL ? 0 : 1;
+    for (idx = 0; idx < ufunc->uf_args.ga_len; ++idx)
+       if (STRCMP(((char_u **)(ufunc->uf_args.ga_data))[idx], name) == 0)
+           return STACK_TV(ectx->ec_frame_idx - ufunc->uf_args.ga_len
+                                                         - varargs_off + idx);
+    if (ufunc->uf_va_name != NULL && STRCMP(ufunc->uf_va_name, name) == 0)
+       return STACK_TV(ectx->ec_frame_idx - 1);
+
     return NULL;
 }
 
@@ -4152,7 +4163,7 @@ exec_instructions(ectx_T *ectx)
 
                    SOURCING_LNUM = iptr->isn_lnum;
                    debug_context = ectx;
-                   debug_arg_count = iptr->isn_arg.number;
+                   debug_var_count = iptr->isn_arg.number;
                    line = ((char_u **)ufunc->uf_lines.ga_data)[
                                                           iptr->isn_lnum - 1];
                    if (line == NULL)