blob: c8c16f5bd682d54f28938c4097f7fc912b9ef596 [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
parcel Lucy;
/**
* Exception.
*
* Most of the time when Lucy encounters an error, it tries to raise a
* Lucy::Object::Err exception with an error message and context
* information.
*
* At present, it is only safe to catch exceptions which are specifically
* documented as catchable; most times when an Err is raised, Lucy leaks
* memory.
*
* The Err module also provides access to a per-thread Err shared variable via
* set_error() and get_error(). It may be used to store an Err object
* temporarily, so that calling code may choose how to handle a particular
* error condition.
*/
class Lucy::Object::Err inherits Lucy::Object::Obj {
CharBuf *mess;
inert incremented Err*
new(decremented CharBuf *mess);
inert Err*
init(Err *self, decremented CharBuf *mess);
public void
Destroy(Err *self);
public incremented CharBuf*
To_String(Err *self);
void*
To_Host(Err *self);
/** Concatenate the supplied argument onto the internal "mess".
*/
public void
Cat_Mess(Err *self, const CharBuf *mess);
public CharBuf*
Get_Mess(Err *self);
/** Add information about the current stack frame onto <code>mess</code>.
*/
void
Add_Frame(Err *self, const char *file, int line, const char *func);
public incremented Err*
Make(Err *self);
/** Set the value of "error", a per-thread Err shared variable.
*/
public inert void
set_error(decremented Err *error);
/** Retrieve per-thread Err shared variable "error".
*/
public inert nullable Err*
get_error();
/** Print an error message to stderr with some C contextual information.
* Usually invoked via the WARN(pattern, ...) macro.
*/
inert void
warn_at(const char *file, int line, const char *func,
const char *pattern, ...);
/** Raise an exception. Usually invoked via the THROW macro.
*/
inert void
throw_at(VTable *vtable, const char *file, int line, const char *func,
const char *pattern, ...);
/** Throw an existing exception after tacking on additional context data.
*/
inert void
rethrow(Err *error, const char *file, int line, const char *func);
/** Raise an exception. Clean up the supplied message by decrementing its
* refcount.
*
* @param vtable The vtable for the Err class to throw.
* @param message Error message, to be output verbatim.
*/
inert void
throw_mess(VTable *vtable, decremented CharBuf *message);
/** Invoke host exception handling.
*/
inert void
do_throw(decremented Err *self);
/** Invoke host warning mechanism. Clean up the supplied message by
* decrementing its refcount.
*
* @param message Error message, to be output verbatim.
*/
inert void
warn_mess(decremented CharBuf *message);
/** Create a formatted error message. Ususally invoked via the MAKE_MESS
* macro.
*/
inert CharBuf*
make_mess(const char *file, int line, const char *func,
const char *pattern, ...);
/** Verify that <code>obj</code> is either NULL or inherits from
* the class represented by <code>vtable</code>.
*
* @return the object.
*/
inert nullable Obj*
downcast(Obj *obj, VTable *vtable, const char *file, int line,
const char *func);
/** Verify that <code>obj</code> is not NULL and inherits from the class
* represented by <code>vtable</code>.
*
* @return the object.
*/
inert Obj*
certify(Obj *obj, VTable *vtable, const char *file, int line,
const char *func);
/** Verify that an object belongs to a subclass and not an abstract class.
*/
inert inline void
abstract_class_check(Obj *obj, VTable *vtable);
/** On Windows, return a newly allocated buffer containing the string
* description for the the last error in the thread.
*/
inert char*
win_error();
}
__C__
#ifdef CHY_HAS_FUNC_MACRO
#define CFISH_ERR_FUNC_MACRO CHY_FUNC_MACRO
#else
#define CFISH_ERR_FUNC_MACRO NULL
#endif
#define CFISH_ERR_ADD_FRAME(_error) \
Lucy_Err_Add_Frame(_error, __FILE__, __LINE__, \
CFISH_ERR_FUNC_MACRO)
#define CFISH_RETHROW(_error) \
lucy_Err_rethrow((lucy_Err*)_error, __FILE__, __LINE__, \
CFISH_ERR_FUNC_MACRO)
/** Macro version of lucy_Err_throw_at which inserts contextual information
* automatically, provided that the compiler supports the necessary features.
*/
#ifdef CHY_HAS_VARIADIC_MACROS
#ifdef CHY_HAS_ISO_VARIADIC_MACROS
#define CFISH_THROW(_vtable, ...) \
lucy_Err_throw_at(_vtable, __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO, \
__VA_ARGS__)
#define CFISH_WARN(...) \
lucy_Err_warn_at(__FILE__, __LINE__, CFISH_ERR_FUNC_MACRO, __VA_ARGS__)
#define CFISH_MAKE_MESS(...) \
lucy_Err_make_mess(__FILE__, __LINE__, CFISH_ERR_FUNC_MACRO, \
__VA_ARGS__)
#elif defined(CHY_HAS_GNUC_VARIADIC_MACROS)
#define CFISH_THROW(_vtable, args...) \
lucy_Err_throw_at(_vtable, __FILE__, __LINE__, \
CFISH_ERR_FUNC_MACRO, ##args)
#define CFISH_WARN(args...) \
lucy_Err_warn_at(__FILE__, __LINE__, CFISH_ERR_FUNC_MACRO, ##args)
#define CFISH_MAKE_MESS(args...) \
lucy_Err_make_mess(__FILE__, __LINE__, CFISH_ERR_FUNC_MACRO, ##args)
#endif
#else
void
CFISH_THROW(lucy_VTable *vtable, char* format, ...);
void
CFISH_WARN(char* format, ...);
lucy_CharBuf*
CFISH_MAKE_MESS(char* format, ...);
#endif
#define CFISH_DOWNCAST(_obj, _vtable) \
lucy_Err_downcast((lucy_Obj*)(_obj), (_vtable), \
__FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)
#define CFISH_CERTIFY(_obj, _vtable) \
lucy_Err_certify((lucy_Obj*)(_obj), (_vtable), \
__FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)
static CHY_INLINE void
lucy_Err_abstract_class_check(lucy_Obj *obj, lucy_VTable *vtable) {
lucy_VTable *const my_vtable = *(lucy_VTable**)obj;
if (my_vtable == vtable) {
lucy_CharBuf *mess = CFISH_MAKE_MESS("%o is an abstract class",
Lucy_Obj_Get_Class_Name(obj));
Lucy_Obj_Dec_RefCount(obj);
lucy_Err_throw_mess(LUCY_ERR, mess);
}
}
#define CFISH_ABSTRACT_CLASS_CHECK(_obj, _vtable) \
lucy_Err_abstract_class_check(((lucy_Obj*)_obj), _vtable)
#ifdef LUCY_USE_SHORT_NAMES
#define THROW CFISH_THROW
#define RETHROW CFISH_RETHROW
#define WARN CFISH_WARN
#define MAKE_MESS CFISH_MAKE_MESS
#define ERR_ADD_FRAME CFISH_ERR_ADD_FRAME
#define ERR_FUNC_MACRO CFISH_ERR_FUNC_MACRO
#define DOWNCAST CFISH_DOWNCAST
#define CERTIFY CFISH_CERTIFY
#define ABSTRACT_CLASS_CHECK CFISH_ABSTRACT_CLASS_CHECK
#endif
__END_C__