changeset 35044:2e492a1539e0 v9.1.0371

patch 9.1.0371: Vim9: compile_def_function() still too long Commit: https://github.com/vim/vim/commit/f6c1fb20e396148f0b372b658c4021917ca1984a Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Thu Apr 25 21:30:56 2024 +0200 patch 9.1.0371: Vim9: compile_def_function() still too long Problem: Vim9: compile_def_function() still too long Solution: Refactor the code into separate functions (Yegappan Lakshmanan) closes: #14632 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Thu, 25 Apr 2024 21:45:03 +0200
parents 6f3be4d81ccb
children ddcdd52e583c
files src/version.c src/vim9compile.c
diffstat 2 files changed, 168 insertions(+), 126 deletions(-) [+]
line wrap: on
line diff
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    371,
+/**/
     370,
 /**/
     369,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -3274,6 +3274,166 @@ add_def_function(ufunc_T *ufunc)
 }
 
 /*
+ * For an object constructor, generate instruction to setup "this" (the first
+ * local variable) and to initialize the object variables.
+ */
+    static int
+obj_constructor_prologue(ufunc_T *ufunc, cctx_T *cctx)
+{
+    generate_CONSTRUCT(cctx, ufunc->uf_class);
+
+    for (int i = 0; i < ufunc->uf_class->class_obj_member_count; ++i)
+    {
+	ocmember_T *m = &ufunc->uf_class->class_obj_members[i];
+
+	if (i < 2 && IS_ENUM(ufunc->uf_class))
+	    // The first two object variables in an enum are the name
+	    // and the ordinal.  These are set by the ISN_CONSTRUCT
+	    // instruction.  So don't generate instructions to set
+	    // these variables.
+	    continue;
+
+	if (m->ocm_init != NULL)
+	{
+	    char_u *expr = m->ocm_init;
+
+	    if (compile_expr0(&expr, cctx) == FAIL)
+		return FAIL;
+
+	    if (!ends_excmd2(m->ocm_init, expr))
+	    {
+		semsg(_(e_trailing_characters_str), expr);
+		return FAIL;
+	    }
+
+	    type_T	*type = get_type_on_stack(cctx, 0);
+	    if (m->ocm_type->tt_type == VAR_ANY
+		    && !(m->ocm_flags & OCMFLAG_HAS_TYPE)
+		    && type->tt_type != VAR_SPECIAL)
+	    {
+		// If the member variable type is not yet set, then use
+		// the initialization expression type.
+		m->ocm_type = type;
+	    }
+	    else if (m->ocm_type->tt_type != type->tt_type)
+	    {
+		// The type of the member initialization expression is
+		// determined at run time.  Add a runtime type check.
+		where_T	where = WHERE_INIT;
+		where.wt_kind = WT_MEMBER;
+		where.wt_func_name = (char *)m->ocm_name;
+		if (need_type_where(type, m->ocm_type, FALSE, -1,
+					where, cctx, FALSE, FALSE) == FAIL)
+		    return FAIL;
+	    }
+	}
+	else
+	    push_default_value(cctx, m->ocm_type->tt_type, FALSE, NULL);
+
+	generate_STORE_THIS(cctx, i);
+    }
+
+    return OK;
+}
+
+/*
+ * For an object method and an constructor, generate instruction to setup
+ * "this" (the first local variable).  For a constructor, generate instructions
+ * to initialize the object variables.
+ */
+    static int
+obj_method_prologue(ufunc_T *ufunc, cctx_T *cctx)
+{
+    dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
+
+    if (GA_GROW_FAILS(&dfunc->df_var_names, 1))
+	return FAIL;
+
+    ((char_u **)dfunc->df_var_names.ga_data)[0] =
+						vim_strsave((char_u *)"this");
+    ++dfunc->df_var_names.ga_len;
+
+    // In the constructor allocate memory for the object and initialize the
+    // object members.
+    if (IS_CONSTRUCTOR_METHOD(ufunc))
+	return obj_constructor_prologue(ufunc, cctx);
+
+    return OK;
+}
+
+/*
+ * Produce instructions for the default values of optional arguments.
+ */
+    static int
+compile_def_function_default_args(
+    ufunc_T	*ufunc,
+    cctx_T	*cctx,
+    garray_T	*instr)
+{
+    int	count = ufunc->uf_def_args.ga_len;
+    int	first_def_arg = ufunc->uf_args.ga_len - count;
+    int	i;
+    int	off = STACK_FRAME_SIZE + (ufunc->uf_va_name != NULL ? 1 : 0);
+    int	did_set_arg_type = FALSE;
+
+    // Produce instructions for the default values of optional arguments.
+    SOURCING_LNUM = 0;  // line number unknown
+    for (i = 0; i < count; ++i)
+    {
+	char_u *arg = ((char_u **)(ufunc->uf_def_args.ga_data))[i];
+	if (STRCMP(arg, "v:none") == 0)
+	    // "arg = v:none" means the argument is optional without
+	    // setting a value when the argument is missing.
+	    continue;
+
+	type_T	*val_type;
+	int		arg_idx = first_def_arg + i;
+	where_T	where = WHERE_INIT;
+	int		jump_instr_idx = instr->ga_len;
+	isn_T	*isn;
+
+	// Use a JUMP_IF_ARG_SET instruction to skip if the value was given.
+	if (generate_JUMP_IF_ARG(cctx, ISN_JUMP_IF_ARG_SET,
+						i - count - off) == FAIL)
+	    return FAIL;
+
+	// Make sure later arguments are not found.
+	ufunc->uf_args_visible = arg_idx;
+
+	int r = compile_expr0(&arg, cctx);
+	if (r == FAIL)
+	    return FAIL;
+
+	// If no type specified use the type of the default value.
+	// Otherwise check that the default value type matches the
+	// specified type.
+	val_type = get_type_on_stack(cctx, 0);
+	where.wt_index = arg_idx + 1;
+	where.wt_kind = WT_ARGUMENT;
+	if (ufunc->uf_arg_types[arg_idx] == &t_unknown)
+	{
+	    did_set_arg_type = TRUE;
+	    ufunc->uf_arg_types[arg_idx] = val_type;
+	}
+	else if (need_type_where(val_type, ufunc->uf_arg_types[arg_idx],
+		    FALSE, -1, where, cctx, FALSE, FALSE) == FAIL)
+	    return FAIL;
+
+	if (generate_STORE(cctx, ISN_STORE, i - count - off, NULL) == FAIL)
+	    return FAIL;
+
+	// set instruction index in JUMP_IF_ARG_SET to here
+	isn = ((isn_T *)instr->ga_data) + jump_instr_idx;
+	isn->isn_arg.jumparg.jump_where = instr->ga_len;
+    }
+
+    if (did_set_arg_type)
+	set_function_type(ufunc);
+
+    return OK;
+}
+
+/*
  * Compile def function body.  Loop over all the lines in the function and
  * generate instructions.
  */
