/* * * 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.constants.IASLanguageConstants; import org.apache.flex.compiler.definitions.IDefinition; import org.apache.flex.compiler.definitions.IVariableDefinition.VariableClassification; 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.definitions.ParameterDefinition; import org.apache.flex.compiler.internal.scopes.ASScope; import org.apache.flex.compiler.internal.scopes.CatchScope; import org.apache.flex.compiler.internal.semantics.PostProcessStep; import org.apache.flex.compiler.internal.tree.as.parts.VariableDecorationPart; import org.apache.flex.compiler.problems.ICompilerProblem; import org.apache.flex.compiler.tree.ASTNodeID; import org.apache.flex.compiler.tree.as.IASNode; import org.apache.flex.compiler.tree.as.IIdentifierNode; import org.apache.flex.compiler.tree.as.ILiteralNode; import org.apache.flex.compiler.tree.as.IParameterNode; import org.apache.flex.compiler.tree.as.IScopedNode; import org.apache.flex.compiler.tree.metadata.IMetaTagsNode; /** * ActionScript parse tree node representing one argument (e.g. str:String) in a * function definition */ public final class ParameterNode extends BaseVariableNode implements IParameterNode { /** * Constructor. * * @param nameNode The identifier node representing the name of the parameter. */ public ParameterNode(IdentifierNode nameNode) { super(nameNode); } /** * Constructor. * * @param nameNode The identifier node representing the name of the parameter. * @param typeNode The expression node reperesenting the type of teh parameter. */ public ParameterNode(IdentifierNode nameNode, ExpressionNodeBase typeNode) { super(nameNode, typeNode); } private boolean isRest = false; // // NodeBase overrides // @Override public ASTNodeID getNodeID() { if (!isRest()) return ASTNodeID.ArgumentID; else return ASTNodeID.ArgumentRestID; } @Override public IScopedNode getScopeNode() { IASNode ancestor = getAncestorOfType(FunctionNode.class); if (ancestor != null && ancestor instanceof FunctionNode) { FunctionNode function = (FunctionNode)ancestor; if (function.getScopedNode() != null) return function.getScopedNode(); } // We should never get here, but just in case... if (getParent() != null) return getParent().getContainingScope(); return null; } @Override protected void analyze(EnumSet<PostProcessStep> set, ASScope scope, Collection<ICompilerProblem> problems) { if (isCatchParameter(scope)) { if (set.contains(PostProcessStep.POPULATE_SCOPE) || set.contains(PostProcessStep.RECONNECT_DEFINITIONS)) { ParameterDefinition definition = buildDefinition(); setDefinition(definition); // Don't hoist the catch scope's parameter definition ((CatchScope)scope).setParameterDefinition(definition); } } else { super.analyze(set, scope, problems); } } // // TreeNode overrides // @Override protected int getInitialChildCount() { return 3; } // // BaseDefinitionNode overrides // @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; } // // BaseVariableNode overrides // @Override protected void ensureTypeNode() { if (typeNode == null && isRest()) { typeNode = new IdentifierNode(IASLanguageConstants.Array); typeNode.span(-1, -1, -1, -1); return; } super.ensureTypeNode(); } /** * Build a Definition for this argument * * @return the Definition for this argument */ @Override ParameterDefinition buildDefinition() { String definitionName = getName(); ParameterDefinition definition = new ParameterDefinition(definitionName); definition.setNode(this); fillInNamespaceAndModifiers(definition); setDefinition(definition); // Set the type of the parameter. If a type annotation doesn't appear in the source, // the parameter type in the definition will be null. IReference typeRef = hasExplicitType() ? typeNode.computeTypeReference() : null; // If there is no type anno, and we're the rest parameter, we're typed as Array if (typeRef == null && this.isRest()) typeRef = ReferenceFactory.builtinReference(IASLanguageConstants.BuiltinType.ARRAY); definition.setTypeReference(typeRef); // Tell the def we have a default value if (hasDefaultValue()) { definition.setHasDefault(); definition.setInitializer(this.getAssignedValueNode()); } // Is it ... ? if (isRest()) definition.setRest(); return definition; } @Override public DefinitionBase getDefinition() { return super.getDefinition(); } @Override protected void setDefinition(IDefinition definition) { assert definition instanceof ParameterDefinition; super.setDefinition(definition); } // // IParameterNode implementations // @Override public boolean isImplicit() { return false; } @Override public String getQualifiedName() { return getName(); } @Override public String getShortName() { return getName(); } @Override public VariableClassification getVariableClassification() { if (getAncestorOfType(CatchNode.class) != null) return VariableClassification.LOCAL; return VariableClassification.PARAMETER; } @Override public boolean isRest() { return isRest; } @Override public boolean hasDefaultValue() { return ((VariableDecorationPart)getDecorationPart()).getAssignedValue() != null; } @Override public String getDefaultValue() { ExpressionNodeBase assignedValueNode = ((VariableDecorationPart)getDecorationPart()).getAssignedValue(); if (assignedValueNode != null) { if (assignedValueNode instanceof ILiteralNode) return ((ILiteralNode)assignedValueNode).getValue(true); else if (assignedValueNode instanceof IIdentifierNode) return ((IIdentifierNode)assignedValueNode).getName(); else if (assignedValueNode instanceof MemberAccessExpressionNode) return ((MemberAccessExpressionNode)assignedValueNode).getDisplayString(); } return null; } // // Other methods // public void setIsRestParameter(boolean isRest) { this.isRest = isRest; } private boolean isCatchParameter(ASScope scope) { return scope instanceof CatchScope && this.getParent() instanceof CatchNode; } }