To: vim_dev@googlegroups.com Subject: Patch 7.3.1063 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.3.1063 Problem: Python: Function is not standard. Solution: Python patch 22: make Function subclassable. (ZyX) Files: src/eval.c, src/if_py_both.h, src/proto/eval.pro, src/testdir/test86.in, src/testdir/test86.ok, src/testdir/test87.in, src/testdir/test87.ok *** ../vim-7.3.1062/src/eval.c 2013-05-30 13:01:14.000000000 +0200 --- src/eval.c 2013-05-30 13:13:53.000000000 +0200 *************** *** 21933,21938 **** --- 21933,21947 ---- } #endif + int + translated_function_exists(name) + char_u *name; + { + if (builtin_function(name)) + return find_internal_func(name) >= 0; + return find_func(name) != NULL; + } + /* * Return TRUE if a function "name" exists. */ *************** *** 21950,21961 **** /* Only accept "funcname", "funcname ", "funcname (..." and * "funcname(...", not "funcname!...". */ if (p != NULL && (*nm == NUL || *nm == '(')) ! { ! if (builtin_function(p)) ! n = (find_internal_func(p) >= 0); ! else ! n = (find_func(p) != NULL); ! } vim_free(p); return n; } --- 21959,21965 ---- /* Only accept "funcname", "funcname ", "funcname (..." and * "funcname(...", not "funcname!...". */ if (p != NULL && (*nm == NUL || *nm == '(')) ! n = translated_function_exists(p); vim_free(p); return n; } *************** *** 21971,21988 **** p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL); if (p != NULL && *nm == NUL) ! { ! if (!check) return p; ! else if (builtin_function(p)) ! { ! if (find_internal_func(p) >= 0) ! return p; ! } ! else ! if (find_func(p) != NULL) ! return p; ! } vim_free(p); return NULL; } --- 21975,21983 ---- p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL); if (p != NULL && *nm == NUL) ! if (!check || translated_function_exists(p)) return p; ! vim_free(p); return NULL; } *** ../vim-7.3.1062/src/if_py_both.h 2013-05-30 13:05:55.000000000 +0200 --- src/if_py_both.h 2013-05-30 13:08:09.000000000 +0200 *************** *** 1991,2020 **** static PyTypeObject FunctionType; static PyObject * ! FunctionNew(char_u *name) { FunctionObject *self; ! self = PyObject_NEW(FunctionObject, &FunctionType); if (self == NULL) return NULL; ! self->name = PyMem_New(char_u, STRLEN(name) + 1); ! if (self->name == NULL) { ! PyErr_NoMemory(); ! return NULL; } ! STRCPY(self->name, name); ! func_ref(name); return (PyObject *)(self); } static void FunctionDestructor(FunctionObject *self) { func_unref(self->name); ! PyMem_Free(self->name); DESTRUCTOR_FINISH(self); } --- 1991,2063 ---- static PyTypeObject FunctionType; + #define NEW_FUNCTION(name) FunctionNew(&FunctionType, name) + static PyObject * ! FunctionNew(PyTypeObject *subtype, char_u *name) { FunctionObject *self; ! self = (FunctionObject *) subtype->tp_alloc(subtype, 0); ! if (self == NULL) return NULL; ! ! if (isdigit(*name)) { ! if (!translated_function_exists(name)) ! { ! PyErr_SetString(PyExc_ValueError, ! _("unnamed function does not exist")); ! return NULL; ! } ! self->name = vim_strsave(name); ! func_ref(self->name); } ! else ! { ! self->name = get_expanded_name(name, TRUE); ! if (self->name == NULL) ! { ! if (script_autoload(name, TRUE) && !aborting()) ! self->name = get_expanded_name(name, TRUE); ! if (self->name == NULL) ! { ! PyErr_SetString(PyExc_ValueError, _("function does not exist")); ! return NULL; ! } ! } ! } ! return (PyObject *)(self); } + static PyObject * + FunctionConstructor(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) + { + PyObject *self; + char_u *name; + + if (kwargs) + { + PyErr_SetString(PyExc_TypeError, + _("function constructor does not accept keyword arguments")); + return NULL; + } + + if (!PyArg_ParseTuple(args, "s", &name)) + return NULL; + + self = FunctionNew(subtype, name); + + return self; + } + static void FunctionDestructor(FunctionObject *self) { func_unref(self->name); ! vim_free(self->name); DESTRUCTOR_FINISH(self); } *************** *** 2093,2099 **** } static struct PyMethodDef FunctionMethods[] = { - {"__call__",(PyCFunction)FunctionCall, METH_VARARGS|METH_KEYWORDS, ""}, {"__dir__", (PyCFunction)FunctionDir, METH_NOARGS, ""}, { NULL, NULL, 0, NULL} }; --- 2136,2141 ---- *************** *** 4895,4901 **** case VAR_DICT: return NEW_DICTIONARY(tv->vval.v_dict); case VAR_FUNC: ! return FunctionNew(tv->vval.v_string == NULL ? (char_u *)"" : tv->vval.v_string); case VAR_UNKNOWN: Py_INCREF(Py_None); --- 4937,4943 ---- case VAR_DICT: return NEW_DICTIONARY(tv->vval.v_dict); case VAR_FUNC: ! return NEW_FUNCTION(tv->vval.v_string == NULL ? (char_u *)"" : tv->vval.v_string); case VAR_UNKNOWN: Py_INCREF(Py_None); *************** *** 5105,5114 **** FunctionType.tp_basicsize = sizeof(FunctionObject); FunctionType.tp_dealloc = (destructor)FunctionDestructor; FunctionType.tp_call = (ternaryfunc)FunctionCall; ! FunctionType.tp_flags = Py_TPFLAGS_DEFAULT; FunctionType.tp_doc = "object that calls vim function"; FunctionType.tp_methods = FunctionMethods; FunctionType.tp_repr = (reprfunc)FunctionRepr; #if PY_MAJOR_VERSION >= 3 FunctionType.tp_getattro = (getattrofunc)FunctionGetattro; #else --- 5147,5158 ---- FunctionType.tp_basicsize = sizeof(FunctionObject); FunctionType.tp_dealloc = (destructor)FunctionDestructor; FunctionType.tp_call = (ternaryfunc)FunctionCall; ! FunctionType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE; FunctionType.tp_doc = "object that calls vim function"; FunctionType.tp_methods = FunctionMethods; FunctionType.tp_repr = (reprfunc)FunctionRepr; + FunctionType.tp_new = (newfunc)FunctionConstructor; + FunctionType.tp_alloc = (allocfunc)PyType_GenericAlloc; #if PY_MAJOR_VERSION >= 3 FunctionType.tp_getattro = (getattrofunc)FunctionGetattro; #else *** ../vim-7.3.1062/src/proto/eval.pro 2013-05-30 13:01:14.000000000 +0200 --- src/proto/eval.pro 2013-05-30 13:08:09.000000000 +0200 *************** *** 79,84 **** --- 79,85 ---- char_u *get_function_name __ARGS((expand_T *xp, int idx)); char_u *get_expr_name __ARGS((expand_T *xp, int idx)); char_u *get_expanded_name __ARGS((char_u *name, int check)); + int translated_function_exists __ARGS((char_u *name)); int func_call __ARGS((char_u *name, typval_T *args, dict_T *selfdict, typval_T *rettv)); void mzscheme_call_vim __ARGS((char_u *name, typval_T *args, typval_T *rettv)); long do_searchpair __ARGS((char_u *spat, char_u *mpat, char_u *epat, int dir, char_u *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit)); *** ../vim-7.3.1062/src/testdir/test86.in 2013-05-30 13:05:55.000000000 +0200 --- src/testdir/test86.in 2013-05-30 13:08:09.000000000 +0200 *************** *** 31,36 **** --- 31,39 ---- :" :" Extending Dictionary directly with different types :let d = {} + :fun d.f() + : return 1 + :endfun py << EOF d=vim.bindeval('d') d['1']='asd' *************** *** 44,55 **** dv.sort(key=repr) di.sort(key=repr) EOF :$put =pyeval('repr(dk)') :$put =substitute(pyeval('repr(dv)'),'0x\x\+','','g') :$put =substitute(pyeval('repr(di)'),'0x\x\+','','g') ! :for [key, val] in sort(items(d)) ! : $put =string(key) . ' : ' . string(val) ! : unlet key val :endfor :" :" removing items with del --- 47,59 ---- dv.sort(key=repr) di.sort(key=repr) EOF + :$put =pyeval('d[''f''](self={})') :$put =pyeval('repr(dk)') :$put =substitute(pyeval('repr(dv)'),'0x\x\+','','g') :$put =substitute(pyeval('repr(di)'),'0x\x\+','','g') ! :for [key, Val] in sort(items(d)) ! : $put =string(key) . ' : ' . string(Val) ! : unlet key Val :endfor :" :" removing items with del *************** *** 66,71 **** --- 70,76 ---- :$put =string(l) :" :py del d['-1'] + :py del d['f'] :$put =string(pyeval('d.get(''b'', 1)')) :$put =string(pyeval('d.pop(''b'')')) :$put =string(pyeval('d.get(''b'', 1)')) *************** *** 187,195 **** :catch : $put =v:exception[:16] :endtry :delfunction New :try ! : py l[0](1, 2, 3) :catch : $put =v:exception[:16] :endtry --- 192,201 ---- :catch : $put =v:exception[:16] :endtry + :py f=l[0] :delfunction New :try ! : py f(1, 2, 3) :catch : $put =v:exception[:16] :endtry *************** *** 737,742 **** --- 743,749 ---- :$put =string(pyeval('vim.Dictionary(((''a'', 1),))')) :$put =string(pyeval('vim.List()')) :$put =string(pyeval('vim.List(iter(''abc''))')) + :$put =string(pyeval('vim.Function(''tr'')')) :" :" Test stdout/stderr :redir => messages *************** *** 747,752 **** --- 754,763 ---- :redir END :$put =string(substitute(messages, '\d\+', '', 'g')) :" Test subclassing + :fun Put(...) + : $put =string(a:000) + : return a:000 + :endfun py << EOF class DupDict(vim.Dictionary): def __setitem__(self, key, value): *************** *** 762,771 **** --- 773,789 ---- dl = DupList() dl2 = DupList(iter('abc')) dl.extend(dl2[0]) + + class DupFun(vim.Function): + def __call__(self, arg): + return super(DupFun, self).__call__(arg, arg) + + df = DupFun('Put') EOF :$put =string(sort(keys(pyeval('dd')))) :$put =string(pyeval('dl')) :$put =string(pyeval('dl2')) + :$put =string(pyeval('df(2)')) :" :" Test exceptions :fun Exe(e) *** ../vim-7.3.1062/src/testdir/test86.ok 2013-05-30 13:05:55.000000000 +0200 --- src/testdir/test86.ok 2013-05-30 13:08:09.000000000 +0200 *************** *** 4,16 **** Vim(put):E684: [0, 'as''d', [1, 2, function('strlen'), {'a': 1}]] [0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]] ! ['-1', '0', '1', 'b'] ! ['asd', -1L, , ] ! [('-1', ), ('0', -1L), ('1', 'asd'), ('b', )] '-1' : {'a': 1} '0' : -1 '1' : 'asd' 'b' : [1, 2, function('strlen')] [0, function('strlen')] [3] [1, 2, function('strlen')] --- 4,18 ---- Vim(put):E684: [0, 'as''d', [1, 2, function('strlen'), {'a': 1}]] [0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]] ! 1 ! ['-1', '0', '1', 'b', 'f'] ! ['asd', -1L, , , ] ! [('-1', ), ('0', -1L), ('1', 'asd'), ('b', ), ('f', )] '-1' : {'a': 1} '0' : -1 '1' : 'asd' 'b' : [1, 2, function('strlen')] + 'f' : function('1') [0, function('strlen')] [3] [1, 2, function('strlen')] *************** *** 407,419 **** range:__dir__,__members__,append,end,start dictionary:__dir__,__members__,get,has_key,items,keys,locked,pop,popitem,scope,update,values list:__dir__,__members__,extend,locked ! function:__call__,__dir__,__members__,softspace output:__dir__,__members__,flush,softspace,write,writelines {} {'a': 1} {'a': 1} [] ['a', 'b', 'c'] ' abcdef line : --- 409,422 ---- range:__dir__,__members__,append,end,start dictionary:__dir__,__members__,get,has_key,items,keys,locked,pop,popitem,scope,update,values list:__dir__,__members__,extend,locked ! function:__dir__,__members__,softspace output:__dir__,__members__,flush,softspace,write,writelines {} {'a': 1} {'a': 1} [] ['a', 'b', 'c'] + function('tr') ' abcdef line : *************** *** 424,429 **** --- 427,434 ---- ['a', 'dup_a'] ['a', 'a'] ['a', 'b', 'c'] + [2, 2] + [2, 2] (, error('abc',)) (, error('def',)) (, error('ghi',)) *** ../vim-7.3.1062/src/testdir/test87.in 2013-05-30 13:05:55.000000000 +0200 --- src/testdir/test87.in 2013-05-30 13:08:09.000000000 +0200 *************** *** 26,31 **** --- 26,34 ---- :" :" Extending Dictionary directly with different types :let d = {} + :fun d.f() + : return 1 + :endfun py3 << EOF d=vim.bindeval('d') d['1']='asd' *************** *** 39,50 **** dv.sort(key=repr) di.sort(key=repr) EOF :$put =py3eval('repr(dk)') :$put =substitute(py3eval('repr(dv)'),'0x\x\+','','g') :$put =substitute(py3eval('repr(di)'),'0x\x\+','','g') ! :for [key, val] in sort(items(d)) ! : $put =string(key) . ' : ' . string(val) ! : unlet key val :endfor :" :" removing items with del --- 42,54 ---- dv.sort(key=repr) di.sort(key=repr) EOF + :$put =py3eval('d[''f''](self={})') :$put =py3eval('repr(dk)') :$put =substitute(py3eval('repr(dv)'),'0x\x\+','','g') :$put =substitute(py3eval('repr(di)'),'0x\x\+','','g') ! :for [key, Val] in sort(items(d)) ! : $put =string(key) . ' : ' . string(Val) ! : unlet key Val :endfor :" :" removing items with del *************** *** 61,66 **** --- 65,71 ---- :$put =string(l) :" :py3 del d['-1'] + :py3 del d['f'] :$put =string(py3eval('d.get(''b'', 1)')) :$put =string(py3eval('d.pop(''b'')')) :$put =string(py3eval('d.get(''b'', 1)')) *************** *** 182,190 **** :catch : $put =v:exception[:13] :endtry :delfunction New :try ! : py3 l[0](1, 2, 3) :catch : $put =v:exception[:13] :endtry --- 187,196 ---- :catch : $put =v:exception[:13] :endtry + :py3 f=l[0] :delfunction New :try ! : py3 f(1, 2, 3) :catch : $put =v:exception[:13] :endtry *************** *** 698,703 **** --- 704,710 ---- :$put =string(py3eval('vim.Dictionary(((''a'', 1),))')) :$put =string(py3eval('vim.List()')) :$put =string(py3eval('vim.List(iter(''abc''))')) + :$put =string(py3eval('vim.Function(''tr'')')) :" :" Test stdout/stderr :redir => messages *************** *** 708,713 **** --- 715,724 ---- :redir END :$put =string(substitute(messages, '\d\+', '', 'g')) :" Test subclassing + :fun Put(...) + : $put =string(a:000) + : return a:000 + :endfun py3 << EOF class DupDict(vim.Dictionary): def __setitem__(self, key, value): *************** *** 723,732 **** --- 734,750 ---- dl = DupList() dl2 = DupList(iter('abc')) dl.extend(dl2[0]) + + class DupFun(vim.Function): + def __call__(self, arg): + return super(DupFun, self).__call__(arg, arg) + + df = DupFun('Put') EOF :$put =string(sort(keys(py3eval('dd')))) :$put =string(py3eval('dl')) :$put =string(py3eval('dl2')) + :$put =string(py3eval('df(2)')) :" :" Test exceptions :fun Exe(e) *** ../vim-7.3.1062/src/testdir/test87.ok 2013-05-30 13:05:55.000000000 +0200 --- src/testdir/test87.ok 2013-05-30 13:08:09.000000000 +0200 *************** *** 4,16 **** Vim(put):E684: [0, 'as''d', [1, 2, function('strlen'), {'a': 1}]] [0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]] ! [b'-1', b'0', b'1', b'b'] ! [-1, , , b'asd'] ! [(b'-1', ), (b'0', -1), (b'1', b'asd'), (b'b', )] '-1' : {'a': 1} '0' : -1 '1' : 'asd' 'b' : [1, 2, function('strlen')] [0, function('strlen')] [3] [1, 2, function('strlen')] --- 4,18 ---- Vim(put):E684: [0, 'as''d', [1, 2, function('strlen'), {'a': 1}]] [0, function('strlen'), [1, 2, function('strlen'), {'a': 1}]] ! 1 ! [b'-1', b'0', b'1', b'b', b'f'] ! [-1, , , , b'asd'] ! [(b'-1', ), (b'0', -1), (b'1', b'asd'), (b'b', ), (b'f', )] '-1' : {'a': 1} '0' : -1 '1' : 'asd' 'b' : [1, 2, function('strlen')] + 'f' : function('1') [0, function('strlen')] [3] [1, 2, function('strlen')] *************** *** 396,408 **** range:__dir__,append,end,start dictionary:__dir__,get,has_key,items,keys,locked,pop,popitem,scope,update,values list:__dir__,extend,locked ! function:__call__,__dir__,softspace output:__dir__,flush,softspace,write,writelines {} {'a': 1} {'a': 1} [] ['a', 'b', 'c'] ' abcdef line : --- 398,411 ---- range:__dir__,append,end,start dictionary:__dir__,get,has_key,items,keys,locked,pop,popitem,scope,update,values list:__dir__,extend,locked ! function:__dir__,softspace output:__dir__,flush,softspace,write,writelines {} {'a': 1} {'a': 1} [] ['a', 'b', 'c'] + function('tr') ' abcdef line : *************** *** 413,418 **** --- 416,423 ---- ['a', 'dup_a'] ['a', 'a'] ['a', 'b', 'c'] + [2, 2] + [2, 2] (, error('abc',)) (, error('def',)) (, error('ghi',)) *** ../vim-7.3.1062/src/version.c 2013-05-30 13:05:55.000000000 +0200 --- src/version.c 2013-05-30 13:07:47.000000000 +0200 *************** *** 730,731 **** --- 730,733 ---- { /* Add new patch number below this line */ + /**/ + 1063, /**/ -- How To Keep A Healthy Level Of Insanity: 6. In the memo field of all your checks, write "for sexual favors". /// 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 ///