@@ -3937,136 +4097,15 @@ compile_def_function(
     if (check_args_shadowing(ufunc, &cctx) == FAIL)
 	goto erret;
 
-    // For an object method and constructor "this" is the first local variable.
+    // For an object method and a constructor generate instructions to
+    // initialize "this" and the object variables.
     if (ufunc->uf_flags & (FC_OBJECT|FC_NEW))
-    {
-	dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
-							 + ufunc->uf_dfunc_idx;
-	if (GA_GROW_FAILS(&dfunc->df_var_names, 1))
+	if (obj_method_prologue(ufunc, &cctx) == FAIL)
 	    goto erret;
-	((char_u **)dfunc->df_var_names.ga_data)[0] =
-						 vim_strsave((char_u *)"this");
-	++dfunc->df_var_names.ga_len;
-
-	// In the constructor allocate memory for the object and initialize the
-	// object members.
-	if (IS_CONSTRUCTOR_METHOD(ufunc))
-	{
-	    generate_CONSTRUCT(&cctx, ufunc->uf_class);
-
-	    for (int i = 0; i < ufunc->uf_class->class_obj_member_count; ++i)
-	    {
-		ocmember_T *m = &ufunc->uf_class->class_obj_members[i];
-
-		if (i < 2 && IS_ENUM(ufunc->uf_class))
-		    // The first two object variables in an enum are the name
-		    // and the ordinal.  These are set by the ISN_CONSTRUCT
-		    // instruction.  So don't generate instructions to set
-		    // these variables.
-		    continue;
-
-		if (m->ocm_init != NULL)
-		{
-		    char_u *expr = m->ocm_init;
-		    if (compile_expr0(&expr, &cctx) == FAIL)
-			goto erret;
-		    if (!ends_excmd2(m->ocm_init, expr))
-		    {
-			semsg(_(e_trailing_characters_str), expr);
-			goto erret;
-		    }
-
-		    type_T	*type = get_type_on_stack(&cctx, 0);
-		    if (m->ocm_type->tt_type == VAR_ANY
-			    && !(m->ocm_flags & OCMFLAG_HAS_TYPE)
-			    && type->tt_type != VAR_SPECIAL)
-		    {
-			// If the member variable type is not yet set, then use
-			// the initialization expression type.
-			m->ocm_type = type;
-		    }
-		    else if (m->ocm_type->tt_type != type->tt_type)
-		    {
-			// The type of the member initialization expression is
-			// determined at run time.  Add a runtime type check.
-			where_T	where = WHERE_INIT;
-			where.wt_kind = WT_MEMBER;
-			where.wt_func_name = (char *)m->ocm_name;
-			if (need_type_where(type, m->ocm_type, FALSE, -1,
-				    where, &cctx, FALSE, FALSE) == FAIL)
-			    goto erret;
-		    }
-		}
-		else
-		    push_default_value(&cctx, m->ocm_type->tt_type,
-								  FALSE, NULL);
-		generate_STORE_THIS(&cctx, i);
-	    }
-	}
-    }
 
     if (ufunc->uf_def_args.ga_len > 0)
-    {
-	int	count = ufunc->uf_def_args.ga_len;
-	int	first_def_arg = ufunc->uf_args.ga_len - count;
-	int	i;
-	int	off = STACK_FRAME_SIZE + (ufunc->uf_va_name != NULL ? 1 : 0);
-	int	did_set_arg_type = FALSE;
-
-	// Produce instructions for the default values of optional arguments.
-	SOURCING_LNUM = 0;  // line number unknown
-	for (i = 0; i < count; ++i)
-	{
-	    char_u *arg = ((char_u **)(ufunc->uf_def_args.ga_data))[i];
-	    if (STRCMP(arg, "v:none") == 0)
-		// "arg = v:none" means the argument is optional without
-		// setting a value when the argument is missing.
-		continue;
-
-	    type_T	*val_type;
-	    int		arg_idx = first_def_arg + i;
-	    where_T	where = WHERE_INIT;
-	    int		jump_instr_idx = instr->ga_len;
-	    isn_T	*isn;
-
-	    // Use a JUMP_IF_ARG_SET instruction to skip if the value was given.
-	    if (generate_JUMP_IF_ARG(&cctx, ISN_JUMP_IF_ARG_SET,
-						      i - count - off) == FAIL)
-		goto erret;
-
-	    // Make sure later arguments are not found.
-	    ufunc->uf_args_visible = arg_idx;
-
-	    int r = compile_expr0(&arg, &cctx);
-	    if (r == FAIL)
-		goto erret;
-
-	    // If no type specified use the type of the default value.
-	    // Otherwise check that the default value type matches the
-	    // specified type.
-	    val_type = get_type_on_stack(&cctx, 0);
-	    where.wt_index = arg_idx + 1;
-	    where.wt_kind = WT_ARGUMENT;
-	    if (ufunc->uf_arg_types[arg_idx] == &t_unknown)
-	    {
-		did_set_arg_type = TRUE;
-		ufunc->uf_arg_types[arg_idx] = val_type;
-	    }
-	    else if (need_type_where(val_type, ufunc->uf_arg_types[arg_idx],
-				FALSE, -1, where, &cctx, FALSE, FALSE) == FAIL)
-		goto erret;
-
-	    if (generate_STORE(&cctx, ISN_STORE, i - count - off, NULL) == FAIL)
-		goto erret;
-
-	    // set instruction index in JUMP_IF_ARG_SET to here
-	    isn = ((isn_T *)instr->ga_data) + jump_instr_idx;
-	    isn->isn_arg.jumparg.jump_where = instr->ga_len;
-	}
-
-	if (did_set_arg_type)
-	    set_function_type(ufunc);
-    }
+	if (compile_def_function_default_args(ufunc, &cctx, instr) == FAIL)
+	    goto erret;
     ufunc->uf_args_visible = ufunc->uf_args.ga_len;
 
     // Compiling a function in an interface is done to get the function type.
@@ -4078,6 +4117,7 @@ compile_def_function(
 	goto erret;
     }
 
+    // compile the function body
     if (compile_def_function_body(&cctx, ufunc->uf_lines.ga_len,
 		check_return_type, &lines_to_free, &errormsg) == FAIL)
 	goto erret;