]> granicus.if.org Git - vim/commitdiff
patch 8.2.3981: Vim9: debugging a for loop doesn't stop before it starts v8.2.3981
authorBram Moolenaar <Bram@vim.org>
Sun, 2 Jan 2022 14:08:18 +0000 (14:08 +0000)
committerBram Moolenaar <Bram@vim.org>
Sun, 2 Jan 2022 14:08:18 +0000 (14:08 +0000)
Problem:    Vim9: debugging a for loop doesn't stop before it starts.
Solution:   Keep the DEBUG instruction before the expression is evaluated.
            (closes #9456)

src/testdir/test_vim9_disassemble.vim
src/version.c
src/vim9cmds.c

index 55a43058419ca65e131ffbc530df6afef4c74f81..d4a5309d996141db3f588e1f48fa773eb0166e91 100644 (file)
@@ -2434,6 +2434,43 @@ def Test_debug_elseif()
         res)
 enddef
 
+def s:DebugFor()
+  echo "hello"
+  for a in [0]
+    echo a
+  endfor
+enddef
+
+def Test_debug_for()
+  var res = execute('disass debug s:DebugFor')
+  assert_match('<SNR>\d*_DebugFor\_s*' ..
+          'echo "hello"\_s*' ..
+          '0 DEBUG line 1-1 varcount 0\_s*' ..
+          '1 PUSHS "hello"\_s*' ..
+          '2 ECHO 1\_s*' ..
+
+          'for a in \[0\]\_s*' ..
+          '3 DEBUG line 2-2 varcount 0\_s*' ..
+          '4 STORE -1 in $0\_s*' ..
+          '5 PUSHNR 0\_s*' ..
+          '6 NEWLIST size 1\_s*' ..
+          '7 DEBUG line 2-2 varcount 2\_s*' ..
+          '8 FOR $0 -> 15\_s*' ..
+          '9 STORE $1\_s*' ..
+
+          'echo a\_s*' ..
+          '10 DEBUG line 3-3 varcount 2\_s*' ..
+          '11 LOAD $1\_s*' ..
+          '12 ECHO 1\_s*' ..
+
+          'endfor\_s*' ..
+          '13 DEBUG line 4-4 varcount 2\_s*' ..
+          '14 JUMP -> 7\_s*' ..
+          '15 DROP\_s*' ..
+          '16 RETURN void*',
+        res)
+enddef
+
 func Legacy() dict
   echo 'legacy'
 endfunc
index 2ca87fec33614d7d7f3c224ded575a56af51c259..521fe3978023d6db947b78771f6f18d4f07602fb 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3981,
 /**/
     3980,
 /**/
index 5a86a940ccfd04e3c90f67ac525c953ae177a292..e11825dde9db3e7a8864e4ebc6b6f3b7b4ac6bd0 100644 (file)
@@ -803,14 +803,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.
+    // Find the already generated ISN_DEBUG to get the line number for the
+    // instruction 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;
-       prev_lnum = ((isn_T *)instr->ga_data)[instr->ga_len]
+       prev_lnum = ((isn_T *)instr->ga_data)[instr->ga_len - 1]
                                                 .isn_arg.debug.dbg_break_lnum;
     }
 
@@ -875,6 +874,22 @@ compile_for(char_u *arg_start, cctx_T *cctx)
        // "for_end" is set when ":endfor" is found
        scope->se_u.se_for.fs_top_label = current_instr_idx(cctx);
 
+       if (cctx->ctx_compile_type == CT_DEBUG)
+       {
+           int         save_prev_lnum = cctx->ctx_prev_lnum;
+           isn_T       *isn;
+
+           // Add ISN_DEBUG here, before deciding to end the loop.  There will
+           // be another ISN_DEBUG before the next instruction.
+           // Use the prev_lnum from the ISN_DEBUG instruction removed above.
+           // Increment the variable count so that the loop variable can be
+           // inspected.
+           cctx->ctx_prev_lnum = prev_lnum;
+           isn = generate_instr_debug(cctx);
+           ++isn->isn_arg.debug.dbg_var_names_len;
+           cctx->ctx_prev_lnum = save_prev_lnum;
+       }
+
        generate_FOR(cctx, loop_lvar->lv_idx);
 
        arg = arg_start;
@@ -979,17 +994,6 @@ compile_for(char_u *arg_start, cctx_T *cctx)
            arg = skipwhite(p);
            vim_free(name);
        }
-
-       if (cctx->ctx_compile_type == CT_DEBUG)
-       {
-           int save_prev_lnum = cctx->ctx_prev_lnum;
-
-           // Add ISN_DEBUG here, so that the loop variables can be inspected.
-           // Use the prev_lnum from the ISN_DEBUG instruction removed above.
-           cctx->ctx_prev_lnum = prev_lnum;
-           generate_instr_debug(cctx);
-           cctx->ctx_prev_lnum = save_prev_lnum;
-       }
     }
 
     return arg_end;
@@ -1029,7 +1033,9 @@ compile_endfor(char_u *arg, cctx_T *cctx)
        generate_JUMP(cctx, JUMP_ALWAYS, forscope->fs_top_label);
 
        // Fill in the "end" label in the FOR statement so it can jump here.
-       isn = ((isn_T *)instr->ga_data) + forscope->fs_top_label;
+       // In debug mode an ISN_DEBUG was inserted.
+       isn = ((isn_T *)instr->ga_data) + forscope->fs_top_label
+                               + (cctx->ctx_compile_type == CT_DEBUG ? 1 : 0);
        isn->isn_arg.forloop.for_end = instr->ga_len;
 
        // Fill in the "end" label any BREAK statements