blob: 13c587b6b148720f2547e9a2efb0f1b4beb0deb8 [file] [log] [blame]
/*
*
* 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.units;
import static com.google.common.collect.Collections2.transform;
import java.util.Collection;
import java.util.HashSet;
import org.apache.royale.compiler.css.ICSSDocument;
import org.apache.royale.compiler.filespecs.IFileSpecification;
import org.apache.royale.compiler.internal.as.codegen.CodeGeneratorManager;
import org.apache.royale.compiler.internal.definitions.ClassDefinition;
import org.apache.royale.compiler.internal.parsing.as.OffsetCue;
import org.apache.royale.compiler.internal.parsing.as.OffsetLookup;
import org.apache.royale.compiler.internal.parsing.mxml.MXMLScopeBuilder;
import org.apache.royale.compiler.internal.projects.CompilerProject;
import org.apache.royale.compiler.internal.projects.DefinitionPriority;
import org.apache.royale.compiler.internal.projects.RoyaleProject;
import org.apache.royale.compiler.internal.scopes.MXMLFileScope;
import org.apache.royale.compiler.internal.scopes.TypeScope;
import org.apache.royale.compiler.internal.tree.mxml.MXMLDocumentNode;
import org.apache.royale.compiler.internal.tree.mxml.MXMLFileNode;
import org.apache.royale.compiler.internal.tree.mxml.MXMLTreeBuilder;
import org.apache.royale.compiler.internal.units.requests.ASFileScopeRequestResult;
import org.apache.royale.compiler.internal.units.requests.SWFTagsRequestResult;
import org.apache.royale.compiler.internal.units.requests.SyntaxTreeRequestResult;
import org.apache.royale.compiler.mxml.IMXMLData;
import org.apache.royale.compiler.mxml.IMXMLDataManager;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.problems.UnexpectedExceptionProblem;
import org.apache.royale.compiler.tree.mxml.IMXMLFileNode;
import org.apache.royale.compiler.tree.mxml.IMXMLStyleNode;
import org.apache.royale.compiler.units.requests.IABCBytesRequestResult;
import org.apache.royale.compiler.units.requests.IFileScopeRequestResult;
import org.apache.royale.compiler.units.requests.IOutgoingDependenciesRequestResult;
import org.apache.royale.compiler.units.requests.ISWFTagsRequestResult;
import org.apache.royale.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 RoyaleProject getProject()
{
return (RoyaleProject)super.getProject();
}
}