blob: 7cbd5f4807acde32275b7938a2ee0a0bf776b9a4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2014 University of Illinois at Urbana-Champaign and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* UIUC - Initial API and implementation
* Chris Hansen (U Washington) - Auto-complete improvements (Bug 414906)
*******************************************************************************/
package org.eclipse.photran.internal.core.analysis.binding;
import java.util.List;
import org.eclipse.photran.internal.core.analysis.types.FunctionType;
import org.eclipse.photran.internal.core.analysis.types.Type;
import org.eclipse.photran.internal.core.lexer.Token;
import org.eclipse.photran.internal.core.parser.ASTFunctionParNode;
import org.eclipse.photran.internal.core.parser.ASTFunctionStmtNode;
import org.eclipse.photran.internal.core.parser.ASTSubroutineParNode;
import org.eclipse.photran.internal.core.parser.ASTSubroutineStmtNode;
import org.eclipse.photran.internal.core.parser.ASTTypeSpecNode;
import org.eclipse.photran.internal.core.parser.IASTListNode;
import org.eclipse.photran.internal.core.vpg.AnnotationType;
import org.eclipse.photran.internal.core.vpg.PhotranTokenRef;
/**
* Phase 5 of name-binding analysis.
* <p>
* Visits subprogram declarations, setting their types in the VPG.
*
* @author Jeff Overbey
* @author Chris Hansen
* @see Binder
*/
class SubprogramTypeCollector extends BindingCollector
{
@Override public void visitASTSubroutineStmtNode(ASTSubroutineStmtNode node)
{
super.traverseChildren(node);
PhotranTokenRef tokenRef = node.getSubroutineName().getSubroutineName().getTokenRef();
IASTListNode<ASTSubroutineParNode> subParams = node.getSubroutinePars();
updateDefinitionWithTypeInfo(tokenRef, typeOf(node));
updateDefinitionWithSubParameters(tokenRef, typeOf(node), subParams);
}
@Override public void visitASTFunctionStmtNode(ASTFunctionStmtNode node)
{
super.traverseChildren(node);
PhotranTokenRef tokenRef = node.getFunctionName().getFunctionName().getTokenRef();
IASTListNode<ASTFunctionParNode> funParams = node.getFunctionPars();
updateDefinitionWithTypeInfo(tokenRef, typeOf(node));
updateDefinitionWithFunParameters(tokenRef, typeOf(node), funParams);
}
private void updateDefinitionWithTypeInfo(PhotranTokenRef tokenRef, FunctionType type)
{
Definition def = vpg.getDefinitionFor(tokenRef);
def.setType(type);
vpgProvider.setDefinitionFor(tokenRef, def);
}
private void updateDefinitionWithSubParameters(PhotranTokenRef tokenRef, FunctionType type, IASTListNode<ASTSubroutineParNode> subParams)
{
Definition def = vpg.getDefinitionFor(tokenRef);
// This is coming back null sometimes if a previous DB request
// was made with a block size too large. For now, ignore
// the error and move on.
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=500007
if (def == null) return;
// Populate subroutines auto-completion with parameters
StringBuilder fullId = new StringBuilder(40);
fullId.append(def.getDeclaredName());
fullId.append('(');
if (subParams != null) {
int paramCount = 0;
for (ASTSubroutineParNode param: subParams) {
Token tmpToken = param.getVariableName();
String paramText;
if (tmpToken != null) {
paramText = tmpToken.getText();
} else {
paramText = "*"; //$NON-NLS-1$
}
if (paramCount>0)
fullId.append(',');
fullId.append(paramText);
//
if (tmpToken != null) {
Definition varDef = bindUniquely(tmpToken);
if (varDef != null) {
if (varDef.isOptional()) {
fullId.append('=');
fullId.append(paramText);
}
}
}
paramCount=paramCount+1;
}
}
fullId.append(')');
def.setCompletionText(fullId.toString());
vpgProvider.setDefinitionFor(tokenRef, def);
}
private void updateDefinitionWithFunParameters(PhotranTokenRef tokenRef, FunctionType type, IASTListNode<ASTFunctionParNode> funParams)
{
Definition def = vpg.getDefinitionFor(tokenRef);
// Populate function auto-completion with parameters
StringBuilder fullId = new StringBuilder(40);
fullId.append(def.getDeclaredName());
fullId.append('(');
if (funParams != null) {
int paramCount = 0;
for (ASTFunctionParNode param: funParams) {
Token tmpToken = param.getVariableName();
String paramText = tmpToken.getText();
if (paramCount>0)
fullId.append(',');
fullId.append(paramText);
//
Definition varDef = bindUniquely(tmpToken);
if (varDef != null) {
if (varDef.isOptional()) {
fullId.append('=');
fullId.append(paramText);
}
}
paramCount=paramCount+1;
}
}
fullId.append(')');
def.setCompletionText(fullId.toString());
vpgProvider.setDefinitionFor(tokenRef, def);
}
private FunctionType typeOf(ASTSubroutineStmtNode node)
{
FunctionType type = new FunctionType(node.getSubroutineName().getSubroutineName().getText());
type.setReturnType(Type.VOID);
if (node.getSubroutinePars() != null)
{
for (ASTSubroutineParNode param : node.getSubroutinePars())
{
if (param.isAsterisk())
{
// TODO: type.addArgument(name, type, intent)
}
else
{
type.addArgument(
param.getVariableName().getText(),
typeOf(param.getVariableName()),
intentOf(param.getVariableName()));
}
}
}
return type;
}
private FunctionType typeOf(ASTFunctionStmtNode node)
{
FunctionType type = new FunctionType(node.getFunctionName().getFunctionName().getText());
if (node.getPrefixSpecList() != null)
{
for (int i = 0; i < node.getPrefixSpecList().size(); i++)
{
ASTTypeSpecNode typeSpec = node.getPrefixSpecList().get(i).getTypeSpec();
if (typeSpec != null)
type.setReturnType(Type.parse(typeSpec));
}
}
if (node.hasResultClause())
type.setReturnType(typeOf(node.getName()));
if (node.getFunctionPars() != null)
{
for (ASTFunctionParNode param : node.getFunctionPars())
type.addArgument(
param.getVariableName().getText(),
typeOf(param.getVariableName()),
intentOf(param.getVariableName()));
}
return type;
}
private Type typeOf(Token variableName)
{
Definition def = bindUniquely(variableName);
return def == null ? Type.UNKNOWN : def.getType();
}
private VariableAccess intentOf(Token variableName)
{
Definition def = bindUniquely(variableName);
if (def == null) return VariableAccess.RW;
if (def.isIntentIn() && def.isIntentOut())
return VariableAccess.RW;
else if (def.isIntentIn())
return VariableAccess.READ;
else if (def.isIntentOut())
return VariableAccess.WRITE;
else
return VariableAccess.RW;
}
private Definition bindUniquely(Token ident)
{
List<PhotranTokenRef> bindings = bind(ident);
if (bindings.size() >= 1)
return bindings.get(0).getAnnotation(AnnotationType.DEFINITION_ANNOTATION_TYPE);
else
return null;
}
}