Source

arana-main / arana / object.h

/*
 * object.h
 *
 * (c) Copyright 2009 by Armin Ronacher.
 */

#ifndef _ARANA_OBJECT_H
#define _ARANA_OBJECT_H

#include "maps.h"

struct _ArObjectType;

/* raising errors.  This is here instead of the error.h module where it would
   belong because of bootstrapping problems. */
#define AR_RAISE(err) do {                                              \
        AI->error = err;                                                \
        arana_traceback_push(AR_ISIG, __FILE__, __LINE__, __func__);    \
        arana_error_jump(AR_ISIG);                                      \
    } while(0)
#define AR_RAISE_OOM() arana_out_of_memory(AR_ISIG)
#define AR_CALL(x, a) arana_call(AR_ISIG, x, a)
#define AR_CALL_METHODA(o, m, a) arana_call_method(AR_ISIG, o, m, a)
#define AR_CALL_METHOD(o, m, ...) AR_CALL_METHODA(o, m, AR_TUPLE_PACK(__VA_ARGS__))

/* common headers */
#define AR_OBJECT_HEAD struct _ArObjectType *_type
#define AR_HEAVY_OBJECT_HEAD AR_OBJECT_HEAD; struct _ArStringMap *_map
#define AR_OBJECT_INIT(x, t) (((ArObject *)(x))->_type = &t)
#define AR_HEAVY_OBJECT_INIT(x, t) ({                                   \
            ArHeavyObject *_ho = (ArHeavyObject *)(x);                  \
            _ho->_type = &t;                                            \
            _ho->_map = (ArStringMap *)arana_stringmap_new(AR_ISIG);    \
        })
#define _AR_ALLOCATE_OBJECT(x, t, c) ({         \
            ArObject *_o = AR_ALLOCT(x);        \
            if (c && !_o)                       \
                AR_RAISE_OOM();                 \
            AR_OBJECT_INIT(_o, t);              \
            (AR)_o;                             \
        })
#define AR_ALLOCATE_OBJECT(x, t) _AR_ALLOCATE_OBJECT(x, t, 1)
#define AR_ALLOCATE_OBJECT_UNSAFE(x, t) _AR_ALLOCATE_OBJECT(x, t, 0)
#define AR_ALLOCATE_HEAVY_OBJECT(x, t) ({       \
            ArObject *_o = AR_ALLOCT(x);        \
            if (!_o)                            \
                AR_RAISE_OOM();                 \
            AR_HEAVY_OBJECT_INIT(_o, t);        \
            (AR)_o;                             \
        })

/* type flags */
#define AR_TYPE_SIMPLE 0                /* default type */
#define AR_TYPE_FAKE 1                  /* objects that are no real objects */
#define AR_TYPE_HAS_MAP 2               /* do instances have a map? */

/* forward decl */
static inline struct _ArObjectType * _arana_get_object_type(AR self);

/* helpers */
#define AR_IS_INTEGER(x) (((unsigned long)x) & 1)
#define AR_IS_OBJECT(x) (!AR_IS_INTEGER(x))
#define AR_TYPE(x) _arana_get_object_type((AR)(x)) /* defined in arana.h */
#define AR_IS_INSTANCE(x, t) arana_is_instance(x, &t)
#define AR_IS_TYPE(x) (AR_TYPE(x) == &ArTypeType)
#define AR_PARENT_TYPE(x) arana_get_parent_type(AR_ISIG, (AR)(x))
#define AR_TYPE_NAME(x) _arana_get_object_type_name((AR)(x)) /* defined in arana.h */
#define AR_GET_TYPE_OBJECT(o) arana_get_type_object(AR_ISIG, o)
#define AR_CREATE_TYPE(x) arana_type_new(AR_ISIG, &x)
#define AR_HAS_MAP(x)                                           \
    (AR_IS_OBJECT(x) && (AR_TYPE(x)->flags & AR_TYPE_HAS_MAP))
