blob: cffd562128c6a18bc0b2233629915319acc5f510 [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 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.royale.abc.ABCConstants;
import org.apache.royale.abc.ABCEmitter;
import org.apache.royale.abc.semantics.Name;
import org.apache.royale.compiler.common.DependencyType;
import org.apache.royale.compiler.css.ICSSDocument;
import org.apache.royale.compiler.definitions.references.IResolvedQualifiersReference;
import org.apache.royale.compiler.definitions.references.ReferenceFactory;
import org.apache.royale.compiler.embedding.IEmbedData;
import org.apache.royale.compiler.filespecs.IFileSpecification;
import org.apache.royale.compiler.internal.css.CSSDocument;
import org.apache.royale.compiler.internal.css.codegen.CSSCompilationSession;
import org.apache.royale.compiler.internal.css.codegen.CSSModuleGenerator;
import org.apache.royale.compiler.internal.definitions.ClassDefinition;
import org.apache.royale.compiler.internal.definitions.NamespaceDefinition;
import org.apache.royale.compiler.internal.projects.CompilerProject;
import org.apache.royale.compiler.internal.projects.RoyaleProject;
import org.apache.royale.compiler.internal.projects.DefinitionPriority.BasePriority;
import org.apache.royale.compiler.internal.scopes.ASFileScope;
import org.apache.royale.compiler.internal.units.requests.ABCBytesRequestResult;
import org.apache.royale.compiler.internal.units.requests.FileScopeRequestResultBase;
import org.apache.royale.compiler.internal.units.requests.SWFTagsRequestResult;
import org.apache.royale.compiler.internal.units.requests.SyntaxTreeRequestResult;
import org.apache.royale.compiler.problems.CSSCodeGenProblem;
import org.apache.royale.compiler.problems.FileNotFoundProblem;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.scopes.IASScope;
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.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.royale.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 RoyaleProject project = (RoyaleProject)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.<IEmbedData>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 RoyaleProject royaleProject = (RoyaleProject)getProject();
updateStyleCompilationUnitDependencies(
session,
royaleProject,
ImmutableList.<ICSSDocument> of(syntaxResult.cssDocument),
cssSemanticProblems);
IResolvedQualifiersReference styleModuleBaseClassRef = ReferenceFactory.packageQualifiedReference(
getProject().getWorkspace(), "StyleModuleBase");
styleModuleBaseClassRef.resolve(royaleProject, this, DependencyType.INHERITANCE);
}
return new StyleModuleSemanticRequestResult(syntaxResult.cssDocument, session, cssSemanticProblems);
}
}