changeset 26905:c2186e32ae42 v8.2.3981

patch 8.2.3981: Vim9: debugging a for loop doesn't stop before it starts Commit: https://github.com/vim/vim/commit/2b4ecc2c31c00df6e1c8ad46a3e4eabb1f1f84e3 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jan 2 14:08:18 2022 +0000 patch 8.2.3981: Vim9: debugging a for loop doesn't stop before it starts Problem: Vim9: debugging a for loop doesn't stop before it starts. Solution: Keep the DEBUG instruction before the expression is evaluated. (closes #9456)
author Bram Moolenaar <Bram@vim.org>
date Sun, 02 Jan 2022 15:15:03 +0100
parents 06cc23a34556
children 1b8859235072
files src/testdir/test_vim9_disassemble.vim src/version.c src/vim9cmds.c
diffstat 3 files changed, 61 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -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
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3981,
+/**/
     3980,
 /**/
     3979,
--- a/src/vim9cmds.c
+++ b/src/vim9cmds.c
@@ -803,14 +803,13 @@ compile_for(char_u *arg_start, cctx_T *c
     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 *c
 	// "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 *c
 	    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