protected void generateBindableImpl() { if (classDefinition.needsEventDispatcher(classScope.getProject())) { // Generate a EventDispatcher member, equivalent to: // private var _bindingEventDispatcher : flash.events.EventDispatcher; // // Note that it is in a separate private namespace, so it won't conflict with user defined // private members // Add init code for the _bindingEventDispatcher to the ctor // this is the equivalent of: // _bindingEventDispatcher = new flash.events.EventDispatcher(this); iinitInsns.addAll(BindableHelper.generateBindingEventDispatcherInit(itraits, false)); BindableHelper.generateAddEventListener(classScope); BindableHelper.generateDispatchEvent(classScope); BindableHelper.generateHasEventListener(classScope); BindableHelper.generateRemoveEventListener(classScope); BindableHelper.generateWillTrigger(classScope); } if (classDefinition.needsStaticEventDispatcher(classScope.getProject())) { cinitInsns.addAll(BindableHelper.generateBindingEventDispatcherInit(ctraits, true)); BindableHelper.generateStaticEventDispatcherGetter(classStaticScope); } }
/** * Check the class definition for various errors related to implemented interfaces, such as making * sure that all interface methods are implemented * * @param cls the class definition to check */ void implementedInterfaceSemanticChecks(ClassDefinition cls) { Iterator<IInterfaceDefinition> it = cls.interfaceIterator(classScope.getProject()); while (it.hasNext()) { IInterfaceDefinition interf = it.next(); if (interf instanceof InterfaceDefinition) { ((InterfaceDefinition) interf) .validateClassImplementsAllMethods( classScope.getProject(), cls, classScope.getProblems()); } } }
private void addAnyEmbeddedAsset() { ICompilerProject project = classScope.getProject(); if (!(project instanceof CompilerProject)) return; EmbedData embedData = classDefinition.getEmbeddedAsset((CompilerProject) project, classScope.getProblems()); if (embedData != null) classScope.getGlobalScope().getEmbeds().add(embedData); }
/** Declare a function. TODO: static vs. instance. */ @Override void declareFunction(FunctionNode func) { func.parseFunctionBody(classScope.getProblems()); final FunctionDefinition funcDef = func.getDefinition(); final boolean is_constructor = func.isConstructor(); functionSemanticChecks(func); // Save the constructor function until // we've seen all the instance variables // that might need initialization. if (is_constructor) { if (this.ctorFunction == null) this.ctorFunction = func; else { // If we already have a ctor, must be multiply defined. Ignore it and generate problem String name = this.className.getBaseName(); classScope.addProblem(new MultipleContructorDefinitionsProblem(func, name)); } } else { LexicalScope ls = funcDef.isStatic() ? classStaticScope : classScope; MethodInfo mi = classScope.getGenerator().generateFunction(func, ls, null); if (mi != null) { Name funcName = funcDef.getMName(classScope.getProject()); ITraitVisitor tv = ls.traitsVisitor.visitMethodTrait( functionTraitKind(func, TRAIT_Method), funcName, 0, mi); if (funcName != null) classScope .getMethodBodySemanticChecker() .checkFunctionForConflictingDefinitions(func, funcDef); if (!funcDef.isStatic()) if (funcDef.getNamespaceReference() instanceof NamespaceDefinition.IProtectedNamespaceDefinition) this.iinfo.flags |= ABCConstants.CLASS_FLAG_protected; ls.processMetadata(tv, getAllMetaTags(funcDef)); if (func.hasModifier(ASModifier.FINAL)) tv.visitAttribute(Trait.TRAIT_FINAL, Boolean.TRUE); if (func.hasModifier(ASModifier.OVERRIDE)) tv.visitAttribute(Trait.TRAIT_OVERRIDE, Boolean.TRUE); tv.visitEnd(); } } }
protected void generateRequiredContingentDefinitions() { List<IDefinition> definitons = classDefinition.getContingentDefinitions(); for (IDefinition definition : definitons) { if (!definition.isContingentNeeded(classScope.getProject())) continue; assert (definition instanceof VariableDefinition) : "The code generator only supports contigent variable definitions"; final IDefinitionNode node = definition.getNode(); declareVariable( (VariableNode) node, (VariableDefinition) definition, definition.isStatic(), definition instanceof IConstantDefinition, LexicalScope.noInitializer); } }
/** Declare a variable. */ @Override void declareVariable(VariableNode var) { verifyVariableModifiers(var); VariableDefinition varDef = (VariableDefinition) var.getDefinition(); boolean is_static = var.hasModifier(ASModifier.STATIC); boolean is_const = SemanticUtils.isConst(var, classScope.getProject()); final ICompilerProject project = this.classScope.getProject(); ICodeGenerator codeGenerator = classScope.getGenerator(); IExpressionNode assignedValueNode = var.getAssignedValueNode(); IConstantValue constantValue = codeGenerator.generateConstantValue(assignedValueNode, project); // initializer is null if no constant value // can be generated, and null is the correct value for "no value." Object initializer = constantValue != null ? constantValue.getValue() : null; // Reducing the constant value may have produced problems in the // LexicalScope used for constant reduction. Transfer them over // to the LexicalScope for this class. Collection<ICompilerProblem> problems = constantValue != null ? constantValue.getProblems() : null; if (problems != null) classScope.addProblems(problems); final MethodBodySemanticChecker checker = MethodBodySemanticCheckerFactory.getChecker(this.classScope); // CO-5148 DefinitionBase varType = (DefinitionBase) varDef.resolveType(project); Object transformed_initializer = null; if ((initializer != null) && (varType != null)) { transformed_initializer = checker .checkInitialValue( var, new Binding(null, varType.getMName(this.classScope.getProject()), varType), new PooledValue(initializer)) .getValue(); } else { transformed_initializer = initializer; } ITraitVisitor tv = declareVariable(var, varDef, is_static, is_const, transformed_initializer); if (is_static) this.classStaticScope.processMetadata(tv, getAllMetaTags(varDef)); else this.classScope.processMetadata(tv, getAllMetaTags(varDef)); tv.visitEnd(); // Generate variable initializers and append them to the // proper initialization list. if (transformed_initializer == null && var.getAssignedValueNode() != null) { // Emit initialization instructions for non-static vars. Static var // instructions will be emitted during finishClassDefinition() if (is_static) staticVariableInitializers.add(var); else generateInstructions(var, false); } else { checker.checkClassField(var, is_static); // Massive kludge -- grovel over chained variable decls and add them one by one for (int i = 0; i < var.getChildCount(); i++) { IASNode candidate = var.getChild(i); if (candidate instanceof VariableNode) { declareVariable((VariableNode) candidate); } } } }
/** * This method performs the semantic analysis of a function declared in a class. * * @param node the FunctionNode to semantically analyze */ void functionSemanticChecks(FunctionNode node) { verifyFunctionModifiers(node); FunctionDefinition func = node.getDefinition(); Collection<ICompilerProblem> problems = classScope.getProblems(); // code model has some peculiar ideas about what makes a function a constructor or not boolean looks_like_ctor = func.isConstructor(); looks_like_ctor |= func.getBaseName() != null && this.className != null && func.getBaseName().equals(this.className.getBaseName()); if (!looks_like_ctor && (func.getBaseName() != null)) { SemanticUtils.checkScopedToDefaultNamespaceProblem( classScope, node, func, this.classDefinition.getQualifiedName()); } if (looks_like_ctor) { // If a constructor has a namespace as part of it's declaration, it must be declared public. // It is ok to omit the namespace // We must check the AST, as CM treats all ctors as public no matter what the user typed in // so the FunctionDefinition will always be in the public namespace if (node.getActualNamespaceNode() != null && node.getActualNamespaceNode().getName() != IASKeywordConstants.PUBLIC) problems.add(new ConstructorMustBePublicProblem(node.getActualNamespaceNode())); // A constructor cannot be static if (func.isStatic()) problems.add(new ConstructorIsStaticProblem(node)); // A constructor cannot declare a return type, other than void. IExpressionNode returnTypeExpression = node.getReturnTypeNode(); if (returnTypeExpression != null) { // We cannot check whether node.resolveReturnType() returns the definition // for the void type, because the return type of a constructor is considered // to be the class of the object being constructed, rather than void. // So instead we simply check whether the type annotation was void. boolean returnTypeIsVoid = false; if (returnTypeExpression instanceof ILanguageIdentifierNode) { LanguageIdentifierKind kind = ((ILanguageIdentifierNode) returnTypeExpression).getKind(); if (kind == LanguageIdentifierKind.VOID) returnTypeIsVoid = true; } if (!returnTypeIsVoid) { ICompilerProblem problem = new ConstructorCannotHaveReturnTypeProblem(returnTypeExpression); problems.add(problem); } } // Is it a getter or setter that appears to be the constructor? if (func instanceof IAccessorDefinition) problems.add(new ConstructorIsGetterSetterProblem(node.getNameExpressionNode())); } else if (!func.isStatic()) { // We have to find the (potentially) overriden function whether we are an override or // not/ FunctionDefinition override = func.resolveOverriddenFunction(classScope.getProject()); if (func.isOverride()) { if (override == null) { // Didn't find the function we are supposed to be overriding problems.add(new OverrideNotFoundProblem(node.getNameExpressionNode())); } else { if (!func.hasCompatibleSignature(override, classScope.getProject())) { // Signatures didn't match problems.add(new IncompatibleOverrideProblem(node.getNameExpressionNode())); } if (override.isFinal()) { // overriding final problems.add(new OverrideFinalProblem(node.getNameExpressionNode())); } } } else if (override != null) { // found overriden function, but function not marked as override problems.add(new FunctionNotMarkedOverrideProblem(node.getNameExpressionNode())); } } }
/** * Constructor. Initializes the ClassDirectiveProcessor and its associated AET data structures. * * @param node - the AST that starts the class' definition in source; used for diagnostics. * @param class_definition - the class' definition * @param enclosing_scope - the immediately enclosing lexical scope. * @param emitter - the active ABC emitter. */ ClassDirectiveProcessor( ICommonClassNode node, ClassDefinition class_definition, LexicalScope enclosing_scope, IABCVisitor emitter) { super(enclosing_scope.getProblems()); this.emitter = emitter; this.definitionSource = node; assert (this.definitionSource != null) : "Class definition AST must be provided."; this.classScope = enclosing_scope.pushFrame(); this.classStaticScope = enclosing_scope.pushFrame(); if (node.getNodeID() == ASTNodeID.ClassID) { classScope.setInitialControlFlowRegionNode(((ClassNode) node).getScopedNode()); classStaticScope.setInitialControlFlowRegionNode(((ClassNode) node).getScopedNode()); } ICompilerProject project = classScope.getProject(); // Set the class Name. this.classDefinition = class_definition; this.className = classDefinition.getMName(project); iinfo.name = className; // Check for a duplicate class name. switch (SemanticUtils.getMultiDefinitionType(this.classDefinition, project)) { case AMBIGUOUS: classScope.addProblem( new DuplicateClassDefinitionProblem(node, class_definition.getBaseName())); break; case NONE: break; default: assert false; // I don't think classes can have other type of multiple definitions } if (node instanceof BaseDefinitionNode) // test doesn't work for MXML, which is OK. { BaseDefinitionNode n = (BaseDefinitionNode) node; SemanticUtils.checkScopedToDefaultNamespaceProblem(classScope, n, classDefinition, null); } // Resolve the super class, checking that it exists, // that it is a class rather than an interface, // that it isn't final, and that it isn't the same as this class. ClassDefinition superclassDefinition = SemanticUtils.resolveBaseClass(node, class_definition, project, classScope.getProblems()); // Check that the superclass isn't a forward reference, but only need to do this if both // definitions come from the same containing source. getContainingFilePath() returns the file // from the ASFileScope, so no need to worry about included files. if (!classDefinition.isGeneratedEmbedClass() && classDefinition .getContainingFilePath() .equals(superclassDefinition.getContainingFilePath())) { // If the absolute offset in the class is less than the // offset of the super class, it must be a forward reference in the file int classOffset = classDefinition.getAbsoluteStart(); int superClassOffset = superclassDefinition.getAbsoluteEnd(); if (classOffset < superClassOffset) classScope.addProblem( new ForwardReferenceToBaseClassProblem(node, superclassDefinition.getQualifiedName())); } // Set the superclass Name. this.superclassName = superclassDefinition.getMName(project); iinfo.superName = superclassName; // Resolve the interfaces. IInterfaceDefinition[] interfaces = classDefinition.resolveImplementedInterfaces(project, classScope.getProblems()); // Set the interface Names. int n_interfaces = interfaces.length; ArrayList<Name> interface_names = new ArrayList<Name>(n_interfaces); 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); } initInstructions.addInstruction(OP_newclass, cinfo); for (int i = 0; i < ancestorClassNames.size(); i++) initInstructions.addInstruction(OP_popscope); initInstructions.addInstruction(OP_initproperty, className); implementedInterfaceSemanticChecks(class_definition); processResourceBundles(class_definition, project, classScope.getProblems()); }