/* * * 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.units; import static com.google.common.collect.Collections2.transform; import java.util.Collection; import java.util.HashSet; import org.apache.flex.compiler.css.ICSSDocument; import org.apache.flex.compiler.filespecs.IFileSpecification; import org.apache.flex.compiler.internal.as.codegen.CodeGeneratorManager; import org.apache.flex.compiler.internal.definitions.ClassDefinition; import org.apache.flex.compiler.internal.parsing.as.OffsetCue; import org.apache.flex.compiler.internal.parsing.as.OffsetLookup; import org.apache.flex.compiler.internal.parsing.mxml.MXMLScopeBuilder; import org.apache.flex.compiler.internal.projects.CompilerProject; import org.apache.flex.compiler.internal.projects.DefinitionPriority; import org.apache.flex.compiler.internal.projects.FlexProject; import org.apache.flex.compiler.internal.scopes.MXMLFileScope; import org.apache.flex.compiler.internal.scopes.TypeScope; import org.apache.flex.compiler.internal.tree.mxml.MXMLDocumentNode; import org.apache.flex.compiler.internal.tree.mxml.MXMLFileNode; import org.apache.flex.compiler.internal.tree.mxml.MXMLTreeBuilder; import org.apache.flex.compiler.internal.units.requests.ASFileScopeRequestResult; import org.apache.flex.compiler.internal.units.requests.SWFTagsRequestResult; import org.apache.flex.compiler.internal.units.requests.SyntaxTreeRequestResult; import org.apache.flex.compiler.mxml.IMXMLData; import org.apache.flex.compiler.mxml.IMXMLDataManager; import org.apache.flex.compiler.problems.ICompilerProblem; import org.apache.flex.compiler.problems.UnexpectedExceptionProblem; import org.apache.flex.compiler.tree.mxml.IMXMLFileNode; import org.apache.flex.compiler.tree.mxml.IMXMLStyleNode; import org.apache.flex.compiler.units.requests.IABCBytesRequestResult; import org.apache.flex.compiler.units.requests.IFileScopeRequestResult; import org.apache.flex.compiler.units.requests.IOutgoingDependenciesRequestResult; import org.apache.flex.compiler.units.requests.ISWFTagsRequestResult; import org.apache.flex.compiler.units.requests.ISyntaxTreeRequestResult; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; public class MXMLCompilationUnit extends CompilationUnitBase { public MXMLCompilationUnit(CompilerProject project, String path, DefinitionPriority.BasePriority basePriority, int order, String qname) { super(project, path, basePriority, qname); this.qname = qname; ((DefinitionPriority)getDefinitionPriority()).setOrder(order); } // The fully-qualified name of the one externally-visible definition // expected to be found in this compilation unit, or null if none is expected. // This qname is determined from the name of the file // and the file's location relative to the source path. private final String qname; @Override public UnitType getCompilationUnitType() { return UnitType.MXML_UNIT; } @Override protected ISyntaxTreeRequestResult handleSyntaxTreeRequest() throws InterruptedException { // Fulfill other requests before profiling this request. final IFileScopeRequestResult fileScopeRequestResult = getFileScopeRequest().get(); final MXMLFileScope fileScope = (MXMLFileScope)fileScopeRequestResult.getScopes()[0]; startProfile(Operation.GET_SYNTAX_TREE); final IMXMLData mxmlData = getMXMLData(); final Collection<ICompilerProblem> problems = new HashSet<ICompilerProblem>(); // Create an MXMLTreeBuilder to store all the contextual information // that we need to build an MXML tree. final MXMLTreeBuilder builder = new MXMLTreeBuilder(this, getFileSpecificationGetter(), qname, mxmlData, fileScope, problems); // Use the MXMLTreeBuilder to build an MXMLFileNode (the root of an MXML AST) // from the MXMLData (the MXML DOM) and the MXMLFileScope. final IMXMLFileNode fileNode = builder.build(); try { // TODO This belongs in MXMLDocumentNode. MXMLDocumentNode documentNode = (MXMLDocumentNode)fileNode.getDocumentNode(); if (documentNode != null) { ClassDefinition mainClassDefinition = fileScope.getMainClassDefinition(); if (mainClassDefinition != null) { TypeScope mainClassScope = (TypeScope)mainClassDefinition.getContainedScope(); documentNode.setScope(mainClassScope); } } // Start CSS semantic analysis. final Function<IMXMLStyleNode, ICSSDocument> parseMXMLStyleNode = new Function<IMXMLStyleNode, ICSSDocument>() { @Override public ICSSDocument apply(IMXMLStyleNode mxmlStyleNode) { // This method will trigger the CSS parser to parse the CSS fragment. return mxmlStyleNode.getCSSDocument(problems); } }; final Collection<ICSSDocument> cssDocumentList = transform(fileNode.getStyleNodes(), parseMXMLStyleNode); // This method will resolve dependencies introduced by the CSS fragment, and add the // dependee's to the dependency graph. This is done at the last step in MXML tree // building phase. // - It can't be done in MXML semantic analysis, because MXML code generation doesn't // depend on MXML semantic analysis; // - It can't be done in MXML code generation either, because the "problems" in that phase are // generated from inside ABCGenerator. updateStyleCompilationUnitDependencies( fileNode.getCSSCompilationSession(), fileScope, cssDocumentList, problems); fileNode.getCSSCompilationSession().cssDocuments.addAll(cssDocumentList); } catch (Exception e) { //something went wrong, so log it. problems.add(new UnexpectedExceptionProblem(e)); } finally { stopProfile(Operation.GET_SYNTAX_TREE); } getProject().addToASTCache(fileNode); return new SyntaxTreeRequestResult(fileNode, ImmutableSet.<String>copyOf(fileScope.getSourceDependencies()), fileNode.getIncludeTreeLastModified(), problems); } @Override protected IFileScopeRequestResult handleFileScopeRequest() throws InterruptedException { startProfile(Operation.GET_FILESCOPE); try { final IMXMLData mxmlData = getMXMLData(); final MXMLScopeBuilder scopeBuilder = new MXMLScopeBuilder(this, getFileSpecificationGetter(), mxmlData, qname, getAbsoluteFilename()); MXMLFileScope fileScope = scopeBuilder.build(); final ImmutableList<OffsetCue> offsetCueList = scopeBuilder.getIncludeHandler().getOffsetCueList(); final OffsetLookup offsetLookup = new OffsetLookup(offsetCueList); fileScope.setOffsetLookup(offsetLookup); final Collection<ICompilerProblem> problemCollection = scopeBuilder.getProblems(); final IFileSpecification rootFileSpec = getRootFileSpecification(); getProject().getWorkspace().addIncludedFilesToCompilationUnit(this, fileScope.getSourceDependencies()); return new ASFileScopeRequestResult(getDefinitionPromises(), getDefinitionPriority(), problemCollection, fileScope, rootFileSpec); } finally { stopProfile(Operation.GET_FILESCOPE); } } @Override protected IABCBytesRequestResult handleABCBytesRequest() throws InterruptedException { // Fulfill other requests before profiling this request. final ISyntaxTreeRequestResult syntaxTreeRequestResult = getSyntaxTreeRequest().get(); final MXMLFileNode fileNode = (MXMLFileNode)syntaxTreeRequestResult.getAST(); final CompilerProject project = getProject(); startProfile(Operation.GET_ABC_BYTES); try { IABCBytesRequestResult result = CodeGeneratorManager.getCodeGenerator().generate( project.getWorkspace().getExecutorService(), project.getUseParallelCodeGeneration(), getFilenameNoPath(), fileNode, getProject(), isInvisible(), getEncodedDebugFiles()); return result; } finally { stopProfile(Operation.GET_ABC_BYTES); } } @Override protected ISWFTagsRequestResult handleSWFTagsRequest() throws InterruptedException { // Fulfill other requests before profiling this request. final IABCBytesRequestResult abc = getABCBytesRequest().get(); startProfile(Operation.GET_SWF_TAGS); try { return new SWFTagsRequestResult(abc.getABCBytes(), qname, abc.getEmbeds()); } finally { stopProfile(Operation.GET_SWF_TAGS); } } @Override protected IOutgoingDependenciesRequestResult handleOutgoingDependenciesRequest () throws InterruptedException { // Fulfill other requests before profiling this request. final ISyntaxTreeRequestResult syntaxTreeRequestResult = getSyntaxTreeRequest().get(); final MXMLFileNode fileNode = (MXMLFileNode)syntaxTreeRequestResult.getAST(); startParsingImports(fileNode); startProfile(Operation.GET_SEMANTIC_PROBLEMS); try { /* do the codegen now, because we don't discover SDK databinding dependencies * until codegen. Long term we probably want to go in this direction anyway, * since semantic analysis and codegen may get folded together for other reasons. */ getABCBytesRequest().get(); Collection<ICompilerProblem> problems = new HashSet<ICompilerProblem>(); updateEmbedCompilationUnitDependencies(fileNode.getEmbedNodes(), problems); getABCBytesRequest().get(); // Resolve all references to definitions. //fileNode.resolveRefs(problems, getProject()); return new IOutgoingDependenciesRequestResult() { @Override public ICompilerProblem[] getProblems() { return IOutgoingDependenciesRequestResult.NO_PROBLEMS; } }; } finally { stopProfile(Operation.GET_SEMANTIC_PROBLEMS); } } private IMXMLData getMXMLData() { // Get the DOM-like MXMLData for the file. // If its not already in the Workspace's MXMLDataManager, // the MXML file will be parsed. final IMXMLDataManager mxmlDataManager = getProject().getWorkspace().getMXMLDataManager(); final IFileSpecification rootFileSpec = getRootFileSpecification(); final IMXMLData mxmlData = mxmlDataManager.get(rootFileSpec); return mxmlData; } @Override public FlexProject getProject() { return (FlexProject)super.getProject(); } }