To: vim_dev@googlegroups.com Subject: Patch 8.2.3851 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3851 Problem: Vim9: overhead when comparing string, dict or function. Solution: Call the intented compare function directly. Refactor to avoid duplicated code. Files: src/vim9execute.c, src/typval.c, src/proto/typval.pro *** ../vim-8.2.3850/src/vim9execute.c 2021-12-17 20:36:11.200135980 +0000 --- src/vim9execute.c 2021-12-19 12:30:11.974774951 +0000 *************** *** 3809,3879 **** break; case ISN_COMPARELIST: { typval_T *tv1 = STACK_TV_BOT(-2); typval_T *tv2 = STACK_TV_BOT(-1); ! list_T *arg1 = tv1->vval.v_list; ! list_T *arg2 = tv2->vval.v_list; ! int cmp = FALSE; int ic = iptr->isn_arg.op.op_ic; ! switch (iptr->isn_arg.op.op_type) { ! case EXPR_EQUAL: cmp = ! list_equal(arg1, arg2, ic, FALSE); break; ! case EXPR_NEQUAL: cmp = ! !list_equal(arg1, arg2, ic, FALSE); break; ! case EXPR_IS: cmp = arg1 == arg2; break; ! case EXPR_ISNOT: cmp = arg1 != arg2; break; ! default: cmp = 0; break; } ! --ectx->ec_stack.ga_len; ! clear_tv(tv1); ! clear_tv(tv2); ! tv1->v_type = VAR_BOOL; ! tv1->vval.v_number = cmp ? VVAL_TRUE : VVAL_FALSE; ! } ! break; ! ! case ISN_COMPAREBLOB: ! { ! typval_T *tv1 = STACK_TV_BOT(-2); ! typval_T *tv2 = STACK_TV_BOT(-1); ! blob_T *arg1 = tv1->vval.v_blob; ! blob_T *arg2 = tv2->vval.v_blob; ! int cmp = FALSE; ! ! switch (iptr->isn_arg.op.op_type) { ! case EXPR_EQUAL: cmp = blob_equal(arg1, arg2); break; ! case EXPR_NEQUAL: cmp = !blob_equal(arg1, arg2); break; ! case EXPR_IS: cmp = arg1 == arg2; break; ! case EXPR_ISNOT: cmp = arg1 != arg2; break; ! default: cmp = 0; break; } --ectx->ec_stack.ga_len; clear_tv(tv1); clear_tv(tv2); tv1->v_type = VAR_BOOL; ! tv1->vval.v_number = cmp ? VVAL_TRUE : VVAL_FALSE; } break; - // TODO: handle separately - case ISN_COMPARESTRING: - case ISN_COMPAREDICT: - case ISN_COMPAREFUNC: case ISN_COMPAREANY: { typval_T *tv1 = STACK_TV_BOT(-2); typval_T *tv2 = STACK_TV_BOT(-1); exprtype_T exprtype = iptr->isn_arg.op.op_type; int ic = iptr->isn_arg.op.op_ic; SOURCING_LNUM = iptr->isn_lnum; ! typval_compare(tv1, tv2, exprtype, ic); clear_tv(tv2); --ectx->ec_stack.ga_len; } break; --- 3809,3875 ---- break; case ISN_COMPARELIST: + case ISN_COMPAREDICT: + case ISN_COMPAREFUNC: + case ISN_COMPARESTRING: + case ISN_COMPAREBLOB: { typval_T *tv1 = STACK_TV_BOT(-2); typval_T *tv2 = STACK_TV_BOT(-1); ! exprtype_T exprtype = iptr->isn_arg.op.op_type; int ic = iptr->isn_arg.op.op_ic; + int res = FALSE; + int status = OK; ! SOURCING_LNUM = iptr->isn_lnum; ! if (iptr->isn_type == ISN_COMPARELIST) { ! status = typval_compare_list(tv1, tv2, ! exprtype, ic, &res); } ! else if (iptr->isn_type == ISN_COMPAREDICT) { ! status = typval_compare_dict(tv1, tv2, ! exprtype, ic, &res); ! } ! else if (iptr->isn_type == ISN_COMPAREFUNC) ! { ! status = typval_compare_func(tv1, tv2, ! exprtype, ic, &res); ! } ! else if (iptr->isn_type == ISN_COMPARESTRING) ! { ! status = typval_compare_string(tv1, tv2, ! exprtype, ic, &res); ! } ! else ! { ! status = typval_compare_blob(tv1, tv2, exprtype, &res); } --ectx->ec_stack.ga_len; clear_tv(tv1); clear_tv(tv2); tv1->v_type = VAR_BOOL; ! tv1->vval.v_number = res ? VVAL_TRUE : VVAL_FALSE; ! if (status == FAIL) ! goto theend; } break; case ISN_COMPAREANY: { typval_T *tv1 = STACK_TV_BOT(-2); typval_T *tv2 = STACK_TV_BOT(-1); exprtype_T exprtype = iptr->isn_arg.op.op_type; int ic = iptr->isn_arg.op.op_ic; + int status; SOURCING_LNUM = iptr->isn_lnum; ! status = typval_compare(tv1, tv2, exprtype, ic); clear_tv(tv2); --ectx->ec_stack.ga_len; + if (status == FAIL) + goto theend; } break; *** ../vim-8.2.3850/src/typval.c 2021-12-18 18:33:41.095346414 +0000 --- src/typval.c 2021-12-19 12:29:26.170874038 +0000 *************** *** 1120,1276 **** } /* ! * Compare "typ1" and "typ2". Put the result in "typ1". */ int typval_compare( ! typval_T *typ1, // first operand ! typval_T *typ2, // second operand ! exprtype_T type, // operator ! int ic) // ignore case { - int i; varnumber_T n1, n2; ! char_u *s1, *s2; ! char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN]; int type_is = type == EXPR_IS || type == EXPR_ISNOT; ! if (type_is && typ1->v_type != typ2->v_type) { // For "is" a different type always means FALSE, for "notis" // it means TRUE. n1 = (type == EXPR_ISNOT); } ! else if (typ1->v_type == VAR_BLOB || typ2->v_type == VAR_BLOB) { ! if (type_is) { ! n1 = (typ1->v_type == typ2->v_type ! && typ1->vval.v_blob == typ2->vval.v_blob); ! if (type == EXPR_ISNOT) ! n1 = !n1; ! } ! else if (typ1->v_type != typ2->v_type ! || (type != EXPR_EQUAL && type != EXPR_NEQUAL)) ! { ! if (typ1->v_type != typ2->v_type) ! emsg(_("E977: Can only compare Blob with Blob")); ! else ! emsg(_(e_invalblob)); ! clear_tv(typ1); return FAIL; } ! else ! { ! // Compare two Blobs for being equal or unequal. ! n1 = blob_equal(typ1->vval.v_blob, typ2->vval.v_blob); ! if (type == EXPR_NEQUAL) ! n1 = !n1; ! } } ! else if (typ1->v_type == VAR_LIST || typ2->v_type == VAR_LIST) { ! if (type_is) ! { ! n1 = (typ1->v_type == typ2->v_type ! && typ1->vval.v_list == typ2->vval.v_list); ! if (type == EXPR_ISNOT) ! n1 = !n1; ! } ! else if (typ1->v_type != typ2->v_type ! || (type != EXPR_EQUAL && type != EXPR_NEQUAL)) { ! if (typ1->v_type != typ2->v_type) ! emsg(_("E691: Can only compare List with List")); ! else ! emsg(_("E692: Invalid operation for List")); ! clear_tv(typ1); return FAIL; } ! else ! { ! // Compare two Lists for being equal or unequal. ! n1 = list_equal(typ1->vval.v_list, typ2->vval.v_list, ! ic, FALSE); ! if (type == EXPR_NEQUAL) ! n1 = !n1; ! } } ! ! else if (typ1->v_type == VAR_DICT || typ2->v_type == VAR_DICT) { ! if (type_is) ! { ! n1 = (typ1->v_type == typ2->v_type ! && typ1->vval.v_dict == typ2->vval.v_dict); ! if (type == EXPR_ISNOT) ! n1 = !n1; ! } ! else if (typ1->v_type != typ2->v_type ! || (type != EXPR_EQUAL && type != EXPR_NEQUAL)) { ! if (typ1->v_type != typ2->v_type) ! emsg(_("E735: Can only compare Dictionary with Dictionary")); ! else ! emsg(_("E736: Invalid operation for Dictionary")); ! clear_tv(typ1); return FAIL; } ! else ! { ! // Compare two Dictionaries for being equal or unequal. ! n1 = dict_equal(typ1->vval.v_dict, typ2->vval.v_dict, ! ic, FALSE); ! if (type == EXPR_NEQUAL) ! n1 = !n1; ! } } ! ! else if (typ1->v_type == VAR_FUNC || typ2->v_type == VAR_FUNC ! || typ1->v_type == VAR_PARTIAL || typ2->v_type == VAR_PARTIAL) { ! if (type != EXPR_EQUAL && type != EXPR_NEQUAL ! && type != EXPR_IS && type != EXPR_ISNOT) { ! emsg(_("E694: Invalid operation for Funcrefs")); ! clear_tv(typ1); return FAIL; } ! if ((typ1->v_type == VAR_PARTIAL ! && typ1->vval.v_partial == NULL) ! || (typ2->v_type == VAR_PARTIAL ! && typ2->vval.v_partial == NULL)) ! // When both partials are NULL, then they are equal. ! // Otherwise they are not equal. ! n1 = (typ1->vval.v_partial == typ2->vval.v_partial); ! else if (type_is) ! { ! if (typ1->v_type == VAR_FUNC && typ2->v_type == VAR_FUNC) ! // strings are considered the same if their value is ! // the same ! n1 = tv_equal(typ1, typ2, ic, FALSE); ! else if (typ1->v_type == VAR_PARTIAL ! && typ2->v_type == VAR_PARTIAL) ! n1 = (typ1->vval.v_partial == typ2->vval.v_partial); ! else ! n1 = FALSE; ! } ! else ! n1 = tv_equal(typ1, typ2, ic, FALSE); ! if (type == EXPR_NEQUAL || type == EXPR_ISNOT) ! n1 = !n1; } #ifdef FEAT_FLOAT // If one of the two variables is a float, compare as a float. // When using "=~" or "!~", always compare as string. ! else if ((typ1->v_type == VAR_FLOAT || typ2->v_type == VAR_FLOAT) && type != EXPR_MATCH && type != EXPR_NOMATCH) { float_T f1, f2; ! f1 = tv_get_float(typ1); ! f2 = tv_get_float(typ2); n1 = FALSE; switch (type) { --- 1120,1193 ---- } /* ! * Compare "tv1" and "tv2". ! * Put the result in "tv1". Caller should clear "tv2". */ int typval_compare( ! typval_T *tv1, // first operand ! typval_T *tv2, // second operand ! exprtype_T type, // operator ! int ic) // ignore case { varnumber_T n1, n2; ! int res = 0; int type_is = type == EXPR_IS || type == EXPR_ISNOT; ! if (type_is && tv1->v_type != tv2->v_type) { // For "is" a different type always means FALSE, for "notis" // it means TRUE. n1 = (type == EXPR_ISNOT); } ! else if (tv1->v_type == VAR_BLOB || tv2->v_type == VAR_BLOB) { ! if (typval_compare_blob(tv1, tv2, type, &res) == FAIL) { ! clear_tv(tv1); return FAIL; } ! n1 = res; } ! else if (tv1->v_type == VAR_LIST || tv2->v_type == VAR_LIST) { ! if (typval_compare_list(tv1, tv2, type, ic, &res) == FAIL) { ! clear_tv(tv1); return FAIL; } ! n1 = res; } ! else if (tv1->v_type == VAR_DICT || tv2->v_type == VAR_DICT) { ! if (typval_compare_dict(tv1, tv2, type, ic, &res) == FAIL) { ! clear_tv(tv1); return FAIL; } ! n1 = res; } ! else if (tv1->v_type == VAR_FUNC || tv2->v_type == VAR_FUNC ! || tv1->v_type == VAR_PARTIAL || tv2->v_type == VAR_PARTIAL) { ! if (typval_compare_func(tv1, tv2, type, ic, &res) == FAIL) { ! clear_tv(tv1); return FAIL; } ! n1 = res; } #ifdef FEAT_FLOAT // If one of the two variables is a float, compare as a float. // When using "=~" or "!~", always compare as string. ! else if ((tv1->v_type == VAR_FLOAT || tv2->v_type == VAR_FLOAT) && type != EXPR_MATCH && type != EXPR_NOMATCH) { float_T f1, f2; ! f1 = tv_get_float(tv1); ! f2 = tv_get_float(tv2); n1 = FALSE; switch (type) { *************** *** 1291,1301 **** // If one of the two variables is a number, compare as a number. // When using "=~" or "!~", always compare as string. ! else if ((typ1->v_type == VAR_NUMBER || typ2->v_type == VAR_NUMBER) && type != EXPR_MATCH && type != EXPR_NOMATCH) { ! n1 = tv_get_number(typ1); ! n2 = tv_get_number(typ2); switch (type) { case EXPR_IS: --- 1208,1218 ---- // If one of the two variables is a number, compare as a number. // When using "=~" or "!~", always compare as string. ! else if ((tv1->v_type == VAR_NUMBER || tv2->v_type == VAR_NUMBER) && type != EXPR_MATCH && type != EXPR_NOMATCH) { ! n1 = tv_get_number(tv1); ! n2 = tv_get_number(tv2); switch (type) { case EXPR_IS: *************** *** 1311,1330 **** default: break; // avoid gcc warning } } ! else if (in_vim9script() && (typ1->v_type == VAR_BOOL ! || typ2->v_type == VAR_BOOL ! || (typ1->v_type == VAR_SPECIAL ! && typ2->v_type == VAR_SPECIAL))) { ! if (typ1->v_type != typ2->v_type) { semsg(_(e_cannot_compare_str_with_str), ! vartype_name(typ1->v_type), vartype_name(typ2->v_type)); ! clear_tv(typ1); return FAIL; } ! n1 = typ1->vval.v_number; ! n2 = typ2->vval.v_number; switch (type) { case EXPR_IS: --- 1228,1247 ---- default: break; // avoid gcc warning } } ! else if (in_vim9script() && (tv1->v_type == VAR_BOOL ! || tv2->v_type == VAR_BOOL ! || (tv1->v_type == VAR_SPECIAL ! && tv2->v_type == VAR_SPECIAL))) { ! if (tv1->v_type != tv2->v_type) { semsg(_(e_cannot_compare_str_with_str), ! vartype_name(tv1->v_type), vartype_name(tv2->v_type)); ! clear_tv(tv1); return FAIL; } ! n1 = tv1->vval.v_number; ! n2 = tv2->vval.v_number; switch (type) { case EXPR_IS: *************** *** 1333,1398 **** case EXPR_NEQUAL: n1 = (n1 != n2); break; default: semsg(_(e_invalid_operation_for_str), ! vartype_name(typ1->v_type)); ! clear_tv(typ1); return FAIL; } } else { ! if (in_vim9script() ! && ((typ1->v_type != VAR_STRING && typ1->v_type != VAR_SPECIAL) ! || (typ2->v_type != VAR_STRING && typ2->v_type != VAR_SPECIAL))) { ! semsg(_(e_cannot_compare_str_with_str), ! vartype_name(typ1->v_type), vartype_name(typ2->v_type)); ! clear_tv(typ1); return FAIL; } ! s1 = tv_get_string_buf(typ1, buf1); ! s2 = tv_get_string_buf(typ2, buf2); ! if (type != EXPR_MATCH && type != EXPR_NOMATCH) ! i = ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2); else ! i = 0; ! n1 = FALSE; ! switch (type) ! { ! case EXPR_IS: ! case EXPR_EQUAL: n1 = (i == 0); break; ! case EXPR_ISNOT: ! case EXPR_NEQUAL: n1 = (i != 0); break; ! case EXPR_GREATER: n1 = (i > 0); break; ! case EXPR_GEQUAL: n1 = (i >= 0); break; ! case EXPR_SMALLER: n1 = (i < 0); break; ! case EXPR_SEQUAL: n1 = (i <= 0); break; ! case EXPR_MATCH: ! case EXPR_NOMATCH: ! n1 = pattern_match(s2, s1, ic); ! if (type == EXPR_NOMATCH) ! n1 = !n1; ! break; ! default: break; // avoid gcc warning ! } } ! clear_tv(typ1); ! if (in_vim9script()) { ! typ1->v_type = VAR_BOOL; ! typ1->vval.v_number = n1 ? VVAL_TRUE : VVAL_FALSE; } else { ! typ1->v_type = VAR_NUMBER; ! typ1->vval.v_number = n1; } return OK; } /* * Convert any type to a string, never give an error. * When "quotes" is TRUE add quotes to a string. * Returns an allocated string. --- 1250,1506 ---- case EXPR_NEQUAL: n1 = (n1 != n2); break; default: semsg(_(e_invalid_operation_for_str), ! vartype_name(tv1->v_type)); ! clear_tv(tv1); return FAIL; } } else { ! if (typval_compare_string(tv1, tv2, type, ic, &res) == FAIL) { ! clear_tv(tv1); return FAIL; } ! n1 = res; ! } ! clear_tv(tv1); ! if (in_vim9script()) ! { ! tv1->v_type = VAR_BOOL; ! tv1->vval.v_number = n1 ? VVAL_TRUE : VVAL_FALSE; ! } ! else ! { ! tv1->v_type = VAR_NUMBER; ! tv1->vval.v_number = n1; ! } ! ! return OK; ! } ! ! /* ! * Compare "tv1" to "tv2" as lists acording to "type" and "ic". ! * Put the result, false or true, in "res". ! * Return FAIL and give an error message when the comparison can't be done. ! */ ! int ! typval_compare_list( ! typval_T *tv1, ! typval_T *tv2, ! exprtype_T type, ! int ic, ! int *res) ! { ! int val = 0; ! ! if (type == EXPR_IS || type == EXPR_ISNOT) ! { ! val = (tv1->v_type == tv2->v_type ! && tv1->vval.v_list == tv2->vval.v_list); ! if (type == EXPR_ISNOT) ! val = !val; ! } ! else if (tv1->v_type != tv2->v_type ! || (type != EXPR_EQUAL && type != EXPR_NEQUAL)) ! { ! if (tv1->v_type != tv2->v_type) ! emsg(_("E691: Can only compare List with List")); else ! emsg(_("E692: Invalid operation for List")); ! return FAIL; ! } ! else ! { ! val = list_equal(tv1->vval.v_list, tv2->vval.v_list, ! ic, FALSE); ! if (type == EXPR_NEQUAL) ! val = !val; ! } ! *res = val; ! return OK; ! } ! /* ! * Compare "tv1" to "tv2" as blobs acording to "type". ! * Put the result, false or true, in "res". ! * Return FAIL and give an error message when the comparison can't be done. ! */ ! int ! typval_compare_blob( ! typval_T *tv1, ! typval_T *tv2, ! exprtype_T type, ! int *res) ! { ! int val = 0; ! if (type == EXPR_IS || type == EXPR_ISNOT) ! { ! val = (tv1->v_type == tv2->v_type ! && tv1->vval.v_blob == tv2->vval.v_blob); ! if (type == EXPR_ISNOT) ! val = !val; } ! else if (tv1->v_type != tv2->v_type ! || (type != EXPR_EQUAL && type != EXPR_NEQUAL)) { ! if (tv1->v_type != tv2->v_type) ! emsg(_("E977: Can only compare Blob with Blob")); ! else ! emsg(_(e_invalblob)); ! return FAIL; } else { ! val = blob_equal(tv1->vval.v_blob, tv2->vval.v_blob); ! if (type == EXPR_NEQUAL) ! val = !val; } + *res = val; + return OK; + } + /* + * Compare "tv1" to "tv2" as dictionaries acording to "type" and "ic". + * Put the result, false or true, in "res". + * Return FAIL and give an error message when the comparison can't be done. + */ + int + typval_compare_dict( + typval_T *tv1, + typval_T *tv2, + exprtype_T type, + int ic, + int *res) + { + int val; + + if (type == EXPR_IS || type == EXPR_ISNOT) + { + val = (tv1->v_type == tv2->v_type + && tv1->vval.v_dict == tv2->vval.v_dict); + if (type == EXPR_ISNOT) + val = !val; + } + else if (tv1->v_type != tv2->v_type + || (type != EXPR_EQUAL && type != EXPR_NEQUAL)) + { + if (tv1->v_type != tv2->v_type) + emsg(_("E735: Can only compare Dictionary with Dictionary")); + else + emsg(_("E736: Invalid operation for Dictionary")); + return FAIL; + } + else + { + val = dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic, FALSE); + if (type == EXPR_NEQUAL) + val = !val; + } + *res = val; + return OK; + } + + /* + * Compare "tv1" to "tv2" as funcrefs acording to "type" and "ic". + * Put the result, false or true, in "res". + * Return FAIL and give an error message when the comparison can't be done. + */ + int + typval_compare_func( + typval_T *tv1, + typval_T *tv2, + exprtype_T type, + int ic, + int *res) + { + int val = 0; + + if (type != EXPR_EQUAL && type != EXPR_NEQUAL + && type != EXPR_IS && type != EXPR_ISNOT) + { + emsg(_("E694: Invalid operation for Funcrefs")); + return FAIL; + } + if ((tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial == NULL) + || (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial == NULL)) + // When both partials are NULL, then they are equal. + // Otherwise they are not equal. + val = (tv1->vval.v_partial == tv2->vval.v_partial); + else if (type == EXPR_IS || type == EXPR_ISNOT) + { + if (tv1->v_type == VAR_FUNC && tv2->v_type == VAR_FUNC) + // strings are considered the same if their value is + // the same + val = tv_equal(tv1, tv2, ic, FALSE); + else if (tv1->v_type == VAR_PARTIAL && tv2->v_type == VAR_PARTIAL) + val = (tv1->vval.v_partial == tv2->vval.v_partial); + else + val = FALSE; + } + else + val = tv_equal(tv1, tv2, ic, FALSE); + if (type == EXPR_NEQUAL || type == EXPR_ISNOT) + val = !val; + *res = val; return OK; } /* + * Compare "tv1" to "tv2" as strings according to "type" and "ic". + * Put the result, false or true, in "res". + * Return FAIL and give an error message when the comparison can't be done. + */ + int + typval_compare_string( + typval_T *tv1, + typval_T *tv2, + exprtype_T type, + int ic, + int *res) + { + int i = 0; + int val = FALSE; + char_u *s1, *s2; + char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN]; + + if (in_vim9script() + && ((tv1->v_type != VAR_STRING && tv1->v_type != VAR_SPECIAL) + || (tv2->v_type != VAR_STRING && tv2->v_type != VAR_SPECIAL))) + { + semsg(_(e_cannot_compare_str_with_str), + vartype_name(tv1->v_type), vartype_name(tv2->v_type)); + return FAIL; + } + s1 = tv_get_string_buf(tv1, buf1); + s2 = tv_get_string_buf(tv2, buf2); + if (type != EXPR_MATCH && type != EXPR_NOMATCH) + i = ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2); + switch (type) + { + case EXPR_IS: + case EXPR_EQUAL: val = (i == 0); break; + case EXPR_ISNOT: + case EXPR_NEQUAL: val = (i != 0); break; + case EXPR_GREATER: val = (i > 0); break; + case EXPR_GEQUAL: val = (i >= 0); break; + case EXPR_SMALLER: val = (i < 0); break; + case EXPR_SEQUAL: val = (i <= 0); break; + + case EXPR_MATCH: + case EXPR_NOMATCH: + val = pattern_match(s2, s1, ic); + if (type == EXPR_NOMATCH) + val = !val; + break; + + default: break; // avoid gcc warning + } + *res = val; + return OK; + } + /* * Convert any type to a string, never give an error. * When "quotes" is TRUE add quotes to a string. * Returns an allocated string. *** ../vim-8.2.3850/src/proto/typval.pro 2021-12-18 18:33:41.095346414 +0000 --- src/proto/typval.pro 2021-12-19 12:30:17.558762887 +0000 *************** *** 27,37 **** int check_for_job_arg(typval_T *args, int idx); int check_for_opt_job_arg(typval_T *args, int idx); int check_for_string_or_number_arg(typval_T *args, int idx); int check_for_buffer_arg(typval_T *args, int idx); int check_for_opt_buffer_arg(typval_T *args, int idx); int check_for_lnum_arg(typval_T *args, int idx); int check_for_opt_lnum_arg(typval_T *args, int idx); - int check_for_opt_string_or_number_arg(typval_T *args, int idx); int check_for_string_or_blob_arg(typval_T *args, int idx); int check_for_string_or_list_arg(typval_T *args, int idx); int check_for_string_or_list_or_blob_arg(typval_T *args, int idx); --- 27,37 ---- int check_for_job_arg(typval_T *args, int idx); int check_for_opt_job_arg(typval_T *args, int idx); int check_for_string_or_number_arg(typval_T *args, int idx); + int check_for_opt_string_or_number_arg(typval_T *args, int idx); int check_for_buffer_arg(typval_T *args, int idx); int check_for_opt_buffer_arg(typval_T *args, int idx); int check_for_lnum_arg(typval_T *args, int idx); int check_for_opt_lnum_arg(typval_T *args, int idx); int check_for_string_or_blob_arg(typval_T *args, int idx); int check_for_string_or_list_arg(typval_T *args, int idx); int check_for_string_or_list_or_blob_arg(typval_T *args, int idx); *************** *** 54,60 **** char_u *tv_stringify(typval_T *varp, char_u *buf); int tv_check_lock(typval_T *tv, char_u *name, int use_gettext); void copy_tv(typval_T *from, typval_T *to); ! int typval_compare(typval_T *typ1, typval_T *typ2, exprtype_T type, int ic); char_u *typval_tostring(typval_T *arg, int quotes); int tv_islocked(typval_T *tv); int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive); --- 54,65 ---- char_u *tv_stringify(typval_T *varp, char_u *buf); int tv_check_lock(typval_T *tv, char_u *name, int use_gettext); void copy_tv(typval_T *from, typval_T *to); ! int typval_compare(typval_T *tv1, typval_T *tv2, exprtype_T type, int ic); ! int typval_compare_list(typval_T *tv1, typval_T *tv2, exprtype_T type, int ic, int *res); ! int typval_compare_blob(typval_T *tv1, typval_T *tv2, exprtype_T type, int *res); ! int typval_compare_dict(typval_T *tv1, typval_T *tv2, exprtype_T type, int ic, int *res); ! int typval_compare_func(typval_T *tv1, typval_T *tv2, exprtype_T type, int ic, int *res); ! int typval_compare_string(typval_T *tv1, typval_T *tv2, exprtype_T type, int ic, int *res); char_u *typval_tostring(typval_T *arg, int quotes); int tv_islocked(typval_T *tv); int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive); *** ../vim-8.2.3850/src/version.c 2021-12-19 11:06:19.666495254 +0000 --- src/version.c 2021-12-19 11:39:49.485112924 +0000 *************** *** 751,752 **** --- 751,754 ---- { /* Add new patch number below this line */ + /**/ + 3851, /**/ -- hundred-and-one symptoms of being an internet addict: 75. You start wondering whether you could actually upgrade your brain with a Pentium Pro microprocessor 80. The upgrade works just fine. /// Bram Moolenaar -- Bram@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 ///