/*
*
* 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 java.util.Collection;
import java.util.EnumSet;
import org.apache.flex.compiler.common.ASImportTarget;
import org.apache.flex.compiler.common.ASModifier;
import org.apache.flex.compiler.common.IImportTarget;
import org.apache.flex.compiler.definitions.IClassDefinition;
import org.apache.flex.compiler.definitions.INamespaceDefinition.NamespaceClassification;
import org.apache.flex.compiler.definitions.references.INamespaceReference;
import org.apache.flex.compiler.internal.definitions.NamespaceDefinition;
import org.apache.flex.compiler.internal.scopes.ASScope;
import org.apache.flex.compiler.internal.scopes.TypeScope;
import org.apache.flex.compiler.internal.semantics.PostProcessStep;
import org.apache.flex.compiler.parsing.IASToken;
import org.apache.flex.compiler.problems.ICompilerProblem;
import org.apache.flex.compiler.scopes.IASScope;
import org.apache.flex.compiler.tree.ASTNodeID;
import org.apache.flex.compiler.tree.as.IASNode;
import org.apache.flex.compiler.tree.as.ICommonClassNode;
import org.apache.flex.compiler.tree.as.INamespaceNode;
import org.apache.flex.compiler.tree.as.IScopedNode;
/**
* AST node for namespace definition.
*/
public class NamespaceNode extends BaseDefinitionNode implements INamespaceNode, IInitializableDefinitionNode
{
private static final String EMPTY_URI = "";
/**
* Create a {@code NamespaceNode} from the namespace name identifier.
*
* @param nameNode Namespace name.
*/
public NamespaceNode(IdentifierNode nameNode)
{
super();
init(nameNode);
}
/**
* Initialized namespace URI value.
*/
private ExpressionNodeBase uriNode;
//
// NodeBase overrides
//
@Override
public final ASTNodeID getNodeID()
{
return ASTNodeID.NamespaceID;
}
@Override
protected void setChildren(boolean fillInOffsets)
{
addDecorationChildren(fillInOffsets);
addChildInOrder(nameNode, fillInOffsets);
if (uriNode != null)
addChildInOrder(uriNode, fillInOffsets);
}
@Override
protected void analyze(EnumSet<PostProcessStep> set, ASScope scope, Collection<ICompilerProblem> problems)
{
if (set.contains(PostProcessStep.POPULATE_SCOPE))
{
// Make sure we respect the static modifier even for code outside of a class,
// as FB still needs lookups to work on broken code.
boolean is_static = this.hasModifier(ASModifier.STATIC);
// Namespace definitions inside of a class are always static
if (scope.getContainingDefinition() instanceof IClassDefinition)
is_static = true;
NamespaceDefinition definition = buildDefinition(is_static);
setDefinition(definition);
scope.addDefinition(definition);
}
super.analyze(set, scope, problems);
}
//
// BaseDefinitionNode overrides
//
@Override
public NamespaceDefinition getDefinition()
{
return (NamespaceDefinition)super.getDefinition();
}
//
// INamespaceNode implementations
//
@Override
public boolean isImplicit()
{
return false;
}
@Override
public String getQualifiedName()
{
String qualifiedName = null;
if (getNamespaceClassification() == NamespaceClassification.PACKAGE_MEMBER)
{
IImportTarget importTarget = ASImportTarget.buildImportFromPackageName(getWorkspace(), getPackageName());
qualifiedName = importTarget.getQualifiedName(getName());
}
if (qualifiedName == null)
qualifiedName = getName();
return qualifiedName;
}
@Override
public String getShortName()
{
return getName();
}
@Override
public NamespaceClassification getNamespaceClassification()
{
IScopedNode scopedNode = getScopeNode();
IASNode node = scopedNode;
if (node.getParent() instanceof PackageNode)
return NamespaceClassification.PACKAGE_MEMBER;
if (node instanceof ICommonClassNode || node.getParent() instanceof ICommonClassNode)
return NamespaceClassification.CLASS_MEMBER;
if (node instanceof FileNode)// this is an include
return NamespaceClassification.FILE_MEMBER;
return NamespaceClassification.LOCAL;
}
@Override
public ExpressionNodeBase getNamespaceURINode()
{
return uriNode;
}
@Override
public String getURI()
{
return uriNode instanceof LiteralNode ? ((LiteralNode)uriNode).getValue() : EMPTY_URI;
}
//
// IInitializableDefinitionNode implementations
//
@Override
public void setAssignedValue(IASToken eq, ExpressionNodeBase value)
{
uriNode = value;
}
//
// Other methods
//
/**
* @return URI string or null.
*/
private String getURILiteral()
{
return uriNode instanceof LiteralNode ? ((LiteralNode)uriNode).getValue() : null;
}
/**
* Build a namespace definition for this node.
*
* @param is_static true if this should be treated as a "static" namespace -
* all namespaces in a class are static, though they won't contain the
* static modifier, which is why we have this flag rather than just checking
* the modifier
* @return the NamespaceDefinition representing this namespace in the symbol
* table
*/
NamespaceDefinition buildDefinition(boolean is_static)
{
String definitionName = getName();
INamespaceReference namespaceReference = NamespaceDefinition.createNamespaceReference(
getASScope(), getNamespaceNode(), is_static);
ExpressionNodeBase initExpr = getNamespaceURINode();
NamespaceDefinition definition =
NamespaceDefinition.createNamespaceDefintionDirective(namespaceReference, getScope(), definitionName, getURILiteral(), initExpr != null ? initExpr.computeNamespaceReference() : null);
definition.setNode(this);
fillInModifiers(definition);
fillInMetadata(definition);
return definition;
}
private IASScope getScope()
{
IASScope scope = getScopeNode().getScope();
if (scope instanceof TypeScope)
{
// Namespaces in a class are always static
scope = ((TypeScope)scope).getStaticScope();
}
return scope;
}
}