blob: 781aaa15e6177af4ec6844eae4575a49bb277024 [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.codegen.as;
import java.util.List;
import org.apache.royale.compiler.codegen.as.IASEmitter;
import org.apache.royale.compiler.definitions.IPackageDefinition;
import org.apache.royale.compiler.internal.semantics.SemanticUtils;
import org.apache.royale.compiler.internal.tree.as.LabeledStatementNode;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.problems.InternalCompilerProblem2;
import org.apache.royale.compiler.projects.IASProject;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IBinaryOperatorNode;
import org.apache.royale.compiler.tree.as.IBlockNode;
import org.apache.royale.compiler.tree.as.ICatchNode;
import org.apache.royale.compiler.tree.as.IClassNode;
import org.apache.royale.compiler.tree.as.IContainerNode;
import org.apache.royale.compiler.tree.as.IDefaultXMLNamespaceNode;
import org.apache.royale.compiler.tree.as.IDynamicAccessNode;
import org.apache.royale.compiler.tree.as.IEmbedNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
import org.apache.royale.compiler.tree.as.IFileNode;
import org.apache.royale.compiler.tree.as.IForLoopNode;
import org.apache.royale.compiler.tree.as.IForLoopNode.ForLoopKind;
import org.apache.royale.compiler.tree.as.IFunctionCallNode;
import org.apache.royale.compiler.tree.as.IFunctionNode;
import org.apache.royale.compiler.tree.as.IFunctionObjectNode;
import org.apache.royale.compiler.tree.as.IGetterNode;
import org.apache.royale.compiler.tree.as.IIdentifierNode;
import org.apache.royale.compiler.tree.as.IIfNode;
import org.apache.royale.compiler.tree.as.IImportNode;
import org.apache.royale.compiler.tree.as.IInterfaceNode;
import org.apache.royale.compiler.tree.as.IIterationFlowNode;
import org.apache.royale.compiler.tree.as.IKeywordNode;
import org.apache.royale.compiler.tree.as.ILanguageIdentifierNode;
import org.apache.royale.compiler.tree.as.ILiteralContainerNode;
import org.apache.royale.compiler.tree.as.ILiteralNode;
import org.apache.royale.compiler.tree.as.ILiteralNode.LiteralType;
import org.apache.royale.compiler.tree.as.IMemberAccessExpressionNode;
import org.apache.royale.compiler.tree.as.INamespaceAccessExpressionNode;
import org.apache.royale.compiler.tree.as.INamespaceNode;
import org.apache.royale.compiler.tree.as.INumericLiteralNode;
import org.apache.royale.compiler.tree.as.IObjectLiteralValuePairNode;
import org.apache.royale.compiler.tree.as.IPackageNode;
import org.apache.royale.compiler.tree.as.IParameterNode;
import org.apache.royale.compiler.tree.as.IReturnNode;
import org.apache.royale.compiler.tree.as.ISetterNode;
import org.apache.royale.compiler.tree.as.ISwitchNode;
import org.apache.royale.compiler.tree.as.ITerminalNode;
import org.apache.royale.compiler.tree.as.ITernaryOperatorNode;
import org.apache.royale.compiler.tree.as.IThrowNode;
import org.apache.royale.compiler.tree.as.ITryNode;
import org.apache.royale.compiler.tree.as.ITypedExpressionNode;
import org.apache.royale.compiler.tree.as.IUnaryOperatorNode;
import org.apache.royale.compiler.tree.as.IUseNamespaceNode;
import org.apache.royale.compiler.tree.as.IVariableExpressionNode;
import org.apache.royale.compiler.tree.as.IVariableNode;
import org.apache.royale.compiler.tree.as.IWhileLoopNode;
import org.apache.royale.compiler.tree.as.IWhileLoopNode.WhileLoopKind;
import org.apache.royale.compiler.tree.as.IWithNode;
import org.apache.royale.compiler.tree.metadata.IMetaTagNode;
import org.apache.royale.compiler.tree.metadata.IMetaTagsNode;
import org.apache.royale.compiler.units.ICompilationUnit;
import org.apache.royale.compiler.utils.DefinitionUtils;
import org.apache.royale.compiler.visitor.IASNodeStrategy;
import org.apache.royale.compiler.visitor.as.IASBlockVisitor;
import org.apache.royale.compiler.visitor.as.IASBlockWalker;
/**
* A base implementation of the {@link IASBlockVisitor} that will walk the
* {@link ICompilationUnit}s AST {@link IASNode} hierarchy.
*
* @author Michael Schmalle
*/
public class ASBlockWalker implements IASBlockVisitor, IASBlockWalker
{
boolean isDebug;
private IASEmitter emitter;
@Override
public IASEmitter getEmitter()
{
return emitter;
}
private final List<ICompilerProblem> errors;
public List<ICompilerProblem> getErrors()
{
return errors;
}
//----------------------------------
// strategy
//----------------------------------
private IASNodeStrategy strategy;
public IASNodeStrategy getStrategy()
{
return strategy;
}
public void setStrategy(IASNodeStrategy value)
{
strategy = value;
}
//----------------------------------
// project
//----------------------------------
private IASProject project;
@Override
public IASProject getProject()
{
return project;
}
public ASBlockWalker(List<ICompilerProblem> errors, IASProject project,
IASEmitter emitter)
{
this.errors = errors;
this.project = project;
this.emitter = emitter;
emitter.setWalker(this);
}
//--------------------------------------------------------------------------
// File level
//--------------------------------------------------------------------------
@Override
public void walk(IASNode node)
{
try {
getStrategy().handle(node);
}
catch (Exception e)
{
String sp = String.format("%s line %d column %d", node.getSourcePath(), node.getLine() + 1, node.getColumn());
if (node.getSourcePath() == null)
{
IASNode parent = node.getParent();
sp = String.format("%s line %d column %d", parent.getSourcePath(), parent.getLine() + 1, parent.getColumn());
}
InternalCompilerProblem2 problem = new InternalCompilerProblem2(sp, e, "ASBlockWalker");
errors.add(problem);
}
}
@Override
public void visitCompilationUnit(ICompilationUnit unit)
{
debug("visitCompilationUnit()");
IFileNode node = null;
try
{
node = (IFileNode) unit.getSyntaxTreeRequest().get().getAST();
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
walk(node);
}
@Override
public void visitFile(IFileNode node)
{
debug("visitFile()");
boolean foundPackage = false;
int nodeCount = node.getChildCount();
for (int i = 0; i < nodeCount; i++)
{
IASNode pnode = node.getChild(i);
// ToDo (erikdebruin): handle other types of root node, such as when
// there is no wrapping Package or Class, like
// in mx.core.Version
if (pnode != null)
{
boolean isPackage = pnode instanceof IPackageNode;
boolean isAllowedAfterPackage = false;
if(isPackage)
{
foundPackage = true;
}
else if(foundPackage)
{
isAllowedAfterPackage = pnode instanceof IInterfaceNode
|| pnode instanceof IClassNode
|| pnode instanceof IFunctionNode
|| pnode instanceof INamespaceNode
|| pnode instanceof IVariableNode;
}
if(isPackage || isAllowedAfterPackage)
{
walk(pnode);
if (i < nodeCount - 1)
{
emitter.writeNewline();
emitter.writeNewline();
emitter.writeNewline();
}
}
}
}
}
@Override
public void visitPackage(IPackageNode node)
{
debug("visitPackage()");
IPackageDefinition definition = (IPackageDefinition) node
.getDefinition();
emitter.emitPackageHeader(definition);
emitter.emitPackageHeaderContents(definition);
emitter.emitPackageContents(definition);
emitter.emitPackageFooter(definition);
}
//--------------------------------------------------------------------------
// Type level
//--------------------------------------------------------------------------
@Override
public void visitClass(IClassNode node)
{
debug("visitClass()");
emitter.emitClass(node);
}
@Override
public void visitInterface(IInterfaceNode node)
{
debug("visitInterface()");
emitter.emitInterface(node);
}
@Override
public void visitVariable(IVariableNode node)
{
debug("visitVariable()");
if (SemanticUtils.isPackageDefinition(node.getDefinition()) ||
SemanticUtils.isMemberDefinition(node.getDefinition()) ||
node.getParent() instanceof IFileNode)
{
emitter.emitField(node);
}
else
{
emitter.emitVarDeclaration(node);
}
}
@Override
public void visitFunction(IFunctionNode node)
{
debug("visitFunction()");
if (SemanticUtils.isPackageDefinition(node.getDefinition()) ||
DefinitionUtils.isMemberDefinition(node.getDefinition()) ||
node.getParent() instanceof IFileNode)
{
emitter.emitMethod(node);
}
else
{
emitter.emitLocalNamedFunction(node);
}
}
@Override
public void visitParameter(IParameterNode node)
{
debug("visitParameter()");
emitter.emitParameter(node);
}
@Override
public void visitGetter(IGetterNode node)
{
debug("visitGetter()");
emitter.emitGetAccessor(node);
}
@Override
public void visitSetter(ISetterNode node)
{
debug("visitSetter()");
emitter.emitSetAccessor(node);
}
@Override
public void visitNamespace(INamespaceNode node)
{
debug("visitNamespace()");
emitter.emitNamespace(node);
}
@Override
public void visitFunctionCall(IFunctionCallNode node)
{
debug("visitFunctionCall()");
emitter.emitFunctionCall(node);
}
@Override
public void visitBlock(IBlockNode node)
{
debug("visitBlock()");
ASTNodeID pnodeId = node.getParent().getNodeID();
// (erikdebruin) 'goog' also needs access to the block header for
// accessor function blocks
if (pnodeId == ASTNodeID.FunctionID || pnodeId == ASTNodeID.GetterID
|| pnodeId == ASTNodeID.SetterID)
{
emitter.emitFunctionBlockHeader((IFunctionNode) node.getParent());
}
final int len = node.getChildCount();
for (int i = 0; i < len; i++)
{
emitter.emitStatement(node.getChild(i));
}
}
@Override
public void visitIf(IIfNode node)
{
debug("visitIf()");
emitter.emitIf(node);
}
@Override
public void visitForLoop(IForLoopNode node)
{
debug("visitForLoop(" + node.getKind() + ")");
if (node.getKind() == ForLoopKind.FOR)
visitFor(node);
else if (node.getKind() == ForLoopKind.FOR_EACH)
visitForEach(node);
}
protected void visitForEach(IForLoopNode node)
{
debug("visitForEach()");
emitter.emitForEachLoop(node);
}
protected void visitFor(IForLoopNode node)
{
debug("visitFor()");
emitter.emitForLoop(node);
}
@Override
public void visitSwitch(ISwitchNode node)
{
debug("visitSwitch()");
emitter.emitSwitch(node);
}
@Override
public void visitWhileLoop(IWhileLoopNode node)
{
debug("visitWhileLoopNode()");
if (node.getKind() == WhileLoopKind.WHILE)
{
emitter.emitWhileLoop(node);
}
else if (node.getKind() == WhileLoopKind.DO)
{
emitter.emitDoLoop(node);
}
}
@Override
public void visitWith(IWithNode node)
{
debug("visitWith()");
emitter.emitWith(node);
}
@Override
public void visitThrow(IThrowNode node)
{
debug("visitThrow()");
emitter.emitThrow(node);
}
@Override
public void visitTry(ITryNode node)
{
debug("visitTry()");
emitter.emitTry(node);
}
@Override
public void visitCatch(ICatchNode node)
{
debug("visitCatch()");
emitter.emitCatch(node);
}
@Override
public void visitIterationFlow(IIterationFlowNode node)
{
debug("visitIterationFlow()");
emitter.emitIterationFlow(node);
}
@Override
public void visitIdentifier(IIdentifierNode node)
{
debug("visitIdentifier(" + node.getName() + ")");
emitter.emitIdentifier(node);
}
@Override
public void visitNumericLiteral(INumericLiteralNode node)
{
debug("visitNumericLiteral(" + node.getNumericValue() + ")");
emitter.emitNumericLiteral(node);
}
@Override
public void visitDefaultXMLNamespace(IDefaultXMLNamespaceNode node)
{
debug("visitDefaultXMLNamespace()");
emitter.emitE4XDefaultNamespaceDirective(node);
}
@Override
public void visitKeyword(IKeywordNode node)
{
debug("visitKeyword(" + node.getNodeID().getParaphrase() + ")");
emitter.emitKeyword(node);
}
@Override
public void visitLiteral(ILiteralNode node)
{
debug("visitLiteral(" + node.getValue() + ")");
if (node.getLiteralType() == LiteralType.NUMBER
|| node.getLiteralType() == LiteralType.BOOLEAN
|| node.getLiteralType() == LiteralType.NULL
|| node.getLiteralType() == LiteralType.NUMBER
|| node.getLiteralType() == LiteralType.REGEXP
|| node.getLiteralType() == LiteralType.STRING
|| node.getLiteralType() == LiteralType.XML
|| node.getLiteralType() == LiteralType.VOID)
{
emitter.emitLiteral(node);
}
else if (node.getLiteralType() == LiteralType.ARRAY
|| node.getLiteralType() == LiteralType.OBJECT
|| node.getLiteralType() == LiteralType.VECTOR
|| node.getLiteralType() == LiteralType.XMLLIST)
{
emitter.emitLiteralContainer((ILiteralContainerNode) node);
}
}
@Override
public void visitMemberAccessExpression(IMemberAccessExpressionNode node)
{
debug("visitMemberAccessExpression()");
emitter.emitMemberAccessExpression(node);
}
@Override
public void visitNamespaceAccessExpression(
INamespaceAccessExpressionNode node)
{
debug("visitNamespaceAccessExpression()");
emitter.emitNamespaceAccessExpression(node);
}
@Override
public void visitDynamicAccess(IDynamicAccessNode node)
{
debug("visitDynamicAccess()");
emitter.emitDynamicAccess(node);
}
@Override
public void visitTypedExpression(ITypedExpressionNode node)
{
debug("visitITypedExpression()");
emitter.emitTypedExpression(node);
}
@Override
public void visitAsOperator(IBinaryOperatorNode node)
{
debug("visitAsOperator()");
emitter.emitAsOperator(node);
}
@Override
public void visitIsOperator(IBinaryOperatorNode node)
{
debug("visitIsOperator()");
emitter.emitIsOperator(node);
}
@Override
public void visitBinaryOperator(IBinaryOperatorNode node)
{
debug("visitBinaryOperator(" + node.getOperator().getOperatorText()
+ ")");
emitter.emitBinaryOperator(node);
}
@Override
public void visitUnaryOperator(IUnaryOperatorNode node)
{
debug("visitUnaryOperator()");
emitter.emitUnaryOperator(node);
}
@Override
public void visitTerminal(ITerminalNode node)
{
debug("visitTerminal(" + node.getKind() + ")");
walk(node.getStatementContentsNode());
}
@Override
public void visitFunctionObject(IFunctionObjectNode node)
{
emitter.emitFunctionObject((IFunctionObjectNode) node);
}
@Override
public void visitVariableExpression(IVariableExpressionNode node)
{
debug("visitVariableExpression()");
emitter.emitVariableExpression(node);
}
@Override
public void visitExpression(IExpressionNode node)
{
debug("visitExpression()");
// XXX (mschmalle) anything getting past here?
}
@Override
public void visitImport(IImportNode node)
{
debug("visitImport()");
emitter.emitImport(node);
}
@Override
public void visitMetaTags(IMetaTagsNode node)
{
debug("visitMetaTags()");
IMetaTagNode[] tags = node.getAllTags();
for (IMetaTagNode tag : tags)
{
walk(tag);
}
}
@Override
public void visitMetaTag(IMetaTagNode node)
{
debug("visitMetaTag(" + node.getTagName() + ")");
emitter.emitMetaTag(node);
}
@Override
public void visitUseNamespace(IUseNamespaceNode node)
{
debug("visitUseNamespace(" + node.getTargetNamespace() + ")");
emitter.emitUseNamespace(node);
}
@Override
public void visitEmbed(IEmbedNode node)
{
debug("visitEmbed(" + node.getAttributes()[0].getValue() + ")");
emitter.emitEmbed(node);
}
@Override
public void visitContainer(IContainerNode node)
{
debug("visitContainer()");
emitter.emitContainer(node);
}
@Override
public void visitE4XFilter(IMemberAccessExpressionNode node)
{
debug("visitE4XFilter()");
emitter.emitE4XFilter(node);
}
@Override
public void visitReturn(IReturnNode node)
{
debug("visitReturn()");
emitter.emitReturn(node);
}
@Override
public void visitTernaryOperator(ITernaryOperatorNode node)
{
debug("visitTernaryOperator()");
emitter.emitTernaryOperator(node);
}
@Override
public void visitLabeledStatement(LabeledStatementNode node)
{
debug("visitLabeledStatement()");
emitter.emitLabelStatement(node);
}
@Override
public void visitObjectLiteralValuePair(IObjectLiteralValuePairNode node)
{
debug("visitIObjectLiteralValuePair()");
emitter.emitObjectLiteralValuePair(node);
}
@Override
public void visitLanguageIdentifierNode(ILanguageIdentifierNode node)
{
emitter.emitLanguageIdentifier(node);
}
//--------------------------------------------------------------------------
//
//--------------------------------------------------------------------------
protected void debug(String message)
{
if (isDebug)
{
System.out.println(message);
}
}
}