Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Branch: pmc_pct
Fetching contributors…

Cannot retrieve contributors at this time

561 lines (386 sloc) 15.051 kB
/*
Copyright (C) 2001-2008, Parrot Foundation.
$Id$
=head1 NAME
src/pmc/pmcproxy.pmc - proxy class object for a PMC enabling introspection
=head1 DESCRIPTION
This class is used to describe a PMC. It can sit in an inheritance hierarchy
of a PDD15 class as well as allowing introspection of the PMC.
PMCProxy is not derived from any other PMC.
=head2 Structure
This class stores its state in the Parrot_Class structure, using the
following fields.
=over 4
=item C<id>
The type number of the PMC that is being described.
=item C<name>
The name of the PMC -- a STRING.
=item C<namespace>
The namespace the PMC is associated with, if any.
=item C<parents>
An array of immediate parent classes.
An empty ResizablePMCArray PMC is allocated during initialization.
=item C<all_parents>
A cached array of ourself and all parent classes, in MRO order.
A ResizablePMCArray PMC is allocated during initialization,
and is populated with the current class.
=back
NOTE: No doubt we will need other things later; this is a start.
=cut
*/
#include "parrot/oo_private.h"
/*
=head2 Functions
=over 4
=cut
*/
pmclass PMCProxy extends Class need_ext {
/*
=item C<void init()>
Initializes a PMCProxy PMC.
=cut
*/
VTABLE void init() {
Parrot_Class_attributes * const _pmc = mem_allocate_zeroed_typed(Parrot_Class_attributes);
PMC * const new_attribute = pmc_new(interp, enum_class_Hash);
STRING * const name = CONST_STRING(interp, "proxy");
PMC_data(SELF) = _pmc;
/* Set flags for custom GC mark and destroy. */
PObj_custom_mark_SET(SELF);
PObj_active_destroy_SET(SELF);
/* Set up the object. */
_pmc->id = 0;
_pmc->name = CONST_STRING(interp, "");
_pmc->_namespace = PMCNULL;
_pmc->parents = pmc_new(interp, enum_class_ResizablePMCArray);
_pmc->all_parents = pmc_new(interp, enum_class_ResizablePMCArray);
_pmc->roles = pmc_new(interp, enum_class_ResizablePMCArray);
_pmc->methods = pmc_new(interp, enum_class_Hash);
_pmc->vtable_overrides = constant_pmc_new(interp, enum_class_Hash);
_pmc->parent_overrides = pmc_new(interp, enum_class_Hash);
_pmc->attrib_metadata = pmc_new(interp, enum_class_Hash);
_pmc->attrib_index = PMCNULL;
_pmc->attrib_cache = PMCNULL;
_pmc->resolve_method = pmc_new(interp, enum_class_ResizablePMCArray);
/* Set up the attribute storage for the proxy instance */
VTABLE_set_string_keyed_str(interp, new_attribute, CONST_STRING(interp, "name"), name);
VTABLE_set_pmc_keyed_str(interp, _pmc->attrib_metadata, name, new_attribute);
/* We put ourself on the all parents list. */
VTABLE_push_pmc(interp, _pmc->all_parents, SELF);
/* We are a class. */
PObj_is_class_SET(SELF);
}
VTABLE void init_pmc(PMC *init_data) {
const INTVAL type_num = VTABLE_get_integer(interp, init_data);
Parrot_Class_attributes *proxy_info;
INTVAL mro_length, i;
/* Ensure that it's a valid type number. */
if (type_num > interp->n_vtable_max || type_num <= 0)
Parrot_ex_throw_from_c_args(interp, NULL, 1,
"Attempt to create PMC Proxy for invalid type number!");
/* Set up the object. */
SELF.init();
/* Set up number, name and namespace. */
proxy_info = PARROT_CLASS(SELF);
proxy_info->id = type_num;
proxy_info->name = interp->vtables[type_num]->whoami;
proxy_info->_namespace = interp->vtables[type_num]->_namespace;
/* Build MRO (skip ourself). */
mro_length = VTABLE_elements(interp, interp->vtables[type_num]->mro);
for (i = 1; i < mro_length; i++) {
PMC *pclass = VTABLE_get_pmc_keyed_int(interp, interp->vtables[type_num]->mro, i);
PMC *cns = pclass->vtable->_namespace;
STRING *cname = pclass->vtable->whoami;
if (Parrot_str_not_equal(interp, cname, CONST_STRING(interp, "scalar"))) {
PMC *pproxy = Parrot_oo_get_class(interp, cns);
VTABLE_push_pmc(interp, proxy_info->all_parents, pproxy);
}
}
/* PMCs just do single inheritance, so we'll assume that if we have a
* second entry in our MRO, it goes in the parents list. */
if (VTABLE_elements(interp, proxy_info->all_parents) >= 2)
VTABLE_push_pmc(interp, proxy_info->parents,
VTABLE_get_pmc_keyed_int(interp, proxy_info->all_parents, 1));
if (!PMC_IS_NULL(proxy_info->_namespace) &&
PMC_IS_NULL(VTABLE_get_class(interp, proxy_info->_namespace))) {
/* Link the proxy and the namespace, caching the proxy object for
* later retrieval on class lookup. */
Parrot_PCCINVOKE(interp, proxy_info->_namespace, CONST_STRING(interp, "set_class"), "P->", SELF);
/* Extract any methods from the namespace */
Parrot_oo_extract_methods_from_namespace(interp, SELF,
proxy_info->_namespace);
}
{ /* Create inherited attributes */
/* Each attribute is prefixed with his type
* and terminated by an space,
* the list is '\0' terminated
*/
const char * attr = interp->vtables[type_num]->attribute_defs;
while (* attr) {
const char * const current = attr + 1;
size_t l;
char attrtype = * attr;
while (* attr != ' ') ++attr;
l= attr - current;
if (attrtype != ':') {
STRING *sattr = Parrot_str_new(interp, current, l);
SELF.add_attribute(sattr, NULL);
}
++attr;
}
}
}
/*
=item C<PMC *instantiate(PMC *init)>
Creates an instance of the PMC.
=cut
*/
VTABLE PMC *instantiate(PMC *init) {
Parrot_Class_attributes * const _pmc = PARROT_CLASS(SELF);
if (!PMC_IS_NULL(init))
return pmc_new_init(interp, _pmc->id, init);
return pmc_new(interp, _pmc->id);
}
/*
=item C<void destroy()>
Free the memory associated with the object's underlying struct.
=cut
*/
VTABLE void destroy() {
mem_sys_free(PMC_data(SELF));
}
/*
=item C<void mark()>
Mark any referenced strings and PMCs in the structure as live.
=cut
*/
VTABLE void mark() {
Parrot_Class_attributes * const _pmc = PARROT_CLASS(SELF);
if (_pmc->name)
Parrot_gc_mark_PObj_alive(interp, (PObj *)_pmc->name);
if (_pmc->_namespace)
Parrot_gc_mark_PObj_alive(interp, (PObj *)_pmc->_namespace);
if (_pmc->parents)
Parrot_gc_mark_PObj_alive(interp, (PObj *)_pmc->parents);
if (_pmc->all_parents)
Parrot_gc_mark_PObj_alive(interp, (PObj *)_pmc->all_parents);
if (_pmc->roles)
Parrot_gc_mark_PObj_alive(interp, (PObj *)_pmc->roles);
if (_pmc->methods)
Parrot_gc_mark_PObj_alive(interp, (PObj *)_pmc->methods);
if (_pmc->vtable_overrides)
Parrot_gc_mark_PObj_alive(interp, (PObj *)_pmc->vtable_overrides);
if (_pmc->parent_overrides)
Parrot_gc_mark_PObj_alive(interp, (PObj *)_pmc->parent_overrides);
if (_pmc->attrib_metadata)
Parrot_gc_mark_PObj_alive(interp, (PObj *)_pmc->attrib_metadata);
if (_pmc->attrib_index)
Parrot_gc_mark_PObj_alive(interp, (PObj *)_pmc->attrib_index);
if (_pmc->attrib_cache)
Parrot_gc_mark_PObj_alive(interp, (PObj *)_pmc->attrib_cache);
if (_pmc->resolve_method)
Parrot_gc_mark_PObj_alive(interp, (PObj *)_pmc->resolve_method);
}
/*
=item C<INTVAL isa_pmc(PMC *classname)>
Returns whether the class is or inherits from C<*classname>.
=cut
*/
VTABLE INTVAL isa_pmc(PMC *lookup) {
Parrot_Class_attributes * const _proxy = PARROT_CLASS(SELF);
INTVAL i, num_classes;
STRING *classname;
PMC *classobj;
if (PMC_IS_NULL(lookup))
return 0;
if (SUPER(lookup))
return 1;
classobj = Parrot_oo_get_class(interp, lookup);
if (PMC_IS_NULL(classobj))
return 0;
classname = VTABLE_get_string(interp, classobj);
/* Check if the passed name is the same as the stored short name. */
if (Parrot_str_equal(interp, classname, _proxy->name))
return 1;
/* Check if the class object is the same as self's class object */
if (VTABLE_is_same(interp, SELF, classobj))
return 1;
/* Check if the passed name is the same as the fully qualified name. */
if (Parrot_str_equal(interp, classname, VTABLE_get_string(interp, SELF)))
return 1;
/* Look in the isa hash. */
if (interp->vtables[_proxy->id]) {
Hash *isa_hash = interp->vtables[_proxy->id]->isa_hash;
if (!isa_hash && Parrot_str_equal(interp,
interp->vtables[_proxy->id]->whoami, classname))
return 1;
if (isa_hash && parrot_hash_exists(interp, isa_hash, classname))
return 1;
}
/* Iterate over all the parents and check if they respond true
* for 'isa' on the original comparison. */
num_classes = VTABLE_elements(interp, _proxy->parents);
for (i = 0; i < num_classes; i++) {
PMC * const cur_class = VTABLE_get_pmc_keyed_int(interp,
_proxy->parents, i);
if (VTABLE_isa_pmc(interp, cur_class, lookup))
return 1;
}
return 0;
}
/*
=item C<INTVAL isa(STRING *classname)>
Returns whether the class is or inherits from C<*classname>.
=cut
*/
VTABLE INTVAL isa(STRING *classname) {
Parrot_Class_attributes * const _proxy = PARROT_CLASS(SELF);
const STRING * const pmc_proxy = CONST_STRING(interp, "PMCProxy");
if (Parrot_str_equal(INTERP, classname, pmc_proxy))
return 1;
if (SUPER(classname))
return 1;
/* Look in the isa hash. */
if (interp->vtables[_proxy->id]) {
Hash *isa_hash = interp->vtables[_proxy->id]->isa_hash;
if (!isa_hash && Parrot_str_equal(interp,
interp->vtables[_proxy->id]->whoami, classname)) {
return 1;
}
if (isa_hash && parrot_hash_exists(interp, isa_hash, classname))
return 1;
}
return 0;
}
/*
=item C<INTVAL does(STRING *role_name)>
Returns whether the class does the role with the given C<*rolename>.
=cut
*/
VTABLE INTVAL does(STRING *role_name) {
Parrot_Class_attributes *_class = PARROT_CLASS(SELF);
INTVAL id = _class->id;
PMC *proxied = pmc_new(interp, id);
if (VTABLE_does(interp, proxied, role_name))
return 1;
return VTABLE_isa(interp, proxied, role_name);
}
/*
=item C<INTVAL type()>
Returns the integer type of the class.
=cut
*/
VTABLE INTVAL type() {
const Parrot_Class_attributes * const _class = PARROT_CLASS(SELF);
return _class->id;
}
/*
=item C<PMC *inspect()>
Returns a Hash describing the PMC, with key/value pairs as described in
inspect_str.
=cut
*/
VTABLE PMC *inspect()
{
/* Create a hash, then use inspect_str to get all of the data to
* fill it up with. */
STRING * const name_str = CONST_STRING(interp, "name");
STRING * const ns_str = CONST_STRING(interp, "namespace");
STRING * const meth_str = CONST_STRING(interp, "methods");
STRING * const parents_str = CONST_STRING(interp, "parents");
PMC * const metadata = pmc_new(interp, enum_class_Hash);
VTABLE_set_pmc_keyed_str(interp, metadata, name_str,
VTABLE_inspect_str(interp, SELF, name_str));
VTABLE_set_pmc_keyed_str(interp, metadata, ns_str,
VTABLE_inspect_str(interp, SELF, ns_str));
VTABLE_set_pmc_keyed_str(interp, metadata, meth_str,
VTABLE_inspect_str(interp, SELF, meth_str));
VTABLE_set_pmc_keyed_str(interp, metadata, parents_str,
VTABLE_inspect_str(interp, SELF, parents_str));
return metadata;
}
/*
=item C<STRING *name()>
Gets the name of the PMC.
=cut
*/
METHOD name() {
Parrot_Class_attributes * const _pmc = PARROT_CLASS(SELF);
STRING * const ret_name = _pmc->name;
RETURN(STRING *ret_name);
}
/*
=item C<void get_namespace()>
Gets the namespace that this class is attached to.
=cut
*/
METHOD get_namespace() {
Parrot_Class_attributes * const _pmc = PARROT_CLASS(SELF);
PMC * const ret_namespace = _pmc->_namespace;
RETURN(PMC *ret_namespace);
}
/*
=item C<void new(PMC *args)>
Creates an instance of the PMC.
=cut
*/
METHOD new(PMC *args :optional, int got_args :opt_flag) {
PMC * const obj = VTABLE_instantiate(interp, SELF, args);
UNUSED(got_args);
RETURN(PMC *obj);
}
/*
=item C<void methods()>
Return a hash where the keys are method names and the values are methods.
=cut
*/
METHOD methods() {
PMC * const ret_methods = VTABLE_inspect_str(interp, SELF, CONST_STRING(interp, "methods"));
RETURN(PMC *ret_methods);
}
/*
=item C<void parents()>
Return the parents array PMC.
=cut
*/
METHOD parents() {
PMC * const ret_parents = VTABLE_inspect_str(interp, SELF, CONST_STRING(interp, "parents"));
RETURN(PMC *ret_parents);
}
/*
=item C<void inspect(STRING *what :optional)>
Gets all introspection data for the PMC or, if the optional string
parameter is supplied, a particular item of introspection data.
=cut
*/
METHOD inspect(STRING *what :optional, int got_what :opt_flag) {
/* Just delegate to the appropriate vtable method. */
PMC * const found =
got_what
? VTABLE_inspect_str(interp, SELF, what)
: VTABLE_inspect(interp, SELF);
RETURN(PMC *found);
}
/*
=item C<STRING *get_string()>
Return the name of the low-level class (without the HLL namespace).
=cut
*/
VTABLE STRING *get_string() {
Parrot_Class_attributes * const proxy_info = PARROT_CLASS(SELF);
/* Copy the stored string name of the proxy. */
return Parrot_str_copy(interp, proxy_info->name);
}
} /* END pmclass */
/*
=back
=head1 SEE ALSO
F<docs/pdds/pdd17_pmc.pod>.
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4:
*/
Jump to Line
Something went wrong with that request. Please try again.