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