blob: bcb6e25ad1b56260cbfdb66cdc8f91623c0022cb [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.as.codegen;
import java.util.List;
import org.apache.flex.compiler.as.codegen.IASEmitter;
import org.apache.flex.compiler.definitions.IClassDefinition;
import org.apache.flex.compiler.definitions.IDefinition;
import org.apache.flex.compiler.definitions.IInterfaceDefinition;
import org.apache.flex.compiler.internal.semantics.SemanticUtils;
import org.apache.flex.compiler.internal.tree.as.BaseLiteralContainerNode;
import org.apache.flex.compiler.internal.tree.as.FunctionObjectNode;
import org.apache.flex.compiler.internal.tree.as.LabeledStatementNode;
import org.apache.flex.compiler.internal.tree.as.NamespaceAccessExpressionNode;
import org.apache.flex.compiler.internal.tree.as.VariableExpressionNode;
import org.apache.flex.compiler.problems.ICompilerProblem;
import org.apache.flex.compiler.projects.IASProject;
import org.apache.flex.compiler.tree.ASTNodeID;
import org.apache.flex.compiler.tree.as.IASNode;
import org.apache.flex.compiler.tree.as.IBinaryOperatorNode;
import org.apache.flex.compiler.tree.as.IBlockNode;
import org.apache.flex.compiler.tree.as.ICatchNode;
import org.apache.flex.compiler.tree.as.IClassNode;
import org.apache.flex.compiler.tree.as.IConditionalNode;
import org.apache.flex.compiler.tree.as.IContainerNode;
import org.apache.flex.compiler.tree.as.IDefaultXMLNamespaceNode;
import org.apache.flex.compiler.tree.as.IDynamicAccessNode;
import org.apache.flex.compiler.tree.as.IEmbedNode;
import org.apache.flex.compiler.tree.as.IExpressionNode;
import org.apache.flex.compiler.tree.as.IFileNode;
import org.apache.flex.compiler.tree.as.IForLoopNode;
import org.apache.flex.compiler.tree.as.IForLoopNode.ForLoopKind;
import org.apache.flex.compiler.tree.as.IFunctionCallNode;
import org.apache.flex.compiler.tree.as.IFunctionNode;
import org.apache.flex.compiler.tree.as.IGetterNode;
import org.apache.flex.compiler.tree.as.IIdentifierNode;
import org.apache.flex.compiler.tree.as.IIfNode;
import org.apache.flex.compiler.tree.as.IInterfaceNode;
import org.apache.flex.compiler.tree.as.IIterationFlowNode;
import org.apache.flex.compiler.tree.as.IKeywordNode;
import org.apache.flex.compiler.tree.as.ILanguageIdentifierNode;
import org.apache.flex.compiler.tree.as.ILiteralNode;
import org.apache.flex.compiler.tree.as.ILiteralNode.LiteralType;
import org.apache.flex.compiler.tree.as.IMemberAccessExpressionNode;
import org.apache.flex.compiler.tree.as.INamespaceNode;
import org.apache.flex.compiler.tree.as.INumericLiteralNode;
import org.apache.flex.compiler.tree.as.IObjectLiteralValuePairNode;
import org.apache.flex.compiler.tree.as.IPackageNode;
import org.apache.flex.compiler.tree.as.IParameterNode;
import org.apache.flex.compiler.tree.as.IReturnNode;
import org.apache.flex.compiler.tree.as.ISetterNode;
import org.apache.flex.compiler.tree.as.ISwitchNode;
import org.apache.flex.compiler.tree.as.ITerminalNode;
import org.apache.flex.compiler.tree.as.ITernaryOperatorNode;
import org.apache.flex.compiler.tree.as.IThrowNode;
import org.apache.flex.compiler.tree.as.ITryNode;
import org.apache.flex.compiler.tree.as.ITypedExpressionNode;
import org.apache.flex.compiler.tree.as.IUnaryOperatorNode;
import org.apache.flex.compiler.tree.as.IVariableNode;
import org.apache.flex.compiler.tree.as.IWhileLoopNode;
import org.apache.flex.compiler.tree.as.IWhileLoopNode.WhileLoopKind;
import org.apache.flex.compiler.tree.as.IWithNode;
import org.apache.flex.compiler.tree.metadata.IMetaTagNode;
import org.apache.flex.compiler.tree.metadata.IMetaTagsNode;
import org.apache.flex.compiler.units.ICompilationUnit;
import org.apache.flex.compiler.visitor.IASBlockVisitor;
import org.apache.flex.compiler.visitor.IASBlockWalker;
import org.apache.flex.compiler.visitor.IASNodeStrategy;
/**
* 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
{
private IASEmitter emitter;
private final List<ICompilerProblem> errors;
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)
{
getStrategy().handle(node);
}
@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()");
IASNode pnode = node.getChild(0);
if (pnode != null)
{
walk(pnode); // IPackageNode
}
else
{
}
}
@Override
public void visitPackage(IPackageNode node)
{
debug("visitPackage()");
emitter.emitPackageHeader(node);
emitter.emitPackageHeaderContents(node);
emitter.emitPackageContents(node);
emitter.emitPackageFooter(node);
}
//--------------------------------------------------------------------------
// 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.isMemberDefinition(node.getDefinition()))
{
emitter.emitField(node);
}
else
{
emitter.emitVarDeclaration(node);
}
}
@Override
public void visitFunction(IFunctionNode node)
{
debug("visitFunction()");
if (isMemberDefinition(node.getDefinition()))
{
emitter.emitMethod(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()");
if (node.getParent().getNodeID() == ASTNodeID.FunctionID)
{
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()");
walk(node.getKeywordNode()); // default xml namespace
walk(node.getExpressionNode()); // "http://ns.whatever.com"
}
@Override
public void visitKeyword(IKeywordNode node)
{
debug("visitKeyword(" + node.getNodeID().getParaphrase() + ")");
emitter.emitKeyword(node);
}
@Override
public void visitLiteral(ILiteralNode node)
{
debug("visitLiteral(" + node.getValue() + ")");
// TODO (mschmalle) visitLiteral()
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.VOID)
{
emitter.emitLiteral(node);
}
else if (node.getLiteralType() == LiteralType.ARRAY
|| node.getLiteralType() == LiteralType.OBJECT)
{
BaseLiteralContainerNode anode = (BaseLiteralContainerNode) node;
IContainerNode cnode = anode.getContentsNode();
emitter.emitLiteralContainer(cnode);
}
}
@Override
public void visitMemberAccessExpression(IMemberAccessExpressionNode node)
{
debug("visitMemberAccessExpression()");
emitter.emitMemberAccessExpression(node);
}
@Override
public void visitNamespaceAccessExpression(
NamespaceAccessExpressionNode node)
{
debug("visitNamespaceAccessExpression()");
walk(node.getLeftOperandNode());
emitter.write(node.getOperator().getOperatorText());
walk(node.getRightOperandNode());
}
@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 visitBinaryOperator(IBinaryOperatorNode node)
{
debug("visitBinaryOperator(" + node.getOperator().getOperatorText()
+ ")");
emitter.emitBinaryOperator(node);
}
@Override
public void visitUnaryOperator(IUnaryOperatorNode node)
{
debug("visitUnaryOperator()");
if (node.getNodeID() == ASTNodeID.Op_PreIncrID
|| node.getNodeID() == ASTNodeID.Op_PreDecrID
|| node.getNodeID() == ASTNodeID.Op_BitwiseNotID
|| node.getNodeID() == ASTNodeID.Op_LogicalNotID
|| node.getNodeID() == ASTNodeID.Op_SubtractID
|| node.getNodeID() == ASTNodeID.Op_AddID)
{
emitter.write(node.getOperator().getOperatorText());
walk(node.getOperandNode());
}
else if (node.getNodeID() == ASTNodeID.Op_PostIncrID
|| node.getNodeID() == ASTNodeID.Op_PostDecrID)
{
walk(node.getOperandNode());
emitter.write(node.getOperator().getOperatorText());
}
else if (node.getNodeID() == ASTNodeID.Op_DeleteID
|| node.getNodeID() == ASTNodeID.Op_VoidID)
{
emitter.write(node.getOperator().getOperatorText());
emitter.write(" ");
walk(node.getOperandNode());
}
else if (node.getNodeID() == ASTNodeID.Op_TypeOfID)
{
emitter.write(node.getOperator().getOperatorText());
emitter.write("(");
walk(node.getOperandNode());
emitter.write(")");
}
}
@Override
public void visitConditional(IConditionalNode node)
{
debug("visitConditional()");
emitter.write("(");
walk(node.getConditionalExpressionNode());
emitter.write(")");
walk(node.getStatementContentsNode());
}
@Override
public void visitTerminal(ITerminalNode node)
{
debug("visitTerminal(" + node.getKind() + ")");
walk(node.getStatementContentsNode());
}
@Override
public void visitExpression(IExpressionNode node)
{
debug("visitExpression()");
// TODO (mschmalle) I think these placements are temp, I am sure a visit method
// should exist for FunctionObjectNode, there is no interface for it right now
if (node instanceof VariableExpressionNode)
{
VariableExpressionNode v = (VariableExpressionNode) node;
walk(v.getTargetVariable());
}
else if (node instanceof FunctionObjectNode)
{
emitter.emitFunctionObject(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() + ")");
// TODO (mschmalle) visitMetaTag()
}
@Override
public void visitEmbed(IEmbedNode node)
{
debug("visitEmbed(" + node.getAttributes()[0].getValue() + ")");
// TODO (mschmalle) visitEmbed()
}
@Override
public void visitReturn(IReturnNode node)
{
debug("visitReturn()");
emitter.write("return");
IExpressionNode rnode = node.getReturnValueNode();
if (rnode != null && rnode.getNodeID() != ASTNodeID.NilID)
{
emitter.write(" ");
walk(rnode);
}
}
@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)
{
if (node.getKind() == ILanguageIdentifierNode.LanguageIdentifierKind.ANY_TYPE)
{
emitter.write("*");
}
else if (node.getKind() == ILanguageIdentifierNode.LanguageIdentifierKind.REST)
{
emitter.write("...");
}
else if (node.getKind() == ILanguageIdentifierNode.LanguageIdentifierKind.SUPER)
{
emitter.write("super");
}
else if (node.getKind() == ILanguageIdentifierNode.LanguageIdentifierKind.THIS)
{
emitter.write("this");
}
else if (node.getKind() == ILanguageIdentifierNode.LanguageIdentifierKind.VOID)
{
emitter.write("void");
}
}
//--------------------------------------------------------------------------
//
//--------------------------------------------------------------------------
protected void debug(String message)
{
System.out.println(message);
}
//--------------------------------------------------------------------------
//
//--------------------------------------------------------------------------
private static boolean isMemberDefinition(IDefinition definition)
{
return definition != null
&& (definition.getParent() instanceof IClassDefinition || definition
.getParent() instanceof IInterfaceDefinition);
}
}