/*
* #%~
* The VDM Type Checker
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.typechecker.utilities;
import java.util.List;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.analysis.QuestionAnswerAdaptor;
import org.overture.ast.definitions.AEqualsDefinition;
import org.overture.ast.definitions.AExplicitFunctionDefinition;
import org.overture.ast.definitions.AExplicitOperationDefinition;
import org.overture.ast.definitions.AExternalDefinition;
import org.overture.ast.definitions.AImplicitFunctionDefinition;
import org.overture.ast.definitions.AImplicitOperationDefinition;
import org.overture.ast.definitions.AImportedDefinition;
import org.overture.ast.definitions.AInheritedDefinition;
import org.overture.ast.definitions.AInstanceVariableDefinition;
import org.overture.ast.definitions.AMultiBindListDefinition;
import org.overture.ast.definitions.AMutexSyncDefinition;
import org.overture.ast.definitions.APerSyncDefinition;
import org.overture.ast.definitions.ARenamedDefinition;
import org.overture.ast.definitions.AStateDefinition;
import org.overture.ast.definitions.AThreadDefinition;
import org.overture.ast.definitions.ATypeDefinition;
import org.overture.ast.definitions.AValueDefinition;
import org.overture.ast.definitions.PDefinition;
import org.overture.ast.definitions.SClassDefinition;
import org.overture.ast.intf.lex.ILexNameToken;
import org.overture.ast.lex.Dialect;
import org.overture.ast.node.INode;
import org.overture.ast.typechecker.NameScope;
import org.overture.config.Release;
import org.overture.config.Settings;
import org.overture.typechecker.TypeCheckerErrors;
import org.overture.typechecker.assistant.ITypeCheckerAssistantFactory;
/**
* This class implements a way to find type from a node in the AST
*
* @author kel
*/
public class NameFinder extends
QuestionAnswerAdaptor<NameFinder.Newquestion, PDefinition>
{
public static class Newquestion
{
public final ILexNameToken sought;
public final NameScope scope;
public Newquestion(ILexNameToken sought, NameScope scope)
{
this.scope = scope;
this.sought = sought;
}
}
protected ITypeCheckerAssistantFactory af;
public NameFinder(ITypeCheckerAssistantFactory af)
{
this.af = af;
}
@Override
public PDefinition defaultSClassDefinition(SClassDefinition node,
Newquestion question) throws AnalysisException
{
PDefinition def = null;
for (PDefinition d : node.getDefinitions())
{
PDefinition found = d.apply(this, question);// PDefinitionAssistantTC.findName(d, question.sought,
// question.scope);
// It is possible to have an ambiguous name if the name has
// type qualifiers that are a union of types that match several
// overloaded functions/ops (even though they themselves are
// distinguishable).
if (found != null)
{
if (def == null)
{
def = found;
if (question.sought.getTypeQualifier() == null)
{
break; // Can't be ambiguous
}
} else
{
if (!def.getLocation().equals(found.getLocation())
&& af.createPDefinitionAssistant().isFunctionOrOperation(def))
{
TypeCheckerErrors.report(3010, "Name "
+ question.sought + " is ambiguous", question.sought.getLocation(), question.sought);
TypeCheckerErrors.detail2("1", def.getLocation(), "2", found.getLocation());
break;
}
}
}
}
if (def == null)
{
for (PDefinition d : node.getAllInheritedDefinitions())
{
PDefinition indef = d.apply(this, question);// PDefinitionAssistantTC.findName(d, question.sought,
// question.scope);
// See above for the following...
if (indef != null)
{
if (def == null)
{
def = indef;
if (question.sought.getTypeQualifier() == null)
{
break; // Can't be ambiguous
}
} else if (def.equals(indef)
&& // Compares qualified names
!def.getLocation().equals(indef.getLocation())
&& !af.createPDefinitionAssistant().hasSupertype(def.getClassDefinition(), indef.getClassDefinition().getType())
&& af.createPDefinitionAssistant().isFunctionOrOperation(def))
{
TypeCheckerErrors.report(3011, "Name "
+ question.sought
+ " is multiply defined in class", question.sought.getLocation(), question.sought);
TypeCheckerErrors.detail2("1", def.getLocation(), "2", indef.getLocation());
break;
}
}
}
}
return def;
}
@Override
public PDefinition caseAEqualsDefinition(AEqualsDefinition node,
Newquestion question) throws AnalysisException
{
List<PDefinition> defs = node.getDefs();
if (defs != null)
{
PDefinition def = af.createPDefinitionListAssistant().findName(defs, question.sought, question.scope);
if (def != null)
{
return def;
}
}
return null;
}
@Override
public PDefinition caseAExplicitFunctionDefinition(
AExplicitFunctionDefinition node, Newquestion question)
throws AnalysisException
{
if (af.createPDefinitionAssistant().findNameBaseCase(node, question.sought, question.scope) != null)
{
return node;
}
PDefinition predef = node.getPredef();
if (predef != null && predef.apply(this, question) != null)// PDefinitionAssistantTC.findName(predef, sought,
// scope) != null)
{
return predef;
}
PDefinition postdef = node.getPostdef();
if (postdef != null && postdef.apply(this, question) != null)// PDefinitionAssistantTC.findName(postdef, sought,
// scope) != null)
{
return postdef;
}
return null;
}
@Override
public PDefinition caseAExplicitOperationDefinition(
AExplicitOperationDefinition node, Newquestion question)
throws AnalysisException
{
if (af.createPDefinitionAssistant().findNameBaseCase(node, question.sought, question.scope) != null)
{
return node;
}
if (Settings.dialect == Dialect.VDM_SL || Settings.release == Release.CLASSIC)
{
PDefinition predef = node.getPredef();
if (predef != null && predef.apply(this, question) != null)
{
return predef;
}
PDefinition postdef = node.getPostdef();
if (postdef != null && postdef.apply(this, question) != null)
{
return postdef;
}
}
return null;
}
@Override
public PDefinition caseAExternalDefinition(AExternalDefinition node,
Newquestion question) throws AnalysisException
{
if (question.sought.getOld() && question.scope == NameScope.NAMESANDANYSTATE)
{
return question.sought.equals(node.getOldname()) ? node : null;
}
return question.sought.equals(node.getState().getName()) ? node : null;
}
@Override
public PDefinition caseAImplicitFunctionDefinition(
AImplicitFunctionDefinition node, Newquestion question)
throws AnalysisException
{
if (af.createPDefinitionAssistant().findNameBaseCase(node, question.sought, question.scope) != null)
{
return node;
}
PDefinition predef = node.getPredef();
if (predef != null && predef.apply(this, question) != null)// PDefinitionAssistantTC.findName(predef, sought,
// scope) != null)
{
return predef;
}
PDefinition postdef = node.getPostdef();
if (postdef != null && postdef.apply(this, question) != null) // PDefinitionAssistantTC.findName(postdef,
// sought, scope) != null)
{
return postdef;
}
return null;
}
@Override
public PDefinition caseAImplicitOperationDefinition(
AImplicitOperationDefinition node, Newquestion question)
throws AnalysisException
{
if (af.createPDefinitionAssistant().findNameBaseCase(node, question.sought, question.scope) != null)
{
return node;
}
if (Settings.dialect == Dialect.VDM_SL || Settings.release == Release.CLASSIC)
{
PDefinition predef = node.getPredef();
if (predef != null && predef.apply(this, question) != null)
{
return predef;
}
PDefinition postdef = node.getPostdef();
if (postdef != null && postdef.apply(this, question) != null)
{
return postdef;
}
}
return null;
}
@Override
public PDefinition caseAImportedDefinition(AImportedDefinition node,
Newquestion question) throws AnalysisException
{
PDefinition def = node.getDef().apply(this, question);// PDefinitionAssistantTC.findName(d.getDef(), sought,
// scope);
if (def != null)
{
af.createPDefinitionAssistant().markUsed(node);
}
return def;
}
@Override
public PDefinition caseAInheritedDefinition(AInheritedDefinition node,
Newquestion question) throws AnalysisException
{
// The problem is, when the InheritedDefinition is created, we
// don't know its fully qualified name.
if (node.getSuperdef() instanceof AInheritedDefinition)
{
node.getSuperdef().apply(this, question);
}
ILexNameToken name = node.getName();
name.setTypeQualifier(node.getSuperdef().getName().getTypeQualifier());
if (af.getLexNameTokenAssistant().isEqual(name, question.sought))
{
return node;
} else if (question.scope.matches(NameScope.OLDSTATE)
&& node.getOldname().equals(question.sought))
{
return node;
}
return null;
}
@Override
public PDefinition caseAInstanceVariableDefinition(
AInstanceVariableDefinition node, Newquestion question)
throws AnalysisException
{
PDefinition found = af.createPDefinitionAssistant().findNameBaseCase(node, question.sought, question.scope);
if (found != null)
{
return found;
}
return question.scope.matches(NameScope.OLDSTATE)
&& node.getOldname().equals(question.sought) ? node : null;
}
@Override
public PDefinition caseAMultiBindListDefinition(
AMultiBindListDefinition node, Newquestion question)
throws AnalysisException
{
if (node.getDefs() != null)
{
PDefinition def = af.createPDefinitionListAssistant().findName(node.getDefs(), question.sought, question.scope);
if (def != null)
{
return def;
}
}
return null;
}
@Override
public PDefinition caseAMutexSyncDefinition(AMutexSyncDefinition node,
Newquestion question) throws AnalysisException
{
return null;
}
@Override
public PDefinition caseAPerSyncDefinition(APerSyncDefinition node,
Newquestion question) throws AnalysisException
{
return null;
}
@Override
public PDefinition caseARenamedDefinition(ARenamedDefinition node,
Newquestion question) throws AnalysisException
{
PDefinition renamed = af.createPDefinitionAssistant().findNameBaseCase(node, question.sought, question.scope);
if (renamed != null)
{
af.createPDefinitionAssistant().markUsed(node.getDef());
return renamed;
} else
{
// Renamed definitions hide the original name
return null;// PDefinitionAssistantTC.findName(d.getDef(),sought, scope);
}
}
@Override
public PDefinition caseAStateDefinition(AStateDefinition node,
Newquestion question) throws AnalysisException
{
if (question.scope.matches(NameScope.NAMES))
{
PDefinition invdef = node.getInvdef();
if (invdef != null && invdef.apply(this, question) != null)// PDefinitionAssistantTC.findName(invdef,
// sought, scope) != null)
{
return invdef;
}
PDefinition initdef = node.getInitdef();
if (initdef != null && initdef.apply(this, question) != null)// PDefinitionAssistantTC.findName(initdef,
// sought, scope) != null)
{
return initdef;
}
}
// if ( PDefinitionAssistantTC.findName(definition.getRecordDefinition(), sought, scope) != null)
// {
// return definition.getRecordDefinition();
// }
for (PDefinition d : node.getStateDefs())
{
PDefinition def = d.apply(this, question);// PDefinitionAssistantTC.findName(d, sought, scope);
if (def != null)
{
return def;
}
}
return null;
}
@Override
public PDefinition caseAThreadDefinition(AThreadDefinition node,
Newquestion question) throws AnalysisException
{
return node.getOperationDef().apply(this, question); // PDefinitionAssistantTC.findName(definition.getOperationDef(),
// sought, scope);
}
@Override
public PDefinition caseATypeDefinition(ATypeDefinition node,
Newquestion question) throws AnalysisException
{
PDefinition invdef = node.getInvdef();
if (invdef != null && invdef.apply(this, question) != null)// PDefinitionAssistantTC.findName(invdef, sought,
// scope) != null)
{
return invdef;
}
return null;
}
@Override
public PDefinition caseAValueDefinition(AValueDefinition node,
Newquestion question) throws AnalysisException
{
return af.createPDefinitionListAssistant().findName(node.getDefs(), question.sought, question.scope);
}
// @Override
// public PDefinition caseAClassType(AClassType node, Newquestion question)
// throws AnalysisException
// {
// return node.apply(THIS, question);
// }
@Override
public PDefinition defaultPDefinition(PDefinition node, Newquestion question)
throws AnalysisException
{
return af.createPDefinitionAssistant().findNameBaseCase(node, question.sought, question.scope);
}
@Override
public PDefinition createNewReturnValue(INode node, Newquestion question)
{
assert false : "should not happen";
return null;
}
@Override
public PDefinition createNewReturnValue(Object node, Newquestion question)
{
assert false : "should not happen";
return null;
}
}