Author: allison
Date: Wed May 30 18:37:32 2007
New Revision: 18699
Modified:
trunk/src/pmc/class.pmc
Log:
Extend the functionality of the Class PMC to pass more of the core object test
suite:
* Classes make entries in the global type registry. This smoothes over the
integration of the two models, but eventually the global type registry will
go away.
* Implement the 'subclass' vtable entry, to create subclasses in an appropriate
way for the new object model.
* Implement the 'name' vtable function.
Modified: trunk/src/pmc/class.pmc
==============================================================================
--- trunk/src/pmc/class.pmc (original)
+++ trunk/src/pmc/class.pmc Wed May 30 18:37:32 2007
@@ -157,6 +157,81 @@
_class->attrib_cache = pmc_new(interp, enum_class_Hash);
}
+/*
+ * This function throws an exception if a PMC or class with the same name
+ * already exists in the global type registry. The global type registry will go
+ * away eventually, but this allows the new object metamodel to interact with
+ * the old one until it does.
+ */
+
+static void
+fail_if_type_exists(Interp *interp, PMC *name)
+{
+ INTVAL type;
+
+ PMC * const classname_hash = interp->class_hash;
+ PMC * const type_pmc = (PMC *)VTABLE_get_pointer_keyed(interp,
+ classname_hash, name);
+ if (PMC_IS_NULL(type_pmc) ||
+ type_pmc->vtable->base_type == enum_class_NameSpace)
+ type = 0;
+ else
+ type = VTABLE_get_integer(interp, type_pmc);
+
+ if (type > enum_type_undef) {
+ /* TODO get printable name */
+ real_exception(interp, NULL, INVALID_OPERATION,
+ "Class %Ss already registered!\n",
+ VTABLE_get_string(interp, name));
+ }
+
+ if (type < enum_type_undef)
+ real_exception(interp, NULL, INVALID_OPERATION,
+ "native type with name '%s' already exists - "
+ "can't register Class", data_types[type].name);
+}
+
+/* This function registers a type in the global registry, first checking if it
+ * already exists. The global type registry will go away eventually, but this
+ * allows the new object metamodel to interact with the old one until it does.
+ */
+
+static INTVAL
+register_type(Parrot_Interp interp, STRING *name)
+{
+ INTVAL type;
+ PMC *classname_hash, *item, *name_pmc;
+
+ if (STRING_IS_NULL(name) || STRING_IS_EMPTY(name)) {
+ real_exception(interp, NULL, INVALID_OPERATION,
+ "Can't register type without a name!\n");
+ }
+
+ name_pmc = pmc_new(interp, enum_class_String);
+ VTABLE_set_string_native(interp, name_pmc, name);
+
+ /* First check if the type already exists */
+ fail_if_type_exists(interp, name_pmc);
+
+ /* Type doesn't exist, so go ahead and register it. Lock interpreter so
+ * pt_shared_fixup() can safely do a type lookup. */
+ LOCK_INTERPRETER(interp);
+ classname_hash = interp->class_hash;
+ type = interp->n_vtable_max++;
+
+ /* Have we overflowed the table? */
+ if (type >= interp->n_vtable_alloced)
+ parrot_realloc_vtables(interp);
+
+ /* set entry in name->type hash */
+ item = pmc_new(interp, enum_class_Integer);
+ PMC_int_val(item) = type;
+ VTABLE_set_pmc_keyed_str(interp, classname_hash, name, item);
+ UNLOCK_INTERPRETER(interp);
+ return type;
+}
+
+
/* Takes a hash and initializes the class based on it. */
static void init_class_from_hash(Parrot_Interp interp, PMC *self, PMC *info)
@@ -197,6 +272,7 @@
/* Set a (string) name. */
_class->name = VTABLE_get_string_keyed_str(interp, info,
string_from_const_cstring(interp, "name", 0));
+ register_type(interp, _class->name);
}
/* Otherwise, we may just have a name. */
@@ -209,6 +285,7 @@
* the class. */
_class->_namespace = Parrot_make_namespace_keyed_str(interp,
CONTEXT(interp->ctx)->current_namespace, _class->name);
+ register_type(interp, _class->name);
}
/* Otherwise, we may just have a namespace. */
@@ -228,9 +305,10 @@
/* Name is that of the most nested part of the namespace. */
_class->name = VTABLE_get_string(interp, _namespace);
+ register_type(interp, _class->name);
}
- /* If we were attached to a namespce and are now attached to a new one,
+ /* If we were attached to a namespace and are now attached to a new one,
* need to unset ourselves in the old namespace. */
if (!PMC_IS_NULL(old_ns) && _class->_namespace != old_ns)
Parrot_PCCINVOKE(interp, old_ns,
@@ -427,6 +505,36 @@
init_class_from_hash(interp, SELF, arg);
}
+/*
+
+=item C<PMC* subclass(PMC* name)>
+
+Creates a subclass, optionally with a given C<name>.
+
+=cut
+
+*/
+
+ PMC* subclass(PMC *name) {
+ PMC *child_class;
+
+ /* Create a new class. Set the classname, if we have one. */
+ if (PMC_IS_NULL(name)) {
+ child_class = pmc_new(interp, enum_class_Class);
+ }
+ else {
+ PMC *naming_hash = pmc_new(interp, enum_class_Hash);
+ VTABLE_set_pmc_keyed_str(interp, naming_hash, CONST_STRING(interp,
"name"), name);
+ child_class = pmc_new_init(interp, enum_class_Class, naming_hash);
+ }
+
+ /* Make the new class a subclass of the current class */
+ VTABLE_add_parent(interp, child_class, SELF);
+
+ return child_class;
+ }
+
+/*
/*
@@ -442,6 +550,23 @@
mem_sys_free(PMC_data(SELF));
}
+/*
+
+=item C<STRING* name()>
+
+Return the classname.
+
+=cut
+
+*/
+
+ STRING* name() {
+ Parrot_Class * const _class = PARROT_CLASS(SELF);
+ if (STRING_IS_NULL(_class->name) || STRING_IS_EMPTY(_class->name)) {
+ return SELF->vtable->whoami;
+ }
+ return _class->name;
+ }
/*