org.apache.flex.compiler.internal.units.FXGCompilationUnit.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.flex.compiler.internal.units.FXGCompilationUnit.java

Source

/*
 *
 *  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 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.flex.compiler.internal.as.codegen.CodeGeneratorManager;
import org.apache.commons.io.FilenameUtils;

import org.apache.flex.compiler.common.DependencyType;
import org.apache.flex.compiler.common.Multiname;
import org.apache.flex.compiler.definitions.INamespaceDefinition;
import org.apache.flex.compiler.definitions.ITypeDefinition;
import org.apache.flex.compiler.definitions.references.INamespaceReference;
import org.apache.flex.compiler.definitions.references.IReference;
import org.apache.flex.compiler.definitions.references.ReferenceFactory;

import org.apache.flex.compiler.filespecs.IFileSpecification;
import org.apache.flex.compiler.fxg.dom.IFXGNode;
import org.apache.flex.compiler.fxg.flex.FXGSymbolClass;
import org.apache.flex.compiler.fxg.flex.FlexFXG2SWFTranscoder;
import org.apache.flex.compiler.internal.definitions.ClassDefinition;
import org.apache.flex.compiler.internal.definitions.PackageDefinition;
import org.apache.flex.compiler.internal.fxg.resources.FXGFileResolver;
import org.apache.flex.compiler.internal.fxg.sax.FXGSAXParser;
import org.apache.flex.compiler.internal.parsing.as.ASParser;
import org.apache.flex.compiler.internal.projects.CompilerProject;
import org.apache.flex.compiler.internal.projects.DefinitionPriority.BasePriority;
import org.apache.flex.compiler.internal.scopes.ASProjectScope;
import org.apache.flex.compiler.internal.scopes.FXGFileScope;
import org.apache.flex.compiler.internal.scopes.PackageScope;
import org.apache.flex.compiler.internal.scopes.TypeScope;
import org.apache.flex.compiler.internal.semantics.PostProcessStep;
import org.apache.flex.compiler.internal.targets.TagSorter;
import org.apache.flex.compiler.internal.tree.as.FileNode;
import org.apache.flex.compiler.internal.units.requests.ABCBytesRequestResult;
import org.apache.flex.compiler.internal.units.requests.ASFileScopeRequestResult;
import org.apache.flex.compiler.internal.units.requests.SyntaxTreeRequestResult;
import org.apache.flex.compiler.problems.ICompilerProblem;
import org.apache.flex.compiler.problems.InternalCompilerProblem2;
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 org.apache.flex.swf.SWFFrame;
import org.apache.flex.swf.tags.DoABCTag;
import org.apache.flex.swf.tags.ICharacterTag;
import org.apache.flex.swf.tags.ITag;
import org.apache.flex.utils.FilenameNormalization;
import com.google.common.collect.Iterables;

/**
 * This is a Compilation Unit which handles FXG compilation
 */
public class FXGCompilationUnit extends CompilationUnitBase {
    private static final 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();
            }

        };
    }

    /**
     * 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;
    }
}