All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.royale.compiler.internal.scopes.MXMLFileScope Maven / Gradle / Ivy

There is a newer version: 0.9.12
Show newest version
/*
 *
 *  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.royale.compiler.internal.scopes;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.royale.compiler.common.Multiname;
import org.apache.royale.compiler.common.XMLName;
import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.metadata.IMetaTag;
import org.apache.royale.compiler.definitions.references.IReference;
import org.apache.royale.compiler.definitions.references.ReferenceFactory;
import org.apache.royale.compiler.internal.definitions.ClassDefinition;
import org.apache.royale.compiler.internal.mxml.MXMLDialect;
import org.apache.royale.compiler.internal.projects.RoyaleProject;
import org.apache.royale.compiler.internal.units.MXMLCompilationUnit;
import org.apache.royale.compiler.mxml.IMXMLData;
import org.apache.royale.compiler.mxml.IMXMLTagData;
import org.apache.royale.compiler.mxml.IMXMLUnitData;
import org.apache.royale.compiler.mxml.IXMLNameResolver;

import com.google.common.collect.ImmutableSet;

/**
 * Subclass of {@link ASFileScope} for MXML file scopes.
 * 

* It keeps track of the main MXML class definition in an MXML file scope. *

* It supports creating additional classes defined by * <fx:Component> and <fx:Definition> tags * in an MXML file. *

* It keeps track of the mapping from an MXML tag such as * <fx:MyDefinition> to the the class defined by * <fx:Definition name="MyDefinition"> *

* It has APIs such as {@code isScriptTag()} for determining whether an MXML tag * is a particular language tag, as determined by the version of MXML being used * in the MXML file that created this file scope. */ public class MXMLFileScope extends ASFileScope implements IXMLNameResolver { /** * Constructor. * * @param compilationUnit The {@link MXMLCompilationUnit} in which the new file scope * resides. * @param filePath The path of the MXML file for which this file scope is * being constructed. * @param mxmlData The {@code IMXMLData} that built this file scope. This is * used to determine which version of MXML is being used. */ public MXMLFileScope(MXMLCompilationUnit compilationUnit, String filePath, IMXMLData mxmlData) { super(compilationUnit.getProject().getWorkspace(), filePath); this.project = compilationUnit.getProject(); this.mxmlDialect = mxmlData.getMXMLDialect(); this.sourceDependencies = new HashSet(); addImplicitImportsForMXML(); } /** * The {@code RoyaleProject} for this file scope. */ private final RoyaleProject project; /** * The {@code MXMLDialect} for this file scope. */ private final MXMLDialect mxmlDialect; /** * Any source files which this file scope includes */ private final Set sourceDependencies; /** * The {@code ClassDefinition} of the main class for the MXML file. */ private ClassDefinition mainClassDefinition; /** * A map from XMLNames that refer to s to the * ClassDefinitions for those s. */ private Map fxDefinitionsMap; /** * A map from the starting offset of an tag to the * ClassDefinition produced by that This is built during MXML * scope-building, and used later by MXML tree-building to find the * already-built definition to connect to the node. */ private Map fxDefinitionsOffsetMap; /** * A map from XMLNames that refer to s to the * ClassDefinitions for those s. */ private Map fxComponentsMap; /** * A map from the starting offset of an tag to the * ClassDefinition produced by that This is built during MXML * scope-building, and used later by MXML tree-building to find the * already-built definition to connect to the node. */ private Map fxComponentsOffsetMap; /** * Adds the appropriate implicit imports for ActionScript. */ private void addImplicitImportsForMXML() { // Add the implicit imports for MXML. for (String implicitImport : project.getImplicitImportsForMXML(mxmlDialect)) { addImport(implicitImport); } } /** * Returns the main class definition in this file scope. * * @return The main class definition in this file scope. */ public ClassDefinition getMainClassDefinition() { assert mainClassDefinition != null : "Main class definition should be set before it is retrieved"; return mainClassDefinition; } /** * Called by the MXML scope-building code to set the main class definition * in this file scope. * * @param mainClassDefinition The main class definition in this file scope. */ public void setMainClassDefinition(ClassDefinition mainClassDefinition) { assert this.mainClassDefinition == null : "Main class definition should only be set once."; assert mainClassDefinition != null; this.mainClassDefinition = mainClassDefinition; } /** * @return a Collection of source files included in this file scope */ public ImmutableSet getSourceDependencies() { return ImmutableSet.copyOf(sourceDependencies); } /** * Add a source file dependency to this file scope * * @param filename Source dependency filename */ public void addSourceDependency(String filename) { sourceDependencies.add(filename); } /** * Creates a new class definition for an <fx:Component> tag and adds * it to this scope. * * @param mainClassQName The fully-qualified class name of the main class * for the entire MXML document (e.g., "MyApp"). * @param componentTagStart The starting offset of the <fx:Component> * tag. * @param componentClassName The class name for the component, as specified * by the className attribute on the <fx:Component> tag, * or null if there was no such attribute. * @param componentBaseClassQName The fully-qualified class name of the base * class for the component class. * @return The newly-added {@code ClassDefinition} for the component class. */ public ClassDefinition addFXComponent(String mainClassQName, int componentTagStart, String componentClassName, String componentBaseClassQName) { // Use the class name specified by the className attribute, // or generate a unique class name for the new component class, // such as "com_whatever_Whatever_component2" // for the 3rd anonymous inside com.whatever.Whatever. String className = componentClassName != null ? componentClassName : generateComponentClassName(mainClassQName); String packageName = Multiname.getPackageNameForQName(className); String baseName = Multiname.getBaseNameForQName(className); String namespace = packageName.isEmpty() ? "*" : packageName + ".*"; XMLName xmlName = new XMLName(namespace, baseName); // Create a ClassDefinition for the component class, // and add it to this file scope. ClassDefinition fxComponentClassDefinition = new ClassDefinition(className, getFilePrivateNamespaceReference()); fxComponentClassDefinition.setBaseClassReference( ReferenceFactory.packageQualifiedReference(getWorkspace(), componentBaseClassQName)); fxComponentClassDefinition.setMetaTags(new IMetaTag[0]); addDefinition(fxComponentClassDefinition); // Create a class scope for the component class. TypeScope classScope = new TypeScope(this, fxComponentClassDefinition); classScope.setContainingDefinition(fxComponentClassDefinition); fxComponentClassDefinition.setContainedScope(classScope); fxComponentClassDefinition.setupThisAndSuper(); // Keep track of the tag-name-to-class-definition mapping so that we can // resolve a tag like . if (fxComponentsMap == null) fxComponentsMap = new HashMap(); fxComponentsMap.put(xmlName, fxComponentClassDefinition); // Keep track of the starting-offset-of-component-tag-to-component-class-definition // mapping so that we can find the class defined by an tag // later when we build the MXML tree. if (fxComponentsOffsetMap == null) fxComponentsOffsetMap = new HashMap(); fxComponentsOffsetMap.put(componentTagStart, fxComponentClassDefinition); return fxComponentClassDefinition; } /** * Generates a class name for a class defined by an anonymous * <fx:Component> tag. *

* If the main class of the MXML document is, for example, * com.whatever.Whatever, then the 3rd anonymous component * class will be named com_whatever_Whatever_component2. * * @return The generated class name. */ private String generateComponentClassName(String mainClassQName) { int currentComponentCount = fxComponentsOffsetMap != null ? fxComponentsOffsetMap.size() : 0; return mainClassQName.replace('.', '_') + "_component" + String.valueOf(currentComponentCount); } /** * Gets the {@code ClassDefinition} for a class defined by a * <fx:Component> tag. * * @param componentTag The {@code MXMLTagData} for the * <fx:Component> tag. * @return The {@code ClassDefinition} associated with the * <fx:Component> tag. */ public ClassDefinition getClassDefinitionForComponentTag(IMXMLTagData componentTag) { return fxComponentsOffsetMap != null ? fxComponentsOffsetMap.get(componentTag.getAbsoluteStart()) : null; } /** * Creates a new class definition for an <fx:Definition> tag and adds * it to this scope. * * @param mainClassQName The fully-qualified class name of the main class * for the entire MXML document (e.g., "MyApp"). * @param definitionTag the MXMLTagData representing the * <fx:Definition> tag * @param definitionName The definition name as specified by the * name attribute on the <fx:Definition> tag. * @param definitionBaseClassQName The fully-qualified class name of the base * class for the definition class. * @return The newly-added {@code ClassDefinition} for the definition class. */ public ClassDefinition addFXDefinition(String mainClassQName, IMXMLTagData definitionTag, String definitionName, String definitionBaseClassQName) { // Generate a unique class name for the new class, // such as "com_whatever_Whatever_definition2" // for the 3rd inside com.whatever.Whatever. String className = generateDefinitionClassName(mainClassQName); XMLName definitionXMLName = new XMLName(definitionTag.getURI(), definitionName); // Create a ClassDefinition for the definition class, // and add it to this file scope. ClassDefinition fxDefinitionClassDefinition = new ClassDefinition(className, getFilePrivateNamespaceReference()); fxDefinitionClassDefinition.setBaseClassReference( ReferenceFactory.packageQualifiedReference(getWorkspace(), definitionBaseClassQName)); fxDefinitionClassDefinition.setMetaTags(new IMetaTag[0]); addDefinition(fxDefinitionClassDefinition); // Create a class scope for the definition class. TypeScope classScope = new TypeScope(this, fxDefinitionClassDefinition); classScope.setContainingDefinition(fxDefinitionClassDefinition); fxDefinitionClassDefinition.setContainedScope(classScope); fxDefinitionClassDefinition.setupThisAndSuper(); // Keep track of the tag-name-to-class-definition mapping so that we can // resolve a tag like . if (fxDefinitionsMap == null) fxDefinitionsMap = new HashMap(); fxDefinitionsMap.put(definitionXMLName, fxDefinitionClassDefinition); // Keep track of the starting-offset-of-definition-tag-to-definition-class-definition // mapping so that we can find the class defined by an tag // later when we build the MXML tree. if (fxDefinitionsOffsetMap == null) fxDefinitionsOffsetMap = new HashMap(); fxDefinitionsOffsetMap.put(definitionTag.getAbsoluteStart(), fxDefinitionClassDefinition); return fxDefinitionClassDefinition; } /** * Generates a class name for a class defined by an * <fx:Definition> tag. *

* If the main class of the MXML document is, for example, * com.whatever.Whatever, then the 3rd definition class will be * named com_whatever_Whatever_definition2. * * @return The generated class name. */ private String generateDefinitionClassName(String mainClassQName) { // TODO when http://bugs.adobe.com/jira/browse/CMP-403 is fixed, // make the name of the definition classes, just the name specified on // the tag and the namespace reference a private implementation namespace. int currentDefinitionCount = fxDefinitionsMap != null ? fxDefinitionsMap.size() : 0; return mainClassQName.replace('.', '_') + "_definition" + String.valueOf(currentDefinitionCount); } /** * Resolves an MXMLTagData to the fully qualified AS3 class name the tag * refers to. *

* TODO This method should return a name object instead of a string. * * @param tag An MXMLTagData whose name potentially refers to a AS3 class * name via manifest or <fx:Definition> tags. * @return Fully qualified AS3 class name the specified tag refers to. */ public String resolveTagToQualifiedName(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); return resolveXMLNameToQualifiedName(tagName, tag.getParent().getMXMLDialect()); } @Override public String resolveXMLNameToQualifiedName(XMLName tagName, MXMLDialect mxmlDialect) { ClassDefinition classDef = getClassDefinitionForDefinitionTagName(tagName); if (classDef != null) return classDef.getQualifiedName(); return project.resolveXMLNameToQualifiedName(tagName, mxmlDialect); } /** * Resolves an MXMLTagData to the IReference class the tag refers to. * * @param tag An MXMLTagData whose name potentially refers to a AS3 class * name via manifest or <fx:Definition> tags. * @return IReference to the specified tag refers to. */ public IReference resolveTagToReference(IMXMLTagData tag) { String qname = resolveTagToQualifiedName(tag); if (qname != null) return ReferenceFactory.packageQualifiedReference(getWorkspace(), qname); return null; } /** * Resolves an MXML tag such as to a class definition that the * manifest information has associated with the tag. *

* This method handles both manifest namespaces (such as in the above * example) and package namespaces such as . * * @param tag An MXML tag. * @return The definition of the ActionScript class, or null if * the tag has a manifest namespace and isn't found in the * MXMLManifestManager. */ public IDefinition resolveTagToDefinition(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); return resolveXMLNameToDefinition(tagName, tag.getParent().getMXMLDialect()); } /** * Resolves an {@link XMLName} such as to a class definition that * the manifest information has associated with the tag. *

* This method handles both manifest namespaces (such as in the above * example) and package namespaces such as . * * @param tagXMLName {@link XMLName} of a tag. * @param mxmlDialect Knowledge about dialect-specific resolution * strategies. * @return The definition of the ActionScript class, or null if * the tag has a manifest namespace and isn't found in the * MXMLManifestManager. */ @Override public IDefinition resolveXMLNameToDefinition(XMLName tagXMLName, MXMLDialect mxmlDialect) { // See if there is a class defined by a tag. ClassDefinition componentTagClassDef = getClassDefinitionForComponentTagName(tagXMLName); if (componentTagClassDef != null) return componentTagClassDef; // See if there is a class defined by a tag. ClassDefinition definitionTagClassDef = getClassDefinitionForDefinitionTagName(tagXMLName); if (definitionTagClassDef != null) return definitionTagClassDef; return project.resolveXMLNameToDefinition(tagXMLName, mxmlDialect); } /** * Gets the {@link ClassDefinition} for a class defined by a * <fx:Component> tag. * * @param componentTagName {@link XMLName} that refers to the * <fx:Component>. The name of the tag is determined by the className * attribute of the <fx:Component> tag. */ public ClassDefinition getClassDefinitionForComponentTagName(XMLName componentTagName) { return fxComponentsMap != null ? fxComponentsMap.get(componentTagName) : null; } /** * Gets the {@code ClassDefinition} for a class defined by a * <fx:Definition> tag. * * @param definitionTag The {@code MXMLTagData} for the * <fx:Definition> tag. * @return The {@code ClassDefinition} associated with the * <fx:Definition> tag. */ public ClassDefinition getClassDefinitionForDefinitionTag(IMXMLTagData definitionTag) { return fxDefinitionsOffsetMap != null ? fxDefinitionsOffsetMap.get(definitionTag.getAbsoluteStart()) : null; } /** * Gets the {@link ClassDefinition} for a class defined by a * <fx:Definition> tag. * * @param definitionTagName {@link XMLName} that refers to the * <fx:Definition>. The name of the tag is determined by the name * attribute of the <fx:Definition> tag. */ public ClassDefinition getClassDefinitionForDefinitionTagName(XMLName definitionTagName) { return fxDefinitionsMap != null ? fxDefinitionsMap.get(definitionTagName) : null; } /** * Gets the class definitions for all the <fx:Definition> tags in this * scope. * * @return The class definitions for all the <fx:Definition> tags in * this scope. */ public IClassDefinition[] getLibraryDefinitions() { return fxDefinitionsMap != null ? fxDefinitionsMap.values().toArray(new IClassDefinition[0]) : new IClassDefinition[0]; } /** * Returns all the {@link XMLName}'s that refer to <fx:Definition>'s * in this file scope. * * @return All the {@link XMLName}'s that refer to <fx:Definition>'s * in this file scope. */ public XMLName[] getLibraryDefinitionTagNames() { return fxDefinitionsMap != null ? fxDefinitionsMap.keySet().toArray(new XMLName[0]) : new XMLName[0]; } public boolean isBindingTag(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); XMLName bindingTagName = mxmlDialect.resolveBinding(); return tagName.equals(bindingTagName); } public boolean isComponentTag(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); XMLName componentTagName = mxmlDialect.resolveComponent(); return tagName.equals(componentTagName); } public boolean isDeclarationsTag(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); XMLName declarationsTagName = mxmlDialect.resolveDeclarations(); return tagName.equals(declarationsTagName); } public boolean isDefinitionTag(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); XMLName definitionTagName = mxmlDialect.resolveDefinition(); return tagName.equals(definitionTagName); } public boolean isLibraryTag(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); XMLName libraryTagName = mxmlDialect.resolveLibrary(); return tagName.equals(libraryTagName); } public boolean isMetadataTag(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); XMLName metadataTagName = mxmlDialect.resolveMetadata(); return tagName.equals(metadataTagName); } public boolean isModelTag(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); XMLName modelTagName = mxmlDialect.resolveModel(); return tagName.equals(modelTagName); } public boolean isPrivateTag(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); XMLName privateTagName = mxmlDialect.resolvePrivate(); return tagName.equals(privateTagName); } public boolean isReparentTag(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); XMLName reparentTagName = mxmlDialect.resolveReparent(); return tagName.equals(reparentTagName); } public boolean isScriptTag(IMXMLUnitData unitData) { if (unitData instanceof IMXMLTagData) return isScriptTag((IMXMLTagData)unitData); return false; } public boolean isScriptTag(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); XMLName scriptTagName = mxmlDialect.resolveScript(); return tagName.equals(scriptTagName); } public boolean isStringTag(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); XMLName stringTagName = mxmlDialect.resolveString(); return tagName.equals(stringTagName); } public boolean isStyleTag(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); XMLName styleTagName = mxmlDialect.resolveStyle(); return tagName.equals(styleTagName); } public boolean isXMLTag(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); XMLName xmlTagName = mxmlDialect.resolveXML(); return tagName.equals(xmlTagName); } public boolean isXMLListTag(IMXMLTagData tag) { XMLName tagName = tag.getXMLName(); XMLName xmlListTagName = mxmlDialect.resolveXMLList(); return tagName.equals(xmlListTagName); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy