/*
* #%~
* 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.QuestionAdaptor;
import org.overture.ast.analysis.intf.IQuestionAnswer;
import org.overture.ast.definitions.AExplicitFunctionDefinition;
import org.overture.ast.definitions.AExplicitOperationDefinition;
import org.overture.ast.definitions.AImplicitFunctionDefinition;
import org.overture.ast.definitions.AImplicitOperationDefinition;
import org.overture.ast.definitions.AInstanceVariableDefinition;
import org.overture.ast.definitions.ALocalDefinition;
import org.overture.ast.definitions.ARenamedDefinition;
import org.overture.ast.definitions.AStateDefinition;
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.expressions.ANotYetSpecifiedExp;
import org.overture.ast.expressions.ASubclassResponsibilityExp;
import org.overture.ast.patterns.APatternListTypePair;
import org.overture.ast.patterns.PPattern;
import org.overture.ast.typechecker.NameScope;
import org.overture.ast.types.AFieldField;
import org.overture.ast.types.AFunctionType;
import org.overture.ast.types.AOperationType;
import org.overture.ast.types.ARecordInvariantType;
import org.overture.ast.types.PType;
import org.overture.ast.types.SInvariantType;
import org.overture.typechecker.Environment;
import org.overture.typechecker.FlatCheckedEnvironment;
import org.overture.typechecker.FlatEnvironment;
import org.overture.typechecker.TypeCheckException;
import org.overture.typechecker.TypeCheckInfo;
import org.overture.typechecker.TypeCheckerErrors;
import org.overture.typechecker.assistant.ITypeCheckerAssistantFactory;
/**
* This class implements a way to resolve types from a node in the AST
*
* @author kel
*/
public class DefinitionTypeResolver extends
QuestionAdaptor<DefinitionTypeResolver.NewQuestion>
{
public static class NewQuestion
{
public final IQuestionAnswer<TypeCheckInfo, PType> rootVisitor;
public final TypeCheckInfo question;
public NewQuestion(IQuestionAnswer<TypeCheckInfo, PType> rootVisitor,
TypeCheckInfo question)
{
this.rootVisitor = rootVisitor;
this.question = question;
}
}
protected ITypeCheckerAssistantFactory af;
public DefinitionTypeResolver(ITypeCheckerAssistantFactory af)
{
this.af = af;
}
@Override
public void defaultSClassDefinition(SClassDefinition node,
NewQuestion question) throws AnalysisException
{
Environment cenv = new FlatEnvironment(question.question.assistantFactory, node.getDefinitions(), question.question.env);
af.createPDefinitionListAssistant().typeResolve(node.getDefinitions(), question.rootVisitor, new TypeCheckInfo(question.question.assistantFactory, cenv));
}
@Override
public void caseAExplicitFunctionDefinition(
AExplicitFunctionDefinition node, NewQuestion question)
throws AnalysisException
{
if (node.getTypeParams().size() != 0)
{
FlatCheckedEnvironment params = new FlatCheckedEnvironment(question.question.assistantFactory, af.createAExplicitFunctionDefinitionAssistant().getTypeParamDefinitions(node), question.question.env, NameScope.NAMES);
TypeCheckInfo newQuestion = new TypeCheckInfo(question.question.assistantFactory, params, question.question.scope);
node.setType(af.createPTypeAssistant().typeResolve(question.question.assistantFactory.createPDefinitionAssistant().getType(node), null, question.rootVisitor, newQuestion));
} else
{
node.setType(af.createPTypeAssistant().typeResolve(node.getType(), null, question.rootVisitor, question.question));
}
if (question.question.env.isVDMPP())
{
AFunctionType fType = (AFunctionType) question.question.assistantFactory.createPDefinitionAssistant().getType(node);
node.getName().setTypeQualifier(fType.getParameters());
}
if (node.getBody() instanceof ASubclassResponsibilityExp
|| node.getBody() instanceof ANotYetSpecifiedExp)
{
node.setIsUndefined(true);
}
if (node.getPrecondition() != null)
{
// PDefinitionAssistantTC.typeResolve(node.getPredef(), rootVisitor, question);
node.getPredef().apply(this, question);
}
if (node.getPostcondition() != null)
{
// PDefinitionAssistantTC.typeResolve(node.getPostdef(), rootVisitor, question);
node.getPostdef().apply(this, question);
}
for (List<PPattern> pp : node.getParamPatternList())
{
af.createPPatternListAssistant().typeResolve(pp, question.rootVisitor, question.question);
}
}
@Override
public void caseAExplicitOperationDefinition(
AExplicitOperationDefinition node, NewQuestion question)
throws AnalysisException
{
node.setType(af.createPTypeAssistant().typeResolve(node.getType(), null, question.rootVisitor, question.question));
if (question.question.env.isVDMPP())
{
node.getName().setTypeQualifier(((AOperationType) node.getType()).getParameters());
if (node.getName().getName().equals(node.getClassDefinition().getName().getName()))
{
node.setIsConstructor(true);
node.getClassDefinition().setHasContructors(true);
}
}
if (node.getPrecondition() != null)
{
node.getPredef().apply(this, question);
}
if (node.getPostcondition() != null)
{
node.getPostdef().apply(this, question);
}
for (PPattern p : node.getParameterPatterns())
{
af.createPPatternAssistant().typeResolve(p, question.rootVisitor, question.question);
}
}
@Override
public void caseAImplicitFunctionDefinition(
AImplicitFunctionDefinition node, NewQuestion question)
throws AnalysisException
{
if (node.getTypeParams().size() > 0)
{
FlatCheckedEnvironment params = new FlatCheckedEnvironment(af, af.createAImplicitFunctionDefinitionAssistant().getTypeParamDefinitions(node), question.question.env, NameScope.NAMES);
node.setType(af.createPTypeAssistant().typeResolve(af.createPDefinitionAssistant().getType(node), null, question.rootVisitor, new TypeCheckInfo(question.question.assistantFactory, params, question.question.scope, question.question.qualifiers)));
} else
{
question.question.qualifiers = null;
node.setType(af.createPTypeAssistant().typeResolve(af.createPDefinitionAssistant().getType(node), null, question.rootVisitor, question.question));
}
if (node.getResult() != null)
{
af.createAPatternTypePairAssistant().typeResolve(node.getResult(), question.rootVisitor, question.question);
}
if (question.question.env.isVDMPP())
{
AFunctionType fType = (AFunctionType) af.createPDefinitionAssistant().getType(node);
node.getName().setTypeQualifier(fType.getParameters());
}
if (node.getBody() instanceof ASubclassResponsibilityExp
|| node.getBody() instanceof ANotYetSpecifiedExp)
{
node.setIsUndefined(true);
}
if (node.getPrecondition() != null)
{
node.getPredef().apply(this, question);
}
if (node.getPostcondition() != null)
{
node.getPostdef().apply(this, question);
}
for (APatternListTypePair pltp : node.getParamPatterns())
{
pltp.apply(THIS, question);
}
}
@Override
public void caseAImplicitOperationDefinition(
AImplicitOperationDefinition node, NewQuestion question)
throws AnalysisException
{
node.setType(af.createPTypeAssistant().typeResolve(node.getType(), null, question.rootVisitor, question.question));
if (node.getResult() != null)
{
af.createAPatternTypePairAssistant().typeResolve(node.getResult(), question.rootVisitor, question.question);
}
if (question.question.env.isVDMPP())
{
node.getName().setTypeQualifier(((AOperationType) node.getType()).getParameters());
if (node.getName().getName().equals(node.getClassDefinition().getName().getName()))
{
node.setIsConstructor(true);
node.getClassDefinition().setHasContructors(true);
}
}
if (node.getPrecondition() != null)
{
node.getPredef().apply(this, question);
}
if (node.getPostcondition() != null)
{
node.getPostdef().apply(this, question);
}
for (APatternListTypePair ptp : node.getParameterPatterns())
{
ptp.apply(THIS, question);
}
}
@Override
public void caseAInstanceVariableDefinition(
AInstanceVariableDefinition node, NewQuestion question)
throws AnalysisException
{
try
{
node.setType(af.createPTypeAssistant().typeResolve(node.getType(), null, question.rootVisitor, question.question));
} catch (TypeCheckException e)
{
af.createPTypeAssistant().unResolve(node.getType());
throw e;
}
}
@Override
public void caseALocalDefinition(ALocalDefinition node, NewQuestion question)
throws AnalysisException
{
if (node.getType() != null)
{
node.setType(af.createPTypeAssistant().typeResolve(question.question.assistantFactory.createPDefinitionAssistant().getType(node), null, question.rootVisitor, question.question));
}
}
@Override
public void caseARenamedDefinition(ARenamedDefinition node,
NewQuestion question) throws AnalysisException
{
node.getDef().apply(this, question);
}
@Override
public void caseAStateDefinition(AStateDefinition node, NewQuestion question)
throws AnalysisException
{
for (AFieldField f : node.getFields())
{
try
{
f.apply(THIS, new NewQuestion(question.rootVisitor, question.question));
} catch (TypeCheckException e)
{
question.question.assistantFactory.createPTypeAssistant().unResolve(f.getType());
throw e;
}
}
node.setRecordType(af.createPTypeAssistant().typeResolve(node.getRecordType(), null, question.rootVisitor, question.question));
if (node.getInvPattern() != null)
{
node.getInvdef().apply(this, question);
ARecordInvariantType rtype = (ARecordInvariantType) node.getRecordType();
rtype.setInvDef(node.getInvdef());
}
if (node.getInitPattern() != null)
{
node.getInitdef().apply(this, question);
}
}
@Override
public void caseATypeDefinition(ATypeDefinition node, NewQuestion question)
throws AnalysisException
{
try
{
node.setInfinite(false);
node.setInvType((SInvariantType) af.createPTypeAssistant().typeResolve((SInvariantType) node.getInvType(), node, question.rootVisitor, question.question));
if (node.getInfinite())
{
TypeCheckerErrors.report(3050, "Type '" + node.getName()
+ "' is infinite", node.getLocation(), node);
}
// set type before in case the invdef uses a type defined in this one
node.setType(node.getInvType());
if (node.getInvdef() != null)
{
node.getInvdef().apply(this, question);
af.createPPatternAssistant().typeResolve(node.getInvPattern(), question.rootVisitor, question.question);
}
node.setType(node.getInvType());
if (!node.getComposeDefinitions().isEmpty())
{
for (PDefinition compose : node.getComposeDefinitions())
{
compose.apply(this, question);
}
}
} catch (TypeCheckException e)
{
af.createPTypeAssistant().unResolve(node.getInvType());
throw e;
}
}
@Override
public void caseAValueDefinition(AValueDefinition node, NewQuestion question)
throws AnalysisException
{
if (node.getType() != null)
{
node.setType(af.createPTypeAssistant().typeResolve(node.getType(), null, question.rootVisitor, question.question));
af.createPPatternAssistant().typeResolve(node.getPattern(), question.rootVisitor, question.question);
// af.createAValueDefinitionAssistant().updateDefs(node, question.question);
updateDefs(node, question.question);
}
}
public void updateDefs(AValueDefinition node, TypeCheckInfo question)
{
PType type = node.getType();
PPattern pattern = node.getPattern();
List<PDefinition> newdefs = af.createPPatternAssistant().getDefinitions(pattern, type, node.getNameScope());
// The untyped definitions may have had "used" markers, so we copy
// those into the new typed definitions, lest we get warnings. We
// also mark the local definitions as "ValueDefintions" (proxies),
// so that classes can be constructed correctly (values are statics).
for (PDefinition d : newdefs)
{
for (PDefinition u : node.getDefs())
{
if (u.getName().equals(d.getName()))
{
if (af.createPDefinitionAssistant().isUsed(u))
{
af.createPDefinitionAssistant().markUsed(d);
}
break;
}
}
ALocalDefinition ld = (ALocalDefinition) d;
setValueDefinition(ld);
}
node.setDefs(newdefs);
List<PDefinition> defs = node.getDefs();
af.createPDefinitionListAssistant().setAccessibility(defs, node.getAccess().clone());
af.createPDefinitionListAssistant().setClassDefinition(defs, node.getClassDefinition());
}
@Override
public void caseAPatternListTypePair(APatternListTypePair pltp,
NewQuestion question) throws AnalysisException
{
af.createPPatternListAssistant().typeResolve(pltp.getPatterns(), question.rootVisitor, question.question);
PType type = af.createPTypeAssistant().typeResolve(pltp.getType(), null, question.rootVisitor, question.question);
pltp.setType(type);
}
@Override
public void defaultPDefinition(PDefinition node, NewQuestion question)
throws AnalysisException
{
return;
}
public void setValueDefinition(ALocalDefinition ld)
{
ld.setValueDefinition(true);
}
}