Forget to remove the return after real_exception, as recomended in a
talk in #parrot.
Second revision attached.
--
Salu2
Index: src/oo.c
===================================================================
--- src/oo.c (revisión: 27509)
+++ src/oo.c (copia de trabajo)
@@ -1148,8 +1148,7 @@
=item C<PMC * Parrot_remove_parent>
-This currently does nothing but return C<PMCNULL>.
-RT#50646
+Remove a parent class from a PMC, by invoking his remove_parent method.
=cut
@@ -1162,11 +1161,8 @@
Parrot_remove_parent(PARROT_INTERP, ARGIN(PMC *removed_class),
ARGIN(PMC *existing_class))
{
- UNUSED(interp);
- UNUSED(removed_class);
- UNUSED(existing_class);
-
- return PMCNULL;
+ VTABLE_remove_parent(interp, existing_class, removed_class);
+ return existing_class;
}
Index: src/pmc/class.pmc
===================================================================
--- src/pmc/class.pmc (revisión: 27509)
+++ src/pmc/class.pmc (copia de trabajo)
@@ -780,6 +780,66 @@
/*
+=item C<void remove_parent(PMC *parent)>
+
+Remove the supplied PMC from the list of parents for the class.
+Throws E_TypeError if parent is NULL, is not a class, or is not a parent.
+Throws INVALID_OPERATION if the class has been instantiated.
+
+=cut
+
+*/
+ VTABLE void remove_parent(PMC *parent) {
+ Parrot_Class * const _class = PARROT_CLASS(SELF);
+
+ /* get number of direct parents */
+ const int parent_count = VTABLE_elements(interp, _class->parents);
+
+ int index; /* loop iterator */
+
+ /* If we've been instantiated already, not allowed. */
+ if (_class->instantiated) {
+ real_exception(interp, NULL, INVALID_OPERATION,
+ "Modifications to classes are not allowed after instantiation.");
+ }
+
+ /* Ensure it really is a class. */
+ if (!PObj_is_class_TEST(parent)) {
+ real_exception(interp, NULL, E_TypeError, "Parent isn't a Class.");
+ }
+
+ /* iterate over all direct parents, looking for
+ * the parent to be removed.
+ */
+ for (index = 0; index < parent_count; index++) {
+ /* get the next parent */
+ PMC * const current_parent = VTABLE_get_pmc_keyed_int(interp,
+ _class->parents, index);
+ if (current_parent == parent)
+ break;
+ }
+ if (index >= parent_count)
+ real_exception(interp, NULL, INVALID_OPERATION,
+ "Can't remove_parent: is not a parent.");
+
+ /* Move up the remaining parents on the list and pops it */
+ for (; index < parent_count - 1; index++) {
+ PMC * const current_parent = VTABLE_get_pmc_keyed_int(interp,
+ _class->parents, index + 1);
+ VTABLE_set_pmc_keyed_int(interp, _class->parents,
+ index, current_parent);
+ }
+ VTABLE_pop_pmc(interp, _class->parents);
+
+ _class->all_parents = Parrot_ComputeMRO_C3(interp, SELF);
+
+ /* Anonymous classes have no entry in the vtable array */
+ if (!CLASS_is_anon_TEST(SELF))
+ interp->vtables[VTABLE_type(interp, SELF)]->mro = _class->all_parents;
+ }
+
+/*
+
=item C<void add_role(PMC *role)>
Adds the supplied PMC to the list of roles for the class, provided there are
Index: t/oo/removeparent.t
===================================================================
--- t/oo/removeparent.t (revisión: 0)
+++ t/oo/removeparent.t (revisión: 0)
@@ -0,0 +1,123 @@
+#! parrot
+# Copyright (C) 2008, The Perl Foundation.
+# $Id: $
+
+=head1 NAME
+
+t/oo/removeparent.t - Test OO inheritance
+
+=head1 SYNOPSIS
+
+ % prove t/oo/removeparent.t
+
+=head1 DESCRIPTION
+
+Tests OO features related to the removeparent opcode.
+
+=cut
+
+.sub main :main
+ .include 'include/test_more.pir'
+
+ plan(4)
+
+ remove_1()
+ remove_2()
+ remove_Y()
+ remove_diamond()
+.end
+
+.sub remove_1
+ $P1 = newclass "Foo"
+ $P2 = newclass "Bar"
+ $I1 = isa $P2, $P1
+ if $I1, fail
+ addparent $P2, $P1
+ $I1 = isa $P2, $P1
+ unless $I1, fail
+ removeparent $P2, $P1
+ $I1 = isa $P2, $P1
+ if $I1, fail
+ $I1 = 1
+ ok( $I1, 'simple')
+fail:
+.end
+
+.sub remove_2
+ $P1 = newclass "Foo2_1"
+ $P2 = newclass "Foo2_2"
+ $P3 = newclass "Bar2"
+ $I1 = isa $P3, $P1
+ if $I1, fail
+ $I1 = isa $P3, $P2
+ if $I1, fail
+ addparent $P3, $P1
+ $I1 = isa $P3, $P1
+ unless $I1, fail
+ $I1 = isa $P3, $P2
+ if $I1, fail
+ addparent $P3, $P2
+ $I1 = isa $P3, $P2
+ unless $I1, fail
+ removeparent $P3, $P1
+ $I1 = isa $P3, $P1
+ if $I1, fail
+ $I1 = isa $P3, $P2
+ unless $I1, fail
+ removeparent $P3, $P2
+ $I1 = isa $P3, $P1
+ if $I1, fail
+ $I1 = isa $P3, $P2
+ if $I1, fail
+ $I1 = 1
+ ok( $I1, 'multiple')
+fail:
+.end
+
+.sub remove_Y
+ $P1 = newclass "FooY_1"
+ $P2 = newclass "FooY_2"
+ $P3 = newclass "BarY_1"
+ $P4 = newclass "BarY_2"
+ addparent $P3, $P1
+ addparent $P3, $P2
+ $I1 = isa $P4, $P1
+ if $I1, fail
+ $I1 = isa $P4, $P2
+ if $I1, fail
+ addparent $P4, $P3
+ $I1 = isa $P4, $P1
+ unless $I1, fail
+ $I1 = isa $P4, $P2
+ unless $I1, fail
+ removeparent $P4, $P3
+ $I1 = isa $P4, $P1
+ if $I1, fail
+ $I1 = isa $P4, $P2
+ if $I1, fail
+ $I1 = 1
+ ok( $I1, 'Y')
+fail:
+.end
+
+.sub remove_diamond
+ $P1 = newclass "FooD1"
+ $P2 = newclass "FooD2"
+ $P3 = newclass "FooD3"
+ $P4 = newclass "BarD1"
+ addparent $P2, $P1
+ addparent $P3, $P1
+ addparent $P4, $P2
+ addparent $P4, $P3
+ $I1 = isa $P4, $P1
+ unless $I1, fail
+ removeparent $P4, $P2
+ $I1 = isa $P4, $P1
+ unless $I1, fail
+ removeparent $P4, $P3
+ $I1 = isa $P4, $P1
+ if $I1, fail
+ $I1 = 1
+ ok( $I1, 'diamond')
+fail:
+.end