/* * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.flex.compiler.internal.tree.mxml; import org.apache.flex.compiler.definitions.IClassDefinition; import org.apache.flex.compiler.definitions.IDefinition; import org.apache.flex.compiler.internal.definitions.ClassDefinition; import org.apache.flex.compiler.internal.projects.FlexProject; import org.apache.flex.compiler.internal.scopes.MXMLFileScope; import org.apache.flex.compiler.internal.tree.as.NodeBase; import org.apache.flex.compiler.mxml.IMXMLLanguageConstants; import org.apache.flex.compiler.mxml.IMXMLTagAttributeData; import org.apache.flex.compiler.mxml.IMXMLTagData; import org.apache.flex.compiler.problems.ICompilerProblem; import org.apache.flex.compiler.problems.MXMLEmptyAttributeProblem; import org.apache.flex.compiler.problems.MXMLInvalidDefinitionNameProblem; import org.apache.flex.compiler.problems.MXMLRequiredAttributeProblem; import org.apache.flex.compiler.problems.MXMLSemanticProblem; import org.apache.flex.compiler.tree.ASTNodeID; import org.apache.flex.compiler.tree.as.IASNode; import org.apache.flex.compiler.tree.mxml.IMXMLClassDefinitionNode; import org.apache.flex.compiler.tree.mxml.IMXMLDefinitionNode; import static org.apache.flex.compiler.mxml.IMXMLLanguageConstants.*; /** * MXML syntax tree node for <fx:Definition> tags. */ class MXMLDefinitionNode extends MXMLNodeBase implements IMXMLDefinitionNode { /** * @param parent */ MXMLDefinitionNode(NodeBase parent) { super(parent); } private String definitionName; private MXMLClassDefinitionNode containedClassDefinitionNode; @Override public ASTNodeID getNodeID() { return ASTNodeID.MXMLDefinitionID; } @Override public String getName() { return IMXMLLanguageConstants.DEFINITION; } @Override public int getChildCount() { return containedClassDefinitionNode != null ? 1 : 0; } @Override public IASNode getChild(int i) { return i == 0 ? containedClassDefinitionNode : null; } @Override protected void processTagSpecificAttribute(MXMLTreeBuilder builder, IMXMLTagData tag, IMXMLTagAttributeData attribute, MXMLNodeInfo info) { if (attribute.isSpecialAttribute(ATTRIBUTE_NAME)) { if (definitionName == null) { String rawValue = attribute.getRawValue(); if (rawValue != null) definitionName = attribute.getMXMLDialect().trim(rawValue); } // TODO Report problems the definition name is set twice or is // set to a name that is not a legal xml tag name. } else { super.processTagSpecificAttribute(builder, tag, attribute, info); } } @Override protected void processChildTag(MXMLTreeBuilder builder, IMXMLTagData tag, IMXMLTagData childTag, MXMLNodeInfo info) { boolean handled = false; if (containedClassDefinitionNode == null) { containedClassDefinitionNode = new MXMLClassDefinitionNode(this); handled = true; // check also that there is only one child tag and that // there are no text units around the child tag FlexProject project = builder.getProject(); IDefinition tagDef = builder.getFileScope().resolveTagToDefinition(childTag); // Check that the root tag mapped to a definition. if (tagDef == null) { // TODO Add a problem subclass for this. ICompilerProblem problem = new MXMLSemanticProblem(childTag); builder.addProblem(problem); } // Check that the definition is for a class. if (!(tagDef instanceof IClassDefinition)) { // TODO Add a problem subclass for this. ICompilerProblem problem = new MXMLSemanticProblem(childTag); builder.addProblem(problem); } IClassDefinition tagDefinition = (IClassDefinition)tagDef; // Check that the class is not final. if (tagDefinition.isFinal()) { // TODO Add a problem subclass for this. ICompilerProblem problem = new MXMLSemanticProblem(childTag); builder.addProblem(problem); } MXMLFileScope fileScope = builder.getFileScope(); ClassDefinition definitionTagClass = fileScope.getClassDefinitionForDefinitionTag(tag); assert tagDefinition == definitionTagClass.resolveBaseClass(project); containedClassDefinitionNode.setClassReference(project, tagDefinition); // TODO Move this logic to initializeFromTag(). containedClassDefinitionNode.setClassDefinition(definitionTagClass); // TODO Move this logic to initializeFromTag(). containedClassDefinitionNode.initializeFromTag(builder, childTag); int nameStart = definitionTagClass.getNameStart(); int nameEnd = definitionTagClass.getNameEnd(); definitionTagClass.setNode(containedClassDefinitionNode); // TODO The above call is setting nameStart and nameEnd to -1 // because the MXML class definition node doesn't have a name expression node. // We need to reset the correct nameStart and nameEnd. definitionTagClass.setNameLocation(nameStart, nameEnd); } if (!handled) { super.processChildTag(builder, tag, childTag, info); } } @Override protected void initializationComplete(MXMLTreeBuilder builder, IMXMLTagData tag, MXMLNodeInfo info) { super.initializationComplete(builder, tag, info); if (definitionName == null) { ICompilerProblem problem = new MXMLRequiredAttributeProblem(tag, ATTRIBUTE_NAME); builder.addProblem(problem); markInvalidForCodeGen(); } else if (definitionName.isEmpty()) { ICompilerProblem problem = new MXMLEmptyAttributeProblem(tag.getTagAttributeData(ATTRIBUTE_NAME)); builder.addProblem(problem); markInvalidForCodeGen(); } else if (!isValidXMLTagName(definitionName)) { ICompilerProblem problem = new MXMLInvalidDefinitionNameProblem(tag.getTagAttributeData(ATTRIBUTE_NAME), definitionName); builder.addProblem(problem); markInvalidForCodeGen(); } } @Override public String getDefinitionName() { return definitionName; } @Override public IMXMLClassDefinitionNode getContainedClassDefinitionNode() { return containedClassDefinitionNode; } @Override public IClassDefinition getContainedClassDefinition() { return containedClassDefinitionNode != null ? containedClassDefinitionNode.getClassDefinition() : null; } }