blob: 710d57787085726f9c79a00b98f327fabc0e5e48 [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.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import org.apache.royale.abc.ABCConstants;
import org.apache.royale.abc.ABCEmitter;
import org.apache.royale.abc.instructionlist.InstructionList;
import org.apache.royale.abc.semantics.Name;
import org.apache.royale.compiler.common.DependencyType;
import org.apache.royale.compiler.common.Multiname;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.INamespaceDefinition;
import org.apache.royale.compiler.definitions.references.INamespaceReference;
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.internal.abc.ClassGeneratorHelper;
import org.apache.royale.compiler.internal.definitions.ClassDefinition;
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.scopes.ASProjectScope;
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.ICompilerProblem;
import org.apache.royale.compiler.problems.InternalCompilerProblem;
import org.apache.royale.compiler.scopes.IASScope;
import org.apache.royale.compiler.units.ICompilationUnit;
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.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* The main compilation unit for a Resource module project. It can compile one
* or more ResourceBundle files into a class to load them at runtime. This
* compilation unit type is created in order to setup the correct dependencies
* in the target.
*/
public class ResourceModuleCompilationUnit extends CompilationUnitBase
{
/**
* Qualified name for the module processed by this compilation unit
*/
private final String qname;
/**
* List of resource bundle compilation units to include in the generated module
*/
private final Collection<ICompilationUnit> resourceBundleCompUnits;
/**
* Create a {@code ResourceModuleCompilationUnit}.
*
* @param project owner project.
* @param resourceBundleCompUnits list of resource bundle compilation units
* to include in this resource module
* @param basePriority base priority.
*/
public ResourceModuleCompilationUnit(CompilerProject project, String qname,
Collection<ICompilationUnit> resourceBundleCompUnits, BasePriority basePriority)
{
super(project, null, basePriority, qname);
this.resourceBundleCompUnits = resourceBundleCompUnits;
this.qname = qname;
}
@Override
public UnitType getCompilationUnitType()
{
return UnitType.RESOURCE_UNIT;
}
/**
* {@code ResourceModuleCompilationUnit} does not provide an AST.
*/
@Override
protected ISyntaxTreeRequestResult handleSyntaxTreeRequest() throws InterruptedException
{
return new SyntaxTreeRequestResult(-1, Collections.<ICompilerProblem>emptyList());
}
/**
* Synthesize a file scope with a public definition of module main class.
*/
@Override
protected IFileScopeRequestResult handleFileScopeRequest() throws InterruptedException
{
startProfile(Operation.GET_FILESCOPE);
try
{
final ASFileScope fileScope = new ASFileScope(getProject().getWorkspace(), null);
Multiname mname = Multiname.crackDottedQName(getProject(), qname);
INamespaceDefinition packageNS = Iterables.getOnlyElement(mname.getNamespaceSet());
final ClassDefinition classDefinition = new ClassDefinition(mname.getBaseName(),
(INamespaceReference)packageNS);
fileScope.addDefinition(classDefinition);
return new FileScopeRequestResultBase(Collections.<ICompilerProblem> emptySet(),
ImmutableSet.<IASScope> of(fileScope));
}
finally
{
stopProfile(Operation.GET_FILESCOPE);
}
}
/**
* Manually add dependencies to all the classes/interfaces used in the module class
* that will be generated for this compilation unit.
*/
@Override
protected IOutgoingDependenciesRequestResult handleOutgoingDependenciesRequest () throws InterruptedException
{
startProfile(Operation.GET_SEMANTIC_PROBLEMS);
final Collection<ICompilerProblem> problems = Collections.emptyList();
try
{
final RoyaleProject royaleProject = (RoyaleProject)getProject();
//flex.compiler.support.ResourceModuleBase
ASProjectScope scope = royaleProject.getScope();
IDefinition def = scope.findDefinitionByName(royaleProject.getResourceModuleBaseClass());
ICompilationUnit resourceModuleBaseCompUnit = scope.getCompilationUnitForDefinition(def);
royaleProject.addDependency(this, resourceModuleBaseCompUnit, DependencyType.INHERITANCE,
def.getQualifiedName());
//Add dependency to all the resource bundle compilation units we want to
//include in the resource module SWF
for(ICompilationUnit compUnit : resourceBundleCompUnits)
{
royaleProject.addDependency(this, compUnit, DependencyType.EXPRESSION);
}
}
catch (Exception t)
{
problems.add(new InternalCompilerProblem(t));
}
finally
{
stopProfile(Operation.GET_SEMANTIC_PROBLEMS);
}
return new IOutgoingDependenciesRequestResult()
{
@Override
public ICompilerProblem[] getProblems()
{
return problems.toArray(new ICompilerProblem[0]);
}
};
}
/**
* Get the ABC byte code generated from this module class. The generated class looks like the following:
*
* --------------------------
* package
* {
* import flex.compiler.support.ResourceModuleBase;
*
* public class GeneratedResourceModule extends ResourceModuleBase
* {
* public function GeneratedResourceModule()
* {
* super(["en_US$core_properties", "en_US$effects_properties"]);
* }
* }
* }
* -------------------------------------
*/
@Override
protected IABCBytesRequestResult handleABCBytesRequest() throws InterruptedException
{
startProfile(Operation.GET_ABC_BYTES);
try
{
final RoyaleProject royaleProject = (RoyaleProject)getProject();
final Collection<ICompilerProblem> problems = new LinkedList<ICompilerProblem>();
final ABCEmitter emitter = new ABCEmitter();
byte[] generatedBytes = null;
try
{
//this class extends "flex.compiler.support.ResourceModuleBase"
IResolvedQualifiersReference resourceModuleBaseRef = ReferenceFactory.packageQualifiedReference(
royaleProject.getWorkspace(), royaleProject.getResourceModuleBaseClass());
//Create constructor instruction list
InstructionList constructorInstructionList = new InstructionList();
constructorInstructionList.addInstruction(ABCConstants.OP_getlocal0);
constructorInstructionList.addInstruction(ABCConstants.OP_pushscope);
int resourceBundleCount = 0;
for(ICompilationUnit compUnit : resourceBundleCompUnits)
{
for(IDefinition def : compUnit.getDefinitionPromises())
{
constructorInstructionList.addInstruction(ABCConstants.OP_pushstring, def.getQualifiedName());
resourceBundleCount++;
}
}
constructorInstructionList.addInstruction(ABCConstants.OP_newarray, resourceBundleCount);
constructorInstructionList.addInstruction(ABCConstants.OP_constructsuper, 1);
constructorInstructionList.addInstruction(ABCConstants.OP_returnvoid);
ClassGeneratorHelper classGen = new ClassGeneratorHelper(royaleProject, emitter,
new Name(qname),
(ClassDefinition)resourceModuleBaseRef.resolve(royaleProject),
Collections.<Name> emptyList(),
constructorInstructionList);
classGen.finishScript();
generatedBytes = emitter.emit();
}
catch (Exception ex)
{
problems.add(new InternalCompilerProblem(ex));
}
return new ABCBytesRequestResult(generatedBytes, problems.toArray(new ICompilerProblem[0]), Collections.<IEmbedData>emptySet());
}
finally
{
stopProfile(Operation.GET_ABC_BYTES);
}
}
@Override
protected ISWFTagsRequestResult handleSWFTagsRequest() throws InterruptedException
{
startProfile(Operation.GET_SWF_TAGS);
try
{
final IABCBytesRequestResult abcResult = getABCBytesRequest().get();
return new SWFTagsRequestResult(abcResult.getABCBytes(), qname);
}
finally
{
stopProfile(Operation.GET_SWF_TAGS);
}
}
}