patch 9.1.0914: Vim9: compile_assignment() is too long

Problem:  Vim9: compile_assignment() is too long
Solution: refactor compile_assignment() into smaller functions
          (Yegappan Lakshmanan)

closes: #16186

Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/vim9compile.c b/src/vim9compile.c
index ea305b7..e75462f 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2584,6 +2584,156 @@
 }
 
 /*
+ * Compile an object member variable assignment in the argument passed to a
+ * class new() method.
+ *
+ * Instruction format:
+ *
+ *	ifargisset <n> this.<varname> = <value>
+ *
+ * where <n> is the object member variable index.
+ *
+ * Generates the ISN_JUMP_IF_ARG_NOT_SET instruction to skip the assignment if
+ * the value is passed as an argument to the new() method call.
+ *
+ * Returns OK on success.
+ */
+    static int
+compile_assignment_obj_new_arg(char_u **argp, cctx_T *cctx)
+{
+    char_u *arg = *argp;
+
+    arg += 11;	    // skip "ifargisset"
+    int def_idx = getdigits(&arg);
+    arg = skipwhite(arg);
+
+    // Use a JUMP_IF_ARG_NOT_SET instruction to skip if the value was not
+    // given and the default value is "v:none".
+    int off = STACK_FRAME_SIZE + (cctx->ctx_ufunc->uf_va_name != NULL
+								? 1 : 0);
+    int count = cctx->ctx_ufunc->uf_def_args.ga_len;
+    if (generate_JUMP_IF_ARG(cctx, ISN_JUMP_IF_ARG_NOT_SET,
+					def_idx - count - off) == FAIL)
+	return FAIL;
+
+    *argp = arg;
+    return OK;
+}
+
+/*
+ * Convert the increment (++) or decrement (--) operator to the corresponding
+ * compound operator.
+ *
+ * Returns OK on success and FAIL on syntax error.
+ */
+    static int
+incdec_op_translate(
+    exarg_T	*eap,
+    char_u	**op,
+    int		*oplen,
+    int		*incdec)
+{
+    if (VIM_ISWHITE(eap->cmd[2]))
+    {
+	semsg(_(e_no_white_space_allowed_after_str_str),
+		eap->cmdidx == CMD_increment ? "++" : "--", eap->cmd);
+	return FAIL;
+    }
+    *op = (char_u *)(eap->cmdidx == CMD_increment ? "+=" : "-=");
+    *oplen = 2;
+    *incdec = TRUE;
+
+    return OK;
+}
+
+/*
+ * Parse a heredoc assignment starting at "p".  Returns a pointer to the
+ * beginning of the heredoc content.
+ */
+    static char_u *
+heredoc_assign_stmt_end_get(char_u *p, exarg_T *eap, cctx_T *cctx)
+{
+    // [let] varname =<< [trim] {end}
+    eap->ea_getline = exarg_getline;
+    eap->cookie = cctx;
+
+    list_T *l = heredoc_get(eap, p + 3, FALSE, TRUE);
+    if (l == NULL)
+	return NULL;
+
+    list_free(l);
+    p += STRLEN(p);
+
+    return p;
+}
+
+    static char_u *
+compile_list_assignment(
+    char_u	*p,
+    char_u	*op,
+    int		oplen,
+    int		var_count,
+    int		semicolon,
+    garray_T	*instr,
+    type_T	**rhs_type,
+    cctx_T	*cctx)
+{
+    char_u *wp;
+
+    // for "[var, var] = expr" evaluate the expression here, loop over the
+    // list of variables below.
+    // A line break may follow the "=".
+
+    wp = op + oplen;
+    if (may_get_next_line_error(wp, &p, cctx) == FAIL)
+	return NULL;
+    if (compile_expr0(&p, cctx) == FAIL)
+	return NULL;
+
+    if (cctx->ctx_skip != SKIP_YES)
+    {
+	type_T	*stacktype;
+	int		needed_list_len;
+	int		did_check = FALSE;
+
+	stacktype = cctx->ctx_type_stack.ga_len == 0 ? &t_void
+						: get_type_on_stack(cctx, 0);
+	if (stacktype->tt_type == VAR_VOID)
+	{
+	    emsg(_(e_cannot_use_void_value));
+	    return NULL;
+	}
+	if (need_type(stacktype, &t_list_any, FALSE, -1, 0, cctx, FALSE,
+							FALSE) == FAIL)
+	    return NULL;
+	// If a constant list was used we can check the length right here.
+	needed_list_len = semicolon ? var_count - 1 : var_count;
+	if (instr->ga_len > 0)
+	{
+	    isn_T	*isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
+
+	    if (isn->isn_type == ISN_NEWLIST)
+	    {
+		did_check = TRUE;
+		if (semicolon ? isn->isn_arg.number < needed_list_len
+			: isn->isn_arg.number != needed_list_len)
+		{
+		    semsg(_(e_expected_nr_items_but_got_nr),
+			    needed_list_len, (int)isn->isn_arg.number);
+		    return NULL;
+		}
+	    }
+	}
+	if (!did_check)
+	    generate_CHECKLEN(cctx, needed_list_len, semicolon);
+	if (stacktype->tt_member != NULL)
+	    *rhs_type = stacktype->tt_member;
+    }
+
+    return p;
+}
+
+/*
  * Compile declaration and assignment:
  * "let name"
  * "var name = expr"
@@ -2625,38 +2775,20 @@
     long	start_lnum = SOURCING_LNUM;
 
     int	has_arg_is_set_prefix = STRNCMP(arg, "ifargisset ", 11) == 0;
-    if (has_arg_is_set_prefix)
-    {
-	arg += 11;
-	int def_idx = getdigits(&arg);
-	arg = skipwhite(arg);
-
-	// Use a JUMP_IF_ARG_NOT_SET instruction to skip if the value was not
-	// given and the default value is "v:none".
-	int off = STACK_FRAME_SIZE + (cctx->ctx_ufunc->uf_va_name != NULL
-								      ? 1 : 0);
-	int count = cctx->ctx_ufunc->uf_def_args.ga_len;
-	if (generate_JUMP_IF_ARG(cctx, ISN_JUMP_IF_ARG_NOT_SET,
-						def_idx - count - off) == FAIL)
-	    goto theend;
-    }
+    if (has_arg_is_set_prefix &&
+	    compile_assignment_obj_new_arg(&arg, cctx) == FAIL)
+	goto theend;
 
     // Skip over the "varname" or "[varname, varname]" to get to any "=".
     p = skip_var_list(arg, TRUE, &var_count, &semicolon, TRUE);
     if (p == NULL)
 	return *arg == '[' ? arg : NULL;
 
+
     if (eap->cmdidx == CMD_increment || eap->cmdidx == CMD_decrement)
     {
-	if (VIM_ISWHITE(eap->cmd[2]))
-	{
-	    semsg(_(e_no_white_space_allowed_after_str_str),
-			 eap->cmdidx == CMD_increment ? "++" : "--", eap->cmd);
+	if (incdec_op_translate(eap, &op, &oplen, &incdec) == FAIL)
 	    return NULL;
-	}
-	op = (char_u *)(eap->cmdidx == CMD_increment ? "+=" : "-=");
-	oplen = 2;
-	incdec = TRUE;
     }
     else
     {
@@ -2678,73 +2810,19 @@
 
     if (heredoc)
     {
-	list_T	   *l;
-
-	// [let] varname =<< [trim] {end}
-	eap->ea_getline = exarg_getline;
-	eap->cookie = cctx;
-	l = heredoc_get(eap, op + 3, FALSE, TRUE);
-	if (l == NULL)
+	p = heredoc_assign_stmt_end_get(p, eap, cctx);
+	if (p == NULL)
 	    return NULL;
-
-	list_free(l);
-	p += STRLEN(p);
 	end = p;
     }
     else if (var_count > 0)
     {
-	char_u *wp;
-
-	// for "[var, var] = expr" evaluate the expression here, loop over the
-	// list of variables below.
-	// A line break may follow the "=".
-
-	wp = op + oplen;
-	if (may_get_next_line_error(wp, &p, cctx) == FAIL)
-	    return FAIL;
-	if (compile_expr0(&p, cctx) == FAIL)
-	    return NULL;
+	// "[var, var] = expr"
+	p = compile_list_assignment(p, op, oplen, var_count, semicolon,
+						instr, &rhs_type, cctx);
+	if (p == NULL)
+	    goto theend;
 	end = p;
-
-	if (cctx->ctx_skip != SKIP_YES)
-	{
-	    type_T	*stacktype;
-	    int		needed_list_len;
-	    int		did_check = FALSE;
-
-	    stacktype = cctx->ctx_type_stack.ga_len == 0 ? &t_void
-						  : get_type_on_stack(cctx, 0);
-	    if (stacktype->tt_type == VAR_VOID)
-	    {
-		emsg(_(e_cannot_use_void_value));
-		goto theend;
-	    }
-	    if (need_type(stacktype, &t_list_any, FALSE, -1, 0, cctx,
-							 FALSE, FALSE) == FAIL)
-		goto theend;
-	    // If a constant list was used we can check the length right here.
-	    needed_list_len = semicolon ? var_count - 1 : var_count;
-	    if (instr->ga_len > 0)
-	    {
-		isn_T	*isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
-
-		if (isn->isn_type == ISN_NEWLIST)
-		{
-		    did_check = TRUE;
-		    if (semicolon ? isn->isn_arg.number < needed_list_len
-			    : isn->isn_arg.number != needed_list_len)
-		    {
-			semsg(_(e_expected_nr_items_but_got_nr),
-				    needed_list_len, (int)isn->isn_arg.number);
-			goto theend;
-		    }
-		}
-	    }
-	    if (!did_check)
-		generate_CHECKLEN(cctx, needed_list_len, semicolon);
-	    if (stacktype->tt_member != NULL)
-		rhs_type = stacktype->tt_member;
-	}
     }
 
     /*