Error Handling
==============

.. _sec-pcall-errorfunc:

pcall errorfunc
---------------

As mentioned in the `Lua documentation`_, it is possible to pass an
error handler function to ``lua_pcall()``. Luabind makes use of
``lua_pcall()`` internally when calling member functions and free functions.
It is possible to set the error handler function that Luabind will use
globally::

    typedef int(*pcall_callback_fun)(lua_State*);
    void set_pcall_callback(pcall_callback_fun fn);

This is primarily useful for adding more information to the error message
returned by a failed protected call. For more information on how to use the
pcall_callback function, see ``errfunc`` under the
`pcall section of the lua manual`_.

For more information on how to retrieve debugging information from lua, see
`the debug section of the lua manual`_.

The message returned by the ``pcall_callback`` is accessable as the top lua
value on the stack. For example, if you would like to access it as a luabind
object, you could do like this::

    catch(error& e)
    {
        object error_msg(from_stack(e.state(), -1));
        std::cout << error_msg << std::endl;
    }

.. _Lua documentation: http://www.lua.org/manual/5.0/manual.html
.. _`pcall section of the lua manual`: http://www.lua.org/manual/5.0/manual.html#3.15
.. _`the debug section of the lua manual`: http://www.lua.org/manual/5.0/manual.html#4

file and line numbers
---------------------

If you want to add file name and line number to the error messages generated
by luabind you can define your own `pcall errorfunc`_. You may want to modify
this callback to better suit your needs, but the basic functionality could be
implemented like this::

   int add_file_and_line(lua_State* L)
   {
      lua_Debug d;
      lua_getstack(L, 1, &d);
      lua_getinfo(L, "Sln", &d);
      std::string err = lua_tostring(L, -1);
      lua_pop(L, 1);
      std::stringstream msg;
      msg << d.short_src << ":" << d.currentline;

      if (d.name != 0)
      {
         msg << "(" << d.namewhat << " " << d.name << ")";
      }
      msg << " " << err;
      lua_pushstring(L, msg.str().c_str());
      return 1;
   }

For more information about what kind of information you can add to the error
message, see `the debug section of the lua manual`_.

Note that the callback set by ``set_pcall_callback()`` will only be used when
luabind executes lua code. Anytime when you call ``lua_pcall`` yourself, you
have to supply your function if you want error messages translated.

.. _sec-lua-panic:

lua panic
---------

When lua encounters a fatal error caused by a bug from the C/C++ side, it will
call its internal panic function. This can happen, for example,  when you call
``lua_gettable`` on a value that isn't a table. If you do the same thing from
within lua, it will of course just fail with an error message.

The default panic function will ``exit()`` the application. If you want to
handle this case without terminating your application, you can define your own
panic function using ``lua_atpanic``. The best way to continue from the panic
function is to make sure lua is compiled as C++ and throw an exception from
the panic function. Throwing an exception instead of using ``setjmp`` and
``longjmp`` will make sure the stack is correctly unwound.

When the panic function is called, the lua state is invalid, and the only
allowed operation on it is to close it.

For more information, see the `lua manual section 3.19`_.

.. _`lua manual section 3.19`: http://www.lua.org/manual/5.0/manual.html#3.19

structured exceptions (MSVC)
----------------------------

Since lua is generally built as a C library, any callbacks called from lua
cannot under any circumstance throw an exception. Because of that, luabind has
to catch all exceptions and translate them into proper lua errors (by calling
``lua_error()``). This means we have a ``catch(...) {}`` in there.

In Visual Studio, ``catch (...)`` will not only catch C++ exceptions, it will
also catch structured exceptions, such as segmentation fault. This means that if
your function, that gets called from luabind, makes an invalid memory
adressing, you won't notice it. All that will happen is that lua will return
an error message saying "unknown exception".

To remedy this, you can create your own *exception translator*::

   void straight_to_debugger(unsigned int, _EXCEPTION_POINTERS*)
   { throw; }

   #ifdef _MSC_VER
      ::_set_se_translator(straight_to_debugger);
   #endif

This will make structured exceptions, like segmentation fault, to actually get
caught by the debugger.


Error messages
--------------

These are the error messages that can be generated by luabind, with a more
in-depth explanation.

- .. parsed-literal::

    the attribute '*class-name.attribute-name*' is read only

  There is no data member named *attribute-name* in the class *class-name*,
  or there's no setter-function registered on that property name. See the
  :ref:`sec-properties` section.

- .. parsed-literal::

    the attribute '*class-name.attribute-name*' is of type: (*class-name*) and does not match (*class_name*)

  This error is generated if you try to assign an attribute with a value
  of a type that cannot be converted to the attributes type.


- .. parsed-literal::

    *class-name()* threw an exception, *class-name:function-name()* threw an exception

  The class' constructor or member function threw an unknown exception.
  Known exceptions are const char*, std::exception. See the
  :ref:`part-exceptions` section.

- .. parsed-literal::

    no overload of '*class-name:function-name*' matched the arguments (*parameter-types*)
    no match for function call '*function-name*' with the parameters (*parameter-types*)
    no constructor of *class-name* matched the arguments (*parameter-types*)
    no operator *operator-name* matched the arguments (*parameter-types*)

  No function/operator with the given name takes the parameters you gave
  it. You have either misspelled the function name, or given it incorrect
  parameters. This error is followed by a list of possible candidate
  functions to help you figure out what parameter has the wrong type. If
  the candidate list is empty there's no function at all with that name.
  See the signature matching section.

- .. parsed-literal::

    call of overloaded '*class-name:function-name*(*parameter-types*)' is ambiguous
    ambiguous match for function call '*function-name*' with the parameters (*parameter-types*)
    call of overloaded constructor '*class-name*(*parameter-types*)' is ambiguous
    call of overloaded operator *operator-name* (*parameter-types*) is ambiguous

  This means that the function/operator you are trying to call has at least
  one other overload that matches the arguments just as good as the first
  overload.

- .. parsed-literal::

    cannot derive from C++ class '*class-name*'. It does not have a wrapped type.
