Patch 8.2.2985
Problem:    Vim9: a compiled function cannot be debugged.
Solution:   Add initial debugging support.
Files:      src/vim9.h, src/vim9compile.c, src/proto/vim9compile.pro,
            src/vim.h, src/eval.c, src/vim9execute.c, src/userfunc.c,
            src/vim9type.c, src/testdir/test_debugger.vim,
            src/testdir/test_vim9_disassemble.vim


*** ../vim-8.2.2984/src/vim9.h  2021-06-06 17:02:49.753789485 +0200
--- src/vim9.h  2021-06-12 18:04:15.659477801 +0200
***************
*** 168,173 ****
--- 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_UNPACK,           // unpack list into items, uses isn_arg.unpack
      ISN_SHUFFLE,    // move item on stack up or down
      ISN_DROP,     // pop stack and discard value
***************
*** 453,458 ****
--- 455,462 ----
      isn_T     *df_instr_prof;      // like "df_instr" with profiling
      int               df_instr_prof_count; // size of "df_instr_prof"
  #endif
+     isn_T     *df_instr_debug;      // like "df_instr" with debugging
+     int               df_instr_debug_count; // size of "df_instr_debug"
  
      int               df_varcount;        // number of local variables
      int               df_has_closure;     // one if a closure was created
*** ../vim-8.2.2984/src/vim9compile.c   2021-06-12 18:30:51.510966898 +0200
--- src/vim9compile.c   2021-06-13 13:58:03.548742416 +0200
***************
*** 174,180 ****
      char_u    *ctx_line_start;    // start of current line or NULL
      garray_T  ctx_instr;          // generated instructions
  
!     int               ctx_profiling;      // when TRUE generate ISN_PROF_START
  
      garray_T  ctx_locals;         // currently visible local variables
      int               ctx_locals_count;   // total number of local variables
--- 174,180 ----
      char_u    *ctx_line_start;    // start of current line or NULL
      garray_T  ctx_instr;          // generated instructions
  
!     compiletype_T ctx_compile_type;
  
      garray_T  ctx_locals;         // currently visible local variables
      int               ctx_locals_count;   // total number of local variables
***************
*** 1857,1863 ****
   * "profile" indicates profiling is to be done.
   */
      int
! func_needs_compiling(ufunc_T *ufunc, int profile UNUSED)
  {
      switch (ufunc->uf_def_status)
      {
--- 1857,1863 ----
   * "profile" indicates profiling is to be done.
   */
      int
! func_needs_compiling(ufunc_T *ufunc, compiletype_T compile_type)
  {
      switch (ufunc->uf_def_status)
      {
***************
*** 1866,1880 ****
  
        case UF_COMPILED:
        {
- #ifdef FEAT_PROFILE
            dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
                                                         + ufunc->uf_dfunc_idx;
  
!           return profile ? dfunc->df_instr_prof == NULL
!                          : dfunc->df_instr == NULL;
! #else
!           break;
! #endif
        }
  
        case UF_NOT_COMPILED:
--- 1866,1883 ----
  
        case UF_COMPILED:
        {
            dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
                                                         + ufunc->uf_dfunc_idx;
  
!           switch (compile_type)
!           {
!               case CT_NONE:
!                   return dfunc->df_instr == NULL;
!               case CT_PROFILE:
!                   return dfunc->df_instr_prof == NULL;
!               case CT_DEBUG:
!                   return dfunc->df_instr_debug == NULL;
!           }
        }
  
        case UF_NOT_COMPILED:
***************
*** 1945,1953 ****
                return FAIL;
            }
        }
!       if (func_needs_compiling(ufunc, PROFILING(ufunc))
                && compile_def_function(ufunc, ufunc->uf_ret_type == NULL,
!                                              PROFILING(ufunc), NULL) == FAIL)
            return FAIL;
      }
      if (ufunc->uf_def_status == UF_COMPILE_ERROR)
--- 1948,1956 ----
                return FAIL;
            }
        }
!       if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
                && compile_def_function(ufunc, ufunc->uf_ret_type == NULL,
!                                           COMPILE_TYPE(ufunc), NULL) == FAIL)
            return FAIL;
      }
      if (ufunc->uf_def_status == UF_COMPILE_ERROR)
***************
*** 2313,2326 ****
      garray_T  *instr = &cctx->ctx_instr;
      int               idx = instr->ga_len;
  
!     if (cctx->ctx_has_cmdmod && ((isn_T *)instr->ga_data)[idx - 1]
                                                       .isn_type == ISN_CMDMOD)
!       --idx;
  #ifdef FEAT_PROFILE
!     if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[idx - 1]
!                                                  .isn_type == ISN_PROF_START)
!       --idx;
  #endif
      return idx;
  }
  
--- 2316,2343 ----
      garray_T  *instr = &cctx->ctx_instr;
      int               idx = instr->ga_len;
  