#define AR_OBJECT_MAP(x)                                                \
    (AR)(AR_HAS_MAP(x) ? ((struct _ArHeavyObject *)(x))->_map : AR_NULL)

#define AR_TO_STRING(x) AR_CALL_METHOD(x, "to_string", 0)
#define AR_REPR(x) AR_CALL_METHOD(x, "to_repr", 0)
#define AR_PRINT(x) AR_CALL_METHOD(x, "print", 0)

#define AR_GET_ITERATOR(x) AR_CALL_METHOD(x, "get_iterator", 0)
#define AR_NEXT(x) AR_CALL_METHOD(x, "next", 0)
#define AR_EACH(x, f, c) arana_each(AR_ISIG, x, f, c)

#define AR_IS_FUNCTION(x) (AR_TYPE(x) == &ArFunctionType)
#define AR_FUNCTION(x, n) arana_function_new(AR_ISIG, (ArFunc)(x), n)
#define AR_IS_METHOD(x) (AR_TYPE(x) == &ArMethodType)

/* basic for all objects.  Links to the object type struct */
typedef struct _ArObject {
    AR_OBJECT_HEAD;
} ArObject;

/* ArObjects with a map.  For object types with AR_TYPE_HAS_MAP set */
typedef struct _ArHeavyObject {
    AR_HEAVY_OBJECT_HEAD;
} ArHeavyObject;

/* object types */
typedef AR (*ArAllocationFunc)(AR_SIG);
typedef void (*ArFreeFunc)(AR_SIG, AR self);
typedef AR (*ArFunc)(AR_SIG, AR self, AR args);
typedef void (*ArIterationFunc)(AR_SIG, AR value, void *closure);

typedef struct _ArObjectType {
    const char *name;
    ArAllocationFunc allocate;
    ArFreeFunc free;
    struct _ArObjectType *parent;
    int flags;
} ArObjectType;

typedef struct _ArType {
    AR_HEAVY_OBJECT_HEAD;
    struct _ArObjectType *reflected_type;
} ArType;

typedef struct _ArFunction {
    AR_OBJECT_HEAD;
    const char *name;
    ArFunc func;
} ArFunction;

typedef struct _ArMethod {
    AR_OBJECT_HEAD;
    AR self;
    AR function;
} ArMethod;

/* functions */
AR_API_FUNC(int) arana_is_instance(AR object, ArObjectType *type);
AR_API_FUNC(AR) arana_create_type_type(AR_SIG);
AR_API_FUNC(AR) arana_create_function_type(AR_SIG);
AR_API_FUNC(AR) arana_create_method_type(AR_SIG);
AR_API_FUNC(AR) arana_type_new(AR_SIG, ArObjectType *type);
AR_API_FUNC(AR) arana_function_new(AR_SIG, ArFunc func, const char *name);
AR_API_FUNC(AR) arana_method_new(AR_SIG, AR function, AR self);
AR_API_FUNC(AR) arana_call(AR_SIG, AR object, AR args);
AR_API_FUNC(AR) arana_call_method(AR_SIG, AR object, const char *message, AR args);
AR_API_FUNC(AR) arana_get_type_object(AR_SIG, AR object);
AR_API_FUNC(AR) arana_get_parent_type(AR_SIG, AR type);
AR_API_FUNC(AR) arana_get_member(AR_SIG, AR object, AR member);
AR_API_FUNC(int) arana_lookup_member(AR_SIG, AR object, const char *member,
                                     AR *value_out, int *from_type_out,
                                     int try_getter);
AR_API_FUNC(void) arana_each(AR_SIG, AR object, ArIterationFunc func,
                             void *closure);
AR_API_FUNC(AR) arana_generic_get_self_iterator(AR_SIG, AR self, AR args);

AR_API_FUNC(void) _arana_dump(AR_SIG, AR obj);

AR_API_DATA(ArObjectType) ArFunctionType;
AR_API_DATA(ArObjectType) ArMethodType;
AR_API_DATA(ArObjectType) ArTypeType;

#endif /* _ARANA_OBJECT_H */