/*
*
* 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.ASModifier;
import org.apache.flex.compiler.internal.definitions.PackageDefinition;
import org.apache.flex.compiler.internal.scopes.ASScope;
import org.apache.flex.compiler.internal.scopes.PackageScope;
import org.apache.flex.compiler.internal.semantics.PostProcessStep;
import org.apache.flex.compiler.internal.tree.as.parts.IDecorationPart;
import org.apache.flex.compiler.internal.tree.as.parts.SparseDecorationPart;
import org.apache.flex.compiler.parsing.IASToken;
import org.apache.flex.compiler.problems.ICompilerProblem;
import org.apache.flex.compiler.tree.ASTNodeID;
import org.apache.flex.compiler.tree.as.IIdentifierNode;
import org.apache.flex.compiler.tree.as.IPackageNode;
import org.apache.flex.compiler.tree.metadata.IMetaTagsNode;
/**
* ActionScript parse tree node representing a package definition
*/
public class PackageNode extends MemberedNode implements IPackageNode
{
/**
* Constructor.
*
* @param packageNameNode node holding this package name
*/
public PackageNode(ExpressionNodeBase packageNameNode, IASToken packageKeyword)
{
super();
init(packageNameNode);
this.packageNameNode = packageNameNode;
contentsNode = new ScopedBlockNode();
if (packageKeyword != null)
packageKeywordStart = packageKeyword.getStart();
else
packageKeywordStart = -1;
}
/**
* Start offset for the package keyword
*/
protected int packageKeywordStart;
/**
* The name of this package
*/
protected ExpressionNodeBase packageNameNode;
//
// NodeBase overrides
//
@Override
public ASTNodeID getNodeID()
{
return ASTNodeID.PackageID;
}
@Override
public String getPackageName()
{
return getName();
}
@Override
protected void setChildren(boolean fillInOffsets)
{
if (packageNameNode == null)
packageNameNode = new NilNode();
addChildInOrder(packageNameNode, fillInOffsets);
addChildInOrder(contentsNode, fillInOffsets);
}
@Override
protected void analyze(EnumSet<PostProcessStep> set, ASScope scope, Collection<ICompilerProblem> problems)
{
if (set.contains(PostProcessStep.POPULATE_SCOPE))
{
PackageDefinition definition = buildDefinition();
setDefinition(definition);
/*
* This could be improved because neither code model or the
* compiler will ever dig package definitions out of there by name.
* CM won't get them out of a file scope by name because of this
* check here. The compiler won't ever get them out of a file scope
* by name because the namespace specifier on all package
* definitions is the CM implicit namespace. I opted to leave the
* package definitions in the file scope for two reasons: #1. We
* need to pin the package scopes otherwise they and their contents
* will get GC'd. #2. There is code that enumerates the contents of
* the file scope and that code wants to find package definitions in
* there. This could be cleaned up somewhat by having a list of
* package scopes on every file scope and then changing things such
* that package scopes are not added the file scope's symbol table.
*/
scope.addDefinition(definition);
PackageScope packageScope = new PackageScope(scope, definition.getQualifiedName(), contentsNode);
definition.setContainedScope(packageScope);
scope = packageScope;
}
if (set.contains(PostProcessStep.RECONNECT_DEFINITIONS))
{
reconnectDef(scope);
scope = this.getDefinition().getContainedScope();
contentsNode.reconnectScope(scope);
}
// Recurse on the package block.
contentsNode.analyze(set, scope, problems);
}
/*
* For debugging only. Builds a string such as <code>"mx.core"</code> from
* the package name.
*/
@Override
protected boolean buildInnerString(StringBuilder sb)
{
sb.append('"');
sb.append(getName());
sb.append('"');
return true;
}
//
// TreeNode overrides
//
@Override
protected int getInitialChildCount()
{
return 2;
}
//
// BaseDefinitionNode overrides
//
@Override
protected IDecorationPart createDecorationPart()
{
return SparseDecorationPart.EMPTY_DECORATION_PART;
}
@Override
public IMetaTagsNode getMetaTags()
{
return null;
}
@Override
public String getNamespace()
{
return null;
}
@Override
public boolean hasNamespace(String namespace)
{
return false;
}
@Override
public boolean hasModifier(ASModifier modifier)
{
return false;
}
@Override
public ExpressionNodeBase getNameExpressionNode()
{
return packageNameNode;
}
@Override
public String getName()
{
return (packageNameNode instanceof IIdentifierNode) ? ((IIdentifierNode)packageNameNode).getName() : "";
}
@Override
public int getNameStart()
{
return packageNameNode instanceof IIdentifierNode ? packageNameNode.getStart() : -1;
}
@Override
public int getNameEnd()
{
return packageNameNode instanceof IIdentifierNode ? packageNameNode.getEnd() : -1;
}
@Override
public int getNameAbsoluteStart()
{
return packageNameNode instanceof IIdentifierNode ? packageNameNode.getAbsoluteStart() : -1;
}
@Override
public int getNameAbsoluteEnd()
{
return packageNameNode instanceof IIdentifierNode ? packageNameNode.getAbsoluteEnd() : -1;
}
@Override
public PackageDefinition getDefinition()
{
return (PackageDefinition)super.getDefinition();
}
//
// IPackageNode implementations
//
@Override
public boolean isImplicit()
{
return false;
}
@Override
public String getQualifiedName()
{
return getName();
}
@Override
public String getShortName()
{
return getName();
}
@Override
public PackageKind getPackageKind()
{
return PackageKind.CONCRETE;
}
//
// Other methods
//
/**
* Sets the name of this package. Should only be used during parsing.
*
* @param packageNameNode the name of the package
*/
public void setPackageName(ExpressionNodeBase packageNameNode)
{
this.packageNameNode = packageNameNode;
}
/**
* Determine whether or not this node has a package keyword
*
* @return true if the node has a package keyword
*/
public boolean hasPackageKeyword()
{
return packageKeywordStart != -1;
}
/**
* Get the start offset for the package keyword
*
* @return start offset for "package"
*/
public int getPackageKeywordStart()
{
return packageKeywordStart;
}
/**
* Get the end offset for the package keyword
*
* @return end offset for "package"
*/
public int getPackageKeywordEnd()
{
return packageKeywordStart + 7;
}
PackageDefinition buildDefinition()
{
String definitionName = getName();
PackageDefinition definition = new PackageDefinition(definitionName);
definition.setNode(this);
this.setDefinition(definition);
return definition;
}
}