Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,41 +1,20 @@
package fr.inria.corese.core.next.query.impl.parser.semantic.rule;

import fr.inria.corese.core.next.data.impl.common.vocabulary.XSD;
import fr.inria.corese.core.next.query.api.validation.QueryDiagnostic;
import fr.inria.corese.core.next.query.impl.parser.semantic.support.AbstractAstVisitor;
import fr.inria.corese.core.next.query.impl.sparql.ast.*;
import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static fr.inria.corese.core.next.query.impl.parser.semantic.support.SemanticValidationUtils.*;

/**
* Validates that FILTER and HAVING expressions are compatible with SPARQL
* effective boolean value evaluation.
*/
public final class FilterArgumentsValidationRule extends AbstractSemanticValidationRule {

private static final String BOOLEAN_DATATYPE = XSD.xsdBoolean.getIRI().stringValue();
private static final String STRING_DATATYPE = XSD.xsdString.getIRI().stringValue();
private static final Set<String> NUMERIC_DATATYPES = Set.of(
XSD.xsdInteger.getIRI().stringValue(),
XSD.xsdNonNegativeInteger.getIRI().stringValue(),
XSD.xsdNonPositiveInteger.getIRI().stringValue(),
XSD.xsdPositiveInteger.getIRI().stringValue(),
XSD.xsdNegativeInteger.getIRI().stringValue(),
XSD.xsdInt.getIRI().stringValue(),
XSD.xsdUnsignedInt.getIRI().stringValue(),
XSD.xsdLong.getIRI().stringValue(),
XSD.xsdUnsignedLong.getIRI().stringValue(),
XSD.xsdDecimal.getIRI().stringValue(),
XSD.xsdShort.getIRI().stringValue(),
XSD.xsdUnsignedShort.getIRI().stringValue(),
XSD.xsdByte.getIRI().stringValue(),
XSD.xsdUnsignedByte.getIRI().stringValue(),
XSD.xsdFloat.getIRI().stringValue(),
XSD.xsdDouble.getIRI().stringValue());

@Override
protected String getDiagnosticSource() {
return FilterArgumentsValidationRule.class.getSimpleName();
Expand All @@ -48,52 +27,6 @@ public List<QueryDiagnostic> validate(QueryAst queryAst) {
return visitor.getResult();
}

/**
* Checks whether the given term is statically compatible with SPARQL
* effective boolean value evaluation.
*/
private static boolean isPotentiallyEbvCompatible(TermAst termAst) {
if (termAst instanceof BooleanExpressionAst
|| termAst instanceof NumericExpressionAst
|| termAst instanceof VarAst
|| termAst instanceof FunctionCallAst
|| termAst instanceof UnlimitedArgumentsFunctionAst) {
return true;
}

if (termAst instanceof LiteralAst literalAst) {
return isEbvCompatibleLiteral(literalAst);
}

if (termAst instanceof IfAst(TermAst condition, TermAst thenExpr, TermAst elseExpr)) {
return isPotentiallyEbvCompatible(condition)
&& isPotentiallyEbvCompatible(thenExpr)
&& isPotentiallyEbvCompatible(elseExpr);
}

if (termAst instanceof LiteralExpressionAst literalExpressionAst) {
return !(literalExpressionAst instanceof XsdDateTimeExpressionAst
|| literalExpressionAst instanceof XsdDayTimeDurationExpressionAst);
}

return false;
}

private static boolean isEbvCompatibleLiteral(LiteralAst literalAst) {
if (literalAst.lang() != null && !literalAst.lang().isBlank()) {
return true;
}

String datatype = literalAst.datatype();
if (datatype == null) {
return true;
}

return BOOLEAN_DATATYPE.equals(datatype)
|| STRING_DATATYPE.equals(datatype)
|| NUMERIC_DATATYPES.contains(datatype);
}

private class FilterArgumentsValidationVisitor extends AbstractAstVisitor {
private final List<QueryDiagnostic> result = new ArrayList<>();

Expand All @@ -103,15 +36,15 @@ public List<QueryDiagnostic> getResult() {

@Override
public void visit(PatternAst patternAst) {
if (patternAst instanceof FilterAst(TermAst operator) && !isPotentiallyEbvCompatible(operator)) {
if (patternAst instanceof FilterAst(TermAst operator) && !isPotentialBooleanCompatible(operator)) {
result.add(buildIncorrectTypeDiagnostic(operator.getName(), "FILTER", "boolean"));
}
}

@Override
public void visit(HavingAst havingAst) {
for (TermAst condition : havingAst.conditions()) {
if (!isPotentiallyEbvCompatible(condition)) {
if (!isPotentialBooleanCompatible(condition)) {
result.add(buildIncorrectTypeDiagnostic(condition.getName(), "HAVING", "boolean"));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package fr.inria.corese.core.next.query.impl.parser.semantic.rule;

import fr.inria.corese.core.next.query.api.validation.QueryDiagnostic;
import fr.inria.corese.core.next.query.impl.parser.semantic.support.AbstractAstVisitor;
import fr.inria.corese.core.next.query.impl.sparql.ast.QueryAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.AndAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.BinaryConstraintAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.BooleanNotAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.OrAst;

import java.util.ArrayList;
import java.util.List;

import static fr.inria.corese.core.next.query.impl.parser.semantic.support.SemanticValidationUtils.isPotentialBooleanCompatible;


public class OperandArgumentBooleanTypeValidationRule extends AbstractSemanticValidationRule {
private static final String BOOLEAN_TYPE = "boolean";

@Override
protected String getDiagnosticSource() {
return OperandArgumentBooleanTypeValidationRule.class.getSimpleName();
}

@Override
public List<QueryDiagnostic> validate(QueryAst queryAst) {
OperandBooleanArgumentTypeVisitor visitor = new OperandBooleanArgumentTypeVisitor();
queryAst.accept(visitor);
return visitor.getResult();
}

private class OperandBooleanArgumentTypeVisitor extends AbstractAstVisitor {
private final List<QueryDiagnostic> result = new ArrayList<>();

public List<QueryDiagnostic> getResult() {
return result;
}

@Override
public void visit(TermAst termAst) {
if (termAst instanceof BooleanNotAst booleanNotAst
&& !isPotentialBooleanCompatible(booleanNotAst.argument())) {
result.add(buildIncorrectTypeDiagnostic(
booleanNotAst.argument().getName(),
booleanNotAst.getName(),
BOOLEAN_TYPE));
}

if (termAst instanceof BinaryConstraintAst binaryConstraintAst
&& (binaryConstraintAst instanceof AndAst || binaryConstraintAst instanceof OrAst)) {
if (!isPotentialBooleanCompatible(binaryConstraintAst.getLeftArgument())) {
result.add(buildIncorrectTypeDiagnostic(
binaryConstraintAst.getLeftArgument().getName(),
binaryConstraintAst.getName(),
BOOLEAN_TYPE));
}
if (!isPotentialBooleanCompatible(binaryConstraintAst.getRightArgument())) {
result.add(buildIncorrectTypeDiagnostic(
binaryConstraintAst.getRightArgument().getName(),
binaryConstraintAst.getName(),
BOOLEAN_TYPE));
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package fr.inria.corese.core.next.query.impl.parser.semantic.rule;

import fr.inria.corese.core.next.query.api.validation.QueryDiagnostic;
import fr.inria.corese.core.next.query.impl.parser.semantic.support.AbstractAstVisitor;
import fr.inria.corese.core.next.query.impl.sparql.ast.QueryAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.*;

import java.util.ArrayList;
import java.util.List;

import static fr.inria.corese.core.next.query.impl.parser.semantic.support.SemanticValidationUtils.isPotentialIri;

/**
* Check that the comparison operand do not compare IRIs (except for the different != operator)
*/
public class OperandArgumentIRITypeValidationRule extends AbstractSemanticValidationRule {

@Override
protected String getDiagnosticSource() {
return OperandArgumentIRITypeValidationRule.class.getSimpleName();
}

@Override
public List<QueryDiagnostic> validate(QueryAst queryAst) {
OperandIRIArgumentTypeVisitor visitor = new OperandIRIArgumentTypeVisitor();
queryAst.accept(visitor);
return visitor.getResult();
}

private class OperandIRIArgumentTypeVisitor extends AbstractAstVisitor {
private final List<QueryDiagnostic> result = new ArrayList<>();

public List<QueryDiagnostic> getResult() {
return result;
}

@Override
public void visit(TermAst termAst) {
if (termAst instanceof BinaryConstraintAst binaryConstraintAst
&& (binaryConstraintAst instanceof LowerThanAst
|| binaryConstraintAst instanceof LowerOrEqualThanAst
|| binaryConstraintAst instanceof GreaterThanAst
|| binaryConstraintAst instanceof GreaterOrEqualThanAst)) {
if (isPotentialIri(binaryConstraintAst.getLeftArgument())) {
result.add(buildIncorrectTypeDiagnostic(
binaryConstraintAst.getLeftArgument().getName(),
binaryConstraintAst.getName(),
"not an IRI"));
}
if (isPotentialIri(binaryConstraintAst.getRightArgument())) {
result.add(buildIncorrectTypeDiagnostic(
binaryConstraintAst.getRightArgument().getName(),
binaryConstraintAst.getName(),
"not an IRI"));
}
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package fr.inria.corese.core.next.query.impl.parser.semantic.rule;

import fr.inria.corese.core.next.query.api.validation.QueryDiagnostic;
import fr.inria.corese.core.next.query.impl.parser.semantic.support.AbstractAstVisitor;
import fr.inria.corese.core.next.query.impl.sparql.ast.QueryAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.*;

import java.util.ArrayList;
import java.util.List;

import static fr.inria.corese.core.next.query.impl.parser.semantic.support.SemanticValidationUtils.isPotentialNumeric;

/**
* Check that the operands and numeric functions use numeric arguments
*/
public final class OperandArgumentNumericTypeValidationRule extends AbstractSemanticValidationRule {
private static final String NUMERIC_TYPE = "numeric";

@Override
protected String getDiagnosticSource() {
return OperandArgumentNumericTypeValidationRule.class.getSimpleName();
}

@Override
public List<QueryDiagnostic> validate(QueryAst queryAst) {
OperandNumericArgumentTypeVisitor visitor = new OperandNumericArgumentTypeVisitor();
queryAst.accept(visitor);
return visitor.getResult();
}

private class OperandNumericArgumentTypeVisitor extends AbstractAstVisitor {
private final List<QueryDiagnostic> result = new ArrayList<>();

public List<QueryDiagnostic> getResult() {
return result;
}

@Override
public void visit(TermAst termAst) {
if (termAst instanceof UnaryConstraintAst unaryConstraintAst
&& (unaryConstraintAst instanceof AbsAst
|| unaryConstraintAst instanceof CeilAst
|| unaryConstraintAst instanceof FloorAst
|| unaryConstraintAst instanceof RoundAst
|| unaryConstraintAst instanceof UnaryMinusAst
|| unaryConstraintAst instanceof UnaryPlusAst)
&& !isPotentialNumeric(unaryConstraintAst.argument())) {
result.add(buildIncorrectTypeDiagnostic(
unaryConstraintAst.argument().getName(),
unaryConstraintAst.getName(),
NUMERIC_TYPE));
}

if (termAst instanceof BinaryConstraintAst binaryConstraintAst
&& (binaryConstraintAst instanceof AddAst
|| binaryConstraintAst instanceof DivideAst
|| binaryConstraintAst instanceof MultiplyAst
|| binaryConstraintAst instanceof SubtractAst)) {
if (!isPotentialNumeric(binaryConstraintAst.getLeftArgument())) {
result.add(buildIncorrectTypeDiagnostic(
binaryConstraintAst.getLeftArgument().getName(),
binaryConstraintAst.getName(),
NUMERIC_TYPE));
}
if (!isPotentialNumeric(binaryConstraintAst.getRightArgument())) {
result.add(buildIncorrectTypeDiagnostic(
binaryConstraintAst.getRightArgument().getName(),
binaryConstraintAst.getName(),
NUMERIC_TYPE));
}
}
}
}
}
Loading
Loading