!     while (idx > 0)
!     {
!       if (cctx->ctx_has_cmdmod && ((isn_T *)instr->ga_data)[idx - 1]
                                                       .isn_type == ISN_CMDMOD)
!       {
!           --idx;
!           continue;
!       }
  #ifdef FEAT_PROFILE
!       if (((isn_T *)instr->ga_data)[idx - 1].isn_type == ISN_PROF_START)
!       {
!           --idx;
!           continue;
!       }
  #endif
+       if (((isn_T *)instr->ga_data)[idx - 1].isn_type == ISN_DEBUG)
+       {
+           --idx;
+           continue;
+       }
+       break;
+     }
      return idx;
  }
  
***************
*** 2328,2334 ****
      static void
  may_generate_prof_end(cctx_T *cctx, int prof_lnum)
  {
!     if (cctx->ctx_profiling && prof_lnum >= 0)
        generate_instr(cctx, ISN_PROF_END);
  }
  #endif
--- 2345,2351 ----
      static void
  may_generate_prof_end(cctx_T *cctx, int prof_lnum)
  {
!     if (cctx->ctx_compile_type == CT_PROFILE && prof_lnum >= 0)
        generate_instr(cctx, ISN_PROF_END);
  }
  #endif
***************
*** 2972,2979 ****
        return FAIL;
  
      // Need to compile any default values to get the argument types.
!     if (func_needs_compiling(ufunc, PROFILING(ufunc))
!           && compile_def_function(ufunc, TRUE, PROFILING(ufunc), NULL)
                                                                       == FAIL)
        return FAIL;
      return generate_PUSHFUNC(cctx, ufunc->uf_name, ufunc->uf_func_type);
--- 2989,2996 ----
        return FAIL;
  
      // Need to compile any default values to get the argument types.
!     if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
!           && compile_def_function(ufunc, TRUE, COMPILE_TYPE(ufunc), NULL)
                                                                       == FAIL)
        return FAIL;
      return generate_PUSHFUNC(cctx, ufunc->uf_name, ufunc->uf_func_type);
***************
*** 3570,3576 ****
      // compile_return().
      if (ufunc->uf_ret_type->tt_type == VAR_VOID)
        ufunc->uf_ret_type = &t_unknown;
!     compile_def_function(ufunc, FALSE, PROFILING(ufunc), cctx);
  
      // evalarg.eval_tofree_cmdline may have a copy of the last line and "*arg"
      // points into it.  Point to the original line to avoid a dangling 
pointer.
--- 3587,3593 ----
      // compile_return().
      if (ufunc->uf_ret_type->tt_type == VAR_VOID)
        ufunc->uf_ret_type = &t_unknown;
!     compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), cctx);
  
      // evalarg.eval_tofree_cmdline may have a copy of the last line and "*arg"
      // points into it.  Point to the original line to avoid a dangling 
pointer.
***************
*** 5566,5573 ****
        }
      }
  
!     if (func_needs_compiling(ufunc, PROFILING(ufunc))
!           && compile_def_function(ufunc, TRUE, PROFILING(ufunc), cctx)
                                                                       == FAIL)
      {
        func_ptr_unref(ufunc);
--- 5583,5590 ----
        }
      }
  
