blob: 59f07e5603d893624d75edd6058f13ccd6db3e89 [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.js.amd;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.royale.compiler.common.ASModifier;
import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.IFunctionDefinition;
import org.apache.royale.compiler.definitions.IParameterDefinition;
import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.definitions.IVariableDefinition;
import org.apache.royale.compiler.definitions.references.IReference;
import org.apache.royale.compiler.internal.definitions.ClassTraitsDefinition;
import org.apache.royale.compiler.internal.tree.as.ExpressionNodeBase;
import org.apache.royale.compiler.internal.tree.as.FunctionCallNode;
import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
import org.apache.royale.compiler.projects.ICompilerProject;
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.IClassNode;
import org.apache.royale.compiler.tree.as.IDefinitionNode;
import org.apache.royale.compiler.tree.as.IDynamicAccessNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
import org.apache.royale.compiler.tree.as.IForLoopNode;
import org.apache.royale.compiler.tree.as.IFunctionCallNode;
import org.apache.royale.compiler.tree.as.IFunctionNode;
import org.apache.royale.compiler.tree.as.IIdentifierNode;
import org.apache.royale.compiler.tree.as.ILanguageIdentifierNode;
import org.apache.royale.compiler.tree.as.ILanguageIdentifierNode.LanguageIdentifierKind;
import org.apache.royale.compiler.tree.as.IMemberAccessExpressionNode;
import org.apache.royale.compiler.tree.as.IParameterNode;
import org.apache.royale.compiler.tree.as.IUnaryOperatorNode;
import org.apache.royale.compiler.tree.as.IVariableNode;
/**
* These tools need to be refactored into utility classes.
*
* @author Michael Schmalle
*/
public class TempTools
{
public static void fillStaticStatements(IClassNode node,
List<IASNode> list, boolean excludeFields)
{
int len = node.getScopedNode().getChildCount();
for (int i = 0; i < len; i++)
{
IASNode child = node.getScopedNode().getChild(i);
if (child instanceof IExpressionNode)
list.add(child);
else if (child instanceof IDefinitionNode)
{
if (!excludeFields
&& ((IDefinitionNode) child)
.hasModifier(ASModifier.STATIC)
&& child instanceof IVariableNode)
list.add(child);
}
}
}
public static void fillInstanceMembers(IDefinitionNode[] members,
List<IDefinitionNode> list)
{
for (IDefinitionNode node : members)
{
if (node instanceof IFunctionNode
&& ((IFunctionNode) node).isConstructor())
continue;
if (!node.hasModifier(ASModifier.STATIC))
{
list.add(node);
}
}
}
public static void fillStaticMembers(IDefinitionNode[] members,
List<IDefinitionNode> list, boolean excludeFields,
boolean excludeFunctions)
{
for (IDefinitionNode node : members)
{
if (node.hasModifier(ASModifier.STATIC))
{
if (!excludeFields && node instanceof IVariableNode)
list.add(node);
else if (!excludeFunctions && node instanceof IFunctionNode)
list.add(node);
}
}
}
public static List<IVariableDefinition> getFields(
IClassDefinition definition, boolean excludePrivate)
{
ArrayList<IVariableDefinition> result = new ArrayList<IVariableDefinition>();
Collection<IDefinition> definitions = definition.getContainedScope()
.getAllLocalDefinitions();
for (IDefinition member : definitions)
{
if (!member.isImplicit() && member instanceof IVariableDefinition)
{
IVariableDefinition vnode = (IVariableDefinition) member;
if (!member.isStatic()
&& (member.isPublic() || member.isProtected()))
result.add(vnode);
// TODO FIX the logic here, this won't add twice though
if (!excludePrivate && member.isPrivate())
result.add(vnode);
}
}
return result;
}
public static boolean isVariableAParameter(IVariableDefinition node,
IParameterDefinition[] parameters)
{
for (IParameterDefinition parameter : parameters)
{
if (node.getBaseName().equals(parameter.getBaseName()))
return true;
}
return false;
}
public static Map<Integer, IParameterNode> getDefaults(
IParameterNode[] nodes)
{
Map<Integer, IParameterNode> result = new HashMap<Integer, IParameterNode>();
int i = 0;
boolean hasDefaults = false;
for (IParameterNode node : nodes)
{
if (node.hasDefaultValue())
{
hasDefaults = true;
result.put(i, node);
}
else
{
result.put(i, null);
}
i++;
}
if (!hasDefaults)
return null;
return result;
}
public static boolean injectThisArgument(FunctionCallNode node,
boolean allowMembers)
{
// if super isSuper checks the nameNode
if (node.isSuperExpression() && !node.isNewExpression())
return true;
ExpressionNodeBase base = node.getNameNode();
if (base.getNodeID() == ASTNodeID.IdentifierID)
return false;
if (allowMembers && base instanceof IMemberAccessExpressionNode)
{
// foo.super()
IMemberAccessExpressionNode mnode = (IMemberAccessExpressionNode) base;
if (mnode.getLeftOperandNode().getNodeID() == ASTNodeID.SuperID)
return true;
}
return false;
}
public static String toInitialValue(IVariableDefinition field,
ICompilerProject project)
{
Object value = field.resolveInitialValue(project);
if (value != null)
return value.toString();
IReference reference = field.getTypeReference();
if (reference == null)
return "undefined";
if (reference.getName().equals("int")
|| reference.getName().equals("uint")
|| reference.getName().equals("Number"))
return "0";
return "null";
}
public static boolean isBinding(IIdentifierNode node,
ICompilerProject project)
{
IDefinition resolve = node.resolve(project);
if (resolve != null && resolve.isPrivate() && !isField(resolve))
{
//if (resolve instanceof IFunctionDefinition)
IExpressionNode rightSide = getNode(node, true, project);
IBinaryOperatorNode parent = (IBinaryOperatorNode) node
.getAncestorOfType(IBinaryOperatorNode.class);
if (isThisLeftOf(node))
parent = (IBinaryOperatorNode) parent
.getAncestorOfType(IBinaryOperatorNode.class);
IVariableNode vparent = (IVariableNode) node
.getAncestorOfType(IVariableNode.class);
if (vparent != null)
{
IExpressionNode indentFromThis = getIndentFromThis(node);
if (vparent.getAssignedValueNode() == node
|| ((IBinaryOperatorNode) vparent
.getAssignedValueNode()).getRightOperandNode() == indentFromThis)
return true;
}
if (rightSide == node && parent != null/*|| isThisLeftOf(node)*/)
{
return true;
}
}
return false;
}
private static boolean isField(IDefinition node)
{
return !(node instanceof IFunctionDefinition);
}
public static boolean isValidThis(IIdentifierNode node,
ICompilerProject project)
{
// added super.foo(), wanted to 'this' behind foo
if (node.getParent() instanceof IMemberAccessExpressionNode)
{
IMemberAccessExpressionNode mnode = (IMemberAccessExpressionNode) node
.getParent();
if (mnode.getLeftOperandNode().getNodeID() == ASTNodeID.SuperID)
return false;
IExpressionNode indentFromThis = getIndentFromThis(node);
if (node == indentFromThis)
return true;
// test that this is the base expression
ExpressionNodeBase enode = (ExpressionNodeBase) node;
ExpressionNodeBase baseExpression = enode.getBaseExpression();
if (indentFromThis == null && baseExpression != null
&& baseExpression != node)
return false;
// check to see if the left is a type
ITypeDefinition type = mnode.getLeftOperandNode().resolveType(
project);
// A.{foo} : Left is a Type
// XXX going to have to test packgeName to com.acme.A
if (type instanceof ClassTraitsDefinition
&& mnode.getLeftOperandNode() == node)
{
return false;
}
// this.{foo} : explicit 'this', in js we are ignoring explicit this identifiers
// because we are inserting all of them with the emitter
else if (indentFromThis == null)
{
//return false;
}
}
IDefinition definition = node.resolve(project);
if (definition == null)
return false; // Is this correct?
if (definition instanceof IParameterDefinition)
return false;
if (definition.getParent() instanceof IMemberAccessExpressionNode)
return false;
if (!(definition.getParent() instanceof IClassDefinition))
return false;
if (definition instanceof IVariableDefinition)
{
IVariableDefinition variable = (IVariableDefinition) definition;
if (variable.isStatic())
return false;
}
if (definition instanceof IFunctionDefinition)
{
IFunctionDefinition function = (IFunctionDefinition) definition;
if (function.isStatic())
return false;
}
return true;
}
private static boolean isThisLeftOf(IIdentifierNode node)
{
if (node.getParent() instanceof IMemberAccessExpressionNode)
{
IMemberAccessExpressionNode parent = (IMemberAccessExpressionNode) node
.getParent();
if (parent.getLeftOperandNode() instanceof ILanguageIdentifierNode
&& ((ILanguageIdentifierNode) parent.getLeftOperandNode())
.getKind() == LanguageIdentifierKind.THIS)
return true;
}
return false;
}
public static IExpressionNode getNode(IASNode iNode, Boolean toRight,
ICompilerProject project)
{
try
{
IASNode node = iNode;
while (node != null)
{
if (node instanceof IBinaryOperatorNode
&& !(node instanceof MemberAccessExpressionNode))
{
if (toRight)
node = ((IBinaryOperatorNode) node)
.getRightOperandNode();
else
node = ((IBinaryOperatorNode) node)
.getLeftOperandNode();
}
else if (node instanceof IFunctionCallNode)
node = ((IFunctionCallNode) node).getNameNode();
else if (node instanceof IDynamicAccessNode)
node = ((IDynamicAccessNode) node).getLeftOperandNode();
else if (node instanceof IUnaryOperatorNode)
node = ((IUnaryOperatorNode) node).getOperandNode();
else if (node instanceof IForLoopNode)
node = ((IForLoopNode) node).getChild(0).getChild(0);
else if (node instanceof IVariableNode)
{
if (toRight)
node = ((IVariableNode) node).getAssignedValueNode();
else
node = ((IVariableNode) node).getVariableTypeNode();
}
else if (node instanceof IExpressionNode)
{
// IDefinition def = ((IExpressionNode) node).resolve(project);
// if (def instanceof VariableDefinition)
// {
// final VariableDefinition variable = (VariableDefinition) def;
// def = variable.resolveType(project);
// }
// else if (def instanceof FunctionDefinition)
// {
// final FunctionDefinition functionDef = (FunctionDefinition) def;
// final IReference typeRef = functionDef
// .getReturnTypeReference();
// if (typeRef != null)
// def = typeRef.resolve(project,
// (ASScope) getScopeFromNode(iNode),
// DependencyType.INHERITANCE, false);
// }
// else if (def instanceof IGetterDefinition)
// {
// final ITypeDefinition returnType = ((IGetterDefinition) def)
// .resolveReturnType(project);
// // def = m_sharedData.getDefinition(returnType
// // .getQualifiedName());
// def = returnType; // XXX figure out
// }
//
// if (def != null && def instanceof ClassDefinition)
// {
// return def;
// }
return (IExpressionNode) node;
}
else
{
node = null;
}
}
}
catch (Exception e)
{
// getDefinitionForNode(iNode,toRight);
// getDefinition() sometimes crashes, e.g. when looking at a cast to an interface in some cases,
// FunctionDefinition.getParameters() returns null and ExpressionNodeBase.determineIfFunction() chokes on it
// printWarning(iNode, "getDefinitionForNode() failed for" + iNode);
}
return null;
}
private static IExpressionNode getIndentFromThis(IIdentifierNode node)
{
if (node.getParent() instanceof IMemberAccessExpressionNode)
{
IMemberAccessExpressionNode parent = (IMemberAccessExpressionNode) node
.getParent();
if (parent.getLeftOperandNode() instanceof ILanguageIdentifierNode
&& ((ILanguageIdentifierNode) parent.getLeftOperandNode())
.getKind() == LanguageIdentifierKind.THIS)
return parent.getRightOperandNode();
}
return null;
}
public static String toPackageName(String name)
{
if (!name.contains("."))
return name;
final String stem = name.substring(0, name.lastIndexOf("."));
return stem;
}
public static String toBaseName(String name)
{
if (!name.contains("."))
return name;
final String basename = name.substring(name.lastIndexOf(".") + 1);
return basename;
}
}