blob: d825fcf9fb91be10ce4492b7db2c5e70739244e7 [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 Clownfish;
__C__
typedef void
(*CFISH_Err_Attempt_t)(void *context);
#ifdef CFISH_USE_SHORT_NAMES
#define Err_Attempt_t CFISH_Err_Attempt_t
#endif
__END_C__
/**
* Exception.
*
* Clownfish::Err is the base class for exceptions in the Clownfish object
* hierarchy.
*
* 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.
*/
public class Clownfish::Err inherits Clownfish::Obj {
String *mess;
inert void
init_class();
inert incremented Err*
new(decremented String *mess);
inert Err*
init(Err *self, decremented String *mess);
/** Return a copy of the error message.
*/
public incremented String*
To_String(Err *self);
/** Concatenate the supplied argument onto the error message.
*/
public void
Cat_Mess(Err *self, String *mess);
/** Return the error message.
*/
public String*
Get_Mess(Err *self);
/** Add information about the current stack frame onto the error message.
*/
void
Add_Frame(Err *self, const char *file, int line, const char *func);
public void
Destroy(Err *self);
/** Set the global error object, a per-thread Err shared variable.
*/
public inert void
set_error(decremented Err *error);
/** Retrieve the global error object, a per-thread Err shared variable.
*/
public inert nullable Err*
get_error();
/** Run `routine` within the host's exception handling
* environment, catching and returning any errors that occur.
*
* If an unrecognized host exception is trapped, it will be wrapped in an
* Err so that it can be handled by Clownfish code.
*
* @return an Err, or NULL if no exception occurs.
*/
public inert incremented nullable Err*
trap(CFISH_Err_Attempt_t routine, void *context);
/** 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(Class *klass, 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 klass The Err class to throw.
* @param message Error message, to be output verbatim.
*/
inert void
throw_mess(Class *klass, decremented String *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 String *message);
/** Create a formatted error message. Ususally invoked via the MAKE_MESS
* macro.
*/
inert String*
make_mess(const char *file, int line, const char *func,
const char *pattern, ...);
/** Verify that `obj` is either NULL or inherits from
* `klass`.
*
* @return the object.
*/
inert nullable Obj*
downcast(Obj *obj, Class *klass, const char *file, int line,
const char *func);
/** Verify that `obj` is not NULL and inherits from
* `klass`.
*
* @return the object.
*/
inert Obj*
certify(Obj *obj, Class *klass, 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, Class *klass);
/** Throw an error after abstract method `method_name` was called on
* object `obj` of class `klass`.
*/
inert void
abstract_method_call(Obj *obj, Class *klass, const char *method_name);
/** Throw an error after an invalid callback was called.
*/
inert void
invalid_callback(const char *method_name);
/** 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 CFISH_HAS_FUNC_MACRO
#define CFISH_ERR_FUNC_MACRO CFISH_FUNC_MACRO
#else
#define CFISH_ERR_FUNC_MACRO NULL
#endif
#define CFISH_ERR_ADD_FRAME(_error) \
CFISH_Err_Add_Frame(_error, __FILE__, __LINE__, \
CFISH_ERR_FUNC_MACRO)
#define CFISH_RETHROW(_error) \
cfish_Err_rethrow((cfish_Err*)_error, __FILE__, __LINE__, \
CFISH_ERR_FUNC_MACRO)
/** Macro version of cfish_Err_throw_at which inserts contextual information
* automatically, provided that the compiler supports the necessary features.
*/
#ifdef CFISH_HAS_VARIADIC_MACROS
#ifdef CFISH_HAS_ISO_VARIADIC_MACROS
#define CFISH_THROW(_class, ...) \
cfish_Err_throw_at(_class, __FILE__, __LINE__, CFISH_ERR_FUNC_MACRO, \
__VA_ARGS__)
#define CFISH_WARN(...) \
cfish_Err_warn_at(__FILE__, __LINE__, CFISH_ERR_FUNC_MACRO, __VA_ARGS__)
#define CFISH_MAKE_MESS(...) \
cfish_Err_make_mess(__FILE__, __LINE__, CFISH_ERR_FUNC_MACRO, \
__VA_ARGS__)
#elif defined(CFISH_HAS_GNUC_VARIADIC_MACROS)
#define CFISH_THROW(_class, args...) \
cfish_Err_throw_at(_class, __FILE__, __LINE__, \
CFISH_ERR_FUNC_MACRO, ##args)
#define CFISH_WARN(args...) \
cfish_Err_warn_at(__FILE__, __LINE__, CFISH_ERR_FUNC_MACRO, ##args)
#define CFISH_MAKE_MESS(args...) \
cfish_Err_make_mess(__FILE__, __LINE__, CFISH_ERR_FUNC_MACRO, ##args)
#endif
#else
void
CFISH_THROW(cfish_Class *klass, char* format, ...);
void
CFISH_WARN(char* format, ...);
cfish_String*
CFISH_MAKE_MESS(char* format, ...);
#endif
#define CFISH_DOWNCAST(_obj, _class) \
cfish_Err_downcast((cfish_Obj*)(_obj), (_class), \
__FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)
#define CFISH_CERTIFY(_obj, _class) \
cfish_Err_certify((cfish_Obj*)(_obj), (_class), \
__FILE__, __LINE__, CFISH_ERR_FUNC_MACRO)
static CFISH_INLINE void
cfish_Err_abstract_class_check(cfish_Obj *obj, cfish_Class *klass) {
cfish_Class *const my_class = (cfish_Class*)((cfish_Dummy*)obj)->klass;
if (my_class == klass) {
cfish_String *mess = CFISH_MAKE_MESS("%o is an abstract class",
cfish_Obj_get_class_name(obj));
CFISH_DECREF_NN(obj);
cfish_Err_throw_mess(CFISH_ERR, mess);
}
}
#define CFISH_ABSTRACT_CLASS_CHECK(_obj, _class) \
cfish_Err_abstract_class_check(((cfish_Obj*)_obj), _class)
#ifdef CFISH_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__