package org.uva.student.calinwouter.qlqls.ql;
import org.uva.student.calinwouter.qlqls.generated.node.AForm;
import org.uva.student.calinwouter.qlqls.ql.interfaces.ITypeDescriptor;
import org.uva.student.calinwouter.qlqls.ql.model.AbstractStaticFormField;
import org.uva.student.calinwouter.qlqls.ql.model.QLTypeCheckResults;
import org.uva.student.calinwouter.qlqls.ql.model.StaticFields;
import org.uva.student.calinwouter.qlqls.ql.typechecker.PFormTypeChecker;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* This type checker checks:
*
* - Reference to undefined questions
* - Duplicate question declarations with different types
* - Conditions that are not of the type boolean
* - Operands of invalid type to operators
* - Cyclic dependencies between questions
* - Duplicate labels (warning)
*/
public class QLTypeChecker {
private final AForm aForm;
private final StaticFields staticFields;
private final QLTypeCheckResults QLTypeCheckResults;
private void collectDuplicateLabels() {
final Set<String> labels = new HashSet<String>();
for (AbstractStaticFormField abstractStaticFormField : staticFields) {
final String fieldLabel = abstractStaticFormField.getLabel();
if (!labels.add(fieldLabel)) {
QLTypeCheckResults.addLabelFoundTwiceWarning(fieldLabel);
}
}
}
private void checkSameType(Map<String, ITypeDescriptor> identifierToTypeMap, AbstractStaticFormField toCheck) {
final String toCheckVariable = toCheck.getVariable();
final ITypeDescriptor earlierFoundValueType = identifierToTypeMap.get(toCheckVariable);
final ITypeDescriptor toCheckType = toCheck.getTypeDescriptor();
if (!earlierFoundValueType.equals(toCheckType)) {
QLTypeCheckResults.addTwoQuestionsSameTypeError(toCheckVariable);
}
}
private void putIfNotSet(Map<String, ITypeDescriptor> identifierToTypeMap, AbstractStaticFormField toPut) {
final String variableToPut = toPut.getVariable();
final ITypeDescriptor variableType = toPut.getTypeDescriptor();
if (!identifierToTypeMap.containsKey(variableToPut)) {
identifierToTypeMap.put(variableToPut, variableType);
}
}
private void collectDuplicateQuestionsWithDifferentTypes() {
final Map<String, ITypeDescriptor> identifierToTypeMap = new HashMap<String, ITypeDescriptor>();
for (AbstractStaticFormField abstractStaticFormField : staticFields) {
putIfNotSet(identifierToTypeMap, abstractStaticFormField);
checkSameType(identifierToTypeMap, abstractStaticFormField);
}
}
private void collectTypeCheckErrorsInDepth() {
final PFormTypeChecker formTypeChecker = new PFormTypeChecker(staticFields, QLTypeCheckResults);
aForm.apply(formTypeChecker);
}
public QLTypeCheckResults typeCheck() {
collectDuplicateQuestionsWithDifferentTypes();
collectDuplicateLabels();
collectTypeCheckErrorsInDepth();
return QLTypeCheckResults;
}
public QLTypeChecker(AForm aForm, StaticFields staticFields) {
this.aForm = aForm;
this.staticFields = staticFields;
this.QLTypeCheckResults = new QLTypeCheckResults();
}
private static StaticFields collectStaticFields(AForm aForm) {
return new QLStaticAnalyser(aForm).collectStaticFields();
}
public QLTypeChecker(AForm aForm) {
this(aForm, collectStaticFields(aForm));
}
}