Author: jonathan
Date: Mon Apr 16 15:06:47 2007
New Revision: 18242
Modified:
trunk/src/pmc/role.pmc
trunk/t/pmc/role.t
Log:
[PDD15]: Semantic clearup of the Role PMC to bring it more in line with PDD15.
.name and .namespace methods do what they should, and init_pmc takes a Hash and
initializes the role based upon it. Also fix inspect('nameapace'). Plus some
new tests for the Role PMC.
Modified: trunk/src/pmc/role.pmc
==============================================================================
--- trunk/src/pmc/role.pmc (original)
+++ trunk/src/pmc/role.pmc Mon Apr 16 15:06:47 2007
@@ -61,6 +61,138 @@
} Parrot_Role;
+/* Takes a hash and initializes the role based on it. */
+static void init_role_from_hash(Parrot_Interp interp, PMC *self, PMC *info)
+{
+ Parrot_Role *role = PARROT_ROLE(self);
+ int have_name, have_ns;
+ PMC *old_ns;
+ int i;
+
+ /* Ensure we actually have some initialization info. */
+ if (PMC_IS_NULL(info))
+ return;
+
+ /* Check if we have a name and/or a namespace. */
+ have_name = VTABLE_exists_keyed_str(interp, info,
+ string_from_const_cstring(interp, "name", 0));
+ have_ns = VTABLE_exists_keyed_str(interp, info,
+ string_from_const_cstring(interp, "namespace", 0));
+
+ /* Take a copy of the current namespace the role is attached to. */
+ old_ns = role->namespace;
+
+ /* Let's roll (no pun intended!) If we have a namespace and a name,
+ * set both. */
+ if (have_name && have_ns) {
+ /* If we weren't passed a NameSpace PMC, assume it's something we have
+ * to look one up with and do so. */
+ PMC *namespace = VTABLE_get_pmc_keyed_str(interp, info,
+ string_from_const_cstring(interp, "namespace", 0));
+ if (!VTABLE_isa(interp, namespace, string_from_const_cstring(interp,
"NameSpace", 0)))
+ namespace = Parrot_make_namespace_autobase(interp, namespace);
+
+ /* If we get something null back it's an error; otherwise, store it. */
+ if (!PMC_IS_NULL(namespace))
+ role->namespace = namespace;
+ else
+ real_exception(interp, NULL, E_NameError, "Namespace not found");
+
+ /* Set a (string) name. */
+ role->name = VTABLE_get_string_keyed_str(interp, info,
+ string_from_const_cstring(interp, "name", 0));
+ }
+
+ /* Otherwise, we may just have a name. */
+ else if (have_name) {
+ /* Set the name. */
+ role->name = VTABLE_get_string_keyed_str(interp, info,
+ string_from_const_cstring(interp, "name", 0));
+
+ /* Namespace is nested in the current namespace and with the name of
+ * the role. */
+ role->namespace = Parrot_make_namespace_keyed_str(interp,
+ CONTEXT(interp->ctx)->current_namespace, role->name);
+ }
+
+ /* Otherwise, we may just have a namespace. */
+ else if (have_ns) {
+ /* If we weren't passed a NameSpace PMC, assume it's something we have
+ * to look one up with and do so. */
+ PMC *namespace = VTABLE_get_pmc_keyed_str(interp, info,
+ string_from_const_cstring(interp, "namespace", 0));
+ if (!VTABLE_isa(interp, namespace, string_from_const_cstring(interp,
"NameSpace", 0)))
+ namespace = Parrot_make_namespace_autobase(interp, namespace);
+
+ /* If we get something null back it's an error; otherwise, store it. */
+ if (!PMC_IS_NULL(namespace))
+ role->namespace = namespace;
+ else
+ real_exception(interp, NULL, E_NameError, "Namespace not found");
+
+ /* Name is that of the most nested part of the namespace. */
+ role->name = VTABLE_get_string(interp, namespace);
+ }
+
+ /* If we were attached to a namespce and are now attached to a new one,
+ * need to unset ourselves in the old namespace. */
+ if (!PMC_IS_NULL(old_ns) && role->namespace != old_ns)
+ Parrot_PCCINVOKE(interp, old_ns,
+ string_from_const_cstring(interp, "set_class", 0),
+ "P->", PMCNULL);
+
+ /* Link namespace to this role, if there is one. */
+ if (!PMC_IS_NULL(role->namespace))
+ Parrot_PCCINVOKE(interp, role->namespace,
+ string_from_const_cstring(interp, "set_class", 0),
+ "P->", self);
+
+ /* Initialize roles, if we have any. */
+ if (VTABLE_exists_keyed_str(interp, info,
+ string_from_const_cstring(interp, "roles", 0))) {
+ /* Loop over roles array and compose them. */
+ PMC *role_list = VTABLE_get_pmc_keyed_str(interp, info,
+ string_from_const_cstring(interp, "roles", 0));
+ int role_count = VTABLE_elements(interp, role_list);
+ for (i = 0; i < role_count; i++) {
+ PMC *cur_role = VTABLE_get_pmc_keyed_int(interp, role_list, i);
+ VTABLE_add_role(interp, self, cur_role);
+ }
+ }
+
+ /* Initialize attributes, if we have any. */
+ if (VTABLE_exists_keyed_str(interp, info,
+ string_from_const_cstring(interp, "attributes", 0))) {
+ /* Loop over attributes array and add them. */
+ PMC *attrib_name_list = VTABLE_get_pmc_keyed_str(interp, info,
+ string_from_const_cstring(interp, "attributes", 0));
+ int attrib_count = VTABLE_elements(interp, attrib_name_list);
+ for (i = 0; i < attrib_count; i++) {
+ STRING *attrib_name = VTABLE_get_string_keyed_int(interp,
+ attrib_name_list, i);
+ VTABLE_add_attribute(interp, self, attrib_name, PMCNULL);
+ }
+ }
+
+ /* Initialize methods, if we have any. */
+ if (VTABLE_exists_keyed_str(interp, info,
+ string_from_const_cstring(interp, "methods", 0))) {
+ /* Get the methods hash. */
+ PMC *methods = VTABLE_get_pmc_keyed_str(interp, info,
+ string_from_const_cstring(interp, "methods", 0));
+
+ /* Iterate over the list of methods. */
+ PMC *iter = VTABLE_get_iter(interp, methods);
+ while (VTABLE_get_bool(interp, iter)) {
+ /* Add the method. */
+ STRING *method_name = VTABLE_shift_string(interp, iter);
+ PMC *method_pmc = VTABLE_get_pmc_keyed_str(interp, methods,
method_name);
+ VTABLE_add_method(interp, self, method_name, method_pmc);
+ }
+ }
+}
+
+
/*
=back
@@ -83,11 +215,10 @@
Initializes a Role PMC.
-=item C<void init_pmc(PMC *name)>
+=item C<void init_pmc(PMC *init_data)>
-The actual role creation code, called from C<newrole> opcode.
-The C<init> argument must stringify to the name of the role.
-The role is attatched to the current namespace.
+Creates a Role and initializes it using the settings from the Hash passed in
+C<init_data>.
=cut
@@ -110,19 +241,12 @@
PMC_data(SELF) = role;
}
- void init_pmc(PMC* name) {
- Parrot_Role *role = NULL;
- STRING *s_name;
-
- /* Set up the role. */
+ void init_pmc(PMC* init_data) {
+ /* Create the role. */
SELF.init();
-
- /* Set name and namespace. */
- role = PARROT_ROLE(SELF);
- if (!PMC_IS_NULL(name))
- role->name = VTABLE_get_string(interp, name);
- role->namespace = CONTEXT(interp->ctx)->current_namespace;
+ /* Initialize the role with the supplied data. */
+ init_role_from_hash(interp, SELF, init_data);
}
@@ -277,7 +401,8 @@
VTABLE_set_string_native(interp, found, role->name);
}
else if (string_equal(interp, what, CONST_STRING(interp, "namespace"))
== 0) {
- found = role->namespace;
+ /* Don't clone the namespace, as it's not part of our state. */
+ return role->namespace;
}
else if (string_equal(interp, what, CONST_STRING(interp,
"attributes")) == 0) {
found = role->attrib_metadata;
@@ -344,7 +469,7 @@
=item C<PCCMETHOD void
name(STRING *name :optional, int got_name :opt_flag)>
-Sets the name of the role.
+Sets the name of the role, and updates the namespace accoringly.
=cut
@@ -355,8 +480,12 @@
STRING *ret_name = NULL;
if (got_name) {
- /* Set role name. */
- role->name = name;
+ /* We'll build a hash just containing the name, then give this to
+ * init_role_from_hash - saves some code duplication. */
+ PMC *naming_hash = pmc_new(interp, enum_class_Hash);
+ VTABLE_set_string_keyed_str(interp, naming_hash,
+ CONST_STRING(interp, "name"), name);
+ init_role_from_hash(interp, SELF, naming_hash);
}
ret_name = role->name;
@@ -366,72 +495,18 @@
/*
-=item C<PCCMETHOD void
- namespace(PMC *namespace :optional, int got_name :opt_flag)>
+=item C<PCCMETHOD void
+ namespace()>
-With a parameter, sets the namespace for the role. Expects a fully
-qualified namespace to be specified as a key. If you already have linked
another
-namespace with this role, this link will be broken and the new namespace
-specified will be linked to this role.
+Gets the namespace associated with this role, if any.
=cut
*/
- PCCMETHOD void namespace(PMC *namespace :optional, int got_name :opt_flag)
{
+ PCCMETHOD void namespace() {
Parrot_Role *role = PARROT_ROLE(SELF);
- PMC *ret_namespace = NULL;
-
- if (got_name) {
- /* If namespace is a key or a string, need to look it up. */
- switch (namespace->vtable->base_type) {
- case enum_class_NameSpace:
- /* It's fine, don't need to do anything. */
- break;
- case enum_class_Key:
- /* Look it up relative to HLL base. */
- namespace = Parrot_get_namespace_keyed(interp,
- interp->HLL_namespace, namespace);
- if (PMC_IS_NULL(namespace))
- real_exception(interp, NULL, E_NameError, "Namespace
cannot be found");
- break;
- case enum_class_String:
- /* Look it up relative to current namespace. */
- namespace = Parrot_get_namespace_keyed_str(interp,
- CONTEXT(interp->ctx)->current_namespace,
- VTABLE_get_string(interp, namespace));
- if (PMC_IS_NULL(namespace))
- real_exception(interp, NULL, E_NameError, "Namespace
cannot be found");
- break;
- default:
- /* Don't know what to do with it. */
- real_exception(interp, NULL, E_NameError, "Namespace must
be a key");
- }
-
- /* Check namespace is a key. */
- if (namespace->vtable->base_type != enum_class_Key) {
- real_exception(interp, NULL, E_NameError, "Namespace must be a
key");
- return;
- }
-
- /* If we already have a namespace, it shouldn't refer to the
- role any more. */
- if (role->namespace) {
- PMC *role_ns = role->namespace;
- PCCINVOKE(interp, role_ns, "set_class", PMC* PMCNULL);
- }
-
- /* Set namespace. */
- role->namespace = Parrot_get_namespace_keyed(interp,
- interp->HLL_namespace, namespace);
-
- /* Link namespace to this role. */
- PCCINVOKE(interp, namespace, "set_class", PMC* SELF);
-
- /* XXX Get methods from the namespace we were linked to. */
- }
-
- ret_namespace = role->namespace;
+ PMC *ret_namespace = role->namespace;
PCCRETURN(PMC *ret_namespace);
}
Modified: trunk/t/pmc/role.t
==============================================================================
--- trunk/t/pmc/role.t (original)
+++ trunk/t/pmc/role.t Mon Apr 16 15:06:47 2007
@@ -31,15 +31,32 @@
test_namespace."export_to"(curr_namespace, exports)
- plan(2)
+ plan(5)
- $P0 = new .Role
+ $P0 = new 'Role'
ok(1, 'Role type exists') # or we've already died.
$I0 = isa $P0, 'Role'
is($I0, 1, 'isa Role')
+
+
+ $P0 = new 'Hash'
+ $P0['name'] = 'Wob'
+ $P1 = new 'Role', $P0
+ ok(1, 'Created a Role initialized with a Hash')
+
+ $P2 = $P1.inspect('name')
+ $S0 = $P2
+ $I0 = $S0 == 'Wob'
+ ok($I0, 'Role name was set correctly')
+
+
+ $P2 = $P1.inspect('namespace')
+ $S0 = $P2
+ $I0 = $S0 == 'Wob'
+ ok($I0, 'Role namespace was set correctly')
.end
## TODO add more tests as this is documented and implemented