!     if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
!           && compile_def_function(ufunc, TRUE, COMPILE_TYPE(ufunc), cctx)
                                                                       == FAIL)
      {
        func_ptr_unref(ufunc);
***************
*** 7376,7382 ****
        scope->se_u.se_if.is_if_label = -1;
  
  #ifdef FEAT_PROFILE
!     if (cctx->ctx_profiling && cctx->ctx_skip == SKIP_YES
                                                      && skip_save != SKIP_YES)
      {
        // generated a profile start, need to generate a profile end, since it
--- 7393,7399 ----
        scope->se_u.se_if.is_if_label = -1;
  
  #ifdef FEAT_PROFILE
!     if (cctx->ctx_compile_type == CT_PROFILE && cctx->ctx_skip == SKIP_YES
                                                      && skip_save != SKIP_YES)
      {
        // generated a profile start, need to generate a profile end, since it
***************
*** 7457,7469 ****
      {
        cctx->ctx_skip = SKIP_UNKNOWN;
  #ifdef FEAT_PROFILE
!       if (cctx->ctx_profiling)
        {
            // the previous block was skipped, need to profile this line
            generate_instr(cctx, ISN_PROF_START);
            instr_count = instr->ga_len;
        }
  #endif
      }
      if (compile_expr1(&p, cctx, &ppconst) == FAIL)
      {
--- 7474,7492 ----
      {
        cctx->ctx_skip = SKIP_UNKNOWN;
  #ifdef FEAT_PROFILE
!       if (cctx->ctx_compile_type == CT_PROFILE)
        {
            // the previous block was skipped, need to profile this line
            generate_instr(cctx, ISN_PROF_START);
            instr_count = instr->ga_len;
        }
  #endif
+       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;
+       }
      }
      if (compile_expr1(&p, cctx, &ppconst) == FAIL)
      {
***************
*** 7531,7542 ****
      scope->se_u.se_if.is_seen_else = TRUE;
  
  #ifdef FEAT_PROFILE
!     if (cctx->ctx_profiling)
      {
        if (cctx->ctx_skip == SKIP_NOT
                && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
                                                   .isn_type == ISN_PROF_START)
!           // the previous block was executed, do not count "else" for 
profiling
            --instr->ga_len;
        if (cctx->ctx_skip == SKIP_YES && !scope->se_u.se_if.is_seen_skip_not)
        {
--- 7554,7566 ----
      scope->se_u.se_if.is_seen_else = TRUE;
  
  #ifdef FEAT_PROFILE
!     if (cctx->ctx_compile_type == CT_PROFILE)
      {
        if (cctx->ctx_skip == SKIP_NOT
                && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
                                                   .isn_type == ISN_PROF_START)
!           // the previous block was executed, do not count "else" for
!           // profiling
            --instr->ga_len;
        if (cctx->ctx_skip == SKIP_YES && !scope->se_u.se_if.is_seen_skip_not)
        {
***************
*** 7612,7618 ****
  #ifdef FEAT_PROFILE
      // even when skipping we count the endif as executed, unless the block 
it's
      // in is skipped
!     if (cctx->ctx_profiling && cctx->ctx_skip == SKIP_YES
                                            && scope->se_skip_save != SKIP_YES)
      {
        cctx->ctx_skip = SKIP_NOT;
--- 7636,7642 ----
  #ifdef FEAT_PROFILE
      // even when skipping we count the endif as executed, unless the block 
it's
      // in is skipped
!     if (cctx->ctx_compile_type == CT_PROFILE && cctx->ctx_skip == SKIP_YES
                                            && scope->se_skip_save != SKIP_YES)
      {
        cctx->ctx_skip = SKIP_NOT;
***************
*** 8183,8189 ****
      {
  #ifdef FEAT_PROFILE
        // the profile-start should be after the jump
!       if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
                                                   .isn_type == ISN_PROF_START)
            --instr->ga_len;
  #endif
--- 8207,8214 ----
      {
  #ifdef FEAT_PROFILE
        // the profile-start should be after the jump
!       if (cctx->ctx_compile_type == CT_PROFILE
!               && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
                                                   .isn_type == ISN_PROF_START)
            --instr->ga_len;
  #endif
***************
*** 8203,8209 ****
            isn->isn_arg.jump.jump_where = instr->ga_len;
        }
  #ifdef FEAT_PROFILE
!       if (cctx->ctx_profiling)
        {
            // a "throw" that jumps here needs to be counted
            generate_instr(cctx, ISN_PROF_END);
--- 8228,8234 ----
            isn->isn_arg.jump.jump_where = instr->ga_len;
        }
  #ifdef FEAT_PROFILE
!       if (cctx->ctx_compile_type == CT_PROFILE)
        {
            // a "throw" that jumps here needs to be counted
            generate_instr(cctx, ISN_PROF_END);
***************
*** 8211,8216 ****
--- 8236,8243 ----
            generate_instr(cctx, ISN_PROF_START);
        }
  #endif
+       if (cctx->ctx_compile_type == CT_DEBUG)
+           generate_instr(cctx, ISN_DEBUG);
      }
  
      p = skipwhite(arg);
***************
*** 8298,8304 ****
  
      this_instr = instr->ga_len;
  #ifdef FEAT_PROFILE
!     if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
                                                   .isn_type == ISN_PROF_START)
        // jump to the profile start of the "finally"
        --this_instr;
--- 8325,8332 ----
  
      this_instr = instr->ga_len;
  #ifdef FEAT_PROFILE
!     if (cctx->ctx_compile_type == CT_PROFILE
!           && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
                                                   .isn_type == ISN_PROF_START)
        // jump to the profile start of the "finally"
        --this_instr;
***************
*** 8367,8373 ****
        }
  
  #ifdef FEAT_PROFILE
!       if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
                                                .isn_type == ISN_PROF_START)
            // move the profile start after "endtry" so that it's not counted 
when
            // the exception is rethrown.
--- 8395,8402 ----
        }
  
  #ifdef FEAT_PROFILE
!       if (cctx->ctx_compile_type == CT_PROFILE
!               && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
                                                .isn_type == ISN_PROF_START)
            // move the profile start after "endtry" so that it's not counted 
when
            // the exception is rethrown.
***************
*** 8399,8405 ****
                                   && generate_instr(cctx, ISN_ENDTRY) == NULL)
            return NULL;
  #ifdef FEAT_PROFILE
!       if (cctx->ctx_profiling)
            generate_instr(cctx, ISN_PROF_START);
  #endif
      }
--- 8428,8434 ----
                                   && generate_instr(cctx, ISN_ENDTRY) == NULL)
            return NULL;
  #ifdef FEAT_PROFILE
!       if (cctx->ctx_compile_type == CT_PROFILE)
            generate_instr(cctx, ISN_PROF_START);
  #endif
      }
***************
*** 8965,8974 ****
   */
      int
  compile_def_function(
!       ufunc_T     *ufunc,
!       int         check_return_type,
!       int         profiling UNUSED,
!       cctx_T      *outer_cctx)
  {
      char_u    *line = NULL;
      char_u    *line_to_free = NULL;
--- 8994,9003 ----
   */
      int
  compile_def_function(
!       ufunc_T         *ufunc,
!       int             check_return_type,
!       compiletype_T   compile_type,
!       cctx_T          *outer_cctx)
  {
      char_u    *line = NULL;
      char_u    *line_to_free = NULL;
***************
*** 8987,8992 ****
--- 9016,9022 ----
  #ifdef FEAT_PROFILE
      int               prof_lnum = -1;
  #endif
+     int               debug_lnum = -1;
  
      // When using a function that was compiled before: Free old instructions.
      // The index is reused.  Otherwise add a new entry in "def_functions".
***************
*** 9007,9015 ****
  
      CLEAR_FIELD(cctx);
  
! #ifdef FEAT_PROFILE
!     cctx.ctx_profiling = profiling;
! #endif
      cctx.ctx_ufunc = ufunc;
      cctx.ctx_lnum = -1;
      cctx.ctx_outer = outer_cctx;
--- 9037,9043 ----
  
      CLEAR_FIELD(cctx);
  
!     cctx.ctx_compile_type = compile_type;
      cctx.ctx_ufunc = ufunc;
      cctx.ctx_lnum = -1;
      cctx.ctx_outer = outer_cctx;
***************
*** 9159,9166 ****
        }
  
  #ifdef FEAT_PROFILE
!       if (cctx.ctx_profiling && cctx.ctx_lnum != prof_lnum &&
!                                                    cctx.ctx_skip != SKIP_YES)
        {
            may_generate_prof_end(&cctx, prof_lnum);
  
--- 9187,9194 ----
        }
  
  #ifdef FEAT_PROFILE
!       if (cctx.ctx_compile_type == CT_PROFILE && cctx.ctx_lnum != prof_lnum
!                                                 && cctx.ctx_skip != SKIP_YES)
        {
            may_generate_prof_end(&cctx, prof_lnum);
  
***************
*** 9168,9173 ****
--- 9196,9207 ----
            generate_instr(&cctx, ISN_PROF_START);
        }
  #endif
+       if (cctx.ctx_compile_type == CT_DEBUG && cctx.ctx_lnum != debug_lnum
+                                                 && cctx.ctx_skip != SKIP_YES)
+       {
+           debug_lnum = cctx.ctx_lnum;
+           generate_instr(&cctx, ISN_DEBUG);
+       }
  
        // Some things can be recognized by the first character.
        switch (*ea.cmd)
***************
*** 9617,9629 ****
        dfunc->df_deleted = FALSE;
        dfunc->df_script_seq = current_sctx.sc_seq;
  #ifdef FEAT_PROFILE
!       if (cctx.ctx_profiling)
        {
            dfunc->df_instr_prof = instr->ga_data;
            dfunc->df_instr_prof_count = instr->ga_len;
        }
        else
  #endif
        {
            dfunc->df_instr = instr->ga_data;
            dfunc->df_instr_count = instr->ga_len;
--- 9651,9669 ----
        dfunc->df_deleted = FALSE;
        dfunc->df_script_seq = current_sctx.sc_seq;
  #ifdef FEAT_PROFILE
!       if (cctx.ctx_compile_type == CT_PROFILE)
        {
            dfunc->df_instr_prof = instr->ga_data;
            dfunc->df_instr_prof_count = instr->ga_len;
        }
        else
  #endif
+       if (cctx.ctx_compile_type == CT_DEBUG)
+       {
+           dfunc->df_instr_debug = instr->ga_data;
+           dfunc->df_instr_debug_count = instr->ga_len;
+       }
+       else
        {
            dfunc->df_instr = instr->ga_data;
            dfunc->df_instr_count = instr->ga_len;
***************
*** 9919,9924 ****
--- 9959,9965 ----
        case ISN_COMPARESTRING:
        case ISN_CONCAT:
        case ISN_COND2BOOL:
+       case ISN_DEBUG:
        case ISN_DROP:
        case ISN_ECHO:
        case ISN_ECHOERR:
***************
*** 9927,9932 ****
--- 9968,9974 ----
        case ISN_EXECCONCAT:
        case ISN_EXECUTE:
        case ISN_FINALLY:
+       case ISN_FINISH:
        case ISN_FOR:
        case ISN_GETITEM:
        case ISN_JUMP:
***************
*** 9949,9955 ****
        case ISN_NEWLIST:
        case ISN_OPANY:
        case ISN_OPFLOAT:
-       case ISN_FINISH:
        case ISN_OPNR:
        case ISN_PCALL:
        case ISN_PCALL_END:
--- 9991,9996 ----
*** ../vim-8.2.2984/src/proto/vim9compile.pro   2021-04-07 21:21:09.473817695 
+0200
--- src/proto/vim9compile.pro   2021-06-12 18:59:23.230860742 +0200
***************
*** 3,9 ****
  int check_compare_types(exprtype_T type, typval_T *tv1, typval_T *tv2);
  int use_typecheck(type_T *actual, type_T *expected);
  int need_type(type_T *actual, type_T *expected, int offset, int arg_idx, 
cctx_T *cctx, int silent, int actual_is_const);
! int func_needs_compiling(ufunc_T *ufunc, int profile);
  int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T 
*cctx);
  imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
  imported_T *find_imported_in_script(char_u *name, size_t len, int sid);
--- 3,9 ----
  int check_compare_types(exprtype_T type, typval_T *tv1, typval_T *tv2);
  int use_typecheck(type_T *actual, type_T *expected);
  int need_type(type_T *actual, type_T *expected, int offset, int arg_idx, 
cctx_T *cctx, int silent, int actual_is_const);
! int func_needs_compiling(ufunc_T *ufunc, compiletype_T compile_type);
  int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T 
*cctx);
  imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
  imported_T *find_imported_in_script(char_u *name, size_t len, int sid);
***************
*** 17,23 ****
  int assignment_len(char_u *p, int *heredoc);
  void vim9_declare_error(char_u *name);
  int check_vim9_unlet(char_u *name);
! int compile_def_function(ufunc_T *ufunc, int check_return_type, int 
profiling, cctx_T *outer_cctx);
  void set_function_type(ufunc_T *ufunc);
  void delete_instr(isn_T *isn);
  void unlink_def_function(ufunc_T *ufunc);
--- 17,23 ----
  int assignment_len(char_u *p, int *heredoc);
  void vim9_declare_error(char_u *name);
  int check_vim9_unlet(char_u *name);
! int compile_def_function(ufunc_T *ufunc, int check_return_type, compiletype_T 
compile_type, cctx_T *outer_cctx);
  void set_function_type(ufunc_T *ufunc);
  void delete_instr(isn_T *isn);
  void unlink_def_function(ufunc_T *ufunc);
*** ../vim-8.2.2984/src/vim.h   2021-06-10 21:07:45.411050902 +0200
--- src/vim.h   2021-06-12 18:56:17.735305076 +0200
***************
*** 1794,1803 ****
  typedef int proftime_T;           // dummy for function prototypes
  #endif
  
  #ifdef FEAT_PROFILE
! # define PROFILING(ufunc) (do_profiling == PROF_YES && (ufunc)->uf_profiling)
  #else
! # define PROFILING(ufunc) FALSE
  #endif
  
  /*
--- 1794,1810 ----
  typedef int proftime_T;           // dummy for function prototypes
  #endif
  
+ // Type of compilation passed to compile_def_function()
+ typedef enum {
+     CT_NONE,      // use df_instr
+     CT_PROFILE,           // use df_instr_prof
+     CT_DEBUG      // use df_instr_debug, overrules CT_PROFILE
+ } compiletype_T;
+ 
  #ifdef FEAT_PROFILE
! # define COMPILE_TYPE(ufunc) (debug_break_level > 0 ? CT_DEBUG : do_profiling 
== PROF_YES && (ufunc)->uf_profiling ? CT_PROFILE : CT_NONE)
  #else
! # define COMPILE_TYPE(ufunc) debug_break_level > 0 ? CT_DEBUG : CT_NONE
  #endif
  
  /*
*** ../vim-8.2.2984/src/eval.c  2021-06-12 15:58:12.482675579 +0200
--- src/eval.c  2021-06-13 13:21:56.749646030 +0200
***************
*** 3536,3542 ****
                        if (ufunc->uf_ret_type->tt_type == VAR_VOID)
                            ufunc->uf_ret_type = &t_unknown;
                        if (compile_def_function(ufunc,
!                                        FALSE, PROFILING(ufunc), NULL) == FAIL)
                        {
                            clear_tv(rettv);
                            ret = FAIL;
--- 3536,3542 ----
                        if (ufunc->uf_ret_type->tt_type == VAR_VOID)
                            ufunc->uf_ret_type = &t_unknown;
                        if (compile_def_function(ufunc,
!                                    FALSE, COMPILE_TYPE(ufunc), NULL) == FAIL)
                        {
                            clear_tv(rettv);
                            ret = FAIL;
*** ../vim-8.2.2984/src/vim9execute.c   2021-06-09 19:29:59.888951195 +0200
--- src/vim9execute.c   2021-06-13 13:56:32.788875420 +0200
***************
*** 204,211 ****
        // Profiling might be enabled/disabled along the way.  This should not
        // fail, since the function was compiled before and toggling profiling
        // doesn't change any errors.
!       if (func_needs_compiling(ufunc, PROFILING(ufunc))
!               && compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL)
                                                                       == FAIL)
            return FAIL;
      }
--- 204,211 ----
        // Profiling might be enabled/disabled along the way.  This should not
        // fail, since the function was compiled before and toggling profiling
        // doesn't change any errors.
!       if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
!               && compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL)
                                                                       == FAIL)
            return FAIL;
      }
***************
*** 264,269 ****
--- 264,270 ----
      // If depth of calling is getting too high, don't execute the function.
      if (funcdepth_increment() == FAIL)
        return FAIL;
+     ++ex_nesting_level;
  
      // Only make a copy of funclocal if it contains something to restore.
      if (ectx->ec_funclocal.floc_restore_cmdmod)
***************
*** 647,652 ****
--- 648,654 ----
        ectx->ec_stack.ga_len = top;
  
      funcdepth_decrement();
+     --ex_nesting_level;
      return OK;
  }
  
***************
*** 737,749 ****
      int               idx;
      int               did_emsg_before = did_emsg;
  #ifdef FEAT_PROFILE
!     int               profiling = do_profiling == PROF_YES && 
ufunc->uf_profiling;
  #else
! # define profiling FALSE
  #endif
  
!     if (func_needs_compiling(ufunc, profiling)
!               && compile_def_function(ufunc, FALSE, profiling, NULL) == FAIL)
        return FAIL;
      if (ufunc->uf_def_status == UF_COMPILED)
      {
--- 739,753 ----
      int               idx;
      int               did_emsg_before = did_emsg;
  #ifdef FEAT_PROFILE
!     compiletype_T compile_type = do_profiling == PROF_YES
!                                && ufunc->uf_profiling ? CT_PROFILE : CT_NONE;
  #else
! # define compile_type CT_NONE
  #endif
  
!     if (func_needs_compiling(ufunc, compile_type)
!               && compile_def_function(ufunc, FALSE, compile_type, NULL)
!                                                                      == FAIL)
        return FAIL;
      if (ufunc->uf_def_status == UF_COMPILED)
      {
***************
*** 4099,4104 ****
--- 4103,4124 ----
                }
                break;
  
+           case ISN_DEBUG:
+               if (ex_nesting_level <= debug_break_level)
+               {
+                   char_u      *line;
+                   ufunc_T     *ufunc = (((dfunc_T *)def_functions.ga_data)
+                                              + ectx->ec_dfunc_idx)->df_ufunc;
+ 
+                   SOURCING_LNUM = iptr->isn_lnum;
+                   line = ((char_u **)ufunc->uf_lines.ga_data)[
+                                                          iptr->isn_lnum - 1];
+                   if (line == NULL)
+                       line = (char_u *)"[empty]";
+                   do_debug(line);
+               }
+               break;
+ 
            case ISN_SHUFFLE:
                {
                    typval_T    tmp_tv;
***************
*** 4258,4263 ****
--- 4278,4284 ----
      int               save_emsg_silent_def = emsg_silent_def;
      int               save_did_emsg_def = did_emsg_def;
      int               orig_funcdepth;
+     int               orig_nesting_level = ex_nesting_level;
  
  // Get pointer to item in the stack.
  #undef STACK_TV
***************
*** 4273,4280 ****
  
      if (ufunc->uf_def_status == UF_NOT_COMPILED
            || ufunc->uf_def_status == UF_COMPILE_ERROR
!           || (func_needs_compiling(ufunc, PROFILING(ufunc))
!               && compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL)
                                                                      == FAIL))
      {
        if (did_emsg_cumul + did_emsg == did_emsg_before)
--- 4294,4301 ----
  
      if (ufunc->uf_def_status == UF_NOT_COMPILED
            || ufunc->uf_def_status == UF_COMPILE_ERROR
!           || (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
!               && compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL)
                                                                      == FAIL))
      {
        if (did_emsg_cumul + did_emsg == did_emsg_before)
***************
*** 4310,4315 ****
--- 4331,4337 ----
      ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10);
      ga_init2(&ectx.ec_funcrefs, sizeof(partial_T *), 10);
      ectx.ec_did_emsg_before = did_emsg_before;
+     ++ex_nesting_level;
  
      idx = argc - ufunc->uf_args.ga_len;
      if (idx > 0 && ufunc->uf_va_name == NULL)
***************
*** 4553,4558 ****
--- 4575,4581 ----
      // Free all local variables, but not arguments.
      for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx)
        clear_tv(STACK_TV(idx));
+     ex_nesting_level = orig_nesting_level;
  
      vim_free(ectx.ec_stack.ga_data);
      vim_free(ectx.ec_trystack.ga_data);
***************
*** 5315,5327 ****
            case ISN_CMDMOD_REV: smsg("%s%4d CMDMOD_REV", pfx, current); break;
  
            case ISN_PROF_START:
!                smsg("%s%4d PROFILE START line %d", pfx, current, 
iptr->isn_lnum);
                 break;
  
            case ISN_PROF_END:
                smsg("%s%4d PROFILE END", pfx, current);
                break;
  
            case ISN_UNPACK: smsg("%s%4d UNPACK %d%s", pfx, current,
                        iptr->isn_arg.unpack.unp_count,
                        iptr->isn_arg.unpack.unp_semicolon ? " semicolon" : "");
--- 5338,5355 ----
            case ISN_CMDMOD_REV: smsg("%s%4d CMDMOD_REV", pfx, current); break;
  
            case ISN_PROF_START:
!                smsg("%s%4d PROFILE START line %d", pfx, current,
!                                                              iptr->isn_lnum);
                 break;
  
            case ISN_PROF_END:
                smsg("%s%4d PROFILE END", pfx, current);
                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,
                        iptr->isn_arg.unpack.unp_count,
                        iptr->isn_arg.unpack.unp_semicolon ? " semicolon" : "");
***************
*** 5358,5363 ****
--- 5386,5403 ----
      isn_T     *instr;
      int               instr_count;
      int               is_global = FALSE;
+     compiletype_T compile_type = CT_NONE;
+ 
+     if (STRNCMP(arg, "profile", 7) == 0)
+     {
+       compile_type = CT_PROFILE;
+       arg = skipwhite(arg + 7);
+     }
+     else if (STRNCMP(arg, "debug", 5) == 0)
+     {
+       compile_type = CT_DEBUG;
+       arg = skipwhite(arg + 5);
+     }
  
      if (STRNCMP(arg, "<lambda>", 8) == 0)
      {
***************
*** 5389,5396 ****
        semsg(_(e_cannot_find_function_str), eap->arg);
        return;
      }
!     if (func_needs_compiling(ufunc, eap->forceit)
!           && compile_def_function(ufunc, FALSE, eap->forceit, NULL) == FAIL)
        return;
      if (ufunc->uf_def_status != UF_COMPILED)
      {
--- 5429,5436 ----
        semsg(_(e_cannot_find_function_str), eap->arg);
        return;
      }
!     if (func_needs_compiling(ufunc, compile_type)
!           && compile_def_function(ufunc, FALSE, compile_type, NULL) == FAIL)
        return;
      if (ufunc->uf_def_status != UF_COMPILED)
      {
***************
*** 5403,5416 ****
        msg((char *)ufunc->uf_name);
  
      dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
  #ifdef FEAT_PROFILE
!     instr = eap->forceit ? dfunc->df_instr_prof : dfunc->df_instr;
!     instr_count = eap->forceit ? dfunc->df_instr_prof_count
!                                                      : dfunc->df_instr_count;
! #else
!     instr = dfunc->df_instr;
!     instr_count = dfunc->df_instr_count;
  #endif
  
      list_instructions("", instr, instr_count, ufunc);
  }
--- 5443,5466 ----
        msg((char *)ufunc->uf_name);
  
      dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
+     switch (compile_type)
+     {
+       case CT_PROFILE:
  #ifdef FEAT_PROFILE
!           instr = dfunc->df_instr_prof;
!           instr_count = dfunc->df_instr_prof_count;
!           break;
  #endif
+           // FALLTHROUGH
+       case CT_NONE:
+           instr = dfunc->df_instr;
+           instr_count = dfunc->df_instr_count;
+           break;
+       case CT_DEBUG:
+           instr = dfunc->df_instr_debug;
+           instr_count = dfunc->df_instr_debug_count;
+           break;
+     }
  
      list_instructions("", instr, instr_count, ufunc);
  }
*** ../vim-8.2.2984/src/userfunc.c      2021-06-12 15:58:12.486675568 +0200
--- src/userfunc.c      2021-06-13 13:25:30.633326829 +0200
***************
*** 4395,4401 ****
                    && ufunc->uf_def_status == UF_TO_BE_COMPILED
                    && (ufunc->uf_flags & FC_DEAD) == 0)
            {
!               (void)compile_def_function(ufunc, FALSE, FALSE, NULL);
  
                if (func_hashtab.ht_changed != changed)
                {
--- 4395,4401 ----
                    && ufunc->uf_def_status == UF_TO_BE_COMPILED
                    && (ufunc->uf_flags & FC_DEAD) == 0)
            {
!               (void)compile_def_function(ufunc, FALSE, CT_NONE, NULL);
  
                if (func_hashtab.ht_changed != changed)
                {
*** ../vim-8.2.2984/src/vim9type.c      2021-05-07 17:55:51.971584412 +0200
--- src/vim9type.c      2021-06-13 13:25:05.817369362 +0200
***************
*** 349,355 ****
            // May need to get the argument types from default values by
            // compiling the function.
            if (ufunc->uf_def_status == UF_TO_BE_COMPILED
!                           && compile_def_function(ufunc, TRUE, FALSE, NULL)
                                                                       == FAIL)
                return NULL;
            if (ufunc->uf_func_type == NULL)
--- 349,355 ----
            // May need to get the argument types from default values by
            // compiling the function.
            if (ufunc->uf_def_status == UF_TO_BE_COMPILED
!                           && compile_def_function(ufunc, TRUE, CT_NONE, NULL)
                                                                       == FAIL)
                return NULL;
            if (ufunc->uf_func_type == NULL)
*** ../vim-8.2.2984/src/testdir/test_debugger.vim       2020-12-18 
19:49:52.345571854 +0100
--- src/testdir/test_debugger.vim       2021-06-13 13:36:38.339864912 +0200
***************
*** 884,902 ****
                  \ ':debug call GlobalFunction()',
                  \ ['cmd: call GlobalFunction()'])
  
!   " FIXME: Vim9 lines are not debugged!
!   call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
  
!   " But they do appear in the backtrace
    call RunDbgCmd(buf, 'backtrace', [
          \ '\V>backtrace',
!         \ '\V  2 function GlobalFunction[1]',
!         \ '\V  1 <SNR>\.\*_CallAFunction[1]',
!         \ '\V->0 <SNR>\.\*_SourceAnotherFile',
!         \ '\Vline 1: source Xtest2.vim'],
          \ #{match: 'pattern'})
  
! 
    call RunDbgCmd(buf, 'step', ['line 1: vim9script'])
    call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number'])
    call RunDbgCmd(buf, 'step', ['line 9: export def File2Function()'])
--- 884,903 ----
                  \ ':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'])
    call RunDbgCmd(buf, 'step', ['line 9: export def File2Function()'])
***************
*** 913,919 ****
          \ #{match: 'pattern'})
  
    " Don't step into compiled functions...
!   call RunDbgCmd(buf, 'step', ['line 15: End of sourced file'])
    call RunDbgCmd(buf, 'backtrace', [
          \ '\V>backtrace',
          \ '\V  3 function GlobalFunction[1]',
--- 914,920 ----
          \ #{match: 'pattern'})
  
    " Don't step into compiled functions...
!   call RunDbgCmd(buf, 'next', ['line 15: End of sourced file'])
    call RunDbgCmd(buf, 'backtrace', [
          \ '\V>backtrace',
          \ '\V  3 function GlobalFunction[1]',
***************
*** 923,929 ****
          \ '\Vline 15: End of sourced file'],
          \ #{match: 'pattern'})
  
- 
    call StopVimInTerminal(buf)
    call delete('Xtest1.vim')
    call delete('Xtest2.vim')
--- 924,929 ----
***************
*** 1116,1121 ****
--- 1116,1122 ----
          \ [ 'E121: Undefined variable: s:file1_var' ] )
    call RunDbgCmd(buf, 'echo s:file2_var', [ 'file2' ] )
  
+   call RunDbgCmd(buf, 'cont')
    call StopVimInTerminal(buf)
    call delete('Xtest1.vim')
    call delete('Xtest2.vim')
*** ../vim-8.2.2984/src/testdir/test_vim9_disassemble.vim       2021-06-06 
17:02:49.753789485 +0200
--- src/testdir/test_vim9_disassemble.vim       2021-06-13 13:59:16.264623917 
+0200
***************
*** 2153,2159 ****
    if !has('profile')
      MissingFeature 'profile'
    endif
!   var res = execute('disass! s:Profiled')
    assert_match('<SNR>\d*_Profiled\_s*' ..
          'echo "profiled"\_s*' ..
          '\d PROFILE START line 1\_s*' ..
--- 2153,2159 ----
    if !has('profile')
      MissingFeature 'profile'
    endif
!   var res = execute('disass profile s:Profiled')
    assert_match('<SNR>\d*_Profiled\_s*' ..
          'echo "profiled"\_s*' ..
          '\d PROFILE START line 1\_s*' ..
***************
*** 2168,2173 ****
--- 2168,2187 ----
          res)
  enddef
  
+ def Test_debugged()
+   var res = execute('disass debug s:Profiled')
+   assert_match('<SNR>\d*_Profiled\_s*' ..
+         'echo "profiled"\_s*' ..
+         '\d DEBUG line 1\_s*' ..
+         '\d PUSHS "profiled"\_s*' ..
+         '\d ECHO 1\_s*' ..
+         'return "done"\_s*' ..
+         '\d DEBUG line 2\_s*' ..
+         '\d PUSHS "done"\_s*' ..
+         '\d RETURN\_s*',
+         res)
+ enddef
+ 
  def s:EchoMessages()
    echohl ErrorMsg | echom v:exception | echohl NONE
  enddef
*** ../vim-8.2.2984/src/version.c       2021-06-12 18:30:51.510966898 +0200
--- src/version.c       2021-06-13 13:59:49.728566286 +0200
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2985,
  /**/

-- 
"Beware of bugs in the above code; I have only proved
it correct, not tried it." -- Donald Knuth

 /// Bram Moolenaar -- b...@moolenaar.net -- 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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202106131202.15DC28ms567996%40masaka.moolenaar.net.

Raspunde prin e-mail lui