/*
*
* 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.tree.as;
import org.apache.flex.abc.semantics.Name;
import org.apache.flex.compiler.common.ISourceLocation;
import org.apache.flex.compiler.constants.IASLanguageConstants;
import org.apache.flex.compiler.definitions.AppliedVectorDefinitionFactory;
import org.apache.flex.compiler.definitions.IDefinition;
import org.apache.flex.compiler.definitions.ITypeDefinition;
import org.apache.flex.compiler.definitions.references.IReference;
import org.apache.flex.compiler.definitions.references.ReferenceFactory;
import org.apache.flex.compiler.internal.definitions.DefinitionBase;
import org.apache.flex.compiler.internal.parsing.as.ASToken;
import org.apache.flex.compiler.projects.ICompilerProject;
import org.apache.flex.compiler.tree.ASTNodeID;
import org.apache.flex.compiler.tree.as.IASNode;
import org.apache.flex.compiler.tree.as.IExpressionNode;
import org.apache.flex.compiler.tree.as.IIdentifierNode;
import org.apache.flex.compiler.tree.as.ITypedExpressionNode;
/**
* AST node for generic type such as: {@code Vector.<T>}.
*/
public class TypedExpressionNode extends ExpressionNodeBase implements ITypedExpressionNode
{
/**
* Constructor.
* <p>
* Creates a {@code TypedExpressionNode} from its two components and the
* {@code .<} token.
*
* @param collection The generic collection type node.
* @param type Type parameter node.
* @param openToken The {@code .<} token. Null-able.
*/
public TypedExpressionNode(ExpressionNodeBase collection, ExpressionNodeBase type, ASToken openToken)
{
assert collection != null : "collection type node can't be null";
assert type != null : "type parameter node can't be null";
collectionNode = collection;
typeNode = type;
if (openToken == null)
{
typeOperatorStart = ISourceLocation.UNKNOWN;
typeOperatorEnd = ISourceLocation.UNKNOWN;
}
else
{
typeOperatorStart = openToken.getStart();
typeOperatorEnd = openToken.getEnd();
}
span(collection, type);
}
/**
* Constructor.
*
* @param collection The node representing the base type (i.e., Vector).
* @param type The node representing the element type.
*/
public TypedExpressionNode(ExpressionNodeBase collection, ExpressionNodeBase type)
{
this(collection, type, null);
}
/**
* Copy constructor.
*
* @param other The node to copy.
*/
protected TypedExpressionNode (TypedExpressionNode other)
{
super(other);
this.collectionNode = other.collectionNode != null ? other.collectionNode.copy() : null;
this.typeNode = other.typeNode != null ? other.typeNode.copy() : null;
this.typeOperatorStart = other.typeOperatorStart;
this.typeOperatorEnd = other.typeOperatorEnd;
}
/**
* The {@code Vector} in {@code Vector.<T>}.
*/
private final ExpressionNodeBase collectionNode;
/**
* The {@code T} in {@code Vector.<T>}.
*/
private final ExpressionNodeBase typeNode;
/**
* Offset at which the type operator {@code .<} starts
*/
private final int typeOperatorStart;
/**
* Offset at which the type operator {@code .<} ends
*/
private final int typeOperatorEnd;
//
// NodeBase overrides
//
@Override
public ASTNodeID getNodeID()
{
return ASTNodeID.TypedExpressionID;
}
@Override
public int getChildCount()
{
if (typeNode != null && collectionNode != null)
return 2;
else if (typeNode != null || collectionNode != null)
return 1;
return 0;
}
@Override
public IASNode getChild(int i)
{
switch (i)
{
case 0:
{
if (typeNode != null && collectionNode != null)
{
if (typeNode.getAbsoluteStart() < collectionNode.getAbsoluteStart())
return typeNode;
}
return collectionNode;
}
case 1:
{
if (typeNode != null && collectionNode != null)
{
if (typeNode.getAbsoluteStart() < collectionNode.getAbsoluteStart())
return collectionNode;
}
return typeNode;
}
}
return null;
}
@Override
protected void setChildren(boolean fillInOffsets)
{
if (collectionNode != null)
collectionNode.setParent(this);
if (typeNode != null)
typeNode.setParent(this);
}
//
// ExpressionNodeBase overrides
//
@Override
public IDefinition resolve(ICompilerProject project)
{
IDefinition base = collectionNode.resolve(project);
IDefinition resolvedType = null;
if (base != null)
{
IDefinition vectorDef = project.getBuiltinType(IASLanguageConstants.BuiltinType.VECTOR);
if (base == vectorDef) // Only works with Vector for now
{
IDefinition param = typeNode.resolve(project);
if (param instanceof ITypeDefinition)
resolvedType = AppliedVectorDefinitionFactory.newVector(project, (ITypeDefinition)param);
}
}
return resolvedType;
}
@Override
public ITypeDefinition resolveType(ICompilerProject project)
{
IDefinition d = resolve(project);
if (d != null)
return d.resolveType(project);
return null;
}
@Override
protected TypedExpressionNode copy()
{
return new TypedExpressionNode(this);
}
@Override
public Name getMName(ICompilerProject project)
{
// resolve the result of the expression, which will
// return a AppliedVectorDefinition for a vectorized type
// or null in other cases.
IDefinition d = resolve(project);
if (d != null)
return ((DefinitionBase)d).getMName(project);
return null;
}
@Override
public String computeSimpleReference()
{
return getName();
}
@Override
public IReference computeTypeReference()
{
IReference base = collectionNode.computeTypeReference();
IReference param = typeNode.computeTypeReference();
return ReferenceFactory.parameterizedReference(getWorkspace(), base, param);
}
//
// ITypedExpressionNode implementations
//
@Override
public String getName()
{
StringBuilder builder = new StringBuilder();
if (collectionNode instanceof IIdentifierNode)
{
builder.append(((IIdentifierNode)collectionNode).getName());
}
if (typeNode instanceof IIdentifierNode)
{
builder.append(".<");
builder.append(((IIdentifierNode)typeNode).getName());
builder.append(">");
}
return builder.toString();
}
@Override
public IdentifierType getIdentifierType()
{
return IdentifierType.TYPED_NAME;
}
@Override
public IExpressionNode getCollectionNode()
{
return collectionNode;
}
@Override
public IExpressionNode getTypeNode()
{
return typeNode;
}
@Override
public boolean hasTypedOperator()
{
return typeOperatorStart != ISourceLocation.UNKNOWN && typeOperatorEnd != ISourceLocation.UNKNOWN;
}
//
// Other methods
//
// Add to interface?
public int getTypedOperatorStart()
{
return typeOperatorStart;
}
// Add to interface?
public int getTypedOperatorEnd()
{
return typeOperatorEnd;
}
}