blob: c00baa79bb80820154a7802b931d41ec53c6c90c [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.flex.compiler.internal.driver;
import java.io.IOException;
import java.util.Collection;
import org.apache.flex.compiler.common.DependencyType;
import org.apache.flex.compiler.definitions.IDefinition;
import org.apache.flex.compiler.internal.as.codegen.JSGeneratingReducer;
import org.apache.flex.compiler.internal.as.codegen.JSGenerator;
import org.apache.flex.compiler.internal.as.codegen.JSSharedData;
import org.apache.flex.compiler.internal.projects.CompilerProject;
import org.apache.flex.compiler.internal.projects.DefinitionPriority;
import org.apache.flex.compiler.internal.scopes.ASProjectScope;
import org.apache.flex.compiler.internal.units.ASCompilationUnit;
import org.apache.flex.compiler.problems.ICompilerProblem;
import org.apache.flex.compiler.targets.ITarget.TargetType;
import org.apache.flex.compiler.tree.as.IASNode;
import org.apache.flex.compiler.units.ICompilationUnit;
import org.apache.flex.compiler.units.requests.IABCBytesRequestResult;
import org.apache.flex.compiler.units.requests.IOutgoingDependenciesRequestResult;
import org.apache.flex.compiler.units.requests.ISyntaxTreeRequestResult;
/**
* JSCompilationUnit is the CompilationUnit for compiling ActionScript source
* files to JavasScript. JSCompilationUnit is derived from ASCompilationUnit and
* overrides the parts that generate the code. JSCompilationUnit also supports
* requests for two-pass compilation (see m_needsSecondPass).
* JSSourceFileHandler provides JSCompilationUnit for *.as files. JSDriver
* registers JSSourceFileHandler at FlexApplicationProject. This implementation
* is part of FalconJS. For more details on FalconJS see
* org.apache.flex.compiler.JSDriver
*/
public class JSCompilationUnit extends ASCompilationUnit
{
private IABCBytesRequestResult m_abcBytes = null;
private Boolean m_needsSecondPass = false;
private Boolean m_inCodeGen = false;
/**
* Create a compilation unit from an ABC file.
*
* @param project compiler project
* @param path ABC file path
* @throws IOException error
*/
public JSCompilationUnit(CompilerProject project, String path) throws IOException
{
this(project, path, DefinitionPriority.BasePriority.LIBRARY_PATH);
}
public JSCompilationUnit(CompilerProject project, String path, DefinitionPriority.BasePriority basePriority)
{
super(project, path, basePriority);
}
public JSCompilationUnit(CompilerProject project, String path, DefinitionPriority.BasePriority basePriority, String qname)
{
super(project, path, basePriority, 0, qname);
}
protected IABCBytesRequestResult _handleABCBytesRequest(Operation buildPhase) throws InterruptedException
{
// If JSEmitter.needsSecondPass() returns true, JSGenerator.generate() will return null during scanning,
// which will result in JSCompilationUnit::handleSemanticProblemsRequest not caching any abcBytes for
// handleABCBytesRequest. The net result is that JSGenerator.generate() will be called again in handleABCBytesRequest.
// This mechanic will ensure selective two-pass compilation.
if (m_abcBytes != null &&
!JSSharedData.instance.hasSymbols() && // Symbol support
!JSSharedData.instance.hasAnyClassInit()) // support for class inits
return m_abcBytes;
JSGenerator jsGenerator = new JSGenerator();
jsGenerator.m_compilationUnit = this;
jsGenerator.setBuildPhase(buildPhase);
// Need to force the file scope request to happen first to get the ASFileScope
// for this compilation unit registered with the project.
// ** TODO this is a hack!
getFileScopeRequest().get();
// This is also a hack! If there are embed directives, need to ensure
// semantic pass has finished, as that is what will generate the embed classes
// which are needed by codegen
if (buildPhase != Operation.GET_SEMANTIC_PROBLEMS)
{
// AJH this was deadlocking as getOutgoingDependencies calls handleABCBytes
if (buildPhase != Operation.GET_ABC_BYTES)
getOutgoingDependenciesRequest().get();
}
final ISyntaxTreeRequestResult fsr = getSyntaxTreeRequest().get();
final IASNode rootNode = fsr.getAST();
startProfile(buildPhase);
IABCBytesRequestResult result = jsGenerator.generate(getFilenameNoPath(), rootNode, this.getProject());
stopProfile(buildPhase);
m_needsSecondPass = jsGenerator.needsSecondPass();
return result;
}
@Override
protected IABCBytesRequestResult handleABCBytesRequest() throws InterruptedException
{
final IABCBytesRequestResult result = _handleABCBytesRequest(Operation.GET_ABC_BYTES);
/*
* // explicitly reference all classes this class depends on if(
* result.getProblems() == null || result.getProblems().length == 0 ) {
* final String code = new String( result.getABCBytes() ); if(
* code.contains(JSSharedData.REQUIRED_TAG_MARKER) ) { final
* ICompilationUnit cu = this; final Set<ICompilationUnit> deps = new
* HashSet<ICompilationUnit>(); deps.addAll(
* getProject().getDependencies(cu) ); if( !deps.isEmpty() ) { String
* depNames = ""; Boolean separator = false; final List<IDefinition>
* defs = MXMLJSC.getClassDefinitions( cu ); for( IDefinition def: defs
* ) { if( def instanceof ClassDefinition ) { final String defName =
* JSGeneratingReducer.createFullNameFromDefinition(def); if( defName !=
* null && !defName.isEmpty() ) { if( separator ) depNames += ":"; else
* separator = true; depNames += defName; } } }
* code.replaceFirst(JSSharedData.REQUIRED_TAG_MARKER, depNames); return
* new ABCBytesRequestResult(code.getBytes(), result.getProblems()); } }
* }
*/
return result;
}
@Override
protected IOutgoingDependenciesRequestResult handleOutgoingDependenciesRequest() throws InterruptedException
{
// Every CU is dependent on the class glue, which is implemented in browser.adobe.
// Add dependency from this JSCompilationUnit to browser.adobe's JSCompilationUnit.
addDependency(JSSharedData.JS_FRAMEWORK_NAME, DependencyType.INHERITANCE);
addDependency(JSSharedData.FRAMEWORK_CLASS, DependencyType.INHERITANCE);
IOutgoingDependenciesRequestResult result = super.handleOutgoingDependenciesRequest();
// SWFTarget::startBuildAndFindAllCompilationUnits() is called by SWFTarget::collectProblems(), which is called by SWFTarget::addToSWF() in JSDriver::main().
// This is our first pass. jsGenerator.generate() will return null if JSGeneratingReducer.getMember
// If JSEmitter.needsSecondPass() returns true, JSGenerator.generate() will return null during scanning,
// which will result in JSCompilationUnit::handleSemanticProblemsRequest not caching any abcBytes for
// handleABCBytesRequest. The net result is that JSGenerator.generate() will be called again in handleABCBytesRequest.
// This mechanic will ensure selective two-pass compilation.
if (result.getProblems().length == 0)
{
m_needsSecondPass = false;
m_abcBytes = _handleABCBytesRequest(Operation.GET_SEMANTIC_PROBLEMS);
if (m_needsSecondPass)
m_abcBytes = null;
}
return result;
}
public Boolean addDependency(String className, DependencyType dt)
{
if (JSGeneratingReducer.isReservedDataType(className))
return false;
final ICompilationUnit fromCU = this;
final CompilerProject compilerProject = this.getProject();
final ASProjectScope projectScope = compilerProject.getScope();
final IDefinition classDef = projectScope.findDefinitionByName(className);
if (classDef == null)
return false;
final ICompilationUnit toCU = projectScope.getCompilationUnitForDefinition(classDef);
if (fromCU == toCU)
return false;
// sharedData.verboseMessage( "Adding dependency: " + className );
compilerProject.addDependency(fromCU, toCU, dt);
return true;
}
@Override
public void startBuildAsync(TargetType targetType)
{
// super.startBuildAsync(targetType);
getSyntaxTreeRequest();
getFileScopeRequest();
getOutgoingDependenciesRequest();
// scanning and code generating phases need to be separated
// in order to create two distinct passes for m_needSecondPass.
if (m_inCodeGen)
{
getABCBytesRequest();
getSWFTagsRequest();
}
}
@Override
public void waitForBuildFinish(final Collection<ICompilerProblem> problems, TargetType targetType) throws InterruptedException
{
m_inCodeGen = true;
super.waitForBuildFinish(problems, targetType);
m_inCodeGen = false;
/*
* assert problems != null :
* "Expected 'problems'. Do not ignore problems."; //$NON-NLS-1$
* Collections.addAll(problems,
* getSyntaxTreeRequest().get().getProblems());
* Collections.addAll(problems,
* getFileScopeRequest().get().getProblems());
* Collections.addAll(problems,
* getSemanticProblemsRequest().get().getProblems());
* Collections.addAll(problems,
* getABCBytesRequest().get().getProblems());
* Collections.addAll(problems,
* getSWFTagsRequest().get().getProblems());
*/
}
}