Created
February 6, 2012 10:01
-
-
Save gerdr/1751167 to your computer and use it in GitHub Desktop.
Parrot object model refactor proposal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef PARROT_H_ | |
#define PARROT_H_ | |
#include <stddef.h> | |
// short names so we don't have to type Parrot_ everywhere | |
#define PInt Parrot_Int | |
#define PNum Parrot_Num | |
// ... | |
// dynamic type id | |
enum parrot_value_type_ | |
{ | |
PARROT_FAIL_VALUE, | |
PARROT_VOID_VALUE, | |
PARROT_INT_VALUE, | |
PARROT_NUM_VALUE, | |
PARROT_STRING_VALUE, | |
PARROT_OBJECT_VALUE, | |
PARROT_POINTER_VALUE | |
}; | |
typedef enum parrot_value_type_ PValueType; | |
// message ids for new dispatch system | |
enum parrot_message_id_ | |
{ | |
PARROT_NO_MSG, | |
PARROT_GET_BY_INT_MSG, | |
PARROT_SET_BY_INT_MSG, | |
PARROT_GET_BY_STRING_MSG, | |
PARROT_SET_BY_STRING_MSG, | |
// ... | |
}; | |
typedef enum parrot_message_id_ PMsgId; | |
// configured types | |
typedef long long PInt; | |
typedef double PNum; | |
// a dynamically typed value | |
// used for generic data structures | |
typedef union parrot_value_ PValue; | |
// a 6model object | |
typedef struct parrot_object_ PObject; | |
// internal 6model objects with known structure | |
typedef struct parrot_interp_ PInterp; | |
typedef struct parrot_string_ PString; | |
typedef struct parrot_stable_ PSTable; | |
typedef struct parrot_array_ PArray; | |
typedef struct parrot_hash_ PHash; | |
typedef struct parrot_pointer_hash_ PPointerHash; | |
// ... | |
// the 6model representation | |
typedef struct parrot_repr_ PRepr; | |
union parrot_value_ | |
{ | |
PValueType type; | |
struct { PValueType type; PInt value; } as_int; | |
struct { PValueType type; PNum value; } as_num; | |
struct { PValueType type; PString *value; } as_string; | |
struct { PValueType type; PObject *value; } as_object; | |
struct { PValueType type; void *value; } as_pointer; | |
}; | |
// every object has this structure as first member | |
struct parrot_object_ | |
{ | |
PSTable *stable; | |
// ... | |
// things like the serialization context and flags need to go here | |
}; | |
// parrot-level objects implemented in C use the message system instead of the | |
// current monolithic vtable | |
// each message has a unique id, which is part of its stable | |
typedef struct parrot_get_by_int_msg_ PGetByIntMsg; | |
typedef struct parrot_set_by_int_msg_ PSetByIntMsg; | |
struct parrot_set_by_int_msg_ | |
{ | |
PObject header; | |
PInt key; | |
PValue value; | |
}; | |
struct parrot_get_by_int_msg_ | |
{ | |
PObject header; | |
PInt key; | |
}; | |
// example usage of message-passing from C: | |
/* PInterp *interp = ...; | |
PObject *obj = ...; | |
// messages can be placed on stack | |
// the initializer takes care of using a correct repr and sets the msg_id | |
PSetByIntMsg msg = PARROT_INIT_SET_BY_INT_MSG_ON_STACK; | |
msg.key = 3; | |
msg.value.type = PARROT_INT_VALUE; | |
msg.value.as_int.value = 42; | |
PValue rv = obj->stable.handle_msg(iterp, obj, &msg.header); | |
switch(rv.type) | |
{ | |
case PARROT_FAIL_VALUE: | |
... | |
} | |
// the message handler dispatches by message id | |
switch(args->stable.msg_id) | |
{ | |
case PARROT_SET_BY_INT_MSG: | |
... | |
} | |
*/ | |
struct parrot_interp_ | |
{ | |
PObject header; | |
PPointerHash *repr_registry; | |
// ... | |
}; | |
struct parrot_repr_ | |
{ | |
// a repr needs no numeric id, so we got rid of it | |
PString *name; | |
// the various repr functions, including gc-specifics... | |
PObject *(*allocate)(PInterp *interp, PSTable *st); | |
void (*initialize)(PInterp *interp, PSTable *st, void *data); | |
// ... | |
// the SixModel_REPROps_* tables get flattened into this as well: | |
// the additional indirection is unnecessary | |
}; | |
struct parrot_stable_ | |
{ | |
PObject header; | |
PRepr *repr; | |
void *repr_data; | |
// only != 0 if object is a message | |
PMsgId msg_id; | |
// the default handler delegates to the meta-object, ie uses find_method | |
// to look up a handler method by message name | |
PValue (*handle_msg)(PInterp *interp, PObject *obj, PObject *msg); | |
PObject *meta_object; | |
PObject *type_object; | |
PObject *method_cache; | |
PObject **static_method_cache; | |
size_t static_method_cache_size; | |
PObject **type_check_cache; | |
size_t type_check_cache_size; | |
// ... | |
}; | |
// meta-object methods need not be virtual | |
extern PObject *Parrot_find_method( | |
PInterp *interp, PObject *obj, PString *name, PInt hint); | |
extern PInt Parrot_type_check(PInterp *interp, PObject *obj, PObject *checkee); | |
// hide short names in foreign source files | |
#ifndef PARROT_SOURCE | |
#undef PInt | |
#undef PNum | |
//... | |
#endif | |
#endif |
also, wrapper-functions like
PValue Parrot_send_set_by_int_msg(
PInterp *interp, PObject *obj, PInt key, PValue value);
can make the C interface less bothersome...
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
the current factoring means that each message needs its own repr, which will probably get quite tedious - some code-generation might come in handy here...