/* * * 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.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import org.antlr.runtime.ANTLRFileStream; import org.apache.commons.io.FilenameUtils; import org.apache.flex.abc.ABCConstants; import org.apache.flex.abc.ABCEmitter; import org.apache.flex.abc.semantics.Name; import org.apache.flex.compiler.common.DependencyType; import org.apache.flex.compiler.css.ICSSDocument; import org.apache.flex.compiler.definitions.references.IResolvedQualifiersReference; import org.apache.flex.compiler.definitions.references.ReferenceFactory; import org.apache.flex.compiler.filespecs.IFileSpecification; import org.apache.flex.compiler.internal.css.CSSDocument; import org.apache.flex.compiler.internal.css.codegen.CSSCompilationSession; import org.apache.flex.compiler.internal.css.codegen.CSSModuleGenerator; import org.apache.flex.compiler.internal.definitions.ClassDefinition; import org.apache.flex.compiler.internal.definitions.NamespaceDefinition; import org.apache.flex.compiler.internal.embedding.EmbedData; import org.apache.flex.compiler.internal.projects.CompilerProject; import org.apache.flex.compiler.internal.projects.FlexProject; import org.apache.flex.compiler.internal.projects.DefinitionPriority.BasePriority; import org.apache.flex.compiler.internal.scopes.ASFileScope; import org.apache.flex.compiler.internal.units.requests.ABCBytesRequestResult; import org.apache.flex.compiler.internal.units.requests.FileScopeRequestResultBase; import org.apache.flex.compiler.internal.units.requests.SWFTagsRequestResult; import org.apache.flex.compiler.internal.units.requests.SyntaxTreeRequestResult; import org.apache.flex.compiler.problems.CSSCodeGenProblem; import org.apache.flex.compiler.problems.FileNotFoundProblem; import org.apache.flex.compiler.problems.ICompilerProblem; import org.apache.flex.compiler.scopes.IASScope; 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.tags.DoABCTag; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; /** * The main compilation unit for a CSS module project. It can compile a CSS file * into a class to load styles at runtime. This compilation unit type is created * in order to setup the correct dependencies in the target. */ public class StyleModuleCompilationUnit extends CompilationUnitBase { /** * This implementation of {@link ISyntaxTreeRequestResult} carries a CSS * model object ({@link CSSDocument}). */ private static class StyleModuleSyntaxTreeRequestResult extends SyntaxTreeRequestResult { private StyleModuleSyntaxTreeRequestResult(final ICSSDocument cssDocument, final Collection<ICompilerProblem> syntaxProblems, final long lastModified) { super(lastModified, syntaxProblems); this.cssDocument = cssDocument; } private final ICSSDocument cssDocument; } /** * This implementation of {@link org.apache.flex.compiler.units.requests.IOutgoingDependenciesRequestResult} carries a CSS * model and a {@link CSSCompilationSession} objects that has all the * resolved symbols in the CSS. */ private static class StyleModuleSemanticRequestResult implements IOutgoingDependenciesRequestResult { private StyleModuleSemanticRequestResult(final ICSSDocument cssDocument, final CSSCompilationSession cssCompilationSession, final Collection<ICompilerProblem> semanticProblems) { this.cssDocument = cssDocument; this.cssCompilationSession = cssCompilationSession; this.semanticProblems = semanticProblems; } private final ICSSDocument cssDocument; private final CSSCompilationSession cssCompilationSession; private final Collection<ICompilerProblem> semanticProblems; @Override public ICompilerProblem[] getProblems() { return semanticProblems.toArray(new ICompilerProblem[0]); } } /** * Create a {@code StyleModuleCompilationUnit}. * * @param project Owner project. * @param cssFile Path to the source file. * @param basePriority Base priority. */ public StyleModuleCompilationUnit(CompilerProject project, IFileSpecification cssFile, BasePriority basePriority) { super(project, cssFile.getPath(), basePriority, false); this.swfTagName = FilenameUtils.getBaseName(cssFile.getPath()); this.cssFile = cssFile; } /** * Name of the generated {@code DoABC} SWF tag. */ private final String swfTagName; /** * Main CSS file. */ private final IFileSpecification cssFile; @Override public UnitType getCompilationUnitType() { return UnitType.CSS_UNIT; } /** * {@code StyleModuleCompilationUnit} does not provide an AST, unless we * decided to start CMP-879. However, the return value will contain the CSS * syntax errors in {@link ISyntaxTreeRequestResult#getProblems()}. */ @Override protected ISyntaxTreeRequestResult handleSyntaxTreeRequest() throws InterruptedException { final List<ICompilerProblem> syntaxErrors = new ArrayList<ICompilerProblem>(); CSSDocument css = null; try { final ANTLRFileStream fileStream = new ANTLRFileStream(cssFile.getPath()); css = CSSDocument.parse(fileStream, syntaxErrors); } catch (IOException e) { ICompilerProblem problem = new FileNotFoundProblem(cssFile.getPath()); syntaxErrors.add(problem); } return new StyleModuleSyntaxTreeRequestResult(css, syntaxErrors, cssFile.getLastModified()); } /** * Synthesize a file scope with a public definition of module main class. */ @Override protected IFileScopeRequestResult handleFileScopeRequest() throws InterruptedException { final ASFileScope fileScope = new ASFileScope(getProject().getWorkspace(), cssFile.getPath()); // TODO: Generate class names from CSS file name after the CSS module runtime code is finalized. final ClassDefinition classDefinition = new ClassDefinition( "CSSModule2Main", NamespaceDefinition.createPackagePublicNamespaceDefinition("")); fileScope.addDefinition(classDefinition); return new FileScopeRequestResultBase( Collections.<ICompilerProblem> emptySet(), ImmutableSet.<IASScope> of(fileScope)); } /** * Get the ABC byte code generated from the CSS file. * <p> * This request depends on {@link #handleOutgoingDependenciesRequest()}. */ @Override protected IABCBytesRequestResult handleABCBytesRequest() throws InterruptedException { final StyleModuleSemanticRequestResult semanticResult = (StyleModuleSemanticRequestResult) getOutgoingDependenciesRequest().get(); final ABCEmitter emitter = new ABCEmitter(); emitter.visit(ABCConstants.VERSION_ABC_MAJOR_FP10, ABCConstants.VERSION_ABC_MINOR_FP10); final FlexProject project = (FlexProject)getProject(); final List<ICompilerProblem> problems = new ArrayList<ICompilerProblem>(); byte[] bytes = null; try { // TODO: Generate class names from CSS file name after the CSS module runtime code is finalized. final String moduleName = "CSSModule2"; final Name mainClassName = new Name(moduleName + "Main"); CSSModuleGenerator.generateMainClass(emitter, project, mainClassName); final Name styleDataClassName = new Name(moduleName + "_StyleData"); CSSModuleGenerator.generateStyleDataClass( emitter, project, semanticResult.cssDocument, semanticResult.cssCompilationSession, styleDataClassName); bytes = emitter.emit(); } catch (Exception e) { final CSSCodeGenProblem problem = new CSSCodeGenProblem(e); problems.add(problem); } return new ABCBytesRequestResult(bytes, problems.toArray(new ICompilerProblem[0]), Collections.<EmbedData>emptySet()); } /** * Get a {@link DoABCTag} that contains the generated ABC byte code. */ @Override protected ISWFTagsRequestResult handleSWFTagsRequest() throws InterruptedException { final IABCBytesRequestResult abcResult = getABCBytesRequest().get(); return new SWFTagsRequestResult(abcResult.getABCBytes(), swfTagName); } /** * Collect CSS semantic problems. Add dependencies to the project. * <p> * This request depends on {@link #handleSyntaxTreeRequest()}. * * @return The result value has two pay-load values: a CSS model and a CSS * compilation session. */ @Override protected IOutgoingDependenciesRequestResult handleOutgoingDependenciesRequest () throws InterruptedException { final StyleModuleSyntaxTreeRequestResult syntaxResult = (StyleModuleSyntaxTreeRequestResult)getSyntaxTreeRequest().get(); final Collection<ICompilerProblem> cssSemanticProblems = new ArrayList<ICompilerProblem>(); final CSSCompilationSession session = new CSSCompilationSession(); if (syntaxResult.cssDocument != null) { final FlexProject flexProject = (FlexProject)getProject(); updateStyleCompilationUnitDependencies( session, flexProject, ImmutableList.<ICSSDocument> of(syntaxResult.cssDocument), cssSemanticProblems); IResolvedQualifiersReference styleModuleBaseClassRef = ReferenceFactory.packageQualifiedReference( getProject().getWorkspace(), "StyleModuleBase"); styleModuleBaseClassRef.resolve(flexProject, this, DependencyType.INHERITANCE); } return new StyleModuleSemanticRequestResult(syntaxResult.cssDocument, session, cssSemanticProblems); } }