To: vim_dev@googlegroups.com Subject: Patch 7.4.1875 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.1875 Problem: Comparing functions and partials doesn't work well. Solution: Add tests. (Nikolai Pavlov) Compare the dict and arguments in the partial. (closes #813) Files: src/eval.c, src/testdir/test_partial.vim *** ../vim-7.4.1874/src/eval.c 2016-06-01 23:08:35.249421504 +0200 --- src/eval.c 2016-06-02 17:37:10.884506528 +0200 *************** *** 4627,4633 **** clear_tv(&var2); return FAIL; } ! n1 = tv_equal(rettv, &var2, FALSE, FALSE); if (type == TYPE_NEQUAL) n1 = !n1; } --- 4627,4652 ---- clear_tv(&var2); return FAIL; } ! if ((rettv->v_type == VAR_PARTIAL ! && rettv->vval.v_partial == NULL) ! || (var2.v_type == VAR_PARTIAL ! && var2.vval.v_partial == NULL)) ! /* when a partial is NULL assume not equal */ ! n1 = FALSE; ! else if (type_is) ! { ! if (rettv->v_type == VAR_FUNC && var2.v_type == VAR_FUNC) ! /* strings are considered the same if their value is ! * the same */ ! n1 = tv_equal(rettv, &var2, ic, FALSE); ! else if (rettv->v_type == VAR_PARTIAL ! && var2.v_type == VAR_PARTIAL) ! n1 = (rettv->vval.v_partial == var2.vval.v_partial); ! else ! n1 = FALSE; ! } ! else ! n1 = tv_equal(rettv, &var2, ic, FALSE); if (type == TYPE_NEQUAL) n1 = !n1; } *************** *** 6258,6263 **** --- 6277,6334 ---- static int tv_equal_recurse_limit; + static int + func_equal( + typval_T *tv1, + typval_T *tv2, + int ic) /* ignore case */ + { + char_u *s1, *s2; + dict_T *d1, *d2; + int a1, a2; + int i; + + /* empty and NULL function name considered the same */ + s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string + : tv1->vval.v_partial->pt_name; + if (s1 != NULL && *s1 == NUL) + s1 = NULL; + s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string + : tv2->vval.v_partial->pt_name; + if (s2 != NULL && *s2 == NUL) + s2 = NULL; + if (s1 == NULL || s2 == NULL) + { + if (s1 != s2) + return FALSE; + } + else if (STRCMP(s1, s2) != 0) + return FALSE; + + /* empty dict and NULL dict is different */ + d1 = tv1->v_type == VAR_FUNC ? NULL : tv1->vval.v_partial->pt_dict; + d2 = tv2->v_type == VAR_FUNC ? NULL : tv2->vval.v_partial->pt_dict; + if (d1 == NULL || d2 == NULL) + { + if (d1 != d2) + return FALSE; + } + else if (!dict_equal(d1, d2, ic, TRUE)) + return FALSE; + + /* empty list and no list considered the same */ + a1 = tv1->v_type == VAR_FUNC ? 0 : tv1->vval.v_partial->pt_argc; + a2 = tv2->v_type == VAR_FUNC ? 0 : tv2->vval.v_partial->pt_argc; + if (a1 != a2) + return FALSE; + for (i = 0; i < a1; ++i) + if (!tv_equal(tv1->vval.v_partial->pt_argv + i, + tv2->vval.v_partial->pt_argv + i, ic, TRUE)) + return FALSE; + + return TRUE; + } + /* * Return TRUE if "tv1" and "tv2" have the same value. * Compares the items just like "==" would compare them, but strings and *************** *** 6275,6296 **** static int recursive_cnt = 0; /* catch recursive loops */ int r; - /* For VAR_FUNC and VAR_PARTIAL only compare the function name. */ - if ((tv1->v_type == VAR_FUNC - || (tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial != NULL)) - && (tv2->v_type == VAR_FUNC - || (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial != NULL))) - { - s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string - : tv1->vval.v_partial->pt_name; - s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string - : tv2->vval.v_partial->pt_name; - return (s1 != NULL && s2 != NULL && STRCMP(s1, s2) == 0); - } - - if (tv1->v_type != tv2->v_type) - return FALSE; - /* Catch lists and dicts that have an endless loop by limiting * recursiveness to a limit. We guess they are equal then. * A fixed limit has the problem of still taking an awful long time. --- 6346,6351 ---- *************** *** 6305,6310 **** --- 6360,6380 ---- return TRUE; } + /* For VAR_FUNC and VAR_PARTIAL only compare the function name. */ + if ((tv1->v_type == VAR_FUNC + || (tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial != NULL)) + && (tv2->v_type == VAR_FUNC + || (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial != NULL))) + { + ++recursive_cnt; + r = func_equal(tv1, tv2, ic); + --recursive_cnt; + return r; + } + + if (tv1->v_type != tv2->v_type) + return FALSE; + switch (tv1->v_type) { case VAR_LIST: *** ../vim-7.4.1874/src/testdir/test_partial.vim 2016-05-28 22:47:08.542193208 +0200 --- src/testdir/test_partial.vim 2016-06-02 17:43:06.292501639 +0200 *************** *** 316,318 **** --- 316,381 ---- call assert_equal([], get(Func, 'args')) call assert_true(empty( get(Func, 'dict'))) endfunc + + func Test_compare_partials() + let d1 = {} + let d2 = {} + + function d1.f1() dict + endfunction + + function d1.f2() dict + endfunction + + let F1 = get(d1, 'f1') + let F2 = get(d1, 'f2') + + let F1d1 = function(F1, d1) + let F2d1 = function(F2, d2) + let F1d1a1 = function(F1d1, [1]) + let F1d1a12 = function(F1d1, [1, 2]) + let F1a1 = function(F1, [1]) + let F1a2 = function(F1, [2]) + let F1d2 = function(F1, d2) + let d3 = {'f1': F1, 'f2': F2} + let F1d3 = function(F1, d3) + let F1ad1 = function(F1, [d1]) + let F1ad3 = function(F1, [d3]) + + call assert_match('^function(''\d\+'')$', string(F1)) " Not a partial + call assert_match('^function(''\d\+'')$', string(F2)) " Not a partial + call assert_match('^function(''\d\+'', {.*})$', string(F1d1)) " A partial + call assert_match('^function(''\d\+'', {.*})$', string(F2d1)) " A partial + call assert_match('^function(''\d\+'', \[.*\])$', string(F1a1)) " No dict + + " != + let X = F1 + call assert_false(F1 != X) " same function + let X = F1d1 + call assert_false(F1d1 != X) " same partial + let X = F1d1a1 + call assert_false(F1d1a1 != X) " same partial + let X = F1a1 + call assert_false(F1a1 != X) " same partial + + call assert_true(F1 != F2) " Different functions + call assert_true(F1 != F1d1) " Partial /= non-partial + call assert_true(F1d1a1 != F1d1a12) " Different number of arguments + call assert_true(F1a1 != F1d1a12) " One has no dict + call assert_true(F1a1 != F1a2) " Different arguments + call assert_true(F1d2 != F1d1) " Different dictionaries + call assert_false(F1d1 != F1d3) " Equal dictionaries, even though d1 isnot d3 + + " isnot, option 1 + call assert_true(F1 isnot# F2) " Different functions + call assert_true(F1 isnot# F1d1) " Partial /= non-partial + call assert_true(F1d1 isnot# F1d3) " d1 isnot d3, even though d1 == d3 + call assert_true(F1a1 isnot# F1d1a12) " One has no dict + call assert_true(F1a1 isnot# F1a2) " Different number of arguments + call assert_true(F1ad1 isnot# F1ad3) " In arguments d1 isnot d3 + + " isnot, option 2 + call assert_true(F1 isnot# F2) " Different functions + call assert_true(F1 isnot# F1d1) " Partial /= non-partial + call assert_true(d1.f1 isnot# d1.f1) " handle_subscript creates new partial each time + endfunc *** ../vim-7.4.1874/src/version.c 2016-06-02 15:49:33.008595362 +0200 --- src/version.c 2016-06-02 17:41:19.840503104 +0200 *************** *** 755,756 **** --- 755,758 ---- { /* Add new patch number below this line */ + /**/ + 1875, /**/ -- hundred-and-one symptoms of being an internet addict: 38. You wake up at 3 a.m. to go to the bathroom and stop and check your e-mail on the way back to bed. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///