package org.yakindu.base.types.validation; import static org.yakindu.base.types.inferrer.AbstractTypeSystemInferrer.ASSERT_COMPATIBLE; import static org.yakindu.base.types.inferrer.AbstractTypeSystemInferrer.ASSERT_NOT_TYPE; import static org.yakindu.base.types.inferrer.AbstractTypeSystemInferrer.ASSERT_SAME; import static org.yakindu.base.types.inferrer.ITypeSystemInferrer.NOT_COMPATIBLE_CODE; import static org.yakindu.base.types.inferrer.ITypeSystemInferrer.NOT_SAME_CODE; import static org.yakindu.base.types.inferrer.ITypeSystemInferrer.NOT_TYPE_CODE; import java.util.ArrayList; import java.util.List; import org.yakindu.base.types.ComplexType; import org.yakindu.base.types.inferrer.ITypeSystemInferrer.InferenceResult; import org.yakindu.base.types.typesystem.ITypeSystem; import com.google.inject.Inject; public class TypeValidator { @Inject protected ITypeSystem registry; public List<TypeValidationError> assertNotType(InferenceResult currentResult, String msg, InferenceResult... candidates) { List<TypeValidationError> errors = new ArrayList<>(); if (currentResult == null) return errors; for (InferenceResult type : candidates) { if (registry.isSame(currentResult.getType(), type.getType())) { msg = msg != null ? msg : String.format(ASSERT_NOT_TYPE, currentResult); errors.add(new TypeValidationError(msg, NOT_TYPE_CODE)); } } return errors; } public List<TypeValidationError> assertSame(InferenceResult result1, InferenceResult result2, String msg) { List<TypeValidationError> errors = new ArrayList<>(); if (result1 == null || result2 == null) return errors; if (!registry.isSame(result1.getType(), result2.getType())) { msg = msg != null ? msg : String.format(ASSERT_SAME, result1, result2); errors.add(new TypeValidationError(msg, NOT_SAME_CODE)); return errors; } return assertTypeBindingsSame(result1, result2, msg); } public List<TypeValidationError> assertCompatible(InferenceResult result1, InferenceResult result2, String msg) { List<TypeValidationError> errors = new ArrayList<>(); if (result1 == null || result2 == null) return errors; if (isNullOnComplexType(result1, result2) || isNullOnComplexType(result2, result1)) { return errors; } if (!registry.haveCommonType(result1.getType(), result2.getType())) { msg = msg != null ? msg : String.format(ASSERT_COMPATIBLE, result1, result2); errors.add(new TypeValidationError(msg, NOT_COMPATIBLE_CODE)); return errors; } return assertTypeBindingsSame(result1, result2, msg); } public List<TypeValidationError> assertAssignable(InferenceResult varResult, InferenceResult valueResult, String msg) { List<TypeValidationError> errors = new ArrayList<>(); if (varResult == null || valueResult == null) return errors; if (isNullOnComplexType(varResult, valueResult)) { return errors; } if (!registry.isSuperType(valueResult.getType(), varResult.getType())) { msg = msg != null ? msg : String.format(ASSERT_COMPATIBLE, varResult, valueResult); errors.add(new TypeValidationError(msg, NOT_COMPATIBLE_CODE)); return errors; } return assertTypeBindingsSame(varResult, valueResult, msg); } public List<TypeValidationError> assertTypeBindingsSame(InferenceResult result1, InferenceResult result2, String msg) { List<TypeValidationError> errors = new ArrayList<>(); List<InferenceResult> bindings1 = result1.getBindings(); List<InferenceResult> bindings2 = result2.getBindings(); msg = msg != null ? msg : String.format(ASSERT_COMPATIBLE, result1, result2); if (bindings1.size() != bindings2.size()) { errors.add(new TypeValidationError(msg, NOT_COMPATIBLE_CODE)); return errors; } for (int i = 0; i < bindings1.size(); i++) { errors.addAll(assertSame(bindings1.get(i), bindings2.get(i), msg)); } return errors; } public List<TypeValidationError> assertIsSubType(InferenceResult subResult, InferenceResult superResult, String msg) { List<TypeValidationError> errors = new ArrayList<>(); if (subResult == null || superResult == null) return errors; if (!registry.isSuperType(subResult.getType(), superResult.getType())) { msg = msg != null ? msg : String.format(ASSERT_COMPATIBLE, subResult, superResult); errors.add(new TypeValidationError(msg, NOT_COMPATIBLE_CODE)); return errors; } return errors; } public boolean isNullOnComplexType(InferenceResult result1, InferenceResult result2) { return result1.getType() instanceof ComplexType && registry.isSame(result2.getType(), registry.getType(ITypeSystem.NULL)); } }