for (int i = 0; i < n_interfaces; i++)
{
InterfaceDefinition idef = (InterfaceDefinition)interfaces[i];
if (idef != null)
{
Name interfaceName = ((InterfaceDefinition)interfaces[i]).getMName(project);
interface_names.add(interfaceName);
}
}
iinfo.interfaceNames = interface_names.toArray(new Name[interface_names.size()]);
// Set the flags corresponding to 'final' and 'dynamic'.
if (classDefinition.isFinal())
iinfo.flags |= ABCConstants.CLASS_FLAG_final;
if (!classDefinition.isDynamic())
iinfo.flags |= ABCConstants.CLASS_FLAG_sealed;
iinfo.protectedNs = ((NamespaceDefinition)classDefinition.getProtectedNamespaceReference()).getAETNamespace();
this.cv = emitter.visitClass(iinfo, cinfo);
cv.visit();
this.itraits = cv.visitInstanceTraits();
this.ctraits = cv.visitClassTraits();
this.classScope.traitsVisitor = this.itraits;
this.classStaticScope.traitsVisitor = this.ctraits;
// Build an array of the names of all the ancestor classes.
ArrayList<Name> ancestorClassNames = new ArrayList<Name>();
// Walk the superclass chain, starting with this class
// and (unless there are problems) ending with Object.
// This will accomplish three things:
// - find loops;
// - build the array of names of ancestor classes;
// - set the needsProtected flag if this class or any of its ancestor classes needs it.
boolean needsProtected = false;
// Remember the most recently examined class in case there's a cycle in the superclass
// chain, in which case we'll need it to issue a diagnostic.
ClassDefinition c = null;
IClassDefinition.IClassIterator classIterator =
classDefinition.classIterator(project, true);
while (classIterator.hasNext())
{
c = (ClassDefinition)classIterator.next();
needsProtected |= c.getOwnNeedsProtected();
if (c != classDefinition)
ancestorClassNames.add(c.getMName(project));
}
// Report a loop in the superclass chain, such as A extends B and B extends A.
// Note: A extends A was found previously by SemanticUtils.resolveBaseClass().
if (classIterator.foundLoop())
classScope.addProblem(new CircularTypeReferenceProblem(c, c.getQualifiedName()));
// In the case of class A extends A, ancestorClassNames will be empty at this point.
// Change it to be Object to prevent "Warning: Stack underflow" in the script init code below.
if (ancestorClassNames.isEmpty())
{
ClassDefinition objectDefinition = (ClassDefinition)project.getBuiltinType(
IASLanguageConstants.BuiltinType.OBJECT);
ancestorClassNames.add(objectDefinition.getMName(project));
}
// If this class or any of its ancestor classes needs the protected flag set, set it.
if (needsProtected)
iinfo.flags |= ABCConstants.CLASS_FLAG_protected;
// Add the class initialization logic to the script init.
// For class B extends A, where class A extends Object, this looks like
// getscopeobject
// findpropstrict Object
// getproperty Object
// pushscope
// findpropstrict A
// getproperty A
// dup
// pushscope
// newclass
// popscope
// popscope
// initproperty B
InstructionList initInstructions = this.classScope.getInitInstructions();
initInstructions.addInstruction(OP_getscopeobject, 0);
// Push ancestor classes onto the scope stack.
for (int i = ancestorClassNames.size() - 1; i >= 0; i--)
{
Name ancestorClassName = ancestorClassNames.get(i);
initInstructions.addInstruction(OP_getlex, ancestorClassName);
// The newclass instruction below also needs the superclass on the stack, so dup it
if (i == 0)
initInstructions.addInstruction(OP_dup);
initInstructions.addInstruction(OP_pushscope);