package org.example.expressions.validation;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.xtext.validation.Check;
import org.example.expressions.expressions.And;
import org.example.expressions.expressions.Comparison;
import org.example.expressions.expressions.Equality;
import org.example.expressions.expressions.Expression;
import org.example.expressions.expressions.ExpressionsPackage;
import org.example.expressions.expressions.Minus;
import org.example.expressions.expressions.MulOrDiv;
import org.example.expressions.expressions.Not;
import org.example.expressions.expressions.Or;
import org.example.expressions.expressions.Plus;
import org.example.expressions.expressions.Variable;
import org.example.expressions.expressions.VariableRef;
import org.example.expressions.typing.ExpressionsModelUtil;
import org.example.expressions.typing.ExpressionsType;
import org.example.expressions.typing.ExpressionsTypeProvider;
import com.google.inject.Inject;
public class ExpressionsJavaValidator extends AbstractExpressionsJavaValidator {
public static final String FORWARD_REFERENCE = "org.example.expressions.ForwardReference";
public static final String WRONG_TYPE = "org.example.expressions.WrongType";
@Inject
private ExpressionsTypeProvider typeProvider;
@Check
public void checkForwardReference(VariableRef varRef) {
Variable variable = varRef.getVariable();
if (variable == null)
return; // it is a linking error (reported elsewhere)
if (!ExpressionsModelUtil.variablesDefinedBefore(varRef).contains(
variable)) {
error("variable forward reference not allowed: '"
+ variable.getName() + "'",
ExpressionsPackage.Literals.VARIABLE_REF__VARIABLE,
FORWARD_REFERENCE, variable.getName());
}
}
@Check
public void checkType(Not not) {
checkExpectedBoolean(not.getExpression(),
ExpressionsPackage.Literals.NOT__EXPRESSION);
}
@Check
public void checkType(MulOrDiv mulOrDiv) {
checkExpectedInt(mulOrDiv.getLeft(),
ExpressionsPackage.Literals.MUL_OR_DIV__LEFT);
checkExpectedInt(mulOrDiv.getRight(),
ExpressionsPackage.Literals.MUL_OR_DIV__RIGHT);
}
@Check
public void checkType(Minus minus) {
checkExpectedInt(minus.getLeft(),
ExpressionsPackage.Literals.MINUS__LEFT);
checkExpectedInt(minus.getRight(),
ExpressionsPackage.Literals.MINUS__RIGHT);
}
@Check
public void checkType(And and) {
checkExpectedBoolean(and.getLeft(),
ExpressionsPackage.Literals.AND__LEFT);
checkExpectedBoolean(and.getRight(),
ExpressionsPackage.Literals.AND__RIGHT);
}
@Check
public void checkType(Or or) {
checkExpectedBoolean(or.getLeft(), ExpressionsPackage.Literals.OR__LEFT);
checkExpectedBoolean(or.getRight(),
ExpressionsPackage.Literals.OR__RIGHT);
}
@Check
public void checkType(Equality equality) {
ExpressionsType left = getTypeAndCheckNotNull(equality.getLeft(),
ExpressionsPackage.Literals.EQUALITY__LEFT);
ExpressionsType right = getTypeAndCheckNotNull(equality.getRight(),
ExpressionsPackage.Literals.EQUALITY__RIGHT);
checkExpectedSame(left, right);
}
@Check
public void checkType(Comparison comparison) {
ExpressionsType left = getTypeAndCheckNotNull(comparison.getLeft(),
ExpressionsPackage.Literals.COMPARISON__LEFT);
ExpressionsType right = getTypeAndCheckNotNull(comparison.getRight(),
ExpressionsPackage.Literals.COMPARISON__RIGHT);
checkExpectedSame(left, right);
checkNotBoolean(left, ExpressionsPackage.Literals.COMPARISON__LEFT);
checkNotBoolean(right, ExpressionsPackage.Literals.COMPARISON__RIGHT);
}
@Check
public void checkType(Plus plus) {
ExpressionsType left = getTypeAndCheckNotNull(plus.getLeft(),
ExpressionsPackage.Literals.PLUS__LEFT);
ExpressionsType right = getTypeAndCheckNotNull(plus.getRight(),
ExpressionsPackage.Literals.PLUS__RIGHT);
if (left == ExpressionsTypeProvider.intType
|| right == ExpressionsTypeProvider.intType
|| (left != ExpressionsTypeProvider.stringType && right != ExpressionsTypeProvider.stringType)) {
checkNotBoolean(left, ExpressionsPackage.Literals.PLUS__LEFT);
checkNotBoolean(right, ExpressionsPackage.Literals.PLUS__RIGHT);
}
}
private void checkExpectedSame(ExpressionsType left, ExpressionsType right) {
if (right != null && left != null && right != left) {
error("expected the same type, but was " + left + ", " + right,
ExpressionsPackage.Literals.EQUALITY.getEIDAttribute(),
WRONG_TYPE);
}
}
private void checkNotBoolean(ExpressionsType type, EReference reference) {
if (type == ExpressionsTypeProvider.boolType) {
error("cannot be boolean", reference, WRONG_TYPE);
}
}
private void checkExpectedBoolean(Expression exp, EReference reference) {
checkExpectedType(exp, ExpressionsTypeProvider.boolType, reference);
}
private void checkExpectedInt(Expression exp, EReference reference) {
checkExpectedType(exp, ExpressionsTypeProvider.intType, reference);
}
private void checkExpectedType(Expression exp,
ExpressionsType expectedType, EReference reference) {
ExpressionsType actualType = getTypeAndCheckNotNull(exp, reference);
if (actualType != expectedType)
error("expected " + expectedType + " type, but was " + actualType,
reference, WRONG_TYPE);
}
private ExpressionsType getTypeAndCheckNotNull(Expression exp,
EReference reference) {
ExpressionsType type = null;
if (exp != null)
type = typeProvider.typeFor(exp);
if (type == null)
error("null type", reference, WRONG_TYPE);
return type;
}
}