blob: bfca01af8ac62f7ffccd1682a47304fb14fb0c0e [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.as.codegen;
import static org.apache.royale.abc.ABCConstants.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
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.MethodBodyInfo;
import org.apache.royale.abc.semantics.MethodInfo;
import org.apache.royale.abc.semantics.Name;
import org.apache.royale.abc.semantics.Namespace;
import org.apache.royale.abc.semantics.PooledValue;
import org.apache.royale.abc.visitors.IMethodBodyVisitor;
import org.apache.royale.abc.visitors.IMethodVisitor;
import org.apache.royale.abc.visitors.IScriptVisitor;
import org.apache.royale.abc.visitors.IVisitor;
import org.apache.royale.compiler.embedding.IEmbedData;
import org.apache.royale.compiler.exceptions.BURMAbortException;
import org.apache.royale.compiler.exceptions.CodegenInterruptedException;
import org.apache.royale.compiler.exceptions.MissingBuiltinException;
import org.apache.royale.compiler.internal.definitions.FunctionDefinition;
import org.apache.royale.compiler.internal.definitions.ParameterDefinition;
import org.apache.royale.compiler.internal.definitions.TypeDefinitionBase;
import org.apache.royale.compiler.internal.embedding.EmbedData;
import org.apache.royale.compiler.internal.semantics.SemanticUtils;
import org.apache.royale.compiler.internal.tree.as.FunctionNode;
import org.apache.royale.compiler.internal.units.EmbedCompilationUnitFactory;
import org.apache.royale.compiler.internal.units.requests.ABCBytesRequestResult;
import org.apache.royale.compiler.problems.CodegenInternalProblem;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.problems.MissingBuiltinProblem;
import org.apache.royale.compiler.problems.NonConstantParamInitializerProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
import org.apache.royale.compiler.tree.as.IFileNodeAccumulator;
import org.apache.royale.compiler.tree.as.IFunctionNode;
import org.apache.royale.compiler.tree.as.IParameterNode;
import org.apache.royale.compiler.units.requests.IABCBytesRequestResult;
import com.google.common.util.concurrent.Futures;
import org.apache.royale.utils.ASTUtil;
/**
* ABCGenerator is the public interface to the code generator.
*/
public class ABCGenerator implements ICodeGenerator
{
private static boolean DEFINITION_NORMALIZATION_DISABLED = false;
@Override
public ABCBytesRequestResult generate (String synthetic_name_prefix, IASNode root_node, ICompilerProject project) throws InterruptedException
{
return generate(null, false, synthetic_name_prefix, root_node, project, DEFINITION_NORMALIZATION_DISABLED, Collections.<String, String>emptyMap());
}
@Override
public ABCBytesRequestResult generate(ExecutorService executorService, boolean useParallelCodegen,
String synthetic_name_prefix, IASNode root_node,
ICompilerProject project, boolean inInvisibleCompilationUnit,
Map<String, String> encodedDebugFiles)
throws InterruptedException
{
// Set up the global lexical scope.
final GlobalLexicalScope global_scope = new GlobalLexicalScope(
project, this, synthetic_name_prefix, inInvisibleCompilationUnit, useParallelCodegen, encodedDebugFiles);
final ABCEmitter emitter = (ABCEmitter)global_scope.getEmitter();
// CG targets the latest version - these ABCs can be postprocessed to downgrade to previous versions
emitter.visit(ABCConstants.VERSION_ABC_MAJOR_FP10, ABCConstants.VERSION_ABC_MINOR_FP10);
IScriptVisitor sv = emitter.visitScript();
sv.visit();
MethodInfo init_method = new MethodInfo();
sv.visitInit(init_method);
MethodBodyInfo init_body = new MethodBodyInfo();
init_body.setMethodInfo(init_method);
IMethodVisitor mv = emitter.visitMethod(init_method);
mv.visit();
IMethodBodyVisitor mbv = mv.visitBody(init_body);
mbv.visit();
global_scope.traitsVisitor = sv.visitTraits();
global_scope.setMethodInfo(init_method);
global_scope.methodBodyVisitor = mbv;
global_scope.setInitialControlFlowRegionNode(root_node);
// Process global directives.
GlobalDirectiveProcessor top_level_processor = new GlobalDirectiveProcessor(executorService, useParallelCodegen, global_scope, emitter);
boolean fatal_error_encountered = false;
try
{
top_level_processor.traverse(root_node);
}
catch (MissingBuiltinException e)
{
global_scope.addProblem(new MissingBuiltinProblem(root_node, e.getBuiltinName()));
fatal_error_encountered = true;
}
catch (CodegenInterruptedException e)
{
// Unwrap the InterruptedException and rethrow it.
throw e.getException();
}
top_level_processor.finish();
byte[] generatedBytes = IABCBytesRequestResult.ZEROBYTES;
if ( !fatal_error_encountered )
{
// Initialize the init script.
InstructionList script_init_insns = new InstructionList();
script_init_insns.addInstruction(OP_getlocal0);
script_init_insns.addInstruction(OP_pushscope);
script_init_insns.addAll(global_scope.getInitInstructions());
script_init_insns.addAll(top_level_processor.directiveInsns);
if ( script_init_insns.canFallThrough() || script_init_insns.hasPendingLabels() )
script_init_insns.addInstruction(OP_returnvoid);
// Allocate temps beginning with register 1,
// register 0 is reserved for "this" global.
global_scope.initializeTempRegisters(1);
// Make any vistEnd method calls
// that were deferred.
// callVisitEnds must be called on the same thread
// that original called ABCGenerator.generate ( this method ).
global_scope.callVisitEnds();
mbv.visitInstructionList(script_init_insns);
mbv.visitEnd();
mv.visitEnd();
global_scope.traitsVisitor.visitEnd();
sv.visitEnd();
try
{
generatedBytes = emitter.emit();
}
catch ( Exception e )
{
global_scope.addProblem(new CodegenInternalProblem(root_node, e));
}
}
Set<EmbedData> embeds = global_scope.getEmbeds();
EmbedCompilationUnitFactory.collectEmbedDatas(project, (IFileNodeAccumulator)root_node, embeds, global_scope.getProblems());
Set<IEmbedData> iembeds = new HashSet<IEmbedData>();
for (EmbedData embed : embeds)
iembeds.add(embed);
ICompilerProblem[] problemsArray = global_scope.getProblems().toArray(IABCBytesRequestResult.ZEROPROBLEMS);
return new ABCBytesRequestResult(generatedBytes, problemsArray, iembeds);
}
/**
* Translate an AST into ABC instructions.
* @param subtree - the CM subtree.
* @param goal_state - the desired goal state.
* One of the nonterminal states in CmcEmitter,
* or 0 if you're feeling lucky and are willing
* to accept whatever instruction sequence the
* BURM decides is optimal.
* @param scope - the active lexical scope.
* @return a list of ABC instructions.
*/
public InstructionList generateInstructions (IASNode subtree, int goal_state, LexicalScope scope)
{
return generateInstructions(subtree, goal_state, scope, null);
}
/**
* Translate an AST into ABC instructions.
* @param subtree - the CM subtree.
* @param goal_state - the desired goal state.
* One of the nonterminal states in CmcEmitter,
* or 0 if you're feeling lucky and are willing
* to accept whatever instruction sequence the
* BURM decides is optimal.
* @param scope - the active lexical scope.
* @param instance_init_insns - a list of instance
* initialization instructions collected outside
* a constructor body that must be included in the
* constructor.
* @post if instance_init_insns is not null then the
* method will have been processed as and marked
* as a constructor.
* @return a list of ABC instructions.
*/
public InstructionList generateInstructions(IASNode subtree, int goal_state, LexicalScope scope, InstructionList instance_init_insns)
{
CmcEmitter burm = new CmcEmitter();
burm.reducer = new ABCGeneratingReducer();
burm.reducer.setCurrentscope(scope);
burm.reducer.setInstanceInitializers(instance_init_insns);
try {
burm.burm(subtree, goal_state);
return ((InstructionList)burm.getResult());
}
catch ( Exception cant_reduce) {
handleBurmError(burm, subtree, cant_reduce, scope);
return new InstructionList();
}
}
/**
* Generate code for a function declaration, and put its initialization code
* on the relevant instruction list.
* <p>
* Post condition: if instance_init_insns is not null then the method will
* have been processed as and marked as a constructor.
*
* @param func the function declaration node.
* @param enclosing_scope the lexical scope in which the function was
* defined.
* @param instance_init_insns a list of instance initialization instructions
* collected outside a constructor body that must be included in the
* constructor.
* @return {@link MethodInfo} created for the function.
*/
public MethodInfo generateFunction (FunctionNode func, LexicalScope enclosing_scope, InstructionList instance_init_insns, Name alternate_name)
{
MethodInfo mi = createMethodInfo(enclosing_scope, func, alternate_name);
if (mi.isNative())
{
generateNativeMethod(func, mi, enclosing_scope);
}
else
{
generateMethodBodyForFunction(mi, func, enclosing_scope, instance_init_insns);
}
func.discardFunctionBody();
return mi;
}
/**
* Generate code for a function declaration, using a background thread
* provided by the specified {@link ExecutorService}.
*
* @param executorService {@link ExecutorService} used to do work in other
* threads.
* @param func the function declaration node.
* @param enclosing_scope the lexical scope in which the function was
* defined.
* @return {@link GenerateFunctionInParallelResult} which can be used to
* wait for code generation of the specified function to complete and to
* extract the {@link MethodInfo} created for the specified function. The
* {@link MethodInfo} may be extracted immediately after this method
* completes ( you don't have to wait for code generation of the specified
* function complete ).
*/
public GenerateFunctionInParallelResult generateFunctionInParallel (ExecutorService executorService, FunctionNode func, LexicalScope enclosing_scope)
{
MethodInfo mi = createMethodInfo(enclosing_scope, func, null);
if (mi.isNative())
{
generateNativeMethod(func, mi, enclosing_scope);
return new GenerateFunctionInParallelResult(Futures.immediateFuture(null), mi, Collections.<IVisitor>emptyList());
}
GenerateFunctionRunnable runnable = new GenerateFunctionRunnable(mi, func, enclosing_scope);
Future<?> future = executorService.submit(runnable);
return new GenerateFunctionInParallelResult(future, mi, runnable.getDeferredVisitEndsList());
}
/**
* Helper method used by <code>generateFunction()</code>.
* @param func - the function declaration node.
* @param mi - the MethodInfo describing the signature
* @param enclosing_scope - the lexical scope
* in which the handler method is autogenerated.
*/
void generateNativeMethod(FunctionNode func, MethodInfo mi,
LexicalScope enclosing_scope)
{
enclosing_scope.getMethodBodySemanticChecker().checkNativeMethod(func);
// don't need to create a new scope, so just use the enclosing scope
// to get a handle to the emitter
IMethodVisitor mv = enclosing_scope.getEmitter().visitMethod(mi);
// Just visit the method info. Do NOT generate a body
// for native methods
mv.visit();
// For non native methods, the return type is set by the burm,
// but for native types, as the burm isn't run, we need to set
// the return type here.
String returnType = func.getReturnType();
int lastDotIndex = returnType.lastIndexOf('.');
if (lastDotIndex != -1)
{
Namespace ns = new Namespace(CONSTANT_PackageNs, returnType.substring(0, lastDotIndex));
String baseName = returnType.substring(lastDotIndex + 1);
mi.setReturnType(new Name(ns, baseName));
}
else
{
mi.setReturnType(new Name(returnType));
}
mv.visitEnd();
}
/**
* Helper method used by <code>generateFunction()</code> (and also by
* <code>generateEventHandler()</code> in MXMLDocumentDirectiveProcessor).
* @param mi - the MethodInfo describing the signature
* @param node - the FunctionNode or MXMLEventSpecifierNode.
* @param enclosing_scope - the lexical scope
* in which the handler method is autogenerated.
* @param instance_init_insns - a list of instance
* initialization instructions collected outside
* a constructor body that must be included in the
* constructor.
* @post if instance_init_insns is not null then the
* method will have been processed as and marked
* as a constructor.
*/
public void generateMethodBodyForFunction(MethodInfo mi, IASNode node,
LexicalScope enclosing_scope,
InstructionList instance_init_insns)
{
List<IVisitor> deferredVisitEnds = new LinkedList<IVisitor>();
generateMethodBodyForFunction(deferredVisitEnds, mi, node, enclosing_scope, instance_init_insns);
for (IVisitor v : deferredVisitEnds)
v.visitEnd();
}
private void generateMethodBodyForFunction(List<IVisitor> deferredVisitEnds,
MethodInfo mi, IASNode node,
LexicalScope enclosing_scope,
InstructionList instance_init_insns)
{
assert node != null;
final boolean is_constructor = SemanticUtils.isInConstructor(node);
// Set up a lexical scope for this function.
LexicalScope function_scope = enclosing_scope.pushFrame();
// If instance_init_insns is not null, then the new
// scope needs to assume ownership of the initializers'
// data, such as hasnext2 instruction initializers.
if ( instance_init_insns != null )
{
function_scope.transferInitializerData();
}
IMethodVisitor mv = function_scope.getEmitter().visitMethod(mi);
mv.visit();
MethodBodyInfo mbi = new MethodBodyInfo();
mbi.setMethodInfo(mi);
IMethodBodyVisitor mbv = mv.visitBody(mbi);
mbv.visit();
function_scope.methodBodyVisitor = mbv;
function_scope.traitsVisitor = mbv.visitTraits();
function_scope.setMethodInfo(mi);
if ( is_constructor )
function_scope.getMethodBodySemanticChecker().enterConstructor();
InstructionList insns = null;
if (node instanceof IFunctionNode)
function_scope.setInitialControlFlowRegionNode(((IFunctionNode)node).getScopedNode());
else
function_scope.setInitialControlFlowRegionNode((IASNode)node);
// If we are passed a single node, generate its instructions
insns = generateInstructions((IASNode)node, CmcEmitter.__function_NT, function_scope, instance_init_insns);
if ( is_constructor )
function_scope.getMethodBodySemanticChecker().leaveConstructor();
assert insns != null;
// Make any vistEnd method calls
// that were deferred.
// callVisitEnds must be called on the same thread
// that started code generation.
function_scope.addVisitEndsToList(deferredVisitEnds);
mbv.visitInstructionList(insns);
deferredVisitEnds.add(function_scope.traitsVisitor);
deferredVisitEnds.add(mbv);
deferredVisitEnds.add(mv);
// Perform semantic checks that require the control flow graph.
function_scope.getMethodBodySemanticChecker().checkControlFlow( node, mi, mbi );
}
/**
* Helper method used by mxml databinding codegen to emit an anonymous
* function used by an mxml data binding destination function. Example:
* <p>
* If the expression node is a.b.c, this method will generate a funtion
* whose source would look something like this:
*
* <pre>
* function (arg:*):void { a.b.c = arg; }
* </pre>
*
* @param mi - the MethodInfo describing the signature
* @param setterExpression {@link IExpressionNode} that is the destination
* expression of a mxml data binding.
* @param enclosing_scope {@link LexicalScope} for the class initializer
* that encloses the function being generated.
*/
public void generateMXMLDataBindingSetterFunction (MethodInfo mi, IExpressionNode setterExpression, LexicalScope enclosing_scope)
{
IMethodVisitor methodVisitor = enclosing_scope.getEmitter().visitMethod(mi);
methodVisitor.visit();
MethodBodyInfo methodBodyInfo = new MethodBodyInfo();
methodBodyInfo.setMethodInfo(mi);
IMethodBodyVisitor methodBodyVisitor = methodVisitor.visitBody(methodBodyInfo);
methodBodyVisitor.visit();
// Set up a lexical scope for this function.
LexicalScope function_scope = enclosing_scope.pushFrame();
function_scope.methodBodyVisitor = methodBodyVisitor;
function_scope.traitsVisitor = methodBodyVisitor.visitTraits();
function_scope.setMethodInfo(mi);
InstructionList functionBody;
if (setterExpression instanceof InstructionListNode)
functionBody = ((InstructionListNode)setterExpression).getInstructions();
else
functionBody = generateInstructions(setterExpression, CmcEmitter.__mxml_data_binding_setter_expression_NT, function_scope, null);
functionBody.addInstruction(OP_returnvoid);
methodBodyVisitor.visitInstructionList(functionBody);
methodBodyVisitor.visitEnd();
methodVisitor.visitEnd();
}
/**
* Helper method used by databinding codegen to emit an anonymous function
* based on a list of {@link IExpressionNode}'s. This method emits a
* function that contains code that evaluates each expression in the list
* and adds the expressions together with {@link ABCConstants#OP_add}.
*
* @param mi - the MethodInfo describing the signature
* @param nodes - a {@link List} of {@link IExpressionNode}'s to be
* codegen'd.
* @param enclosing_scope {@link LexicalScope} for the class initializer
* that encloses the function being generated.
*/
public void generateMXMLDataBindingGetterFunction (MethodInfo mi, List<IExpressionNode> nodes,
LexicalScope enclosing_scope)
{
IMethodVisitor methodVisitor = enclosing_scope.getEmitter().visitMethod(mi);
methodVisitor.visit();
MethodBodyInfo methodBodyInfo = new MethodBodyInfo();
methodBodyInfo.setMethodInfo(mi);
IMethodBodyVisitor methodBodyVisitor = methodVisitor.visitBody(methodBodyInfo);
methodBodyVisitor.visit();
// Set up a lexical scope for this function.
LexicalScope function_scope = enclosing_scope.pushFrame();
function_scope.methodBodyVisitor = methodBodyVisitor;
function_scope.traitsVisitor = methodBodyVisitor.visitTraits();
function_scope.setMethodInfo(mi);
InstructionList functionBody = null;
// for a list of nodes, generate all their instructions and add the results together.
// typically we are doing this to concatenate strings
for (IExpressionNode expressionNode : nodes)
{
InstructionList instructionsForExpression = generateInstructions(expressionNode, CmcEmitter.__expression_NT, function_scope, null);
if (functionBody == null)
{
// First one in the list makes a new IL and puts
// instructions into it
functionBody = instructionsForExpression;
}
else
{
// successive children generate into the same IL, then add the results
functionBody.addAll(instructionsForExpression);
functionBody.addInstruction(OP_add);
}
}
functionBody.addInstruction(OP_returnvalue);
methodBodyVisitor.visitInstructionList(functionBody);
function_scope.traitsVisitor.visitEnd();
methodBodyVisitor.visitEnd();
methodVisitor.visitEnd();
}
/**
* Creates a MethodInfo specifying the signature of a method
* declared by a FunctionNode.
* @param func - A FunctionNode representing a method declaration.
* @return The MethodInfo specifying the signature of the method.
*/
@Override
public MethodInfo createMethodInfo (LexicalScope scope, FunctionNode func, Name alternate_name)
{
return createMethodInfoWithOptionalDefaultArgumentValues(scope, func, false, alternate_name);
}
/**
**
* Creates a MethodInfo specifying the signature of a method
* declared by a FunctionNode, and adds in the information for any
* default argument values.
*
* @param func - A FunctionNode representing a method declaration.
* @return The MethodInfo specifying the signature of the method.
*
* Will generate a compiler problem is the default value is bad
*/
@Override
public MethodInfo createMethodInfoWithDefaultArgumentValues (LexicalScope scope, FunctionNode func)
{
return createMethodInfoWithOptionalDefaultArgumentValues(scope, func, true, null);
}
private static MethodInfo createMethodInfoWithOptionalDefaultArgumentValues(LexicalScope scope, FunctionNode func,
boolean addDefalutValues, Name alternate_name)
{
MethodInfo mi = new MethodInfo();
mi.setMethodName(alternate_name != null ? alternate_name.getBaseName() : func.getName());
FunctionDefinition funcDef = func.getDefinition();
// Marshal the function's arguments.
ParameterDefinition[] args = funcDef.getParameters();
List<String> param_names = new ArrayList<String>();
ICompilerProject project = scope.getProject();
if ( args.length > 0 )
{
Vector<Name> method_args = new Vector<Name>();
for ( ParameterDefinition arg: args)
{
TypeDefinitionBase arg_type = (TypeDefinitionBase)arg.resolveType(project);
Name type_name = arg_type != null ? arg_type.getMName(project) : null;
if ( arg.isRest() )
{
mi.setFlags( (byte)(mi.getFlags() | ABCConstants.NEED_REST) );
}
else
{
method_args.add(type_name);
param_names.add(arg.getBaseName());
}
// If appropriate, tell the MethodInfo about the default parameter value
if (addDefalutValues && arg.hasDefaultValue())
{
Object initValue = arg.resolveInitialValue(project);
// init value might resolve to null, if the source code is bad
if (initValue == null)
{
IParameterNode paramNode = arg.getNode();
scope.addProblem(new NonConstantParamInitializerProblem(paramNode.getAssignedValueNode()));
// re-write non-constant expression to undefined, so resulting ABC will pass the verifier.
initValue = ABCConstants.UNDEFINED_VALUE;
}
mi.addDefaultValue(new PooledValue(initValue));
}
}
mi.setParamTypes(method_args);
mi.setParamNames(param_names);
}
// check for native modifier
if ( func.getDefinition().isNative() )
{
mi.setFlags( (byte)(mi.getFlags() | ABCConstants.NATIVE) );
}
// The return type will be set by the BURM.
return mi;
}
/**
* Helper method to expose the constant folding code to clients outside of the burm, such
* as org.apache.royale.compiler.internal.as.definitions.ConstantDefinition.
* @param subtree the tree to generate a constant value for
* @param project the project to use to evaluate the tree
* @return the constant value for the subtree, or null if a constant value can't be determined
*/
@Override
public IConstantValue generateConstantValue (IASNode subtree, ICompilerProject project)
{
IConstantValue result = null;
LexicalScope scope = new GlobalLexicalScope(project, this);
if ( subtree != null )
{
try
{
Object value = reduceSubtree(subtree, scope, CmcEmitter.__constant_value_NT);
result = new ConstantValue(value, scope.getProblems());
}
catch ( Exception cant_reduce)
{
// Can't generate a constant value, just return null
// Do not add a problem for this exception as it could be a non-constant
// initializer like: var foo = new Date();
}
}
return result;
}
/**
* Reduce an AST to its equivalent ABC structures.
* @param subtree - the root of the AST subtree.
* May be null, in which case this routine returns null.
* @param scope - the active LexicalScope.
* @param goal - the BURM's goal state. One of the CmcEmitter.__foo_NT constants.
* @return the result of reducing the subtree to the desired goal state,
* or null if the input subtree was null.
* @throws Exception from the BURM if the computation didn't succeed or was interrupted.
*/
public Object reduceSubtree (IASNode subtree, LexicalScope scope, int goal)
throws Exception
{
CmcEmitter burm = new CmcEmitter();
burm.reducer = new ABCGeneratingReducer();
burm.reducer.setCurrentscope(scope);
burm.burm(subtree, CmcEmitter.__constant_value_NT);
return burm.getResult();
}
/**
* Handle an error from a BURM: emit diagnostics and bump the error count.
* @param n - the subtree that was to be reduced.
* @param ex - the exception.
*/
private void handleBurmError(CmcEmitter burm, IASNode n, Exception ex, LexicalScope scope)
{
if ( ex instanceof CodegenInterruptedException )
{
// If the exception is an InterruptedException, do nothing, as not
// a real error. The incremental flow kicked in and interrupted
// the current work, so just throw away the current work and carry
// on our merry way.
// No problem should be reported in this case.
scope.getProblems().clear();
return;
}
else if ( ! ( ex instanceof BURMAbortException ) )
{
scope.addProblem( new CodegenInternalProblem(n, ex) );
}
DumpBURMState.dump(burm, n);
}
/**
* Implementation of {@link Runnable} that is used to code generate a
* function on a background thread.
*/
private class GenerateFunctionRunnable implements Runnable
{
GenerateFunctionRunnable(MethodInfo methodInfo, FunctionNode func, LexicalScope enclosing_scope)
{
this.methodInfo = methodInfo;
this.functionNode = func;
this.enclosingScope = enclosing_scope;
this.deferredVisitEnds = new LinkedList<IVisitor>();
}
private final MethodInfo methodInfo;
private final FunctionNode functionNode;
private final LexicalScope enclosingScope;
private final List<IVisitor> deferredVisitEnds;
@Override
public void run()
{
assert !methodInfo.isNative() : "Native methods should be handled in the main thread and not be dispatched to a background thread!";
functionNode.parseFunctionBody(enclosingScope.getProblems());
ASTUtil.processFunctionNode(functionNode, enclosingScope.getProject());
generateMethodBodyForFunction(deferredVisitEnds, methodInfo, functionNode, enclosingScope, null);
}
public List<IVisitor> getDeferredVisitEndsList()
{
return deferredVisitEnds;
}
}
/**
* Get an ICodeGeneratorFactory that will always return the same ABCGenerator instance
*/
public static ICodeGeneratorFactory getABCGeneratorFactory()
{
return new ICodeGeneratorFactory()
{
public ICodeGenerator get ()
{
return new ABCGenerator();
}
};
}
/**
* Represents the result of {@link #generateConstantValue}(}.
* <p>
* In addition to producing the constant value itself,
* the constant reduction process can also produce compiler problems.
*/
public static final class ConstantValue implements IConstantValue
{
public ConstantValue(Object value, Collection<ICompilerProblem> problems)
{
this.value = value;
this.problems = problems;
}
private final Object value;
private final Collection<ICompilerProblem> problems;
@Override
public Object getValue()
{
return value;
}
@Override
public Collection<ICompilerProblem> getProblems()
{
return problems;
}
}
}