This is a fix for https://groups.google.com/forum/#!topic/vim_use/UW3YAAQ5ulk.

# HG changeset patch
# User ZyX <[email protected]>
# Date 1385490752 -14400
#      Tue Nov 26 22:32:32 2013 +0400
# Branch fix-vim.eval-throw
# Node ID 50125a7e0dea60b72db9fc73ccd5bcc697d788cf
# Parent  7adbbf32444ecedb1c81f3306af29aa640a4249c
Throw exceptions on errors in vim.eval

diff -r 7adbbf32444e -r 50125a7e0dea src/ex_eval.c
--- a/src/ex_eval.c     Thu Nov 21 18:13:38 2013 +0100
+++ b/src/ex_eval.c     Tue Nov 26 22:32:32 2013 +0400
@@ -321,6 +321,17 @@
 }
 
 /*
+ * Free global "*msg_list" and the messages it contains, then set "*msg_list" 
to 
+ * NULL.
+ */
+    void
+free_global_msglist()
+{
+    free_msglist(*msg_list);
+    *msg_list = NULL;
+}
+
+/*
  * Throw the message specified in the call to cause_errthrow() above as an
  * error exception.  If cstack is NULL, postpone the throw until do_cmdline()
  * has returned (see do_one_cmd()).
@@ -410,66 +421,41 @@
     return TRUE;
 }
 
-
 /*
- * Throw a new exception.  Return FAIL when out of memory or it was tried to
- * throw an illegal user exception.  "value" is the exception string for a user
- * or interrupt exception, or points to a message list in case of an error
- * exception.
+ * Get an exception message that is to be stored in current_exception->value.
  */
-    static int
-throw_exception(value, type, cmdname)
+    char_u *
+get_exception_string(value, type, cmdname, should_free)
     void       *value;
     int                type;
     char_u     *cmdname;
