| /* |
| * |
| * 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 java.io.FileNotFoundException; |
| import java.io.Reader; |
| import java.io.StringReader; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.EnumSet; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.royale.compiler.internal.as.codegen.CodeGeneratorManager; |
| import org.apache.commons.io.FilenameUtils; |
| |
| import org.apache.royale.compiler.common.DependencyType; |
| import org.apache.royale.compiler.common.Multiname; |
| import org.apache.royale.compiler.definitions.INamespaceDefinition; |
| import org.apache.royale.compiler.definitions.ITypeDefinition; |
| import org.apache.royale.compiler.definitions.references.INamespaceReference; |
| import org.apache.royale.compiler.definitions.references.IReference; |
| import org.apache.royale.compiler.definitions.references.ReferenceFactory; |
| |
| import org.apache.royale.compiler.filespecs.IFileSpecification; |
| import org.apache.royale.compiler.fxg.dom.IFXGNode; |
| import org.apache.royale.compiler.fxg.flex.FXGSymbolClass; |
| import org.apache.royale.compiler.fxg.flex.FlexFXG2SWFTranscoder; |
| import org.apache.royale.compiler.internal.definitions.ClassDefinition; |
| import org.apache.royale.compiler.internal.definitions.PackageDefinition; |
| import org.apache.royale.compiler.internal.fxg.resources.FXGFileResolver; |
| import org.apache.royale.compiler.internal.fxg.sax.FXGSAXParser; |
| import org.apache.royale.compiler.internal.parsing.as.ASParser; |
| import org.apache.royale.compiler.internal.projects.CompilerProject; |
| import org.apache.royale.compiler.internal.projects.DefinitionPriority.BasePriority; |
| import org.apache.royale.compiler.internal.scopes.ASProjectScope; |
| import org.apache.royale.compiler.internal.scopes.FXGFileScope; |
| import org.apache.royale.compiler.internal.scopes.PackageScope; |
| import org.apache.royale.compiler.internal.scopes.TypeScope; |
| import org.apache.royale.compiler.internal.semantics.PostProcessStep; |
| import org.apache.royale.compiler.internal.targets.TagSorter; |
| import org.apache.royale.compiler.internal.tree.as.FileNode; |
| import org.apache.royale.compiler.internal.units.requests.ABCBytesRequestResult; |
| import org.apache.royale.compiler.internal.units.requests.ASFileScopeRequestResult; |
| import org.apache.royale.compiler.internal.units.requests.SyntaxTreeRequestResult; |
| import org.apache.royale.compiler.problems.ICompilerProblem; |
| import org.apache.royale.compiler.problems.InternalCompilerProblem2; |
| 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 org.apache.royale.swf.SWFFrame; |
| import org.apache.royale.swf.tags.DoABCTag; |
| import org.apache.royale.swf.tags.ICharacterTag; |
| import org.apache.royale.swf.tags.ITag; |
| import org.apache.royale.utils.FilenameNormalization; |
| import com.google.common.collect.Iterables; |
| |
| /** |
| * This is a Compilation Unit which handles FXG compilation |
| */ |
| public class FXGCompilationUnit extends CompilationUnitBase |
| { |
| public static String fxgBaseClassName = "spark.core.SpriteVisualElement"; |
| |
| private String qname; |
| |
| private static final String SUB_SYSTEM = "FXGCompilationUnit"; // used for error reporting |
| |
| /** |
| * A {@code IFileSpecification} implementation from {@code String}. |
| */ |
| private class GeneratedSourceFileSpecfication implements IFileSpecification |
| { |
| public GeneratedSourceFileSpecfication(String name, String content) |
| { |
| this.reader = new StringReader(content); |
| this.name = FilenameNormalization.normalize(name); |
| } |
| |
| private final StringReader reader; |
| private final String name; |
| |
| @Override |
| public String getPath() |
| { |
| return name; |
| } |
| |
| @Override |
| public Reader createReader() throws FileNotFoundException |
| { |
| return reader; |
| } |
| |
| @Override |
| public long getLastModified() |
| { |
| return 0; |
| } |
| |
| @Override |
| public boolean isOpenDocument() |
| { |
| return false; |
| } |
| } |
| |
| public FXGCompilationUnit(CompilerProject project, String path, BasePriority basePriority, String qname) |
| { |
| super(project, path, basePriority, qname); |
| this.qname = qname; |
| } |
| |
| @Override |
| public UnitType getCompilationUnitType() |
| { |
| return UnitType.FXG_UNIT; |
| } |
| |
| @Override |
| protected ISyntaxTreeRequestResult handleSyntaxTreeRequest() throws InterruptedException |
| { |
| startProfile(Operation.GET_SYNTAX_TREE); |
| |
| getProject().clearScopeCacheForCompilationUnit(this); |
| |
| final Collection<ICompilerProblem> problems = new ArrayList<ICompilerProblem>(); |
| IFXGNode fxgroot = null; |
| try |
| { |
| fxgroot = new FXGSAXParser().parse(getRootFileSpecification().createReader(), qname, problems); |
| } |
| catch(Exception ex) |
| { |
| ex.printStackTrace(); |
| problems.add(new InternalCompilerProblem2(getAbsoluteFilename(), ex, SUB_SYSTEM)); |
| } |
| finally |
| { |
| stopProfile(Operation.GET_SYNTAX_TREE); |
| } |
| |
| return new FXGSyntaxTreeRequestResult(fxgroot, getRootFileSpecification().getLastModified(), problems); |
| } |
| |
| /** |
| * Syntax Tree request result for FXG files. FXG files are not represented |
| * by a traditional AST, they use their own tree and this class allows |
| * {@link FXGCompilationUnit} to cache an FXG tree result. |
| */ |
| private static class FXGSyntaxTreeRequestResult extends SyntaxTreeRequestResult { |
| |
| private IFXGNode rootNode; |
| |
| public FXGSyntaxTreeRequestResult(IFXGNode rootNode, long lastModified, Collection<ICompilerProblem> problems) |
| { |
| super(lastModified, problems); |
| this.rootNode = rootNode; |
| } |
| |
| /** |
| * Returns the root node for the FXG file handled |
| * by this compilation unit |
| * |
| * @return root node |
| */ |
| public IFXGNode getRootNode() |
| { |
| return rootNode; |
| } |
| |
| } |
| |
| /** |
| * This function will create a temporary filscope. Please note that this will not be the filescope that is used in the actual AST |
| */ |
| @Override |
| protected IFileScopeRequestResult handleFileScopeRequest() throws InterruptedException |
| { |
| startProfile(Operation.GET_FILESCOPE); |
| try |
| { |
| List<ICompilerProblem> noProblems = Collections.emptyList(); |
| IFileSpecification rootFileSpec = getRootFileSpecification(); |
| FXGFileScope fileScope = createFileScope(); |
| |
| return new ASFileScopeRequestResult(getDefinitionPromises(), getDefinitionPriority(), noProblems, fileScope, rootFileSpec); |
| } |
| finally |
| { |
| stopProfile(Operation.GET_FILESCOPE); |
| } |
| } |
| |
| @Override |
| protected IOutgoingDependenciesRequestResult handleOutgoingDependenciesRequest () throws InterruptedException |
| { |
| startProfile(Operation.GET_SEMANTIC_PROBLEMS); |
| |
| final Collection<ICompilerProblem> problems = new ArrayList<ICompilerProblem>(); |
| Map<ITag, ITag> extraTags = new HashMap<ITag, ITag>(); |
| FXGSymbolClass symbolClass = null; |
| FileNode fileNode = null; |
| ASProjectScope projectScope = getProject().getScope(); |
| |
| try |
| { |
| FXGSyntaxTreeRequestResult syntaxTreeResult = (FXGSyntaxTreeRequestResult)getSyntaxTreeRequest().get(); |
| IFXGNode tree = syntaxTreeResult.getRootNode(); |
| |
| FlexFXG2SWFTranscoder transcoder = new FlexFXG2SWFTranscoder(getProject()); |
| transcoder.setResourceResolver(new FXGFileResolver(FilenameUtils.getFullPath(getRootFileSpecification().getPath()))); |
| |
| symbolClass = transcoder.transcode(tree, |
| Multiname.getPackageNameForQName(qname), Multiname.getBaseNameForQName(qname), extraTags, problems); |
| |
| |
| //Add dependencies to the classes required by the FXG processed by this compilation unit |
| for (ITypeDefinition definition : transcoder.getDependencies()) |
| { |
| getProject().addDependency(this, projectScope.getCompilationUnitForDefinition(definition), |
| DependencyType.EXPRESSION, definition.getQualifiedName()); |
| } |
| |
| StringBuilder sb = new StringBuilder(symbolClass.getGeneratedSource()); |
| if (symbolClass.getAdditionalSymbolClasses() != null) |
| { |
| for (FXGSymbolClass symbol : symbolClass.getAdditionalSymbolClasses()) |
| { |
| sb.append(symbol.getGeneratedSource()); |
| } |
| } |
| |
| IFileSpecification virtualSymbolSource = new GeneratedSourceFileSpecfication(qname, sb.toString()); |
| fileNode = ASParser.parseFile(virtualSymbolSource, getProject().getWorkspace()); |
| fileNode.runPostProcess(EnumSet.of(PostProcessStep.POPULATE_SCOPE)); |
| |
| projectScope.addScopeForCompilationUnit(this, fileNode.getFileScope()); |
| |
| updateEmbedCompilationUnitDependencies(fileNode.getEmbedNodes(), problems); |
| } |
| catch (Exception e) |
| { |
| e.printStackTrace(); |
| problems.add(new InternalCompilerProblem2(getAbsoluteFilename(), e, SUB_SYSTEM)); |
| } |
| finally |
| { |
| stopProfile(Operation.GET_SEMANTIC_PROBLEMS); |
| } |
| |
| return new FXGOutgoingDependenciesResult(fileNode, symbolClass, extraTags, problems); |
| } |
| |
| /** |
| * Semantic problems result for FXG files. |
| */ |
| private static class FXGOutgoingDependenciesResult implements IOutgoingDependenciesRequestResult |
| { |
| |
| private Collection<ICompilerProblem> problems; |
| protected FileNode fileNode; |
| protected FXGSymbolClass symbolClass; |
| protected Map<ITag, ITag> extraTags; |
| |
| public FXGOutgoingDependenciesResult (FileNode fileNode, FXGSymbolClass symbolClass, |
| Map<ITag, ITag> extraTags, Collection<ICompilerProblem> problems) |
| { |
| this.problems = problems; |
| this.fileNode = fileNode; |
| this.symbolClass = symbolClass; |
| this.extraTags = extraTags; |
| } |
| |
| @Override |
| public ICompilerProblem[] getProblems() |
| { |
| return problems.toArray(new ICompilerProblem[0]); |
| } |
| |
| } |
| |
| @Override |
| protected IABCBytesRequestResult handleABCBytesRequest() throws InterruptedException |
| { |
| FXGOutgoingDependenciesResult semanticResults = (FXGOutgoingDependenciesResult) getOutgoingDependenciesRequest().get(); |
| |
| startProfile(Operation.GET_ABC_BYTES); |
| try |
| { |
| byte abc[] = CodeGeneratorManager.getCodeGenerator().generate(getFilenameNoPath(), semanticResults.fileNode, getProject()).getABCBytes(); |
| |
| return new ABCBytesRequestResult(abc); |
| } |
| finally |
| { |
| stopProfile(Operation.GET_ABC_BYTES); |
| } |
| } |
| |
| @Override |
| protected ISWFTagsRequestResult handleSWFTagsRequest() throws InterruptedException |
| { |
| FXGOutgoingDependenciesResult semanticResults = (FXGOutgoingDependenciesResult) getOutgoingDependenciesRequest().get(); |
| IABCBytesRequestResult byteResult = getABCBytesRequest().get(); |
| |
| startProfile(Operation.GET_SWF_TAGS); |
| |
| final FXGSymbolClass symbolClass = semanticResults.symbolClass; |
| final Map<ITag, ITag> extraTags = semanticResults.extraTags; |
| final Collection<ICompilerProblem> problems = new ArrayList<ICompilerProblem>(); |
| final DoABCTag abcTag = new DoABCTag(); |
| |
| try |
| { |
| abcTag.setName(qname); |
| abcTag.setABCData(byteResult.getABCBytes()); |
| } |
| catch (Exception e) |
| { |
| ICompilerProblem problem = new InternalCompilerProblem2(getRootFileSpecification().getPath(), e, SUB_SYSTEM); |
| problems.add(problem); |
| } |
| finally |
| { |
| stopProfile(Operation.GET_SWF_TAGS); |
| } |
| |
| return new ISWFTagsRequestResult() |
| { |
| @Override |
| public boolean addToFrame(SWFFrame frame) |
| { |
| ICharacterTag symbolTag = symbolClass.getSymbol(); |
| |
| List<ITag> symbolTags = TagSorter.sortFullGraph(Collections.singletonList((ITag)symbolTag)); |
| |
| for (ITag tag : symbolTags) |
| { |
| frame.addTag(tag); |
| if (extraTags.containsKey(tag)) |
| { |
| frame.addTag(extraTags.get(tag)); |
| } |
| } |
| |
| if (symbolClass.getAdditionalSymbolClasses() != null ) |
| { |
| for (FXGSymbolClass symbol : symbolClass.getAdditionalSymbolClasses()) |
| { |
| frame.defineSymbol(symbol.getSymbol(), symbol.getQualifiedClassName()); |
| } |
| } |
| |
| frame.addTag(abcTag); |
| frame.defineSymbol(symbolClass.getSymbol(), qname); |
| |
| return true; |
| } |
| |
| @Override |
| public ICompilerProblem[] getProblems() |
| { |
| return problems.toArray(new ICompilerProblem[0]); |
| } |
| |
| @Override |
| public String getDoABCTagName() |
| { |
| return abcTag.getName(); |
| } |
| |
| @Override |
| public DoABCTag getDoABCTag() |
| { |
| return abcTag; |
| } |
| }; |
| } |
| |
| /** |
| * Creates an empty FileScope for purposes of definition reporting |
| * |
| * @return a {@link FXGFileScope} with a class definition for the FXG source |
| */ |
| private FXGFileScope createFileScope() |
| { |
| FXGFileScope fileScope = new FXGFileScope(this, getAbsoluteFilename()); |
| |
| String packageName = Multiname.getPackageNameForQName(qname); |
| PackageScope packageScope = new PackageScope(fileScope, packageName); |
| packageScope.setContainingScope(fileScope); |
| |
| PackageDefinition packageDefinition = new PackageDefinition(packageName); |
| packageDefinition.setContainedScope(packageScope); |
| |
| fileScope.addDefinition(packageDefinition); |
| |
| Multiname mname = Multiname.crackDottedQName(getProject(), qname); |
| INamespaceDefinition packageNS = Iterables.getOnlyElement(mname.getNamespaceSet()); |
| |
| ClassDefinition classDefinition = new ClassDefinition(mname.getBaseName(), (INamespaceReference)packageNS); |
| IReference baseClass = ReferenceFactory.packageQualifiedReference(getProject().getWorkspace(), fxgBaseClassName); |
| classDefinition.setBaseClassReference(baseClass); |
| |
| TypeScope classScope = new TypeScope(packageScope, classDefinition); |
| classScope.setContainingDefinition(classDefinition); |
| classDefinition.setContainedScope(classScope); |
| classDefinition.setupThisAndSuper(); |
| |
| packageScope.addDefinition(classDefinition); |
| |
| return fileScope; |
| } |
| } |