/*
* #%~
* 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.pattern;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.analysis.QuestionAnswerAdaptor;
import org.overture.ast.definitions.AInstanceVariableDefinition;
import org.overture.ast.definitions.PDefinition;
import org.overture.ast.definitions.SClassDefinition;
import org.overture.ast.factory.AstFactory;
import org.overture.ast.node.INode;
import org.overture.ast.patterns.ABooleanPattern;
import org.overture.ast.patterns.ACharacterPattern;
import org.overture.ast.patterns.AConcatenationPattern;
import org.overture.ast.patterns.AExpressionPattern;
import org.overture.ast.patterns.AIdentifierPattern;
import org.overture.ast.patterns.AIgnorePattern;
import org.overture.ast.patterns.AIntegerPattern;
import org.overture.ast.patterns.AMapPattern;
import org.overture.ast.patterns.AMapUnionPattern;
import org.overture.ast.patterns.AMapletPatternMaplet;
import org.overture.ast.patterns.ANamePatternPair;
import org.overture.ast.patterns.ANilPattern;
import org.overture.ast.patterns.AObjectPattern;
import org.overture.ast.patterns.AQuotePattern;
import org.overture.ast.patterns.ARealPattern;
import org.overture.ast.patterns.ARecordPattern;
import org.overture.ast.patterns.ASeqPattern;
import org.overture.ast.patterns.ASetPattern;
import org.overture.ast.patterns.AStringPattern;
import org.overture.ast.patterns.ATuplePattern;
import org.overture.ast.patterns.AUnionPattern;
import org.overture.ast.patterns.PPattern;
import org.overture.ast.typechecker.NameScope;
import org.overture.ast.types.AClassType;
import org.overture.ast.types.AFieldField;
import org.overture.ast.types.AProductType;
import org.overture.ast.types.ARecordInvariantType;
import org.overture.ast.types.SSetType;
import org.overture.ast.types.PType;
import org.overture.ast.types.SMapType;
import org.overture.typechecker.TypeCheckerErrors;
import org.overture.typechecker.assistant.ITypeCheckerAssistantFactory;
import org.overture.typechecker.assistant.definition.PDefinitionAssistantTC;
import org.overture.typechecker.assistant.type.PTypeAssistantTC;
/**
* Get a complete list of all definitions, including duplicates. This method should only be used only by PP
*
* @author gkanos
*/
public class AllDefinitionLocator
extends
QuestionAnswerAdaptor<AllDefinitionLocator.NewQuestion, List<PDefinition>>
{
public static class NewQuestion
{
PType ptype;
NameScope scope;
public NewQuestion(PType ptype, NameScope scope)
{
this.ptype = ptype;
this.scope = scope;
}
}
protected ITypeCheckerAssistantFactory af;
public AllDefinitionLocator(ITypeCheckerAssistantFactory af)
{
this.af = af;
}
@Override
public List<PDefinition> caseAIdentifierPattern(AIdentifierPattern pattern,
NewQuestion question) throws AnalysisException
{
List<PDefinition> defs = new ArrayList<PDefinition>();
defs.add(AstFactory.newALocalDefinition(pattern.getLocation(), pattern.getName().clone(), question.scope, question.ptype));
return defs;
}
@Override
public List<PDefinition> caseABooleanPattern(ABooleanPattern pattern,
NewQuestion question) throws AnalysisException
{
return new Vector<PDefinition>();
}
@Override
public List<PDefinition> caseACharacterPattern(ACharacterPattern pattern,
NewQuestion question) throws AnalysisException
{
return new Vector<PDefinition>();
}
@Override
public List<PDefinition> caseAExpressionPattern(AExpressionPattern pattern,
NewQuestion question) throws AnalysisException
{
return new Vector<PDefinition>();
}
@Override
public List<PDefinition> caseAIgnorePattern(AIgnorePattern pattern,
NewQuestion question) throws AnalysisException
{
return new Vector<PDefinition>();
}
@Override
public List<PDefinition> caseAIntegerPattern(AIntegerPattern pattern,
NewQuestion question) throws AnalysisException
{
return new Vector<PDefinition>();
}
@Override
public List<PDefinition> caseANilPattern(ANilPattern pattern,
NewQuestion question) throws AnalysisException
{
return new Vector<PDefinition>();
}
@Override
public List<PDefinition> caseAQuotePattern(AQuotePattern pattern,
NewQuestion question) throws AnalysisException
{
return new Vector<PDefinition>();
}
@Override
public List<PDefinition> caseARealPattern(ARealPattern node,
NewQuestion question) throws AnalysisException
{
return new Vector<PDefinition>();
}
@Override
public List<PDefinition> caseAStringPattern(AStringPattern pattern,
NewQuestion question) throws AnalysisException
{
return new Vector<PDefinition>();
}
@Override
public List<PDefinition> caseAConcatenationPattern(
AConcatenationPattern pattern, NewQuestion question)
throws AnalysisException
{
List<PDefinition> list = af.createPPatternAssistant().getDefinitions(pattern.getLeft(), question.ptype, question.scope);
list.addAll(af.createPPatternAssistant().getDefinitions(pattern.getRight(), question.ptype, question.scope));
return list;
}
@Override
public List<PDefinition> caseARecordPattern(ARecordPattern pattern,
NewQuestion question) throws AnalysisException
{
List<PDefinition> defs = new Vector<PDefinition>();
PType type = pattern.getType();
if (!af.createPTypeAssistant().isTag(type)) //.isRecord(type))
{
TypeCheckerErrors.report(3200, "Mk_ expression is not a record type", pattern.getLocation(), pattern);
TypeCheckerErrors.detail("Type", type);
return defs;
}
ARecordInvariantType pattype = af.createPTypeAssistant().getRecord(type);
PType using = af.createPTypeAssistant().isType(question.ptype, pattype.getName().getFullName());
if (using == null || !(using instanceof ARecordInvariantType))
{
TypeCheckerErrors.report(3201, "Matching expression is not a compatible record type", pattern.getLocation(), pattern);
TypeCheckerErrors.detail2("Pattern type", type, "Expression type", question.ptype);
return defs;
}
// RecordType usingrec = (RecordType)using;
if (pattype.getFields().size() != pattern.getPlist().size())
{
TypeCheckerErrors.report(3202, "Record pattern argument/field count mismatch", pattern.getLocation(), pattern);
} else
{
Iterator<AFieldField> patfi = pattype.getFields().iterator();
for (PPattern p : pattern.getPlist())
{
AFieldField pf = patfi.next();
// defs.addAll(p.getDefinitions(usingrec.findField(pf.tag).type, scope));
defs.addAll(af.createPPatternAssistant().getDefinitions(p, pf.getType(), question.scope));
}
}
return defs;
}
@Override
public List<PDefinition> caseASeqPattern(ASeqPattern pattern,
NewQuestion question) throws AnalysisException
{
List<PDefinition> defs = new Vector<PDefinition>();
if (!af.createPTypeAssistant().isSeq(question.ptype))
{
TypeCheckerErrors.report(3203, "Sequence pattern is matched against "
+ question.ptype, pattern.getLocation(), pattern);
} else
{
PType elem = af.createPTypeAssistant().getSeq(question.ptype).getSeqof();
for (PPattern p : pattern.getPlist())
{
defs.addAll(af.createPPatternAssistant().getDefinitions(p, elem, question.scope));
}
}
return defs;
}
@Override
public List<PDefinition> caseASetPattern(ASetPattern pattern,
NewQuestion question) throws AnalysisException
{
// return ASetPatternAssistantTC.getAllDefinitions(pattern, question.ptype, question.scope);
List<PDefinition> defs = new Vector<PDefinition>();
if (!af.createPTypeAssistant().isSet(question.ptype))
{
TypeCheckerErrors.report(3204, "Set pattern is not matched against set type", pattern.getLocation(), pattern);
TypeCheckerErrors.detail("Actual type", question.ptype);
} else
{
SSetType set = af.createPTypeAssistant().getSet(question.ptype);
if (!set.getEmpty())
{
for (PPattern p : pattern.getPlist())
{
defs.addAll(af.createPPatternAssistant().getDefinitions(p, set.getSetof(), question.scope));
}
}
}
return defs;
}
@Override
public List<PDefinition> caseATuplePattern(ATuplePattern pattern,
NewQuestion question) throws AnalysisException
{
List<PDefinition> defs = new Vector<PDefinition>();
if (!af.createPTypeAssistant().isProduct(question.ptype, pattern.getPlist().size()))
{
TypeCheckerErrors.report(3205, "Matching expression is not a product of cardinality "
+ pattern.getPlist().size(), pattern.getLocation(), pattern);
TypeCheckerErrors.detail("Actual", question.ptype);
return defs;
}
AProductType product = af.createPTypeAssistant().getProduct(question.ptype, pattern.getPlist().size());
Iterator<PType> ti = product.getTypes().iterator();
for (PPattern p : pattern.getPlist())
{
defs.addAll(af.createPPatternAssistant().getDefinitions(p, ti.next(), question.scope));
}
return defs;
}
@Override
public List<PDefinition> caseAUnionPattern(AUnionPattern pattern,
NewQuestion question) throws AnalysisException
{
List<PDefinition> defs = new Vector<PDefinition>();
if (!af.createPTypeAssistant().isSet(question.ptype))
{
TypeCheckerErrors.report(3206, "Matching expression is not a set type", pattern.getLocation(), pattern);
}
defs.addAll(af.createPPatternAssistant().getDefinitions(pattern.getLeft(), question.ptype, question.scope));
defs.addAll(af.createPPatternAssistant().getDefinitions(pattern.getRight(), question.ptype, question.scope));
return defs;
}
@Override
public List<PDefinition> caseAMapUnionPattern(AMapUnionPattern pattern,
NewQuestion question) throws AnalysisException
{
List<PDefinition> defs = new Vector<PDefinition>();
if (!af.createPTypeAssistant().isMap(question.ptype))
{
TypeCheckerErrors.report(3315, "Matching expression is not a map type", pattern.getLocation(), pattern);
}
defs.addAll(af.createPPatternAssistant().getDefinitions(pattern.getLeft(), question.ptype, question.scope));
defs.addAll(af.createPPatternAssistant().getDefinitions(pattern.getRight(), question.ptype, question.scope));
return defs;
}
@Override
public List<PDefinition> caseAMapPattern(AMapPattern pattern,
NewQuestion question) throws AnalysisException
{
List<PDefinition> defs = new Vector<PDefinition>();
if (!af.createPTypeAssistant().isMap(question.ptype))
{
TypeCheckerErrors.report(3314, "Map pattern is not matched against map type", pattern.getLocation(), pattern);
TypeCheckerErrors.detail("Actual type", question.ptype);
} else
{
SMapType map = af.createPTypeAssistant().getMap(question.ptype);
if (!map.getEmpty())
{
for (AMapletPatternMaplet p : pattern.getMaplets())
{
defs.addAll(getDefinitions(p, map, question.scope));
// defs.addAll(p.apply(THIS, question));
}
}
}
return defs;
}
@Override
public List<PDefinition> caseAObjectPattern(AObjectPattern pattern,
NewQuestion question) throws AnalysisException
{
List<PDefinition> defs = new Vector<PDefinition>();
PTypeAssistantTC typeAssistant = af.createPTypeAssistant();
AClassType pattype = typeAssistant.getClassType(pattern.getType(), null);
AClassType exptype = typeAssistant.getClassType(question.ptype, null);
if (exptype == null || !af.getTypeComparator().isSubType(pattype, exptype))
{
TypeCheckerErrors.report(3333, "Matching expression is not a compatible object type", pattern.getLocation(), question.ptype);
TypeCheckerErrors.detail2("Pattern type", pattype, "Expression type", exptype);
return defs;
}
SClassDefinition classdef = pattype.getClassdef();
PDefinitionAssistantTC definitionAssistant = af.createPDefinitionAssistant();
for (ANamePatternPair npp: pattern.getFields())
{
PDefinition d = definitionAssistant.findName(classdef, npp.getName(), NameScope.STATE); // NB. state lookup
if (d != null)
{
d = definitionAssistant.deref(d);
}
if (d instanceof AInstanceVariableDefinition)
{
defs.addAll(af.createPPatternAssistant().getDefinitions(npp.getPattern(), d.getType(), NameScope.LOCAL));
}
else
{
TypeCheckerErrors.report(3334, npp.getName().getName() + " is not a matchable field of class " + pattype, npp.getName().getLocation(), npp.getName());
}
}
return defs;
}
@Override
public List<PDefinition> createNewReturnValue(INode node,
NewQuestion question) throws AnalysisException
{
assert false : "PPatternAssistant.getDefinitions - should not hit this case";
return null;
}
@Override
public List<PDefinition> createNewReturnValue(Object node,
NewQuestion question) throws AnalysisException
{
assert false : "PPatternAssistant.getDefinitions - should not hit this case";
return null;
}
public Collection<? extends PDefinition> getDefinitions(
AMapletPatternMaplet p, SMapType map, NameScope scope) {
List<PDefinition> list = new Vector<PDefinition>();
list.addAll(af.createPPatternAssistant().getDefinitions(p.getFrom(),
map.getFrom(), scope));
list.addAll(af.createPPatternAssistant().getDefinitions(p.getTo(),
map.getTo(), scope));
return list;
}
}