+    int                *should_free;
 {
-    except_T   *excp;
-    char_u     *p, *mesg, *val;
+    char_u     *ret, *mesg;
     int                cmdlen;
-
-    /*
-     * Disallow faking Interrupt or error exceptions as user exceptions.  They
-     * would be treated differently from real interrupt or error exceptions 
when
-     * no active try block is found, see do_cmdline().
-     */
-    if (type == ET_USER)
-    {
-       if (STRNCMP((char_u *)value, "Vim", 3) == 0 &&
-               (((char_u *)value)[3] == NUL || ((char_u *)value)[3] == ':' ||
-                ((char_u *)value)[3] == '('))
-       {
-           EMSG(_("E608: Cannot :throw exceptions with 'Vim' prefix"));
-           goto fail;
-       }
-    }
-
-    excp = (except_T *)alloc((unsigned)sizeof(except_T));
-    if (excp == NULL)
-       goto nomem;
+    char_u     *p, *val;
 
     if (type == ET_ERROR)
     {
-       /* Store the original message and prefix the exception value with
-        * "Vim:" or, if a command name is given, "Vim(cmdname):". */
-       excp->messages = (struct msglist *)value;
-       mesg = excp->messages->throw_msg;
+       *should_free = FALSE;
+       mesg = ((struct msglist *)value)->throw_msg;
        if (cmdname != NULL && *cmdname != NUL)
        {
            cmdlen = (int)STRLEN(cmdname);
-           excp->value = vim_strnsave((char_u *)"Vim(",
+           ret = vim_strnsave((char_u *)"Vim(",
                                           4 + cmdlen + 2 + (int)STRLEN(mesg));
-           if (excp->value == NULL)
-               goto nomem;
-           STRCPY(&excp->value[4], cmdname);
-           STRCPY(&excp->value[4 + cmdlen], "):");
-           val = excp->value + 4 + cmdlen + 2;
+           if (ret == NULL)
+               return ret;
+           STRCPY(&ret[4], cmdname);
+           STRCPY(&ret[4 + cmdlen], "):");
+           val = ret + 4 + cmdlen + 2;
        }
        else
        {
-           excp->value = vim_strnsave((char_u *)"Vim:", 4 + (int)STRLEN(mesg));
-           if (excp->value == NULL)
-               goto nomem;
-           val = excp->value + 4;
+           ret = vim_strnsave((char_u *)"Vim:", 4 + (int)STRLEN(mesg));
+           if (ret == NULL)
+               return ret;
+           val = ret + 4;
        }
 
        /* msg_add_fname may have been used to prefix the message with a file
@@ -506,14 +492,65 @@
        }
     }
     else
-       excp->value = value;
+    {
+       *should_free = FALSE;
+       ret = (char_u *) value;
+    }
+
+    return ret;
+}
+
+
+/*
+ * Throw a new exception.  Return FAIL when out of memory or it was tried to
+ * throw an illegal user exception.  "value" is the exception string for a user
+ * or interrupt exception, or points to a message list in case of an error
+ * exception.
+ */
+    static int
+throw_exception(value, type, cmdname)
+    void       *value;
+    int                type;
+    char_u     *cmdname;
+{
+    except_T   *excp;
+    int                should_free;
+
+    /*
+     * Disallow faking Interrupt or error exceptions as user exceptions.  They
+     * would be treated differently from real interrupt or error exceptions 
when
+     * no active try block is found, see do_cmdline().
+     */
+    if (type == ET_USER)
+    {
+       if (STRNCMP((char_u *)value, "Vim", 3) == 0 &&
+               (((char_u *)value)[3] == NUL || ((char_u *)value)[3] == ':' ||
+                ((char_u *)value)[3] == '('))
+       {
+           EMSG(_("E608: Cannot :throw exceptions with 'Vim' prefix"));
+           goto fail;
+       }
+    }
+
+    excp = (except_T *)alloc((unsigned)sizeof(except_T));
+    if (excp == NULL)
+       goto nomem;
+
+    if (type == ET_ERROR)
+       /* Store the original message and prefix the exception value with
+        * "Vim:" or, if a command name is given, "Vim(cmdname):". */
+       excp->messages = (struct msglist *)value;
+
+    excp->value = get_exception_string(value, type, cmdname, &should_free);
+    if (excp->value == NULL && should_free)
+       goto nomem;
 
     excp->type = type;
     excp->throw_name = vim_strsave(sourcing_name == NULL
                                              ? (char_u *)"" : sourcing_name);
     if (excp->throw_name == NULL)
     {
-       if (type == ET_ERROR)
+       if (should_free)
            vim_free(excp->value);
        goto nomem;
     }
@@ -2033,10 +2070,7 @@
        /* If an error was about to be converted to an exception when
         * enter_cleanup() was called, free the message list. */
        if (msg_list != NULL)
-       {
-           free_msglist(*msg_list);
-           *msg_list = NULL;
-       }
+           free_global_msglist();
     }
 
     /*
diff -r 7adbbf32444e -r 50125a7e0dea src/if_py_both.h
--- a/src/if_py_both.h  Thu Nov 21 18:13:38 2013 +0100
+++ b/src/if_py_both.h  Tue Nov 26 22:32:32 2013 +0400
@@ -566,6 +566,28 @@
        PyErr_SetNone(PyExc_KeyboardInterrupt);
        return -1;
     }
+    else if (!(msg_list == NULL || *msg_list == NULL))
+    {
+       int     should_free;
+       char_u  *msg;
+
+       msg = get_exception_string(*msg_list, ET_ERROR, NULL, &should_free);
+
+       if (msg == NULL)
+       {
+           PyErr_NoMemory();
+           return -1;
+       }
+
+       PyErr_SetVim((char *) msg);
+
+       free_global_msglist();
+
+       if (should_free)
+           vim_free(msg);
+
+       return -1;
+    }
     else if (!did_throw)
        return (PyErr_Occurred() ? -1 : 0);
     /* Python exception is preferred over vim one; unlikely to occur though */
diff -r 7adbbf32444e -r 50125a7e0dea src/proto/ex_eval.pro
--- a/src/proto/ex_eval.pro     Thu Nov 21 18:13:38 2013 +0100
+++ b/src/proto/ex_eval.pro     Tue Nov 26 22:32:32 2013 +0400
@@ -29,4 +29,6 @@
 void rewind_conditionals __ARGS((struct condstack *cstack, int idx, int 
cond_type, int *cond_level));
 void ex_endfunction __ARGS((exarg_T *eap));
 int has_loop_cmd __ARGS((char_u *p));
+char_u *get_exception_string __ARGS((void *value, int type, char_u *cmdname, 
int *should_free));
+void free_global_msglist __ARGS((void));
 /* vim: set ft=c : */
diff -r 7adbbf32444e -r 50125a7e0dea src/testdir/test86.in
--- a/src/testdir/test86.in     Thu Nov 21 18:13:38 2013 +0100
+++ b/src/testdir/test86.in     Tue Nov 26 22:32:32 2013 +0400
@@ -179,6 +179,32 @@
 :unlockvar! l
 :"
 :" Function calls
+py << EOF
+import sys
+def ee(expr, g=globals(), l=locals()):
+    try:
+        exec(expr, g, l)
+    except:
+        ei = sys.exc_info()
+        msg = sys.exc_info()[0].__name__ + ':' + repr(sys.exc_info()[1].args)
+        msg = msg.replace('TypeError:(\'argument 1 ', 'TypeError:(\'')
+        if expr.find('None') > -1:
+            msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
+                              'TypeError:("\'NoneType\' object is not 
iterable",)')
+        if expr.find('FailingNumber') > -1:
+            msg = msg.replace(', not \'FailingNumber\'', '').replace('"', '\'')
+            msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
+                              'TypeError:("\'FailingNumber\' object is not 
iterable",)')
+        if msg.find('(\'\'') > -1 or msg.find('(\'can\'t') > -1:
+            msg = msg.replace('(\'', '("').replace('\',)', '",)')
+        if expr == 'fd(self=[])':
+            # HACK: PyMapping_Check changed meaning
+            msg = msg.replace('AttributeError:(\'keys\',)',
+                              'TypeError:(\'unable to convert list to vim 
dictionary\',)')
+        vim.current.buffer.append(expr + ':' + msg)
+    else:
+        vim.current.buffer.append(expr + ':NOT FAILED')
+EOF
 :fun New(...)
 :   return ['NewStart']+a:000+['NewEnd']
 :endfun
@@ -193,18 +219,10 @@
 :$put =string(l)
 :py l.extend([l[0].name])
 :$put =string(l)
-:try
-:   py l[1](1, 2, 3)
-:catch
-:   $put =v:exception[:16]
-:endtry
+:py ee('l[1](1, 2, 3)')
 :py f=l[0]
 :delfunction New
-:try
-:   py f(1, 2, 3)
-:catch
-:   $put =v:exception[:16]
-:endtry
+:py ee('f(1, 2, 3)')
 :if has('float')
 :   let l=[0.0]
 :   py l=vim.bindeval('l')
@@ -216,7 +234,6 @@
 :let messages=[]
 :delfunction DictNew
 py <<EOF
-import sys
 d=vim.bindeval('{}')
 m=vim.bindeval('messages')
 def em(expr, g=globals(), l=locals()):
@@ -323,6 +340,7 @@
 :py l[0] = t.t > 8  # check if the background thread is working
 :py del time
 :py del threading
+:py del t
 :$put =string(l)
 :"
 :" settrace
@@ -882,29 +900,6 @@
 :fun D()
 :endfun
 py << EOF
-def ee(expr, g=globals(), l=locals()):
-    try:
-        exec(expr, g, l)
-    except:
-        ei = sys.exc_info()
-        msg = sys.exc_info()[0].__name__ + ':' + repr(sys.exc_info()[1].args)
-        msg = msg.replace('TypeError:(\'argument 1 ', 'TypeError:(\'')
-        if expr.find('None') > -1:
-            msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
-                              'TypeError:("\'NoneType\' object is not 
iterable",)')
-        if expr.find('FailingNumber') > -1:
-            msg = msg.replace(', not \'FailingNumber\'', '').replace('"', '\'')
-            msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
-                              'TypeError:("\'FailingNumber\' object is not 
iterable",)')
-        if msg.find('(\'\'') > -1 or msg.find('(\'can\'t') > -1:
-            msg = msg.replace('(\'', '("').replace('\',)', '",)')
-        if expr == 'fd(self=[])':
-            # HACK: PyMapping_Check changed meaning
-            msg = msg.replace('AttributeError:(\'keys\',)',
-                              'TypeError:(\'unable to convert list to vim 
dictionary\',)')
-        cb.append(expr + ':' + msg)
-    else:
-        cb.append(expr + ':NOT FAILED')
 d = vim.Dictionary()
 ned = vim.Dictionary(foo='bar', baz='abcD')
 dl = vim.Dictionary(a=1)
@@ -1276,6 +1271,7 @@
 ee('vim.eval("Exe(\'throw \'\'ghi\'\'\')")')
 ee('vim.eval("Exe(\'echoerr \'\'jkl\'\'\')")')
 ee('vim.eval("Exe(\'xxx_non_existent_command_xxx\')")')
+ee('vim.eval("xxx_unknown_function_xxx()")')
 ee('vim.bindeval("Exe(\'xxx_non_existent_command_xxx\')")')
 del Exe
 EOF
diff -r 7adbbf32444e -r 50125a7e0dea src/testdir/test86.ok
--- a/src/testdir/test86.ok     Thu Nov 21 18:13:38 2013 +0100
+++ b/src/testdir/test86.ok     Tue Nov 26 22:32:32 2013 +0400
@@ -53,8 +53,8 @@
 [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
 [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 
'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
 [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 
'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']
-Vim(python):E725:
-Vim(python):E117:
+l[1](1, 2, 3):error:('Vim:E725: Calling dict function without Dictionary: 
DictNew',)
+f(1, 2, 3):error:('Vim:E117: Unknown function: New',)
 [0.0, 0.0]
 KeyError
 TypeError
@@ -1197,6 +1197,7 @@
 vim.eval("Exe('throw ''ghi''')"):error:('ghi',)
 vim.eval("Exe('echoerr ''jkl''')"):error:('Vim(echoerr):jkl',)
 vim.eval("Exe('xxx_non_existent_command_xxx')"):error:('Vim:E492: Not an 
editor command: xxx_non_existent_command_xxx',)
+vim.eval("xxx_unknown_function_xxx()"):error:('Vim:E117: Unknown function: 
xxx_unknown_function_xxx',)
 vim.bindeval("Exe('xxx_non_existent_command_xxx')"):error:('Vim:E492: Not an 
editor command: xxx_non_existent_command_xxx',)
 Caught KeyboardInterrupt
 Running :put
diff -r 7adbbf32444e -r 50125a7e0dea src/testdir/test87.in
--- a/src/testdir/test87.in     Thu Nov 21 18:13:38 2013 +0100
+++ b/src/testdir/test87.in     Tue Nov 26 22:32:32 2013 +0400
@@ -172,6 +172,36 @@
 :unlockvar! l
 :"
 :" Function calls
+py3 << EOF
+import sys
+import re
+
+py33_type_error_pattern = re.compile('^__call__\(\) takes (\d+) positional 
argument but (\d+) were given$')
+
+def ee(expr, g=globals(), l=locals()):
+    cb = vim.current.buffer
+    try:
+        try:
+            exec(expr, g, l)
+        except Exception as e:
+            if sys.version_info >= (3, 3) and e.__class__ is AttributeError 
and str(e).find('has no attribute')>=0 and not str(e).startswith("'vim."):
+                cb.append(expr + ':' + repr((e.__class__, 
AttributeError(str(e)[str(e).rfind(" '") + 2:-1]))))
+            elif sys.version_info >= (3, 3) and e.__class__ is ImportError and 
str(e).find('No module named \'') >= 0:
+                cb.append(expr + ':' + repr((e.__class__, 
ImportError(str(e).replace("'", '')))))
+            elif sys.version_info >= (3, 3) and e.__class__ is TypeError:
+                m = py33_type_error_pattern.search(str(e))
+                if m:
+                    msg = '__call__() takes exactly {0} positional argument 
({1} given)'.format(m.group(1), m.group(2))
+                    cb.append(expr + ':' + repr((e.__class__, TypeError(msg))))
+                else:
+                    cb.append(expr + ':' + repr((e.__class__, e)))
+            else:
+                cb.append(expr + ':' + repr((e.__class__, e)))
+        else:
+            cb.append(expr + ':NOT FAILED')
+    except Exception as e:
+        cb.append(expr + '::' + repr((e.__class__, e)))
+EOF
 :fun New(...)
 :   return ['NewStart']+a:000+['NewEnd']
 :endfun
@@ -186,18 +216,10 @@
 :$put =string(l)
 :py3 l+=[l[0].name]
 :$put =string(l)
-:try
-:   py3 l[1](1, 2, 3)
-:catch
-:   $put =v:exception[:13]
-:endtry
+:py3 ee('l[1](1, 2, 3)')
 :py3 f=l[0]
 :delfunction New
-:try
-:   py3 f(1, 2, 3)
-:catch
-:   $put =v:exception[:13]
-:endtry
+:py3 ee('f(1, 2, 3)')
 :if has('float')
 :   let l=[0.0]
 :   py3 l=vim.bindeval('l')
@@ -315,6 +337,7 @@
 :py3 l[0] = t.t > 8  # check if the background thread is working
 :py3 del time
 :py3 del threading
+:py3 del t
 :$put =string(l)
 :"
 :" settrace
@@ -829,33 +852,6 @@
 :fun D()
 :endfun
 py3 << EOF
-import re
-
-py33_type_error_pattern = re.compile('^__call__\(\) takes (\d+) positional 
argument but (\d+) were given$')
-
-def ee(expr, g=globals(), l=locals()):
-    try:
-        try:
-            exec(expr, g, l)
-        except Exception as e:
-            if sys.version_info >= (3, 3) and e.__class__ is AttributeError 
and str(e).find('has no attribute')>=0 and not str(e).startswith("'vim."):
-                cb.append(expr + ':' + repr((e.__class__, 
AttributeError(str(e)[str(e).rfind(" '") + 2:-1]))))
-            elif sys.version_info >= (3, 3) and e.__class__ is ImportError and 
str(e).find('No module named \'') >= 0:
-                cb.append(expr + ':' + repr((e.__class__, 
ImportError(str(e).replace("'", '')))))
-            elif sys.version_info >= (3, 3) and e.__class__ is TypeError:
-                m = py33_type_error_pattern.search(str(e))
-                if m:
-                    msg = '__call__() takes exactly {0} positional argument 
({1} given)'.format(m.group(1), m.group(2))
-                    cb.append(expr + ':' + repr((e.__class__, TypeError(msg))))
-                else:
-                    cb.append(expr + ':' + repr((e.__class__, e)))
-            else:
-                cb.append(expr + ':' + repr((e.__class__, e)))
-        else:
-            cb.append(expr + ':NOT FAILED')
-    except Exception as e:
-        cb.append(expr + '::' + repr((e.__class__, e)))
-
 d = vim.Dictionary()
 ned = vim.Dictionary(foo='bar', baz='abcD')
 dl = vim.Dictionary(a=1)
@@ -1227,6 +1223,7 @@
 ee('vim.eval("Exe(\'throw \'\'ghi\'\'\')")')
 ee('vim.eval("Exe(\'echoerr \'\'jkl\'\'\')")')
 ee('vim.eval("Exe(\'xxx_non_existent_command_xxx\')")')
+ee('vim.eval("xxx_unknown_function_xxx()")')
 ee('vim.bindeval("Exe(\'xxx_non_existent_command_xxx\')")')
 del Exe
 EOF
diff -r 7adbbf32444e -r 50125a7e0dea src/testdir/test87.ok
--- a/src/testdir/test87.ok     Thu Nov 21 18:13:38 2013 +0100
+++ b/src/testdir/test87.ok     Tue Nov 26 22:32:32 2013 +0400
@@ -53,8 +53,8 @@
 [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
 [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 
'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
 [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 
'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']
-Vim(py3):E725:
-Vim(py3):E117:
+l[1](1, 2, 3):(<class 'vim.error'>, error('Vim:E725: Calling dict function 
without Dictionary: DictNew',))
+f(1, 2, 3):(<class 'vim.error'>, error('Vim:E117: Unknown function: New',))
 [0.0, 0.0]
 KeyError
 TypeError
@@ -1186,6 +1186,7 @@
 vim.eval("Exe('throw ''ghi''')"):(<class 'vim.error'>, error('ghi',))
 vim.eval("Exe('echoerr ''jkl''')"):(<class 'vim.error'>, 
error('Vim(echoerr):jkl',))
 vim.eval("Exe('xxx_non_existent_command_xxx')"):(<class 'vim.error'>, 
error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',))
+vim.eval("xxx_unknown_function_xxx()"):(<class 'vim.error'>, error('Vim:E117: 
Unknown function: xxx_unknown_function_xxx',))
 vim.bindeval("Exe('xxx_non_existent_command_xxx')"):(<class 'vim.error'>, 
error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',))
 Caught KeyboardInterrupt
 Running :put

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.
diff -crN vim-small-patches.7adbbf32444e/src/ex_eval.c vim-small-patches.50125a7e0dea/src/ex_eval.c
*** vim-small-patches.7adbbf32444e/src/ex_eval.c	2013-11-26 22:41:25.765341503 +0400
--- vim-small-patches.50125a7e0dea/src/ex_eval.c	2013-11-26 22:41:25.777341502 +0400
***************
*** 321,326 ****
--- 321,337 ----
  }
  
  /*
+  * Free global "*msg_list" and the messages it contains, then set "*msg_list" to 
+  * NULL.
+  */
+     void
+ free_global_msglist()
+ {
+     free_msglist(*msg_list);
+     *msg_list = NULL;
+ }
+ 
+ /*
   * Throw the message specified in the call to cause_errthrow() above as an
   * error exception.  If cstack is NULL, postpone the throw until do_cmdline()
   * has returned (see do_one_cmd()).
***************
*** 410,475 ****
      return TRUE;
  }
  
- 
  /*
!  * Throw a new exception.  Return FAIL when out of memory or it was tried to
!  * throw an illegal user exception.  "value" is the exception string for a user
!  * or interrupt exception, or points to a message list in case of an error
!  * exception.
   */
!     static int
! throw_exception(value, type, cmdname)
      void	*value;
      int		type;
      char_u	*cmdname;
  {
!     except_T	*excp;
!     char_u	*p, *mesg, *val;
      int		cmdlen;
! 
!     /*
!      * Disallow faking Interrupt or error exceptions as user exceptions.  They
!      * would be treated differently from real interrupt or error exceptions when
!      * no active try block is found, see do_cmdline().
!      */
!     if (type == ET_USER)
!     {
! 	if (STRNCMP((char_u *)value, "Vim", 3) == 0 &&
! 		(((char_u *)value)[3] == NUL || ((char_u *)value)[3] == ':' ||
! 		 ((char_u *)value)[3] == '('))
! 	{
! 	    EMSG(_("E608: Cannot :throw exceptions with 'Vim' prefix"));
! 	    goto fail;
! 	}
!     }
! 
!     excp = (except_T *)alloc((unsigned)sizeof(except_T));
!     if (excp == NULL)
! 	goto nomem;
  
      if (type == ET_ERROR)
      {
! 	/* Store the original message and prefix the exception value with
! 	 * "Vim:" or, if a command name is given, "Vim(cmdname):". */
! 	excp->messages = (struct msglist *)value;
! 	mesg = excp->messages->throw_msg;
  	if (cmdname != NULL && *cmdname != NUL)
  	{
  	    cmdlen = (int)STRLEN(cmdname);
! 	    excp->value = vim_strnsave((char_u *)"Vim(",
  					   4 + cmdlen + 2 + (int)STRLEN(mesg));
! 	    if (excp->value == NULL)
! 		goto nomem;
! 	    STRCPY(&excp->value[4], cmdname);
! 	    STRCPY(&excp->value[4 + cmdlen], "):");
! 	    val = excp->value + 4 + cmdlen + 2;
  	}
  	else
  	{
! 	    excp->value = vim_strnsave((char_u *)"Vim:", 4 + (int)STRLEN(mesg));
! 	    if (excp->value == NULL)
! 		goto nomem;
! 	    val = excp->value + 4;
  	}
  
  	/* msg_add_fname may have been used to prefix the message with a file
--- 421,461 ----
      return TRUE;
  }
  
  /*
!  * Get an exception message that is to be stored in current_exception->value.
   */
!     char_u *
! get_exception_string(value, type, cmdname, should_free)
      void	*value;
      int		type;
      char_u	*cmdname;
+     int		*should_free;
  {
!     char_u	*ret, *mesg;
      int		cmdlen;
!     char_u	*p, *val;
  
      if (type == ET_ERROR)
      {
! 	*should_free = FALSE;
! 	mesg = ((struct msglist *)value)->throw_msg;
  	if (cmdname != NULL && *cmdname != NUL)
  	{
  	    cmdlen = (int)STRLEN(cmdname);
! 	    ret = vim_strnsave((char_u *)"Vim(",
  					   4 + cmdlen + 2 + (int)STRLEN(mesg));
! 	    if (ret == NULL)
! 		return ret;
! 	    STRCPY(&ret[4], cmdname);
! 	    STRCPY(&ret[4 + cmdlen], "):");
! 	    val = ret + 4 + cmdlen + 2;
  	}
  	else
  	{
! 	    ret = vim_strnsave((char_u *)"Vim:", 4 + (int)STRLEN(mesg));
! 	    if (ret == NULL)
! 		return ret;
! 	    val = ret + 4;
  	}
  
  	/* msg_add_fname may have been used to prefix the message with a file
***************
*** 506,519 ****
  	}
      }
      else
! 	excp->value = value;
  
      excp->type = type;
      excp->throw_name = vim_strsave(sourcing_name == NULL
  					      ? (char_u *)"" : sourcing_name);
      if (excp->throw_name == NULL)
      {
! 	if (type == ET_ERROR)
  	    vim_free(excp->value);
  	goto nomem;
      }
--- 492,556 ----
  	}
      }
      else
!     {
! 	*should_free = FALSE;
! 	ret = (char_u *) value;
!     }
! 
!     return ret;
! }
! 
! 
! /*
!  * Throw a new exception.  Return FAIL when out of memory or it was tried to
!  * throw an illegal user exception.  "value" is the exception string for a user
!  * or interrupt exception, or points to a message list in case of an error
!  * exception.
!  */
!     static int
! throw_exception(value, type, cmdname)
!     void	*value;
!     int		type;
!     char_u	*cmdname;
! {
!     except_T	*excp;
!     int		should_free;
! 
!     /*
!      * Disallow faking Interrupt or error exceptions as user exceptions.  They
!      * would be treated differently from real interrupt or error exceptions when
!      * no active try block is found, see do_cmdline().
!      */
!     if (type == ET_USER)
!     {
! 	if (STRNCMP((char_u *)value, "Vim", 3) == 0 &&
! 		(((char_u *)value)[3] == NUL || ((char_u *)value)[3] == ':' ||
! 		 ((char_u *)value)[3] == '('))
! 	{
! 	    EMSG(_("E608: Cannot :throw exceptions with 'Vim' prefix"));
! 	    goto fail;
! 	}
!     }
! 
!     excp = (except_T *)alloc((unsigned)sizeof(except_T));
!     if (excp == NULL)
! 	goto nomem;
! 
!     if (type == ET_ERROR)
! 	/* Store the original message and prefix the exception value with
! 	 * "Vim:" or, if a command name is given, "Vim(cmdname):". */
! 	excp->messages = (struct msglist *)value;
! 
!     excp->value = get_exception_string(value, type, cmdname, &should_free);
!     if (excp->value == NULL && should_free)
! 	goto nomem;
  
      excp->type = type;
      excp->throw_name = vim_strsave(sourcing_name == NULL
  					      ? (char_u *)"" : sourcing_name);
      if (excp->throw_name == NULL)
      {
! 	if (should_free)
  	    vim_free(excp->value);
  	goto nomem;
      }
***************
*** 2033,2042 ****
  	/* If an error was about to be converted to an exception when
  	 * enter_cleanup() was called, free the message list. */
  	if (msg_list != NULL)
! 	{
! 	    free_msglist(*msg_list);
! 	    *msg_list = NULL;
! 	}
      }
  
      /*
--- 2070,2076 ----
  	/* If an error was about to be converted to an exception when
  	 * enter_cleanup() was called, free the message list. */
  	if (msg_list != NULL)
! 	    free_global_msglist();
      }
  
      /*
diff -crN vim-small-patches.7adbbf32444e/src/if_py_both.h vim-small-patches.50125a7e0dea/src/if_py_both.h
*** vim-small-patches.7adbbf32444e/src/if_py_both.h	2013-11-26 22:41:25.760341503 +0400
--- vim-small-patches.50125a7e0dea/src/if_py_both.h	2013-11-26 22:41:25.772341503 +0400
***************
*** 566,571 ****
--- 566,593 ----
  	PyErr_SetNone(PyExc_KeyboardInterrupt);
  	return -1;
      }
+     else if (!(msg_list == NULL || *msg_list == NULL))
+     {
+ 	int	should_free;
+ 	char_u	*msg;
+ 
+ 	msg = get_exception_string(*msg_list, ET_ERROR, NULL, &should_free);
+ 
+ 	if (msg == NULL)
+ 	{
+ 	    PyErr_NoMemory();
+ 	    return -1;
+ 	}
+ 
+ 	PyErr_SetVim((char *) msg);
+ 
+ 	free_global_msglist();
+ 
+ 	if (should_free)
+ 	    vim_free(msg);
+ 
+ 	return -1;
+     }
      else if (!did_throw)
  	return (PyErr_Occurred() ? -1 : 0);
      /* Python exception is preferred over vim one; unlikely to occur though */
diff -crN vim-small-patches.7adbbf32444e/src/proto/ex_eval.pro vim-small-patches.50125a7e0dea/src/proto/ex_eval.pro
*** vim-small-patches.7adbbf32444e/src/proto/ex_eval.pro	2013-11-26 22:41:25.761341503 +0400
--- vim-small-patches.50125a7e0dea/src/proto/ex_eval.pro	2013-11-26 22:41:25.769341503 +0400
***************
*** 29,32 ****
--- 29,34 ----
  void rewind_conditionals __ARGS((struct condstack *cstack, int idx, int cond_type, int *cond_level));
  void ex_endfunction __ARGS((exarg_T *eap));
  int has_loop_cmd __ARGS((char_u *p));
+ char_u *get_exception_string __ARGS((void *value, int type, char_u *cmdname, int *should_free));
+ void free_global_msglist __ARGS((void));
  /* vim: set ft=c : */
diff -crN vim-small-patches.7adbbf32444e/src/testdir/test86.in vim-small-patches.50125a7e0dea/src/testdir/test86.in
*** vim-small-patches.7adbbf32444e/src/testdir/test86.in	2013-11-26 22:41:25.762341503 +0400
--- vim-small-patches.50125a7e0dea/src/testdir/test86.in	2013-11-26 22:41:25.773341503 +0400
***************
*** 179,184 ****
--- 179,210 ----
  :unlockvar! l
  :"
  :" Function calls
+ py << EOF
+ import sys
+ def ee(expr, g=globals(), l=locals()):
+     try:
+         exec(expr, g, l)
+     except:
+         ei = sys.exc_info()
+         msg = sys.exc_info()[0].__name__ + ':' + repr(sys.exc_info()[1].args)
+         msg = msg.replace('TypeError:(\'argument 1 ', 'TypeError:(\'')
+         if expr.find('None') > -1:
+             msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
+                               'TypeError:("\'NoneType\' object is not iterable",)')
+         if expr.find('FailingNumber') > -1:
+             msg = msg.replace(', not \'FailingNumber\'', '').replace('"', '\'')
+             msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
+                               'TypeError:("\'FailingNumber\' object is not iterable",)')
+         if msg.find('(\'\'') > -1 or msg.find('(\'can\'t') > -1:
+             msg = msg.replace('(\'', '("').replace('\',)', '",)')
+         if expr == 'fd(self=[])':
+             # HACK: PyMapping_Check changed meaning
+             msg = msg.replace('AttributeError:(\'keys\',)',
+                               'TypeError:(\'unable to convert list to vim dictionary\',)')
+         vim.current.buffer.append(expr + ':' + msg)
+     else:
+         vim.current.buffer.append(expr + ':NOT FAILED')
+ EOF
  :fun New(...)
  :   return ['NewStart']+a:000+['NewEnd']
  :endfun
***************
*** 193,210 ****
  :$put =string(l)
  :py l.extend([l[0].name])
  :$put =string(l)
! :try
! :   py l[1](1, 2, 3)
! :catch
! :   $put =v:exception[:16]
! :endtry
  :py f=l[0]
  :delfunction New
! :try
! :   py f(1, 2, 3)
! :catch
! :   $put =v:exception[:16]
! :endtry
  :if has('float')
  :   let l=[0.0]
  :   py l=vim.bindeval('l')
--- 219,228 ----
  :$put =string(l)
  :py l.extend([l[0].name])
  :$put =string(l)
! :py ee('l[1](1, 2, 3)')
  :py f=l[0]
  :delfunction New
! :py ee('f(1, 2, 3)')
  :if has('float')
  :   let l=[0.0]
  :   py l=vim.bindeval('l')
***************
*** 216,222 ****
  :let messages=[]
  :delfunction DictNew
  py <<EOF
- import sys
  d=vim.bindeval('{}')
  m=vim.bindeval('messages')
  def em(expr, g=globals(), l=locals()):
--- 234,239 ----
***************
*** 323,328 ****
--- 340,346 ----
  :py l[0] = t.t > 8  # check if the background thread is working
  :py del time
  :py del threading
+ :py del t
  :$put =string(l)
  :"
  :" settrace
***************
*** 882,910 ****
  :fun D()
  :endfun
  py << EOF
- def ee(expr, g=globals(), l=locals()):
-     try:
-         exec(expr, g, l)
-     except:
-         ei = sys.exc_info()
-         msg = sys.exc_info()[0].__name__ + ':' + repr(sys.exc_info()[1].args)
-         msg = msg.replace('TypeError:(\'argument 1 ', 'TypeError:(\'')
-         if expr.find('None') > -1:
-             msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
-                               'TypeError:("\'NoneType\' object is not iterable",)')
-         if expr.find('FailingNumber') > -1:
-             msg = msg.replace(', not \'FailingNumber\'', '').replace('"', '\'')
-             msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
-                               'TypeError:("\'FailingNumber\' object is not iterable",)')
-         if msg.find('(\'\'') > -1 or msg.find('(\'can\'t') > -1:
-             msg = msg.replace('(\'', '("').replace('\',)', '",)')
-         if expr == 'fd(self=[])':
-             # HACK: PyMapping_Check changed meaning
-             msg = msg.replace('AttributeError:(\'keys\',)',
-                               'TypeError:(\'unable to convert list to vim dictionary\',)')
-         cb.append(expr + ':' + msg)
-     else:
-         cb.append(expr + ':NOT FAILED')
  d = vim.Dictionary()
  ned = vim.Dictionary(foo='bar', baz='abcD')
  dl = vim.Dictionary(a=1)
--- 900,905 ----
***************
*** 1276,1281 ****
--- 1271,1277 ----
  ee('vim.eval("Exe(\'throw \'\'ghi\'\'\')")')
  ee('vim.eval("Exe(\'echoerr \'\'jkl\'\'\')")')
  ee('vim.eval("Exe(\'xxx_non_existent_command_xxx\')")')
+ ee('vim.eval("xxx_unknown_function_xxx()")')
  ee('vim.bindeval("Exe(\'xxx_non_existent_command_xxx\')")')
  del Exe
  EOF
diff -crN vim-small-patches.7adbbf32444e/src/testdir/test86.ok vim-small-patches.50125a7e0dea/src/testdir/test86.ok
*** vim-small-patches.7adbbf32444e/src/testdir/test86.ok	2013-11-26 22:41:25.764341503 +0400
--- vim-small-patches.50125a7e0dea/src/testdir/test86.ok	2013-11-26 22:41:25.776341502 +0400
***************
*** 53,60 ****
  [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
  [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
  [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']
! Vim(python):E725:
! Vim(python):E117:
  [0.0, 0.0]
  KeyError
  TypeError
--- 53,60 ----
  [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
  [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
  [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']
! l[1](1, 2, 3):error:('Vim:E725: Calling dict function without Dictionary: DictNew',)
! f(1, 2, 3):error:('Vim:E117: Unknown function: New',)
  [0.0, 0.0]
  KeyError
  TypeError
***************
*** 1197,1202 ****
--- 1197,1203 ----
  vim.eval("Exe('throw ''ghi''')"):error:('ghi',)
  vim.eval("Exe('echoerr ''jkl''')"):error:('Vim(echoerr):jkl',)
  vim.eval("Exe('xxx_non_existent_command_xxx')"):error:('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',)
+ vim.eval("xxx_unknown_function_xxx()"):error:('Vim:E117: Unknown function: xxx_unknown_function_xxx',)
  vim.bindeval("Exe('xxx_non_existent_command_xxx')"):error:('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',)
  Caught KeyboardInterrupt
  Running :put
diff -crN vim-small-patches.7adbbf32444e/src/testdir/test87.in vim-small-patches.50125a7e0dea/src/testdir/test87.in
*** vim-small-patches.7adbbf32444e/src/testdir/test87.in	2013-11-26 22:41:25.756341503 +0400
--- vim-small-patches.50125a7e0dea/src/testdir/test87.in	2013-11-26 22:41:25.767341503 +0400
***************
*** 172,177 ****
--- 172,207 ----
  :unlockvar! l
  :"
  :" Function calls
+ py3 << EOF
+ import sys
+ import re
+ 
+ py33_type_error_pattern = re.compile('^__call__\(\) takes (\d+) positional argument but (\d+) were given$')
+ 
+ def ee(expr, g=globals(), l=locals()):
+     cb = vim.current.buffer
+     try:
+         try:
+             exec(expr, g, l)
+         except Exception as e:
+             if sys.version_info >= (3, 3) and e.__class__ is AttributeError and str(e).find('has no attribute')>=0 and not str(e).startswith("'vim."):
+                 cb.append(expr + ':' + repr((e.__class__, AttributeError(str(e)[str(e).rfind(" '") + 2:-1]))))
+             elif sys.version_info >= (3, 3) and e.__class__ is ImportError and str(e).find('No module named \'') >= 0:
+                 cb.append(expr + ':' + repr((e.__class__, ImportError(str(e).replace("'", '')))))
+             elif sys.version_info >= (3, 3) and e.__class__ is TypeError:
+                 m = py33_type_error_pattern.search(str(e))
+                 if m:
+                     msg = '__call__() takes exactly {0} positional argument ({1} given)'.format(m.group(1), m.group(2))
+                     cb.append(expr + ':' + repr((e.__class__, TypeError(msg))))
+                 else:
+                     cb.append(expr + ':' + repr((e.__class__, e)))
+             else:
+                 cb.append(expr + ':' + repr((e.__class__, e)))
+         else:
+             cb.append(expr + ':NOT FAILED')
+     except Exception as e:
+         cb.append(expr + '::' + repr((e.__class__, e)))
+ EOF
  :fun New(...)
  :   return ['NewStart']+a:000+['NewEnd']
  :endfun
***************
*** 186,203 ****
  :$put =string(l)
  :py3 l+=[l[0].name]
  :$put =string(l)
! :try
! :   py3 l[1](1, 2, 3)
! :catch
! :   $put =v:exception[:13]
! :endtry
  :py3 f=l[0]
  :delfunction New
! :try
! :   py3 f(1, 2, 3)
! :catch
! :   $put =v:exception[:13]
! :endtry
  :if has('float')
  :   let l=[0.0]
  :   py3 l=vim.bindeval('l')
--- 216,225 ----
  :$put =string(l)
  :py3 l+=[l[0].name]
  :$put =string(l)
! :py3 ee('l[1](1, 2, 3)')
  :py3 f=l[0]
  :delfunction New
! :py3 ee('f(1, 2, 3)')
  :if has('float')
  :   let l=[0.0]
  :   py3 l=vim.bindeval('l')
***************
*** 315,320 ****
--- 337,343 ----
  :py3 l[0] = t.t > 8  # check if the background thread is working
  :py3 del time
  :py3 del threading
+ :py3 del t
  :$put =string(l)
  :"
  :" settrace
***************
*** 829,861 ****
  :fun D()
  :endfun
  py3 << EOF
- import re
- 
- py33_type_error_pattern = re.compile('^__call__\(\) takes (\d+) positional argument but (\d+) were given$')
- 
- def ee(expr, g=globals(), l=locals()):
-     try:
-         try:
-             exec(expr, g, l)
-         except Exception as e:
-             if sys.version_info >= (3, 3) and e.__class__ is AttributeError and str(e).find('has no attribute')>=0 and not str(e).startswith("'vim."):
-                 cb.append(expr + ':' + repr((e.__class__, AttributeError(str(e)[str(e).rfind(" '") + 2:-1]))))
-             elif sys.version_info >= (3, 3) and e.__class__ is ImportError and str(e).find('No module named \'') >= 0:
-                 cb.append(expr + ':' + repr((e.__class__, ImportError(str(e).replace("'", '')))))
-             elif sys.version_info >= (3, 3) and e.__class__ is TypeError:
-                 m = py33_type_error_pattern.search(str(e))
-                 if m:
-                     msg = '__call__() takes exactly {0} positional argument ({1} given)'.format(m.group(1), m.group(2))
-                     cb.append(expr + ':' + repr((e.__class__, TypeError(msg))))
-                 else:
-                     cb.append(expr + ':' + repr((e.__class__, e)))
-             else:
-                 cb.append(expr + ':' + repr((e.__class__, e)))
-         else:
-             cb.append(expr + ':NOT FAILED')
-     except Exception as e:
-         cb.append(expr + '::' + repr((e.__class__, e)))
- 
  d = vim.Dictionary()
  ned = vim.Dictionary(foo='bar', baz='abcD')
  dl = vim.Dictionary(a=1)
--- 852,857 ----
***************
*** 1227,1232 ****
--- 1223,1229 ----
  ee('vim.eval("Exe(\'throw \'\'ghi\'\'\')")')
  ee('vim.eval("Exe(\'echoerr \'\'jkl\'\'\')")')
  ee('vim.eval("Exe(\'xxx_non_existent_command_xxx\')")')
+ ee('vim.eval("xxx_unknown_function_xxx()")')
  ee('vim.bindeval("Exe(\'xxx_non_existent_command_xxx\')")')
  del Exe
  EOF
diff -crN vim-small-patches.7adbbf32444e/src/testdir/test87.ok vim-small-patches.50125a7e0dea/src/testdir/test87.ok
*** vim-small-patches.7adbbf32444e/src/testdir/test87.ok	2013-11-26 22:41:25.758341503 +0400
--- vim-small-patches.50125a7e0dea/src/testdir/test87.ok	2013-11-26 22:41:25.769341503 +0400
***************
*** 53,60 ****
  [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
  [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
  [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']
! Vim(py3):E725:
! Vim(py3):E117:
  [0.0, 0.0]
  KeyError
  TypeError
--- 53,60 ----
  [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
  [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
  [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']
! l[1](1, 2, 3):(<class 'vim.error'>, error('Vim:E725: Calling dict function without Dictionary: DictNew',))
! f(1, 2, 3):(<class 'vim.error'>, error('Vim:E117: Unknown function: New',))
  [0.0, 0.0]
  KeyError
  TypeError
***************
*** 1186,1191 ****
--- 1186,1192 ----
  vim.eval("Exe('throw ''ghi''')"):(<class 'vim.error'>, error('ghi',))
  vim.eval("Exe('echoerr ''jkl''')"):(<class 'vim.error'>, error('Vim(echoerr):jkl',))
  vim.eval("Exe('xxx_non_existent_command_xxx')"):(<class 'vim.error'>, error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',))
+ vim.eval("xxx_unknown_function_xxx()"):(<class 'vim.error'>, error('Vim:E117: Unknown function: xxx_unknown_function_xxx',))
  vim.bindeval("Exe('xxx_non_existent_command_xxx')"):(<class 'vim.error'>, error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',))
  Caught KeyboardInterrupt
  Running :put

Raspunde prin e-mail lui